summaryrefslogtreecommitdiffstats
path: root/src/multimedia
diff options
context:
space:
mode:
Diffstat (limited to 'src/multimedia')
-rw-r--r--src/multimedia/CMakeLists.txt373
-rw-r--r--src/multimedia/alsa/alsa.json3
-rw-r--r--src/multimedia/alsa/qalsaaudiodevice.cpp71
-rw-r--r--src/multimedia/alsa/qalsaaudiodevice_p.h49
-rw-r--r--src/multimedia/alsa/qalsaaudiosink.cpp698
-rw-r--r--src/multimedia/alsa/qalsaaudiosink_p.h121
-rw-r--r--src/multimedia/alsa/qalsaaudiosource.cpp770
-rw-r--r--src/multimedia/alsa/qalsaaudiosource_p.h142
-rw-r--r--src/multimedia/alsa/qalsamediadevices.cpp130
-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.cpp614
-rw-r--r--src/multimedia/android/qandroidaudiosink_p.h127
-rw-r--r--src/multimedia/android/qandroidaudiosource.cpp470
-rw-r--r--src/multimedia/android/qandroidaudiosource_p.h101
-rw-r--r--src/multimedia/android/qandroidmediadevices.cpp113
-rw-r--r--src/multimedia/android/qandroidmediadevices_p.h42
-rw-r--r--src/multimedia/android/qopenslesengine.cpp378
-rw-r--r--src/multimedia/android/qopenslesengine_p.h65
-rw-r--r--src/multimedia/audio/audio.pri50
-rw-r--r--src/multimedia/audio/qaudio.h88
-rw-r--r--src/multimedia/audio/qaudiobuffer.cpp511
-rw-r--r--src/multimedia/audio/qaudiobuffer.h230
-rw-r--r--src/multimedia/audio/qaudiobuffer_p.h96
-rw-r--r--src/multimedia/audio/qaudiobufferinput.cpp184
-rw-r--r--src/multimedia/audio/qaudiobufferinput.h48
-rw-r--r--src/multimedia/audio/qaudiobufferoutput.cpp78
-rw-r--r--src/multimedia/audio/qaudiobufferoutput.h37
-rw-r--r--src/multimedia/audio/qaudiobufferoutput_p.h42
-rw-r--r--src/multimedia/audio/qaudiodecoder.cpp345
-rw-r--r--src/multimedia/audio/qaudiodecoder.h85
-rw-r--r--src/multimedia/audio/qaudiodecoder_p.h40
-rw-r--r--src/multimedia/audio/qaudiodevice.cpp373
-rw-r--r--src/multimedia/audio/qaudiodevice.h84
-rw-r--r--src/multimedia/audio/qaudiodevice_p.h62
-rw-r--r--src/multimedia/audio/qaudiodevicefactory.cpp259
-rw-r--r--src/multimedia/audio/qaudiodevicefactory_p.h91
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo.cpp476
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo.h109
-rw-r--r--src/multimedia/audio/qaudioformat.cpp550
-rw-r--r--src/multimedia/audio/qaudioformat.h214
-rw-r--r--src/multimedia/audio/qaudiohelpers.cpp137
-rw-r--r--src/multimedia/audio/qaudiohelpers_p.h41
-rw-r--r--src/multimedia/audio/qaudioinput.cpp461
-rw-r--r--src/multimedia/audio/qaudioinput.h113
-rw-r--r--src/multimedia/audio/qaudiooutput.cpp490
-rw-r--r--src/multimedia/audio/qaudiooutput.h117
-rw-r--r--src/multimedia/audio/qaudioprobe.cpp205
-rw-r--r--src/multimedia/audio/qaudioprobe.h74
-rw-r--r--src/multimedia/audio/qaudiosink.cpp339
-rw-r--r--src/multimedia/audio/qaudiosink.h74
-rw-r--r--src/multimedia/audio/qaudiosource.cpp369
-rw-r--r--src/multimedia/audio/qaudiosource.h72
-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.cpp379
-rw-r--r--src/multimedia/audio/qaudiosystem.h138
-rw-r--r--src/multimedia/audio/qaudiosystem_p.h96
-rw-r--r--src/multimedia/audio/qaudiosystemplugin.cpp138
-rw-r--r--src/multimedia/audio/qaudiosystemplugin.h86
-rw-r--r--src/multimedia/audio/qaudiosystempluginext_p.h71
-rw-r--r--src/multimedia/audio/qsamplecache_p.cpp145
-rw-r--r--src/multimedia/audio/qsamplecache_p.h47
-rw-r--r--src/multimedia/audio/qsound.cpp244
-rw-r--r--src/multimedia/audio/qsound.h85
-rw-r--r--src/multimedia/audio/qsoundeffect.cpp574
-rw-r--r--src/multimedia/audio/qsoundeffect.h65
-rw-r--r--src/multimedia/audio/qsoundeffect_pulse_p.cpp1214
-rw-r--r--src/multimedia/audio/qsoundeffect_pulse_p.h188
-rw-r--r--src/multimedia/audio/qsoundeffect_qaudio_p.cpp457
-rw-r--r--src/multimedia/audio/qsoundeffect_qaudio_p.h151
-rw-r--r--src/multimedia/audio/qtaudio.cpp (renamed from src/multimedia/audio/qaudio.cpp)198
-rw-r--r--src/multimedia/audio/qtaudio.h18
-rw-r--r--src/multimedia/audio/qwavedecoder.cpp507
-rw-r--r--src/multimedia/audio/qwavedecoder.h115
-rw-r--r--src/multimedia/audio/qwavedecoder_p.cpp312
-rw-r--r--src/multimedia/audio/qwavedecoder_p.h133
-rw-r--r--src/multimedia/camera/camera.pri22
-rw-r--r--src/multimedia/camera/qcamera.cpp1789
-rw-r--r--src/multimedia/camera/qcamera.h427
-rw-r--r--src/multimedia/camera/qcamera_p.h130
-rw-r--r--src/multimedia/camera/qcameradevice.cpp470
-rw-r--r--src/multimedia/camera/qcameradevice.h104
-rw-r--r--src/multimedia/camera/qcameradevice_p.h75
-rw-r--r--src/multimedia/camera/qcameraexposure.cpp707
-rw-r--r--src/multimedia/camera/qcameraexposure.h195
-rw-r--r--src/multimedia/camera/qcamerafocus.cpp614
-rw-r--r--src/multimedia/camera/qcamerafocus.h177
-rw-r--r--src/multimedia/camera/qcameraimagecapture.cpp651
-rw-r--r--src/multimedia/camera/qcameraimagecapture.h161
-rw-r--r--src/multimedia/camera/qcameraimageprocessing.cpp401
-rw-r--r--src/multimedia/camera/qcameraimageprocessing.h139
-rw-r--r--src/multimedia/camera/qcamerainfo.cpp287
-rw-r--r--src/multimedia/camera/qcamerainfo.h84
-rw-r--r--src/multimedia/camera/qcameraviewfindersettings.cpp331
-rw-r--r--src/multimedia/camera/qcameraviewfindersettings.h104
-rw-r--r--src/multimedia/camera/qimagecapture.cpp548
-rw-r--r--src/multimedia/camera/qimagecapture.h135
-rw-r--r--src/multimedia/compat/removed_api.cpp16
-rw-r--r--src/multimedia/configure.cmake203
-rw-r--r--src/multimedia/configure.json300
-rw-r--r--src/multimedia/controls/controls.pri80
-rw-r--r--src/multimedia/controls/qaudiodecodercontrol.cpp267
-rw-r--r--src/multimedia/controls/qaudiodecodercontrol.h103
-rw-r--r--src/multimedia/controls/qaudioencodersettingscontrol.cpp140
-rw-r--r--src/multimedia/controls/qaudioencodersettingscontrol.h84
-rw-r--r--src/multimedia/controls/qaudioinputselectorcontrol.cpp131
-rw-r--r--src/multimedia/controls/qaudioinputselectorcontrol.h80
-rw-r--r--src/multimedia/controls/qaudiooutputselectorcontrol.cpp131
-rw-r--r--src/multimedia/controls/qaudiooutputselectorcontrol.h80
-rw-r--r--src/multimedia/controls/qaudiorolecontrol.cpp118
-rw-r--r--src/multimedia/controls/qaudiorolecontrol.h75
-rw-r--r--src/multimedia/controls/qcameracapturebufferformatcontrol.cpp113
-rw-r--r--src/multimedia/controls/qcameracapturebufferformatcontrol.h75
-rw-r--r--src/multimedia/controls/qcameracapturedestinationcontrol.cpp115
-rw-r--r--src/multimedia/controls/qcameracapturedestinationcontrol.h75
-rw-r--r--src/multimedia/controls/qcameracontrol.cpp205
-rw-r--r--src/multimedia/controls/qcameracontrol.h96
-rw-r--r--src/multimedia/controls/qcameraexposurecontrol.cpp207
-rw-r--r--src/multimedia/controls/qcameraexposurecontrol.h104
-rw-r--r--src/multimedia/controls/qcamerafeedbackcontrol.cpp182
-rw-r--r--src/multimedia/controls/qcamerafeedbackcontrol.h96
-rw-r--r--src/multimedia/controls/qcameraflashcontrol.cpp134
-rw-r--r--src/multimedia/controls/qcameraflashcontrol.h81
-rw-r--r--src/multimedia/controls/qcamerafocuscontrol.cpp198
-rw-r--r--src/multimedia/controls/qcamerafocuscontrol.h90
-rw-r--r--src/multimedia/controls/qcameraimagecapturecontrol.cpp195
-rw-r--r--src/multimedia/controls/qcameraimagecapturecontrol.h93
-rw-r--r--src/multimedia/controls/qcameraimageprocessingcontrol.cpp189
-rw-r--r--src/multimedia/controls/qcameraimageprocessingcontrol.h98
-rw-r--r--src/multimedia/controls/qcamerainfocontrol.cpp103
-rw-r--r--src/multimedia/controls/qcamerainfocontrol.h69
-rw-r--r--src/multimedia/controls/qcameralockscontrol.cpp128
-rw-r--r--src/multimedia/controls/qcameralockscontrol.h80
-rw-r--r--src/multimedia/controls/qcameraviewfindersettingscontrol.cpp206
-rw-r--r--src/multimedia/controls/qcameraviewfindersettingscontrol.h103
-rw-r--r--src/multimedia/controls/qcamerazoomcontrol.cpp188
-rw-r--r--src/multimedia/controls/qcamerazoomcontrol.h86
-rw-r--r--src/multimedia/controls/qcustomaudiorolecontrol.cpp119
-rw-r--r--src/multimedia/controls/qcustomaudiorolecontrol.h75
-rw-r--r--src/multimedia/controls/qimageencodercontrol.cpp137
-rw-r--r--src/multimedia/controls/qimageencodercontrol.h82
-rw-r--r--src/multimedia/controls/qmediaaudioprobecontrol.cpp103
-rw-r--r--src/multimedia/controls/qmediaaudioprobecontrol.h68
-rw-r--r--src/multimedia/controls/qmediaavailabilitycontrol.cpp109
-rw-r--r--src/multimedia/controls/qmediaavailabilitycontrol.h73
-rw-r--r--src/multimedia/controls/qmediacontainercontrol.cpp122
-rw-r--r--src/multimedia/controls/qmediacontainercontrol.h74
-rw-r--r--src/multimedia/controls/qmediagaplessplaybackcontrol.cpp157
-rw-r--r--src/multimedia/controls/qmediagaplessplaybackcontrol.h77
-rw-r--r--src/multimedia/controls/qmediaplayercontrol.cpp386
-rw-r--r--src/multimedia/controls/qmediaplayercontrol.h123
-rw-r--r--src/multimedia/controls/qmediaplaylistcontrol.cpp206
-rw-r--r--src/multimedia/controls/qmediaplaylistcontrol_p.h102
-rw-r--r--src/multimedia/controls/qmediaplaylistsourcecontrol.cpp126
-rw-r--r--src/multimedia/controls/qmediaplaylistsourcecontrol_p.h85
-rw-r--r--src/multimedia/controls/qmediarecordercontrol.cpp223
-rw-r--r--src/multimedia/controls/qmediarecordercontrol.h100
-rw-r--r--src/multimedia/controls/qmediastreamscontrol.cpp161
-rw-r--r--src/multimedia/controls/qmediastreamscontrol.h89
-rw-r--r--src/multimedia/controls/qmediavideoprobecontrol.cpp102
-rw-r--r--src/multimedia/controls/qmediavideoprobecontrol.h70
-rw-r--r--src/multimedia/controls/qmetadatareadercontrol.cpp149
-rw-r--r--src/multimedia/controls/qmetadatareadercontrol.h81
-rw-r--r--src/multimedia/controls/qmetadatawritercontrol.cpp169
-rw-r--r--src/multimedia/controls/qmetadatawritercontrol.h84
-rw-r--r--src/multimedia/controls/qvideodeviceselectorcontrol.cpp143
-rw-r--r--src/multimedia/controls/qvideodeviceselectorcontrol.h82
-rw-r--r--src/multimedia/controls/qvideoencodersettingscontrol.cpp161
-rw-r--r--src/multimedia/controls/qvideoencodersettingscontrol.h88
-rw-r--r--src/multimedia/controls/qvideorenderercontrol.cpp109
-rw-r--r--src/multimedia/controls/qvideorenderercontrol.h68
-rw-r--r--src/multimedia/controls/qvideowindowcontrol.cpp259
-rw-r--r--src/multimedia/controls/qvideowindowcontrol.h106
-rw-r--r--src/multimedia/darwin/qcoreaudiosessionmanager.mm437
-rw-r--r--src/multimedia/darwin/qcoreaudiosessionmanager_p.h95
-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.mm609
-rw-r--r--src/multimedia/darwin/qdarwinaudiosink_p.h170
-rw-r--r--src/multimedia/darwin/qdarwinaudiosource.mm942
-rw-r--r--src/multimedia/darwin/qdarwinaudiosource_p.h244
-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/qtmultimedia.qdocconf36
-rw-r--r--src/multimedia/doc/snippets/CMakeLists.txt15
-rw-r--r--src/multimedia/doc/snippets/doc_src_qtmultimedia.cpp53
-rw-r--r--src/multimedia/doc/snippets/doc_src_qtmultimedia.pro3
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/audio.cpp118
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/audiorecorder.cpp211
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/camera.cpp216
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/devices.cpp38
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/media.cpp318
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/multimedia-snippets.pro26
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/multiple-videooutputs.qml50
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/qaudioprobe.cpp51
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/qsound.cpp64
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/qtvideosink.qml52
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/soundeffect.qml44
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/video.cpp136
-rw-r--r--src/multimedia/doc/snippets/snippets.pro3
-rw-r--r--src/multimedia/doc/src/audiooverview.qdoc158
-rw-r--r--src/multimedia/doc/src/cameraoverview.qdoc309
-rw-r--r--src/multimedia/doc/src/changes.qdoc140
-rw-r--r--src/multimedia/doc/src/examples/video-qml-paint-rate.qdocinc8
-rw-r--r--src/multimedia/doc/src/images/Zoom.gifbin0 -> 706673 bytes
-rw-r--r--src/multimedia/doc/src/images/camera_correctionAngle_90.pngbin0 -> 48562 bytes
-rw-r--r--src/multimedia/doc/src/images/how-focus-works.gifbin0 -> 289878 bytes
-rw-r--r--src/multimedia/doc/src/images/image_processing.pngbin0 -> 215435 bytes
-rw-r--r--src/multimedia/doc/src/images/noun_Media_166644.svg64
-rw-r--r--src/multimedia/doc/src/images/qS1FmgPVL.jpgbin0 -> 23184 bytes
-rw-r--r--src/multimedia/doc/src/images/sound-wave-small.jpgbin0 -> 37707 bytes
-rw-r--r--src/multimedia/doc/src/multimedia-overview.qdoc142
-rw-r--r--src/multimedia/doc/src/multimedia.qdoc186
-rw-r--r--src/multimedia/doc/src/multimediabackend.qdoc139
-rw-r--r--src/multimedia/doc/src/platform-notes-apple.qdoc19
-rw-r--r--src/multimedia/doc/src/platform-notes-gstreamer-on-android.qdoc59
-rw-r--r--src/multimedia/doc/src/platform-notes-ios.qdoc43
-rw-r--r--src/multimedia/doc/src/platform-notes-wasm.qdoc35
-rw-r--r--src/multimedia/doc/src/platform-notes-windows.qdoc62
-rw-r--r--src/multimedia/doc/src/plugins/qml-multimedia.qdoc216
-rw-r--r--src/multimedia/doc/src/qm-external-pages.qdoc232
-rw-r--r--src/multimedia/doc/src/qt6-changes.qdoc145
-rw-r--r--src/multimedia/doc/src/qtaudioengine.qdoc59
-rw-r--r--src/multimedia/doc/src/qtmultimedia-building-from-source.qdoc94
-rw-r--r--src/multimedia/doc/src/qtmultimedia-cpp.qdoc48
-rw-r--r--src/multimedia/doc/src/qtmultimedia-examples.qdoc38
-rw-r--r--src/multimedia/doc/src/qtmultimedia-index.qdoc328
-rw-r--r--src/multimedia/doc/src/qtmultimedia-qml-types.qdoc45
-rw-r--r--src/multimedia/doc/src/qtmultimedia5.qdoc66
-rw-r--r--src/multimedia/doc/src/videooverview.qdoc127
-rw-r--r--src/multimedia/multimedia.pro98
-rw-r--r--src/multimedia/platform/qgstreamer_platformspecificinterface.cpp27
-rw-r--r--src/multimedia/platform/qgstreamer_platformspecificinterface_p.h46
-rw-r--r--src/multimedia/platform/qplatformaudiobufferinput.cpp10
-rw-r--r--src/multimedia/platform/qplatformaudiobufferinput_p.h56
-rw-r--r--src/multimedia/platform/qplatformaudiodecoder.cpp81
-rw-r--r--src/multimedia/platform/qplatformaudiodecoder_p.h92
-rw-r--r--src/multimedia/platform/qplatformaudioinput_p.h46
-rw-r--r--src/multimedia/platform/qplatformaudiooutput_p.h44
-rw-r--r--src/multimedia/platform/qplatformaudioresampler_p.h33
-rw-r--r--src/multimedia/platform/qplatformcamera.cpp233
-rw-r--r--src/multimedia/platform/qplatformcamera_p.h165
-rw-r--r--src/multimedia/platform/qplatformcapturablewindows_p.h44
-rw-r--r--src/multimedia/platform/qplatformimagecapture.cpp27
-rw-r--r--src/multimedia/platform/qplatformimagecapture_p.h97
-rw-r--r--src/multimedia/platform/qplatformmediacapture.cpp37
-rw-r--r--src/multimedia/platform/qplatformmediacapture_p.h89
-rw-r--r--src/multimedia/platform/qplatformmediadevices.cpp114
-rw-r--r--src/multimedia/platform/qplatformmediadevices_p.h63
-rw-r--r--src/multimedia/platform/qplatformmediaformatinfo.cpp76
-rw-r--r--src/multimedia/platform/qplatformmediaformatinfo_p.h50
-rw-r--r--src/multimedia/platform/qplatformmediaintegration.cpp222
-rw-r--r--src/multimedia/platform/qplatformmediaintegration_p.h139
-rw-r--r--src/multimedia/platform/qplatformmediaplayer.cpp40
-rw-r--r--src/multimedia/platform/qplatformmediaplayer_p.h170
-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.h161
-rw-r--r--src/multimedia/platform/qplatformsurfacecapture.cpp83
-rw-r--r--src/multimedia/platform/qplatformsurfacecapture_p.h87
-rw-r--r--src/multimedia/platform/qplatformvideodevices.cpp12
-rw-r--r--src/multimedia/platform/qplatformvideodevices_p.h46
-rw-r--r--src/multimedia/platform/qplatformvideoframeinput.cpp10
-rw-r--r--src/multimedia/platform/qplatformvideoframeinput_p.h55
-rw-r--r--src/multimedia/platform/qplatformvideosink.cpp78
-rw-r--r--src/multimedia/platform/qplatformvideosink_p.h84
-rw-r--r--src/multimedia/platform/qplatformvideosource.cpp15
-rw-r--r--src/multimedia/platform/qplatformvideosource_p.h58
-rw-r--r--src/multimedia/playback/playback.pri24
-rw-r--r--src/multimedia/playback/qmediacontent.cpp249
-rw-r--r--src/multimedia/playback/qmediacontent.h81
-rw-r--r--src/multimedia/playback/qmedianetworkplaylistprovider.cpp284
-rw-r--r--src/multimedia/playback/qmedianetworkplaylistprovider_p.h96
-rw-r--r--src/multimedia/playback/qmediaplayer.cpp1868
-rw-r--r--src/multimedia/playback/qmediaplayer.h238
-rw-r--r--src/multimedia/playback/qmediaplayer_p.h90
-rw-r--r--src/multimedia/playback/qmediaplaylist.cpp824
-rw-r--r--src/multimedia/playback/qmediaplaylist.h148
-rw-r--r--src/multimedia/playback/qmediaplaylist_p.h173
-rw-r--r--src/multimedia/playback/qmediaplaylistioplugin.cpp188
-rw-r--r--src/multimedia/playback/qmediaplaylistioplugin_p.h125
-rw-r--r--src/multimedia/playback/qmediaplaylistnavigator.cpp544
-rw-r--r--src/multimedia/playback/qmediaplaylistnavigator_p.h118
-rw-r--r--src/multimedia/playback/qmediaplaylistprovider.cpp321
-rw-r--r--src/multimedia/playback/qmediaplaylistprovider_p.h122
-rw-r--r--src/multimedia/playback/qplaylistfileparser.cpp632
-rw-r--r--src/multimedia/playback/qplaylistfileparser_p.h122
-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.h93
-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.h116
-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/qmediabindableinterface.cpp82
-rw-r--r--src/multimedia/qmediabindableinterface.h69
-rw-r--r--src/multimedia/qmediacontrol.cpp136
-rw-r--r--src/multimedia/qmediacontrol.h79
-rw-r--r--src/multimedia/qmediacontrol_p.h72
-rw-r--r--src/multimedia/qmediadevices.cpp288
-rw-r--r--src/multimedia/qmediadevices.h56
-rw-r--r--src/multimedia/qmediaenumdebug.h40
-rw-r--r--src/multimedia/qmediaformat.cpp883
-rw-r--r--src/multimedia/qmediaformat.h149
-rw-r--r--src/multimedia/qmediaframeinput.cpp43
-rw-r--r--src/multimedia/qmediaframeinput_p.h74
-rw-r--r--src/multimedia/qmediainputencoderinterface_p.h31
-rw-r--r--src/multimedia/qmediametadata.cpp632
-rw-r--r--src/multimedia/qmediametadata.h321
-rw-r--r--src/multimedia/qmediaobject.cpp427
-rw-r--r--src/multimedia/qmediaobject.h108
-rw-r--r--src/multimedia/qmediaobject_p.h94
-rw-r--r--src/multimedia/qmediapluginloader.cpp186
-rw-r--r--src/multimedia/qmediapluginloader_p.h92
-rw-r--r--src/multimedia/qmediaresourcepolicy_p.cpp114
-rw-r--r--src/multimedia/qmediaresourcepolicy_p.h78
-rw-r--r--src/multimedia/qmediaresourcepolicyplugin_p.cpp53
-rw-r--r--src/multimedia/qmediaresourcepolicyplugin_p.h81
-rw-r--r--src/multimedia/qmediaresourceset_p.cpp54
-rw-r--r--src/multimedia/qmediaresourceset_p.h88
-rw-r--r--src/multimedia/qmediaservice.cpp143
-rw-r--r--src/multimedia/qmediaservice.h85
-rw-r--r--src/multimedia/qmediaservice_p.h73
-rw-r--r--src/multimedia/qmediaserviceprovider.cpp1004
-rw-r--r--src/multimedia/qmediaserviceprovider_p.h95
-rw-r--r--src/multimedia/qmediaserviceproviderplugin.h245
-rw-r--r--src/multimedia/qmediastoragelocation.cpp161
-rw-r--r--src/multimedia/qmediastoragelocation_p.h70
-rw-r--r--src/multimedia/qmediatimerange.cpp321
-rw-r--r--src/multimedia/qmediatimerange.h158
-rw-r--r--src/multimedia/qmultimedia.cpp116
-rw-r--r--src/multimedia/qmultimedia.h96
-rw-r--r--src/multimedia/qmultimediautils.cpp135
-rw-r--r--src/multimedia/qmultimediautils_p.h82
-rw-r--r--src/multimedia/qnx/qqnxaudiodevice.cpp85
-rw-r--r--src/multimedia/qnx/qqnxaudiodevice_p.h35
-rw-r--r--src/multimedia/qnx/qqnxaudiosink.cpp516
-rw-r--r--src/multimedia/qnx/qqnxaudiosink_p.h119
-rw-r--r--src/multimedia/qnx/qqnxaudiosource.cpp376
-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/qsymbolsresolveutils.cpp79
-rw-r--r--src/multimedia/qsymbolsresolveutils_p.h178
-rw-r--r--src/multimedia/qt_cmdline.cmake8
-rw-r--r--src/multimedia/qtmultimediaglobal.h56
-rw-r--r--src/multimedia/qtmultimediaglobal_p.h40
-rw-r--r--src/multimedia/recording/qaudiorecorder.cpp248
-rw-r--r--src/multimedia/recording/qaudiorecorder.h88
-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.cpp688
-rw-r--r--src/multimedia/recording/qmediacapturesession.h106
-rw-r--r--src/multimedia/recording/qmediacapturesession_p.h53
-rw-r--r--src/multimedia/recording/qmediaencodersettings.cpp952
-rw-r--r--src/multimedia/recording/qmediaencodersettings.h180
-rw-r--r--src/multimedia/recording/qmediarecorder.cpp1347
-rw-r--r--src/multimedia/recording/qmediarecorder.h249
-rw-r--r--src/multimedia/recording/qmediarecorder_p.h99
-rw-r--r--src/multimedia/recording/qscreencapture-limitations.qdocinc25
-rw-r--r--src/multimedia/recording/qscreencapture.cpp261
-rw-r--r--src/multimedia/recording/qscreencapture.h72
-rw-r--r--src/multimedia/recording/qvideoframeinput.cpp181
-rw-r--r--src/multimedia/recording/qvideoframeinput.h48
-rw-r--r--src/multimedia/recording/qwindowcapture.cpp268
-rw-r--r--src/multimedia/recording/qwindowcapture.h71
-rw-r--r--src/multimedia/recording/recording.pri14
-rw-r--r--src/multimedia/shaders/abgr.frag19
-rw-r--r--src/multimedia/shaders/argb.frag19
-rw-r--r--src/multimedia/shaders/ayuv.frag25
-rw-r--r--src/multimedia/shaders/bgra.frag19
-rw-r--r--src/multimedia/shaders/colorconvert.glsl19
-rw-r--r--src/multimedia/shaders/colortransfer.glsl118
-rwxr-xr-xsrc/multimedia/shaders/compile.bat16
-rw-r--r--src/multimedia/shaders/externalsampler.frag14
-rw-r--r--src/multimedia/shaders/externalsampler.vert16
-rw-r--r--src/multimedia/shaders/externalsampler_gles.frag28
-rw-r--r--src/multimedia/shaders/hdrtonemapper.glsl38
-rw-r--r--src/multimedia/shaders/imc2.frag29
-rw-r--r--src/multimedia/shaders/imc4.frag29
-rw-r--r--src/multimedia/shaders/nv12.frag27
-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.frag27
-rw-r--r--src/multimedia/shaders/rectsampler.vert16
-rw-r--r--src/multimedia/shaders/rectsampler_bgra.frag19
-rw-r--r--src/multimedia/shaders/rgba.frag19
-rw-r--r--src/multimedia/shaders/uniformbuffer.glsl11
-rw-r--r--src/multimedia/shaders/uyvy.frag27
-rw-r--r--src/multimedia/shaders/vertex.vert16
-rw-r--r--src/multimedia/shaders/y.frag25
-rw-r--r--src/multimedia/shaders/yuv_triplanar.frag29
-rw-r--r--src/multimedia/shaders/yuv_triplanar_p10.frag29
-rw-r--r--src/multimedia/shaders/yuyv.frag27
-rw-r--r--src/multimedia/shaders/yvu_triplanar.frag29
-rw-r--r--src/multimedia/video/qabstractvideobuffer.cpp400
-rw-r--r--src/multimedia/video/qabstractvideobuffer.h125
-rw-r--r--src/multimedia/video/qabstractvideobuffer_p.h97
-rw-r--r--src/multimedia/video/qabstractvideofilter.cpp325
-rw-r--r--src/multimedia/video/qabstractvideofilter.h91
-rw-r--r--src/multimedia/video/qabstractvideosurface.cpp389
-rw-r--r--src/multimedia/video/qabstractvideosurface.h112
-rw-r--r--src/multimedia/video/qhwvideobuffer.cpp17
-rw-r--r--src/multimedia/video/qhwvideobuffer_p.h58
-rw-r--r--src/multimedia/video/qimagevideobuffer.cpp144
-rw-r--r--src/multimedia/video/qimagevideobuffer_p.h67
-rw-r--r--src/multimedia/video/qmemoryvideobuffer.cpp113
-rw-r--r--src/multimedia/video/qmemoryvideobuffer_p.h59
-rw-r--r--src/multimedia/video/qtvideo.cpp51
-rw-r--r--src/multimedia/video/qtvideo.h57
-rw-r--r--src/multimedia/video/qvideoframe.cpp1451
-rw-r--r--src/multimedia/video/qvideoframe.h214
-rw-r--r--src/multimedia/video/qvideoframe_p.h93
-rw-r--r--src/multimedia/video/qvideoframeconversionhelper.cpp506
-rw-r--r--src/multimedia/video/qvideoframeconversionhelper_avx2.cpp146
-rw-r--r--src/multimedia/video/qvideoframeconversionhelper_p.h145
-rw-r--r--src/multimedia/video/qvideoframeconversionhelper_sse2.cpp138
-rw-r--r--src/multimedia/video/qvideoframeconversionhelper_ssse3.cpp99
-rw-r--r--src/multimedia/video/qvideoframeconverter.cpp462
-rw-r--r--src/multimedia/video/qvideoframeconverter_p.h36
-rw-r--r--src/multimedia/video/qvideoframeformat.cpp1044
-rw-r--r--src/multimedia/video/qvideoframeformat.h225
-rw-r--r--src/multimedia/video/qvideooutputorientationhandler.cpp55
-rw-r--r--src/multimedia/video/qvideooutputorientationhandler_p.h45
-rw-r--r--src/multimedia/video/qvideoprobe.cpp218
-rw-r--r--src/multimedia/video/qvideoprobe.h74
-rw-r--r--src/multimedia/video/qvideosink.cpp194
-rw-r--r--src/multimedia/video/qvideosink.h57
-rw-r--r--src/multimedia/video/qvideosurfaceformat.cpp678
-rw-r--r--src/multimedia/video/qvideosurfaceformat.h146
-rw-r--r--src/multimedia/video/qvideosurfaceoutput.cpp101
-rw-r--r--src/multimedia/video/qvideosurfaceoutput_p.h90
-rw-r--r--src/multimedia/video/qvideosurfaces.cpp102
-rw-r--r--src/multimedia/video/qvideosurfaces_p.h77
-rw-r--r--src/multimedia/video/qvideotexturehelper.cpp855
-rw-r--r--src/multimedia/video/qvideotexturehelper_p.h93
-rw-r--r--src/multimedia/video/qvideowindow.cpp531
-rw-r--r--src/multimedia/video/qvideowindow_p.h127
-rw-r--r--src/multimedia/video/video.pri37
-rw-r--r--src/multimedia/wasm/qwasmaudiodevice.cpp56
-rw-r--r--src/multimedia/wasm/qwasmaudiodevice_p.h31
-rw-r--r--src/multimedia/wasm/qwasmaudiosink.cpp464
-rw-r--r--src/multimedia/wasm/qwasmaudiosink_p.h89
-rw-r--r--src/multimedia/wasm/qwasmaudiosource.cpp315
-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.cpp229
-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.cpp215
-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
485 files changed, 40931 insertions, 42114 deletions
diff --git a/src/multimedia/CMakeLists.txt b/src/multimedia/CMakeLists.txt
new file mode 100644
index 000000000..8ccf81c0c
--- /dev/null
+++ b/src/multimedia/CMakeLists.txt
@@ -0,0 +1,373 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Generated from multimedia.pro.
+
+#####################################################################
+## Multimedia Module:
+#####################################################################
+
+find_package(Qt6 COMPONENTS ShaderTools)
+
+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(FWCoreMedia CoreMedia) # special case
+qt_internal_find_apple_system_framework(FWAudioToolbox AudioToolbox) # special case
+
+qt_internal_add_module(Multimedia
+ PLUGIN_TYPES multimedia
+ SOURCES
+ audio/qtaudio.cpp audio/qtaudio.h audio/qaudio.h
+ audio/qaudiobuffer.cpp audio/qaudiobuffer.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/qaudiobufferinput.cpp audio/qaudiobufferinput.h
+ audio/qaudiobufferoutput.cpp audio/qaudiobufferoutput.h audio/qaudiobufferoutput_p.h
+ audio/qaudiooutput.cpp audio/qaudiooutput.h
+ audio/qaudioformat.cpp audio/qaudioformat.h
+ audio/qaudiohelpers.cpp audio/qaudiohelpers_p.h
+ 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/qgstreamer_platformspecificinterface.cpp platform/qgstreamer_platformspecificinterface_p.h
+ platform/qplatformaudiodecoder.cpp platform/qplatformaudiodecoder_p.h
+ platform/qplatformaudioinput_p.h
+ platform/qplatformaudiooutput_p.h
+ platform/qplatformaudioresampler_p.h
+ platform/qplatformcamera.cpp platform/qplatformcamera_p.h
+ platform/qplatformcapturablewindows_p.h
+ platform/qplatformimagecapture.cpp platform/qplatformimagecapture_p.h
+ platform/qplatformmediacapture.cpp platform/qplatformmediacapture_p.h
+ platform/qplatformmediadevices.cpp platform/qplatformmediadevices_p.h
+ platform/qplatformmediaformatinfo.cpp platform/qplatformmediaformatinfo_p.h
+ platform/qplatformmediaintegration.cpp platform/qplatformmediaintegration_p.h
+ platform/qplatformmediaplayer.cpp platform/qplatformmediaplayer_p.h
+ platform/qplatformmediaplugin.cpp platform/qplatformmediaplugin_p.h
+ platform/qplatformmediarecorder.cpp platform/qplatformmediarecorder_p.h
+ platform/qplatformsurfacecapture.cpp platform/qplatformsurfacecapture_p.h
+ platform/qplatformvideodevices.cpp platform/qplatformvideodevices_p.h
+ platform/qplatformvideosink.cpp platform/qplatformvideosink_p.h
+ platform/qplatformvideosource.cpp platform/qplatformvideosource_p.h
+ platform/qplatformvideoframeinput.cpp platform/qplatformvideoframeinput_p.h
+ platform/qplatformaudiobufferinput.cpp platform/qplatformaudiobufferinput_p.h
+ playback/qmediaplayer.cpp playback/qmediaplayer.h playback/qmediaplayer_p.h
+ qmediadevices.cpp qmediadevices.h
+ qmediaenumdebug.h
+ qmediaformat.cpp qmediaformat.h
+ qmediametadata.cpp qmediametadata.h
+ qmediastoragelocation.cpp qmediastoragelocation_p.h
+ qmediatimerange.cpp qmediatimerange.h
+ qmultimediautils.cpp qmultimediautils_p.h
+ qmediaframeinput.cpp qmediaframeinput_p.h
+ qmaybe_p.h
+ qtmultimediaglobal.h qtmultimediaglobal_p.h
+ qerrorinfo_p.h
+ qmediainputencoderinterface_p.h
+ recording/qmediacapturesession.cpp recording/qmediacapturesession.h recording/qmediacapturesession_p.h
+ recording/qmediarecorder.cpp recording/qmediarecorder.h recording/qmediarecorder_p.h
+ recording/qscreencapture.cpp recording/qscreencapture.h
+ recording/qwindowcapture.cpp recording/qwindowcapture.h
+ recording/qcapturablewindow.cpp recording/qcapturablewindow.h recording/qcapturablewindow_p.h
+ recording/qvideoframeinput.cpp recording/qvideoframeinput.h
+ video/qabstractvideobuffer.cpp video/qabstractvideobuffer.h
+ video/qhwvideobuffer.cpp video/qhwvideobuffer_p.h
+ video/qmemoryvideobuffer.cpp video/qmemoryvideobuffer_p.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
+ controls
+ platform
+ playback
+ recording
+ video
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::GuiPrivate
+ PUBLIC_LIBRARIES
+ Qt::Core
+ Qt::Gui
+ Qt::Network
+ PRIVATE_MODULE_INTERFACE
+ Qt::CorePrivate
+ Qt::GuiPrivate
+ NO_PCH_SOURCES
+ compat/removed_api.cpp
+)
+
+qt_internal_extend_target(Multimedia
+ CONDITION LINUX OR ANDROID
+ SOURCES qsymbolsresolveutils.cpp qsymbolsresolveutils_p.h)
+
+qt_internal_add_simd_part(Multimedia SIMD sse2
+ SOURCES
+ video/qvideoframeconversionhelper_sse2.cpp
+)
+
+qt_internal_add_simd_part(Multimedia SIMD ssse3
+ SOURCES
+ video/qvideoframeconversionhelper_ssse3.cpp
+)
+
+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
+)
+
+qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_alsa
+ SOURCES
+ 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
+ alsa
+ LIBRARIES
+ ALSA::ALSA
+)
+
+qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_pulseaudio
+ SOURCES
+ 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
+ pulseaudio
+ LIBRARIES
+ WrapPulseAudio::WrapPulseAudio
+)
+
+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
+ OpenSLES
+)
+
+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 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
+ ${FWAudioToolbox}
+ ${FWCoreAudio}
+ ${FWCoreMedia}
+ ${FWCoreFoundation}
+)
+
+qt_internal_extend_target(Multimedia CONDITION MACOS
+ SOURCES
+ darwin/qmacosaudiodatautils_p.h
+)
+
+qt_internal_extend_target(Multimedia CONDITION IOS OR TVOS
+ SOURCES
+ darwin/qcoreaudiosessionmanager.mm darwin/qcoreaudiosessionmanager_p.h
+ LIBRARIES
+ ${FWAVFoundation}
+ ${FWFoundation}
+)
+
+qt_internal_extend_target(Multimedia CONDITION QNX
+ SOURCES
+ 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
+ qnx
+ LIBRARIES
+ asound
+)
+
+qt_internal_extend_target(Multimedia CONDITION QT_FEATURE_wmf
+ 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
+ INCLUDE_DIRECTORIES
+ windows
+ LIBRARIES
+ winmm
+ ksuser
+)
+
+# 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 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
+ openal
+ NO_UNITY_BUILD_SOURCES
+ wasm/qwasmaudiosink.cpp
+ # To avoid collision between symbols defined in wasm/qwasmaudiosource.cpp.
+)
+
+set(VIDEO_VERTEX_SHADERS
+ "shaders/vertex.vert"
+ "shaders/externalsampler.vert"
+)
+
+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_add_shaders(Multimedia "qtmultimedia_shaders"
+ SILENT
+ BATCHABLE
+ PRECOMPILE
+ OPTIMIZED
+ PREFIX
+ "/qt-project.org/multimedia"
+ FILES
+ ${VIDEO_VERTEX_SHADERS}
+ ${VIDEO_SHADERS}
+)
+
+string(REPLACE ".frag" "_linear.frag.qsb" LINEAR_VIDEO_SHADERS "${VIDEO_SHADERS}")
+
+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 "qtmultimedia_shaders_gl_macos"
+ SILENT
+ BATCHABLE
+ PRECOMPILE
+ OPTIMIZED
+ PREFIX
+ "/qt-project.org/multimedia"
+ GLSL
+ "120,150"
+ NOHLSL
+ NOMSL
+ FILES
+ "shaders/rectsampler.vert"
+ "shaders/rectsampler_bgra.frag"
+)
+
+qt_internal_add_shaders(Multimedia "qtmultimedia_shaders_gl_macos_linear"
+ SILENT
+ BATCHABLE
+ PRECOMPILE
+ OPTIMIZED
+ PREFIX
+ "/qt-project.org/multimedia"
+ GLSL
+ "120,150"
+ NOHLSL
+ NOMSL
+ FILES
+ "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/alsa/qalsaaudiodevice.cpp b/src/multimedia/alsa/qalsaaudiodevice.cpp
new file mode 100644
index 000000000..893375270
--- /dev/null
+++ b/src/multimedia/alsa/qalsaaudiodevice.cpp
@@ -0,0 +1,71 @@
+// 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 "qalsaaudiodevice_p.h"
+
+#include <alsa/version.h>
+
+QT_BEGIN_NAMESPACE
+
+QAlsaAudioDeviceInfo::QAlsaAudioDeviceInfo(const QByteArray &dev, const QString &desc, QAudioDevice::Mode mode)
+ : QAudioDevicePrivate(dev, mode)
+{
+ description = desc;
+
+ checkSurround();
+
+ minimumChannelCount = 1;
+ maximumChannelCount = 2;
+ if (surround71)
+ maximumChannelCount = 8;
+ else if (surround40)
+ maximumChannelCount = 4;
+ else if (surround51)
+ maximumChannelCount = 6;
+
+ minimumSampleRate = 8000;
+ 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() = default;
+
+void QAlsaAudioDeviceInfo::checkSurround()
+{
+ if (mode != QAudioDevice::Output)
+ return;
+
+ surround40 = false;
+ surround51 = false;
+ surround71 = false;
+
+ if (id.startsWith(QLatin1String("surround40")))
+ surround40 = true;
+ if (id.startsWith(QLatin1String("surround51")))
+ surround51 = true;
+ if (id.startsWith(QLatin1String("surround71")))
+ surround71 = true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/alsa/qalsaaudiodevice_p.h b/src/multimedia/alsa/qalsaaudiodevice_p.h
new file mode 100644
index 000000000..dcbc9e692
--- /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/alsa/qalsaaudiosink.cpp b/src/multimedia/alsa/qalsaaudiosink.cpp
new file mode 100644
index 000000000..e515219a2
--- /dev/null
+++ b/src/multimedia/alsa/qalsaaudiosink.cpp
@@ -0,0 +1,698 @@
+// 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 <QtCore/qcoreapplication.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtMultimedia/private/qaudiohelpers_p.h>
+#include "qalsaaudiosink_p.h"
+#include "qalsaaudiodevice_p.h"
+#include <QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+static Q_LOGGING_CATEGORY(lcAlsaOutput, "qt.multimedia.alsa.output")
+//#define DEBUG_AUDIO 1
+
+QAlsaAudioSink::QAlsaAudioSink(const QByteArray &device, QObject *parent)
+ : QPlatformAudioSink(parent)
+{
+ m_device = device;
+
+ timer = new QTimer(this);
+ connect(timer, &QTimer::timeout, this, &QAlsaAudioSink::userFeed);
+}
+
+QAlsaAudioSink::~QAlsaAudioSink()
+{
+ close();
+ disconnect(timer, &QTimer::timeout, this, &QAlsaAudioSink::userFeed);
+ QCoreApplication::processEvents();
+ delete timer;
+}
+
+void QAlsaAudioSink::setVolume(qreal vol)
+{
+ m_volume = vol;
+}
+
+qreal QAlsaAudioSink::volume() const
+{
+ return m_volume;
+}
+
+QAudio::Error QAlsaAudioSink::error() const
+{
+ return errorState;
+}
+
+QAudio::State QAlsaAudioSink::state() const
+{
+ return deviceState;
+}
+
+int QAlsaAudioSink::xrun_recovery(int err)
+{
+ int count = 0;
+ bool reset = false;
+
+ // ESTRPIPE is not available in all OSes where ALSA is available
+ int estrpipe = EIO;
+#ifdef ESTRPIPE
+ estrpipe = ESTRPIPE;
+#endif
+
+ if(err == -EPIPE) {
+ errorState = QAudio::UnderrunError;
+ emit errorChanged(errorState);
+ err = snd_pcm_prepare(handle);
+ if(err < 0)
+ reset = true;
+
+ } else if ((err == -estrpipe)||(err == -EIO)) {
+ errorState = QAudio::IOError;
+ emit errorChanged(errorState);
+ while((err = snd_pcm_resume(handle)) == -EAGAIN){
+ usleep(100);
+ count++;
+ if(count > 5) {
+ reset = true;
+ break;
+ }
+ }
+ if(err < 0) {
+ err = snd_pcm_prepare(handle);
+ if(err < 0)
+ reset = true;
+ }
+ }
+ if(reset) {
+ close();
+ open();
+ snd_pcm_prepare(handle);
+ return 0;
+ }
+ return err;
+}
+
+int QAlsaAudioSink::setFormat()
+{
+ snd_pcm_format_t pcmformat = SND_PCM_FORMAT_UNKNOWN;
+
+ switch (settings.sampleFormat()) {
+ case QAudioFormat::UInt8:
+ pcmformat = SND_PCM_FORMAT_U8;
+ break;
+ case QAudioFormat::Int16:
+ if constexpr (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ 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_BE;
+ else
+ pcmformat = SND_PCM_FORMAT_S32_LE;
+ break;
+ case QAudioFormat::Float:
+ if constexpr (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ pcmformat = SND_PCM_FORMAT_FLOAT_BE;
+ else
+ pcmformat = SND_PCM_FORMAT_FLOAT_LE;
+ break;
+ default:
+ break;
+ }
+
+ return pcmformat != SND_PCM_FORMAT_UNKNOWN
+ ? snd_pcm_hw_params_set_format( handle, hwparams, pcmformat)
+ : -1;
+}
+
+void QAlsaAudioSink::start(QIODevice* device)
+{
+ if(deviceState != QAudio::StoppedState)
+ deviceState = QAudio::StoppedState;
+
+ errorState = QAudio::NoError;
+
+ // Handle change of mode
+ if(audioSource && !pullMode) {
+ delete audioSource;
+ audioSource = 0;
+ }
+
+ close();
+
+ pullMode = true;
+ audioSource = device;
+
+ connect(audioSource, &QIODevice::readyRead, timer, [this] {
+ if (!timer->isActive()) {
+ timer->start(period_time / 1000);
+ }
+ });
+ deviceState = QAudio::ActiveState;
+
+ open();
+
+ emit stateChanged(deviceState);
+}
+
+QIODevice* QAlsaAudioSink::start()
+{
+ if(deviceState != QAudio::StoppedState)
+ deviceState = QAudio::StoppedState;
+
+ errorState = QAudio::NoError;
+
+ // Handle change of mode
+ if(audioSource && !pullMode) {
+ delete audioSource;
+ audioSource = 0;
+ }
+
+ close();
+
+ audioSource = new AlsaOutputPrivate(this);
+ audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered);
+ pullMode = false;
+
+ deviceState = QAudio::IdleState;
+
+ open();
+
+ emit stateChanged(deviceState);
+
+ return audioSource;
+}
+
+void QAlsaAudioSink::stop()
+{
+ if(deviceState == QAudio::StoppedState)
+ return;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::StoppedState;
+ close();
+ emit stateChanged(deviceState);
+}
+
+bool QAlsaAudioSink::open()
+{
+ if(opened)
+ return true;
+
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
+#endif
+ elapsedTimeOffset = 0;
+
+ int dir;
+ int err = 0;
+ int count=0;
+ unsigned int sampleRate = settings.sampleRate();
+
+ if (!settings.isValid()) {
+ qWarning("QAudioSink: open error, invalid format.");
+ } else if (settings.sampleRate() <= 0) {
+ qWarning("QAudioSink: open error, invalid sample rate (%d).",
+ settings.sampleRate());
+ } else {
+ err = -1;
+ }
+
+ if (err == 0) {
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StoppedState;
+ emit errorChanged(errorState);
+ return false;
+ }
+
+ // Step 1: try and open the device
+ while((count < 5) && (err < 0)) {
+ err=snd_pcm_open(&handle, m_device.constData(),SND_PCM_STREAM_PLAYBACK,0);
+ if(err < 0)
+ count++;
+ }
+ if (( err < 0)||(handle == 0)) {
+ errorState = QAudio::OpenError;
+ emit errorChanged(errorState);
+ deviceState = QAudio::StoppedState;
+ return false;
+ }
+ snd_pcm_nonblock( handle, 0 );
+
+ // Step 2: Set the desired HW parameters.
+ snd_pcm_hw_params_alloca( &hwparams );
+
+ bool fatal = false;
+ QString errMessage;
+ unsigned int chunks = 8;
+
+ err = snd_pcm_hw_params_any( handle, hwparams );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSink: snd_pcm_hw_params_any: err = %1").arg(err);
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_rate_resample( handle, hwparams, 1 );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSink: snd_pcm_hw_params_set_rate_resample: err = %1").arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_access( handle, hwparams, access );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSink: snd_pcm_hw_params_set_access: err = %1").arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = setFormat();
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSink: snd_pcm_hw_params_set_format: err = %1").arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_channels( handle, hwparams, (unsigned int)settings.channelCount() );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSink: snd_pcm_hw_params_set_channels: err = %1").arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_rate_near( handle, hwparams, &sampleRate, 0 );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSink: snd_pcm_hw_params_set_rate_near: err = %1").arg(err);
+ }
+ }
+ if ( !fatal ) {
+ unsigned int maxBufferTime = 0;
+ unsigned int minBufferTime = 0;
+ unsigned int maxPeriodTime = 0;
+ unsigned int minPeriodTime = 0;
+
+ err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &maxBufferTime, &dir);
+ if ( err >= 0)
+ err = snd_pcm_hw_params_get_buffer_time_min(hwparams, &minBufferTime, &dir);
+ if ( err >= 0)
+ err = snd_pcm_hw_params_get_period_time_max(hwparams, &maxPeriodTime, &dir);
+ if ( err >= 0)
+ err = snd_pcm_hw_params_get_period_time_min(hwparams, &minPeriodTime, &dir);
+
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSink: buffer/period min and max: err = %1").arg(err);
+ } else {
+ static unsigned user_buffer_time = qEnvironmentVariableIntValue("QT_ALSA_OUTPUT_BUFFER_TIME");
+ static unsigned user_period_time = qEnvironmentVariableIntValue("QT_ALSA_OUTPUT_PERIOD_TIME");
+ const bool outOfRange = maxBufferTime < buffer_time || buffer_time < minBufferTime || maxPeriodTime < period_time || minPeriodTime > period_time;
+ if (outOfRange || user_period_time || user_buffer_time) {
+ period_time = user_period_time ? user_period_time : minPeriodTime;
+ if (!user_buffer_time) {
+ chunks = maxBufferTime / period_time;
+ buffer_time = period_time * chunks;
+ } else {
+ buffer_time = user_buffer_time;
+ chunks = buffer_time / period_time;
+ }
+ }
+ qCDebug(lcAlsaOutput) << "buffer time: [" << minBufferTime << "-" << maxBufferTime << "] =" << buffer_time;
+ qCDebug(lcAlsaOutput) << "period time: [" << minPeriodTime << "-" << maxPeriodTime << "] =" << period_time;
+ qCDebug(lcAlsaOutput) << "chunks =" << chunks;
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSink: snd_pcm_hw_params_set_buffer_time_near: err = %1").arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSink: snd_pcm_hw_params_set_period_time_near: err = %1").arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &chunks, &dir);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSink: snd_pcm_hw_params_set_periods_near: err = %1").arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params(handle, hwparams);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSink: snd_pcm_hw_params: err = %1").arg(err);
+ }
+ }
+ if( err < 0) {
+ qWarning()<<errMessage;
+ errorState = QAudio::OpenError;
+ emit errorChanged(errorState);
+ deviceState = QAudio::StoppedState;
+ return false;
+ }
+ snd_pcm_hw_params_get_buffer_size(hwparams,&buffer_frames);
+ buffer_size = snd_pcm_frames_to_bytes(handle,buffer_frames);
+ snd_pcm_hw_params_get_period_size(hwparams,&period_frames, &dir);
+ period_size = snd_pcm_frames_to_bytes(handle,period_frames);
+ snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir);
+ snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir);
+
+ // Step 3: Set the desired SW parameters.
+ snd_pcm_sw_params_t *swparams;
+ snd_pcm_sw_params_alloca(&swparams);
+ snd_pcm_sw_params_current(handle, swparams);
+ snd_pcm_sw_params_set_start_threshold(handle,swparams,period_frames);
+ snd_pcm_sw_params_set_stop_threshold(handle,swparams,buffer_frames);
+ snd_pcm_sw_params_set_avail_min(handle, swparams,period_frames);
+ snd_pcm_sw_params(handle, swparams);
+
+ // Step 4: Prepare audio
+ if(audioBuffer == 0)
+ audioBuffer = new char[snd_pcm_frames_to_bytes(handle,buffer_frames)];
+ snd_pcm_prepare( handle );
+ snd_pcm_start(handle);
+
+ // Step 5: Setup timer
+ bytesAvailable = bytesFree();
+
+ // Step 6: Start audio processing
+ timer->start(period_time/1000);
+
+ elapsedTimeOffset = 0;
+ errorState = QAudio::NoError;
+ totalTimeValue = 0;
+ opened = true;
+
+ return true;
+}
+
+void QAlsaAudioSink::close()
+{
+ timer->stop();
+
+ if ( handle ) {
+ snd_pcm_drain( handle );
+ snd_pcm_close( handle );
+ handle = 0;
+ delete [] audioBuffer;
+ audioBuffer=0;
+ }
+ if(!pullMode && audioSource) {
+ delete audioSource;
+ audioSource = 0;
+ }
+ opened = false;
+}
+
+qsizetype QAlsaAudioSink::bytesFree() const
+{
+ if(resuming)
+ return period_size;
+
+ if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
+ return 0;
+
+ int frames = snd_pcm_avail_update(handle);
+ if (frames == -EPIPE) {
+ // Try and handle buffer underrun
+ int err = snd_pcm_recover(handle, frames, 0);
+ if (err < 0)
+ return 0;
+ else
+ frames = snd_pcm_avail_update(handle);
+ } else if (frames < 0) {
+ return 0;
+ }
+
+ if ((int)frames > (int)buffer_frames)
+ frames = buffer_frames;
+
+ return snd_pcm_frames_to_bytes(handle, frames);
+}
+
+qint64 QAlsaAudioSink::write( const char *data, qint64 len )
+{
+ // Write out some audio data
+ if ( !handle )
+ return 0;
+#ifdef DEBUG_AUDIO
+ qDebug()<<"frames to write out = "<<
+ snd_pcm_bytes_to_frames( handle, (int)len )<<" ("<<len<<") bytes";
+#endif
+ int frames, err;
+ int space = bytesFree();
+
+ if (!space)
+ return 0;
+
+ if (len < space)
+ space = len;
+
+ frames = snd_pcm_bytes_to_frames(handle, space);
+
+ if (m_volume < 1.0f) {
+ QVarLengthArray<char, 4096> out(space);
+ QAudioHelperInternal::qMultiplySamples(m_volume, settings, data, out.data(), space);
+ err = snd_pcm_writei(handle, out.constData(), frames);
+ } else {
+ err = snd_pcm_writei(handle, data, frames);
+ }
+
+ if(err > 0) {
+ totalTimeValue += err;
+ resuming = false;
+ errorState = QAudio::NoError;
+ if (deviceState != QAudio::ActiveState) {
+ deviceState = QAudio::ActiveState;
+ emit stateChanged(deviceState);
+ }
+ return snd_pcm_frames_to_bytes( handle, err );
+ } else
+ err = xrun_recovery(err);
+
+ if(err < 0) {
+ close();
+ errorState = QAudio::FatalError;
+ emit errorChanged(errorState);
+ deviceState = QAudio::StoppedState;
+ emit stateChanged(deviceState);
+ }
+ return 0;
+}
+
+void QAlsaAudioSink::setBufferSize(qsizetype value)
+{
+ if(deviceState == QAudio::StoppedState)
+ buffer_size = value;
+}
+
+qsizetype QAlsaAudioSink::bufferSize() const
+{
+ return buffer_size;
+}
+
+qint64 QAlsaAudioSink::processedUSecs() const
+{
+ return qint64(1000000) * totalTimeValue / settings.sampleRate();
+}
+
+void QAlsaAudioSink::resume()
+{
+ if(deviceState == QAudio::SuspendedState) {
+ int err = 0;
+
+ if(handle) {
+ err = snd_pcm_prepare( handle );
+ if(err < 0)
+ xrun_recovery(err);
+
+ err = snd_pcm_start(handle);
+ if(err < 0)
+ xrun_recovery(err);
+
+ bytesAvailable = (int)snd_pcm_frames_to_bytes(handle, buffer_frames);
+ }
+ resuming = true;
+
+ deviceState = suspendedInState;
+ errorState = QAudio::NoError;
+ timer->start(period_time/1000);
+ emit stateChanged(deviceState);
+ }
+}
+
+void QAlsaAudioSink::setFormat(const QAudioFormat& fmt)
+{
+ settings = fmt;
+}
+
+QAudioFormat QAlsaAudioSink::format() const
+{
+ return settings;
+}
+
+void QAlsaAudioSink::suspend()
+{
+ if(deviceState == QAudio::ActiveState || deviceState == QAudio::IdleState || resuming) {
+ suspendedInState = deviceState;
+ snd_pcm_drain(handle);
+ timer->stop();
+ deviceState = QAudio::SuspendedState;
+ errorState = QAudio::NoError;
+ emit stateChanged(deviceState);
+ }
+}
+
+void QAlsaAudioSink::userFeed()
+{
+ if(deviceState == QAudio::StoppedState || deviceState == QAudio::SuspendedState)
+ return;
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :userFeed() OUT";
+#endif
+ if(deviceState == QAudio::IdleState)
+ bytesAvailable = bytesFree();
+
+ deviceReady();
+}
+
+bool QAlsaAudioSink::deviceReady()
+{
+ if(pullMode) {
+ int l = 0;
+ int chunks = bytesAvailable/period_size;
+ if(chunks==0) {
+ bytesAvailable = bytesFree();
+ return false;
+ }
+#ifdef DEBUG_AUDIO
+ qDebug()<<"deviceReady() avail="<<bytesAvailable<<" bytes, period size="<<period_size<<" bytes";
+ qDebug()<<"deviceReady() no. of chunks that can fit ="<<chunks<<", chunks in bytes ="<<period_size*chunks;
+#endif
+ int input = period_frames*chunks;
+ if(input > (int)buffer_frames)
+ input = buffer_frames;
+ l = audioSource->read(audioBuffer,snd_pcm_frames_to_bytes(handle, input));
+
+ // reading can take a while and stream may have been stopped
+ if (!handle)
+ return false;
+
+ if(l > 0) {
+ // Got some data to output
+ if (deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
+ return true;
+ qint64 bytesWritten = write(audioBuffer,l);
+ if (bytesWritten != l)
+ audioSource->seek(audioSource->pos()-(l-bytesWritten));
+ bytesAvailable = bytesFree();
+
+ } 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 = audioSource->atEnd() ? QAudio::NoError : QAudio::UnderrunError;
+ emit errorChanged(errorState);
+ deviceState = QAudio::IdleState;
+ emit stateChanged(deviceState);
+ }
+ }
+
+ } else if(l < 0) {
+ close();
+ deviceState = QAudio::StoppedState;
+ errorState = QAudio::IOError;
+ emit errorChanged(errorState);
+ emit stateChanged(deviceState);
+ }
+ } else {
+ bytesAvailable = bytesFree();
+ if(bytesAvailable > snd_pcm_frames_to_bytes(handle, buffer_frames-period_frames)) {
+ // Underrun
+ if (deviceState != QAudio::IdleState) {
+ errorState = QAudio::UnderrunError;
+ emit errorChanged(errorState);
+ deviceState = QAudio::IdleState;
+ emit stateChanged(deviceState);
+ }
+ }
+ }
+
+ if(deviceState != QAudio::ActiveState)
+ return true;
+
+ return true;
+}
+
+void QAlsaAudioSink::reset()
+{
+ if(handle)
+ snd_pcm_reset(handle);
+
+ stop();
+}
+
+AlsaOutputPrivate::AlsaOutputPrivate(QAlsaAudioSink* audio)
+{
+ audioDevice = qobject_cast<QAlsaAudioSink*>(audio);
+}
+
+AlsaOutputPrivate::~AlsaOutputPrivate() {}
+
+qint64 AlsaOutputPrivate::readData( char* data, qint64 len)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(len);
+
+ return 0;
+}
+
+qint64 AlsaOutputPrivate::writeData(const char* data, qint64 len)
+{
+ int retry = 0;
+ qint64 written = 0;
+ if((audioDevice->deviceState == QAudio::ActiveState)
+ ||(audioDevice->deviceState == QAudio::IdleState)) {
+ while(written < len) {
+ int chunk = audioDevice->write(data+written,(len-written));
+ if(chunk <= 0)
+ retry++;
+ written+=chunk;
+ if(retry > 10)
+ return written;
+ }
+ }
+ return written;
+
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qalsaaudiosink_p.cpp"
diff --git a/src/multimedia/alsa/qalsaaudiosink_p.h b/src/multimedia/alsa/qalsaaudiosink_p.h
new file mode 100644
index 000000000..0f5a5aa5a
--- /dev/null
+++ b/src/multimedia/alsa/qalsaaudiosink_p.h
@@ -0,0 +1,121 @@
+// 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_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/alsa/qalsaaudiosource.cpp b/src/multimedia/alsa/qalsaaudiosource.cpp
new file mode 100644
index 000000000..ebf6e24e2
--- /dev/null
+++ b/src/multimedia/alsa/qalsaaudiosource.cpp
@@ -0,0 +1,770 @@
+// 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 <QtCore/qcoreapplication.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtMultimedia/private/qaudiohelpers_p.h>
+#include "qalsaaudiosource_p.h"
+
+QT_BEGIN_NAMESPACE
+
+//#define DEBUG_AUDIO 1
+
+QAlsaAudioSource::QAlsaAudioSource(const QByteArray &device, QObject *parent)
+ : QPlatformAudioSource(parent)
+{
+ bytesAvailable = 0;
+ handle = 0;
+ access = SND_PCM_ACCESS_RW_INTERLEAVED;
+ pcmformat = SND_PCM_FORMAT_S16;
+ buffer_size = 0;
+ period_size = 0;
+ buffer_time = 100000;
+ period_time = 20000;
+ totalTimeValue = 0;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::StoppedState;
+ audioSource = 0;
+ pullMode = true;
+ resuming = false;
+
+ m_volume = 1.0f;
+
+ m_device = device;
+
+ timer = new QTimer(this);
+ connect(timer, &QTimer::timeout, this, &QAlsaAudioSource::userFeed);
+}
+
+QAlsaAudioSource::~QAlsaAudioSource()
+{
+ close();
+ disconnect(timer, &QTimer::timeout, this, &QAlsaAudioSource::userFeed);
+ QCoreApplication::processEvents();
+ delete timer;
+}
+
+void QAlsaAudioSource::setVolume(qreal vol)
+{
+ m_volume = vol;
+}
+
+qreal QAlsaAudioSource::volume() const
+{
+ return m_volume;
+}
+
+QAudio::Error QAlsaAudioSource::error() const
+{
+ return errorState;
+}
+
+QAudio::State QAlsaAudioSource::state() const
+{
+ return deviceState;
+}
+
+void QAlsaAudioSource::setFormat(const QAudioFormat& fmt)
+{
+ if (deviceState == QAudio::StoppedState)
+ settings = fmt;
+}
+
+QAudioFormat QAlsaAudioSource::format() const
+{
+ return settings;
+}
+
+int QAlsaAudioSource::xrun_recovery(int err)
+{
+ int count = 0;
+ bool reset = false;
+
+ // ESTRPIPE is not available in all OSes where ALSA is available
+ int estrpipe = EIO;
+#ifdef ESTRPIPE
+ estrpipe = ESTRPIPE;
+#endif
+
+ if(err == -EPIPE) {
+ errorState = QAudio::UnderrunError;
+ err = snd_pcm_prepare(handle);
+ if(err < 0)
+ reset = true;
+ else {
+ bytesAvailable = checkBytesReady();
+ if (bytesAvailable <= 0)
+ reset = true;
+ }
+ } else if ((err == -estrpipe)||(err == -EIO)) {
+ errorState = QAudio::IOError;
+ while((err = snd_pcm_resume(handle)) == -EAGAIN){
+ usleep(100);
+ count++;
+ if(count > 5) {
+ reset = true;
+ break;
+ }
+ }
+ if(err < 0) {
+ err = snd_pcm_prepare(handle);
+ if(err < 0)
+ reset = true;
+ }
+ }
+ if(reset) {
+ close();
+ open();
+ snd_pcm_prepare(handle);
+ return 0;
+ }
+ return err;
+}
+
+int QAlsaAudioSource::setFormat()
+{
+ snd_pcm_format_t pcmformat = SND_PCM_FORMAT_UNKNOWN;
+
+ switch (settings.sampleFormat()) {
+ case QAudioFormat::UInt8:
+ pcmformat = SND_PCM_FORMAT_U8;
+ break;
+ case QAudioFormat::Int16:
+ if constexpr (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ 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_BE;
+ else
+ pcmformat = SND_PCM_FORMAT_S32_LE;
+ break;
+ case QAudioFormat::Float:
+ if constexpr (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ pcmformat = SND_PCM_FORMAT_FLOAT_BE;
+ else
+ pcmformat = SND_PCM_FORMAT_FLOAT_LE;
+ break;
+ default:
+ break;
+ }
+
+ return pcmformat != SND_PCM_FORMAT_UNKNOWN
+ ? snd_pcm_hw_params_set_format( handle, hwparams, pcmformat)
+ : -1;
+}
+
+void QAlsaAudioSource::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* QAlsaAudioSource::start()
+{
+ if(deviceState != QAudio::StoppedState)
+ close();
+
+ if(!pullMode && audioSource)
+ delete audioSource;
+
+ pullMode = false;
+ audioSource = new AlsaInputPrivate(this);
+ audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
+
+ deviceState = QAudio::IdleState;
+
+ if( !open() )
+ return 0;
+
+ emit stateChanged(deviceState);
+
+ return audioSource;
+}
+
+void QAlsaAudioSource::stop()
+{
+ if(deviceState == QAudio::StoppedState)
+ return;
+
+ deviceState = QAudio::StoppedState;
+
+ close();
+ emit stateChanged(deviceState);
+}
+
+bool QAlsaAudioSource::open()
+{
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
+#endif
+ elapsedTimeOffset = 0;
+
+ int dir;
+ int err = 0;
+ int count=0;
+ unsigned int sampleRate=settings.sampleRate();
+
+ if (!settings.isValid()) {
+ qWarning("QAudioSource: open error, invalid format.");
+ } else if (settings.sampleRate() <= 0) {
+ qWarning("QAudioSource: open error, invalid sample rate (%d).",
+ settings.sampleRate());
+ } else {
+ err = -1;
+ }
+
+ if (err == 0) {
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StoppedState;
+ emit errorChanged(errorState);
+ return false;
+ }
+
+
+ // Step 1: try and open the device
+ while((count < 5) && (err < 0)) {
+ err = snd_pcm_open(&handle, m_device.constData(), SND_PCM_STREAM_CAPTURE,0);
+ if(err < 0)
+ count++;
+ }
+ if (( err < 0)||(handle == 0)) {
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StoppedState;
+ emit stateChanged(deviceState);
+ return false;
+ }
+ snd_pcm_nonblock( handle, 0 );
+
+ // Step 2: Set the desired HW parameters.
+ snd_pcm_hw_params_alloca( &hwparams );
+
+ bool fatal = false;
+ QString errMessage;
+ unsigned int chunks = 8;
+
+ err = snd_pcm_hw_params_any( handle, hwparams );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSource: snd_pcm_hw_params_any: err = %1").arg(err);
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_rate_resample( handle, hwparams, 1 );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSource: snd_pcm_hw_params_set_rate_resample: err = %1").arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_access( handle, hwparams, access );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSource: snd_pcm_hw_params_set_access: err = %1").arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = setFormat();
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSource: snd_pcm_hw_params_set_format: err = %1").arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_channels( handle, hwparams, (unsigned int)settings.channelCount() );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSource: snd_pcm_hw_params_set_channels: err = %1").arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_rate_near( handle, hwparams, &sampleRate, 0 );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSource: snd_pcm_hw_params_set_rate_near: err = %1").arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSource: snd_pcm_hw_params_set_buffer_time_near: err = %1").arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSource: snd_pcm_hw_params_set_period_time_near: err = %1").arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &chunks, &dir);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSource: snd_pcm_hw_params_set_periods_near: err = %1").arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params(handle, hwparams);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString::fromLatin1("QAudioSource: snd_pcm_hw_params: err = %1").arg(err);
+ }
+ }
+ if( err < 0) {
+ qWarning()<<errMessage;
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StoppedState;
+ emit stateChanged(deviceState);
+ return false;
+ }
+ snd_pcm_hw_params_get_buffer_size(hwparams,&buffer_frames);
+ buffer_size = snd_pcm_frames_to_bytes(handle,buffer_frames);
+ snd_pcm_hw_params_get_period_size(hwparams,&period_frames, &dir);
+ period_size = snd_pcm_frames_to_bytes(handle,period_frames);
+ snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir);
+ snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir);
+
+ // Step 3: Set the desired SW parameters.
+ snd_pcm_sw_params_t *swparams;
+ snd_pcm_sw_params_alloca(&swparams);
+ snd_pcm_sw_params_current(handle, swparams);
+ snd_pcm_sw_params_set_start_threshold(handle,swparams,period_frames);
+ snd_pcm_sw_params_set_stop_threshold(handle,swparams,buffer_frames);
+ snd_pcm_sw_params_set_avail_min(handle, swparams,period_frames);
+ snd_pcm_sw_params(handle, swparams);
+
+ // Step 4: Prepare audio
+ ringBuffer.resize(buffer_size);
+ snd_pcm_prepare( handle );
+ snd_pcm_start(handle);
+
+ // Step 5: Setup timer
+ bytesAvailable = checkBytesReady();
+
+ if(pullMode)
+ connect(audioSource, &QIODevice::readyRead, this, &QAlsaAudioSource::userFeed);
+
+ // Step 6: Start audio processing
+ chunks = buffer_size/period_size;
+ timer->start(period_time*chunks/2000);
+
+ errorState = QAudio::NoError;
+
+ totalTimeValue = 0;
+
+ return true;
+}
+
+void QAlsaAudioSource::close()
+{
+ timer->stop();
+
+ if ( handle ) {
+ snd_pcm_drop( handle );
+ snd_pcm_close( handle );
+ handle = 0;
+ }
+}
+
+int QAlsaAudioSource::checkBytesReady()
+{
+ if(resuming)
+ bytesAvailable = period_size;
+ else if(deviceState != QAudio::ActiveState
+ && deviceState != QAudio::IdleState)
+ bytesAvailable = 0;
+ else {
+ int frames = snd_pcm_avail_update(handle);
+ if (frames < 0) {
+ bytesAvailable = frames;
+ } else {
+ if((int)frames > (int)buffer_frames)
+ frames = buffer_frames;
+ bytesAvailable = snd_pcm_frames_to_bytes(handle, frames);
+ }
+ }
+ return bytesAvailable;
+}
+
+qsizetype QAlsaAudioSource::bytesReady() const
+{
+ return qMax(bytesAvailable, 0);
+}
+
+qint64 QAlsaAudioSource::read(char* data, qint64 len)
+{
+ // Read in some audio data and write it to QIODevice, pull mode
+ if ( !handle )
+ return 0;
+
+ int bytesRead = 0;
+ int bytesInRingbufferBeforeRead = ringBuffer.bytesOfDataInBuffer();
+
+ if (ringBuffer.bytesOfDataInBuffer() < len) {
+
+ // bytesAvaiable is saved as a side effect of checkBytesReady().
+ int bytesToRead = checkBytesReady();
+
+ if (bytesToRead < 0) {
+ // bytesAvailable as negative is error code, try to recover from it.
+ xrun_recovery(bytesToRead);
+ bytesToRead = checkBytesReady();
+ if (bytesToRead < 0) {
+ // recovery failed must stop and set error.
+ close();
+ errorState = QAudio::IOError;
+ deviceState = QAudio::StoppedState;
+ emit stateChanged(deviceState);
+ return 0;
+ }
+ }
+
+ bytesToRead = qMin<qint64>(len, bytesToRead);
+ bytesToRead = qMin<qint64>(ringBuffer.freeBytes(), bytesToRead);
+ bytesToRead -= bytesToRead % period_size;
+
+ int count=0;
+ int err = 0;
+ QVarLengthArray<char, 4096> buffer(bytesToRead);
+ while(count < 5 && bytesToRead > 0) {
+ int chunks = bytesToRead / period_size;
+ int frames = chunks * period_frames;
+ if (frames > (int)buffer_frames)
+ frames = buffer_frames;
+
+ int readFrames = snd_pcm_readi(handle, buffer.data(), frames);
+ bytesRead = snd_pcm_frames_to_bytes(handle, readFrames);
+ if (m_volume < 1.0f)
+ QAudioHelperInternal::qMultiplySamples(m_volume, settings,
+ buffer.constData(),
+ buffer.data(), bytesRead);
+
+ if (readFrames >= 0) {
+ ringBuffer.write(buffer.data(), bytesRead);
+#ifdef DEBUG_AUDIO
+ qDebug() << QString::fromLatin1("read in bytes = %1 (frames=%2)").arg(bytesRead).arg(readFrames).toLatin1().constData();
+#endif
+ break;
+ } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) {
+ errorState = QAudio::IOError;
+ err = 0;
+ break;
+ } else {
+ if(readFrames == -EPIPE) {
+ errorState = QAudio::UnderrunError;
+ err = snd_pcm_prepare(handle);
+#ifdef ESTRPIPE
+ } else if(readFrames == -ESTRPIPE) {
+ err = snd_pcm_prepare(handle);
+#endif
+ }
+ if(err != 0) break;
+ }
+ count++;
+ }
+
+ }
+
+ bytesRead += bytesInRingbufferBeforeRead;
+
+ if (bytesRead > 0) {
+ // got some send it onward
+#ifdef DEBUG_AUDIO
+ qDebug() << "frames to write to QIODevice = " <<
+ snd_pcm_bytes_to_frames( handle, (int)bytesRead ) << " (" << bytesRead << ") bytes";
+#endif
+ if (deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
+ return 0;
+
+ if (pullMode) {
+ qint64 l = 0;
+ qint64 bytesWritten = 0;
+ while (ringBuffer.bytesOfDataInBuffer() > 0) {
+ l = audioSource->write(ringBuffer.availableData(), ringBuffer.availableDataBlockSize());
+ if (l > 0) {
+ ringBuffer.readBytes(l);
+ bytesWritten += l;
+ } else {
+ break;
+ }
+ }
+
+ if (l < 0) {
+ close();
+ errorState = QAudio::IOError;
+ deviceState = QAudio::StoppedState;
+ emit stateChanged(deviceState);
+ } else if (l == 0 && bytesWritten == 0) {
+ if (deviceState != QAudio::IdleState) {
+ errorState = QAudio::NoError;
+ deviceState = QAudio::IdleState;
+ emit stateChanged(deviceState);
+ }
+ } else {
+ bytesAvailable -= bytesWritten;
+ totalTimeValue += bytesWritten;
+ resuming = false;
+ if (deviceState != QAudio::ActiveState) {
+ errorState = QAudio::NoError;
+ deviceState = QAudio::ActiveState;
+ emit stateChanged(deviceState);
+ }
+ }
+
+ return bytesWritten;
+ } else {
+ while (ringBuffer.bytesOfDataInBuffer() > 0) {
+ int size = ringBuffer.availableDataBlockSize();
+ memcpy(data, ringBuffer.availableData(), size);
+ data += size;
+ ringBuffer.readBytes(size);
+ }
+
+ bytesAvailable -= bytesRead;
+ totalTimeValue += bytesRead;
+ resuming = false;
+ if (deviceState != QAudio::ActiveState) {
+ errorState = QAudio::NoError;
+ deviceState = QAudio::ActiveState;
+ emit stateChanged(deviceState);
+ }
+
+ return bytesRead;
+ }
+ }
+
+ return 0;
+}
+
+void QAlsaAudioSource::resume()
+{
+ if(deviceState == QAudio::SuspendedState) {
+ int err = 0;
+
+ if(handle) {
+ err = snd_pcm_prepare( handle );
+ if(err < 0)
+ xrun_recovery(err);
+
+ err = snd_pcm_start(handle);
+ if(err < 0)
+ xrun_recovery(err);
+
+ bytesAvailable = buffer_size;
+ }
+ resuming = true;
+ deviceState = QAudio::ActiveState;
+ int chunks = buffer_size/period_size;
+ timer->start(period_time*chunks/2000);
+ emit stateChanged(deviceState);
+ }
+}
+
+void QAlsaAudioSource::setBufferSize(qsizetype value)
+{
+ buffer_size = value;
+}
+
+qsizetype QAlsaAudioSource::bufferSize() const
+{
+ return buffer_size;
+}
+
+qint64 QAlsaAudioSource::processedUSecs() const
+{
+ qint64 result = qint64(1000000) * totalTimeValue /
+ settings.bytesPerFrame() /
+ settings.sampleRate();
+
+ return result;
+}
+
+void QAlsaAudioSource::suspend()
+{
+ if(deviceState == QAudio::ActiveState||resuming) {
+ snd_pcm_drain(handle);
+ timer->stop();
+ deviceState = QAudio::SuspendedState;
+ emit stateChanged(deviceState);
+ }
+}
+
+void QAlsaAudioSource::userFeed()
+{
+ if(deviceState == QAudio::StoppedState || deviceState == QAudio::SuspendedState)
+ return;
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :userFeed() IN";
+#endif
+ deviceReady();
+}
+
+bool QAlsaAudioSource::deviceReady()
+{
+ 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
+ AlsaInputPrivate* a = qobject_cast<AlsaInputPrivate*>(audioSource);
+ a->trigger();
+ }
+ bytesAvailable = checkBytesReady();
+
+ if(deviceState != QAudio::ActiveState)
+ return true;
+
+ if (bytesAvailable < 0) {
+ // bytesAvailable as negative is error code, try to recover from it.
+ xrun_recovery(bytesAvailable);
+ bytesAvailable = checkBytesReady();
+ if (bytesAvailable < 0) {
+ // recovery failed must stop and set error.
+ close();
+ errorState = QAudio::IOError;
+ deviceState = QAudio::StoppedState;
+ emit stateChanged(deviceState);
+ return 0;
+ }
+ }
+
+ return true;
+}
+
+void QAlsaAudioSource::reset()
+{
+ if(handle)
+ snd_pcm_reset(handle);
+ stop();
+ bytesAvailable = 0;
+}
+
+void QAlsaAudioSource::drain()
+{
+ if(handle)
+ snd_pcm_drain(handle);
+}
+
+AlsaInputPrivate::AlsaInputPrivate(QAlsaAudioSource* audio)
+{
+ audioDevice = qobject_cast<QAlsaAudioSource*>(audio);
+}
+
+AlsaInputPrivate::~AlsaInputPrivate()
+{
+}
+
+qint64 AlsaInputPrivate::readData( char* data, qint64 len)
+{
+ return audioDevice->read(data,len);
+}
+
+qint64 AlsaInputPrivate::writeData(const char* data, qint64 len)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(len);
+ return 0;
+}
+
+void AlsaInputPrivate::trigger()
+{
+ emit readyRead();
+}
+
+RingBuffer::RingBuffer() :
+ m_head(0),
+ m_tail(0)
+{
+}
+
+void RingBuffer::resize(int size)
+{
+ m_data.resize(size);
+}
+
+int RingBuffer::bytesOfDataInBuffer() const
+{
+ if (m_head < m_tail)
+ return m_tail - m_head;
+ else if (m_tail < m_head)
+ return m_data.size() + m_tail - m_head;
+ else
+ return 0;
+}
+
+int RingBuffer::freeBytes() const
+{
+ if (m_head > m_tail)
+ return m_head - m_tail - 1;
+ else if (m_tail > m_head)
+ return m_data.size() - m_tail + m_head - 1;
+ else
+ return m_data.size() - 1;
+}
+
+const char *RingBuffer::availableData() const
+{
+ return (m_data.constData() + m_head);
+}
+
+int RingBuffer::availableDataBlockSize() const
+{
+ if (m_head > m_tail)
+ return m_data.size() - m_head;
+ else if (m_tail > m_head)
+ return m_tail - m_head;
+ else
+ return 0;
+}
+
+void RingBuffer::readBytes(int bytes)
+{
+ m_head = (m_head + bytes) % m_data.size();
+}
+
+void RingBuffer::write(char *data, int len)
+{
+ if (m_tail + len < m_data.size()) {
+ memcpy(m_data.data() + m_tail, data, len);
+ m_tail += len;
+ } else {
+ int bytesUntilEnd = m_data.size() - m_tail;
+ memcpy(m_data.data() + m_tail, data, bytesUntilEnd);
+ if (len - bytesUntilEnd > 0)
+ memcpy(m_data.data(), data + bytesUntilEnd, len - bytesUntilEnd);
+ m_tail = len - bytesUntilEnd;
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qalsaaudiosource_p.cpp"
diff --git a/src/multimedia/alsa/qalsaaudiosource_p.h b/src/multimedia/alsa/qalsaaudiosource_p.h
new file mode 100644
index 000000000..87487a6ad
--- /dev/null
+++ b/src/multimedia/alsa/qalsaaudiosource_p.h
@@ -0,0 +1,142 @@
+// 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 QAUDIOINPUTALSA_H
+#define QAUDIOINPUTALSA_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 AlsaInputPrivate;
+
+class RingBuffer
+{
+public:
+ RingBuffer();
+
+ void resize(int size);
+
+ int bytesOfDataInBuffer() const;
+ int freeBytes() const;
+
+ const char *availableData() const;
+ int availableDataBlockSize() const;
+ void readBytes(int bytes);
+
+ void write(char *data, int len);
+
+private:
+ int m_head;
+ int m_tail;
+
+ QByteArray m_data;
+};
+
+class QAlsaAudioSource : public QPlatformAudioSource
+{
+ Q_OBJECT
+public:
+ QAlsaAudioSource(const QByteArray &device, QObject *parent);
+ ~QAlsaAudioSource();
+
+ qint64 read(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 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) override;
+ qreal volume() const override;
+ bool resuming;
+ snd_pcm_t* handle;
+ qint64 totalTimeValue;
+ QIODevice* audioSource;
+ QAudioFormat settings;
+ QAudio::Error errorState;
+ QAudio::State deviceState;
+
+private slots:
+ void userFeed();
+ bool deviceReady();
+
+private:
+ int checkBytesReady();
+ int xrun_recovery(int err);
+ int setFormat();
+ bool open();
+ void close();
+ void drain();
+
+ QTimer* timer;
+ qint64 elapsedTimeOffset;
+ RingBuffer ringBuffer;
+ qsizetype bytesAvailable;
+ QByteArray m_device;
+ bool pullMode;
+ qsizetype buffer_size;
+ int period_size;
+ unsigned int buffer_time;
+ unsigned int period_time;
+ snd_pcm_uframes_t buffer_frames;
+ snd_pcm_uframes_t period_frames;
+ snd_pcm_access_t access;
+ snd_pcm_format_t pcmformat;
+ snd_pcm_hw_params_t *hwparams;
+ qreal m_volume;
+};
+
+class AlsaInputPrivate : public QIODevice
+{
+ Q_OBJECT
+public:
+ AlsaInputPrivate(QAlsaAudioSource* audio);
+ ~AlsaInputPrivate();
+
+ qint64 readData( char* data, qint64 len) override;
+ qint64 writeData(const char* data, qint64 len) override;
+
+ void trigger();
+private:
+ QAlsaAudioSource *audioDevice;
+};
+
+QT_END_NAMESPACE
+
+
+#endif
diff --git a/src/multimedia/alsa/qalsamediadevices.cpp b/src/multimedia/alsa/qalsamediadevices.cpp
new file mode 100644
index 000000000..9466fa0cd
--- /dev/null
+++ b/src/multimedia/alsa/qalsamediadevices.cpp
@@ -0,0 +1,130 @@
+// 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
+
+namespace {
+
+struct free_char
+{
+ void operator()(char *c) const { ::free(c); }
+};
+
+using unique_str = std::unique_ptr<char, free_char>;
+
+bool operator==(const unique_str &str, std::string_view sv)
+{
+ return std::string_view{ str.get() } == sv;
+}
+bool operator!=(const unique_str &str, std::string_view sv)
+{
+ return !(str == sv);
+}
+
+} // namespace
+
+QAlsaMediaDevices::QAlsaMediaDevices()
+ : QPlatformMediaDevices()
+{
+}
+
+static QList<QAudioDevice> availableDevices(QAudioDevice::Mode mode)
+{
+ QList<QAudioDevice> devices;
+
+ // Create a list of all current audio devices that support mode
+ void **hints;
+ if (snd_device_name_hint(-1, "pcm", &hints) < 0) {
+ qWarning() << "no alsa devices available";
+ return devices;
+ }
+
+ std::string_view filter = (mode == QAudioDevice::Input) ? "Input" : "Output";
+
+ QAlsaAudioDeviceInfo *sysdefault = nullptr;
+
+ auto makeDeviceInfo = [&filter, mode](void *entry) -> QAlsaAudioDeviceInfo * {
+ unique_str name{ snd_device_name_get_hint(entry, "NAME") };
+ if (name && name != "null") {
+ unique_str descr{ snd_device_name_get_hint(entry, "DESC") };
+ unique_str io{ snd_device_name_get_hint(entry, "IOID") };
+
+ if (descr && (!io || (io == filter))) {
+ auto *infop = new QAlsaAudioDeviceInfo{
+ name.get(),
+ QString::fromUtf8(descr.get()),
+ mode,
+ };
+ return infop;
+ }
+ }
+ return nullptr;
+ };
+
+ bool hasDefault = false;
+ void **n = hints;
+ while (*n != NULL) {
+ QAlsaAudioDeviceInfo *infop = makeDeviceInfo(*n++);
+
+ if (infop) {
+ devices.append(infop->create());
+ if (!hasDefault && infop->id.startsWith("default")) {
+ infop->isDefault = true;
+ hasDefault = true;
+ }
+ if (!sysdefault && infop->id.startsWith("sysdefault"))
+ sysdefault = infop;
+ }
+ }
+
+ 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) {
+ // forcefully declare the first device as "default"
+ QAlsaAudioDeviceInfo *infop = makeDeviceInfo(hints[0]);
+ if (infop) {
+ infop->isDefault = true;
+ devices.prepend(infop->create());
+ }
+ }
+
+ 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);
+}
+
+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/android/qandroidaudiosink.cpp b/src/multimedia/android/qandroidaudiosink.cpp
new file mode 100644
index 000000000..4da4c5fdc
--- /dev/null
+++ b/src/multimedia/android/qandroidaudiosink.cpp
@@ -0,0 +1,614 @@
+// 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"
+#include <QDebug>
+#include <qmath.h>
+#include <qmediadevices.h>
+
+#ifdef ANDROID
+#include <SLES/OpenSLES_Android.h>
+#include <SLES/OpenSLES_AndroidConfiguration.h>
+#endif // ANDROID
+
+QT_BEGIN_NAMESPACE
+
+static inline void openSlDebugInfo()
+{
+ const QAudioFormat &format = QMediaDevices::defaultAudioOutput().preferredFormat();
+ qDebug() << "======= OpenSL ES Device info ======="
+ << "\nSupports low-latency playback: " << (QOpenSLESEngine::supportsLowLatency() ? "YES" : "NO")
+ << "\nPreferred sample rate: " << QOpenSLESEngine::getOutputValue(QOpenSLESEngine::SampleRate, -1)
+ << "\nFrames per buffer: " << QOpenSLESEngine::getOutputValue(QOpenSLESEngine::FramesPerBuffer, -1)
+ << "\nPreferred Format: " << format
+ << "\nLow-latency buffer size: " << QOpenSLESEngine::getLowLatencyBufferSize(format)
+ << "\nDefault buffer size: " << QOpenSLESEngine::getDefaultBufferSize(format);
+}
+
+QAndroidAudioSink::QAndroidAudioSink(const QByteArray &device, QObject *parent)
+ : QPlatformAudioSink(parent),
+ m_deviceName(device)
+{
+#ifndef ANDROID
+ m_streamType = -1;
+#else
+ m_streamType = SL_ANDROID_STREAM_MEDIA;
+#endif // ANDROID
+}
+
+QAndroidAudioSink::~QAndroidAudioSink()
+{
+ destroyPlayer();
+}
+
+QAudio::Error QAndroidAudioSink::error() const
+{
+ return m_error;
+}
+
+QAudio::State QAndroidAudioSink::state() const
+{
+ return m_state;
+}
+
+void QAndroidAudioSink::start(QIODevice *device)
+{
+ Q_ASSERT(device);
+
+ if (m_state != QAudio::StoppedState)
+ stop();
+
+ if (!preparePlayer())
+ return;
+
+ m_endSound = false;
+ m_pullMode = true;
+ m_audioSource = device;
+ m_nextBuffer = 0;
+ m_processedBytes = 0;
+ m_availableBuffers = BufferCount;
+ setState(QAudio::ActiveState);
+ setError(QAudio::NoError);
+
+ // Attempt to fill buffers first.
+ 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,
+ m_buffers + index,
+ readSize)) {
+ setError(QAudio::FatalError);
+ destroyPlayer();
+ return;
+ }
+ m_processedBytes += readSize;
+ }
+
+ if (m_processedBytes < 1)
+ onEOSEvent();
+
+ // 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()
+{
+ if (m_state != QAudio::StoppedState)
+ stop();
+
+ if (!preparePlayer())
+ return nullptr;
+
+ m_pullMode = false;
+ m_processedBytes = 0;
+ m_availableBuffers = BufferCount;
+ m_audioSource = new SLIODevicePrivate(this);
+ m_audioSource->open(QIODevice::WriteOnly | QIODevice::Unbuffered);
+
+ // Change the state to playing
+ startPlayer();
+
+ setState(QAudio::IdleState);
+ return m_audioSource;
+}
+
+void QAndroidAudioSink::stop()
+{
+ if (m_state == QAudio::StoppedState)
+ return;
+
+ stopPlayer();
+ setError(QAudio::NoError);
+}
+
+qsizetype QAndroidAudioSink::bytesFree() const
+{
+ if (m_state != QAudio::ActiveState && m_state != QAudio::IdleState)
+ return 0;
+
+ return m_availableBuffers.loadAcquire() ? m_bufferSize : 0;
+}
+
+void QAndroidAudioSink::setBufferSize(qsizetype value)
+{
+ if (m_state != QAudio::StoppedState)
+ return;
+
+ m_startRequiresInit = true;
+ m_bufferSize = value;
+}
+
+qsizetype QAndroidAudioSink::bufferSize() const
+{
+ return m_bufferSize;
+}
+
+qint64 QAndroidAudioSink::processedUSecs() const
+{
+ if (m_state == QAudio::IdleState || m_state == QAudio::SuspendedState)
+ return m_format.durationForBytes(m_processedBytes);
+
+ SLmillisecond processMSec = 0;
+ if (m_playItf)
+ (*m_playItf)->GetPosition(m_playItf, &processMSec);
+
+ return processMSec * 1000;
+}
+
+void QAndroidAudioSink::resume()
+{
+ if (m_state != QAudio::SuspendedState)
+ return;
+
+ if (SL_RESULT_SUCCESS != (*m_playItf)->SetPlayState(m_playItf, SL_PLAYSTATE_PLAYING)) {
+ setError(QAudio::FatalError);
+ destroyPlayer();
+ return;
+ }
+
+ setState(m_suspendedInState);
+ setError(QAudio::NoError);
+}
+
+void QAndroidAudioSink::setFormat(const QAudioFormat &format)
+{
+ m_startRequiresInit = true;
+ m_format = format;
+}
+
+QAudioFormat QAndroidAudioSink::format() const
+{
+ return m_format;
+}
+
+void QAndroidAudioSink::suspend()
+{
+ if (m_state != QAudio::ActiveState && m_state != QAudio::IdleState)
+ return;
+
+ if (SL_RESULT_SUCCESS != (*m_playItf)->SetPlayState(m_playItf, SL_PLAYSTATE_PAUSED)) {
+ setError(QAudio::FatalError);
+ destroyPlayer();
+ return;
+ }
+
+ m_suspendedInState = m_state;
+ setState(QAudio::SuspendedState);
+ setError(QAudio::NoError);
+}
+
+void QAndroidAudioSink::reset()
+{
+ destroyPlayer();
+}
+
+void QAndroidAudioSink::setVolume(qreal vol)
+{
+ m_volume = qBound(qreal(0.0), vol, qreal(1.0));
+ const SLmillibel newVolume = adjustVolume(m_volume);
+ if (m_volumeItf && SL_RESULT_SUCCESS != (*m_volumeItf)->SetVolumeLevel(m_volumeItf, newVolume))
+ qWarning() << "Unable to change volume";
+}
+
+qreal QAndroidAudioSink::volume() const
+{
+ return m_volume;
+}
+
+void QAndroidAudioSink::onEOSEvent()
+{
+ if (m_state != QAudio::ActiveState)
+ return;
+
+ SLBufferQueueState state;
+ if (SL_RESULT_SUCCESS != (*m_bufferQueueItf)->GetState(m_bufferQueueItf, &state))
+ return;
+
+ if (state.count > 0)
+ return;
+
+ setState(QAudio::IdleState);
+ setError(QAudio::UnderrunError);
+}
+
+void QAndroidAudioSink::onBytesProcessed(qint64 bytes)
+{
+ m_processedBytes += bytes;
+}
+
+void QAndroidAudioSink::bufferAvailable()
+{
+ 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 == BufferCount)
+ QMetaObject::invokeMethod(this, "onEOSEvent", Qt::QueuedConnection);
+
+ return;
+ }
+
+ // We're in pull mode.
+ const int index = m_nextBuffer * 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);
+ return;
+ }
+
+
+ if (SL_RESULT_SUCCESS != (*m_bufferQueueItf)->Enqueue(m_bufferQueueItf,
+ m_buffers + index,
+ readSize)) {
+ setError(QAudio::FatalError);
+ destroyPlayer();
+ return;
+ }
+
+ 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)
+{
+ Q_UNUSED(player);
+ QAndroidAudioSink *audioOutput = reinterpret_cast<QAndroidAudioSink *>(ctx);
+ if (event & SL_PLAYEVENT_HEADATEND)
+ QMetaObject::invokeMethod(audioOutput, "onEOSEvent", Qt::QueuedConnection);
+}
+
+void QAndroidAudioSink::bufferQueueCallback(SLBufferQueueItf bufferQueue, void *ctx)
+{
+ Q_UNUSED(bufferQueue);
+ QAndroidAudioSink *audioOutput = reinterpret_cast<QAndroidAudioSink *>(ctx);
+ QMetaObject::invokeMethod(audioOutput, "bufferAvailable", Qt::QueuedConnection);
+}
+
+bool QAndroidAudioSink::preparePlayer()
+{
+ if (m_startRequiresInit)
+ destroyPlayer();
+ 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";
+ setError(QAudio::FatalError);
+ return false;
+ }
+
+ SLDataLocator_BufferQueue bufferQueueLocator = { SL_DATALOCATOR_BUFFERQUEUE, BufferCount };
+ SLAndroidDataFormat_PCM_EX pcmFormat = QOpenSLESEngine::audioFormatToSLFormatPCM(m_format);
+
+ SLDataSource audioSrc = { &bufferQueueLocator, &pcmFormat };
+
+ // OutputMix
+ if (SL_RESULT_SUCCESS != (*engine)->CreateOutputMix(engine,
+ &m_outputMixObject,
+ 0,
+ nullptr,
+ nullptr)) {
+ qWarning() << "Unable to create output mix";
+ setError(QAudio::FatalError);
+ return false;
+ }
+
+ if (SL_RESULT_SUCCESS != (*m_outputMixObject)->Realize(m_outputMixObject, SL_BOOLEAN_FALSE)) {
+ qWarning() << "Unable to initialize output mix";
+ setError(QAudio::FatalError);
+ return false;
+ }
+
+ SLDataLocator_OutputMix outputMixLocator = { SL_DATALOCATOR_OUTPUTMIX, m_outputMixObject };
+ SLDataSink audioSink = { &outputMixLocator, nullptr };
+
+#ifndef ANDROID
+ const int iids = 2;
+ const SLInterfaceID ids[iids] = { SL_IID_BUFFERQUEUE, SL_IID_VOLUME };
+ const SLboolean req[iids] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
+#else
+ const int iids = 3;
+ const SLInterfaceID ids[iids] = { SL_IID_BUFFERQUEUE,
+ SL_IID_VOLUME,
+ SL_IID_ANDROIDCONFIGURATION };
+ const SLboolean req[iids] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
+#endif // ANDROID
+
+ // AudioPlayer
+ if (SL_RESULT_SUCCESS != (*engine)->CreateAudioPlayer(engine,
+ &m_playerObject,
+ &audioSrc,
+ &audioSink,
+ iids,
+ ids,
+ req)) {
+ qWarning() << "Unable to create AudioPlayer";
+ setError(QAudio::OpenError);
+ return false;
+ }
+
+#ifdef ANDROID
+ // Set profile/category
+ SLAndroidConfigurationItf playerConfig;
+ if (SL_RESULT_SUCCESS == (*m_playerObject)->GetInterface(m_playerObject,
+ SL_IID_ANDROIDCONFIGURATION,
+ &playerConfig)) {
+ (*playerConfig)->SetConfiguration(playerConfig,
+ SL_ANDROID_KEY_STREAM_TYPE,
+ &m_streamType,
+ sizeof(SLint32));
+ }
+#endif // ANDROID
+
+ if (SL_RESULT_SUCCESS != (*m_playerObject)->Realize(m_playerObject, SL_BOOLEAN_FALSE)) {
+ qWarning() << "Unable to initialize AudioPlayer";
+ setError(QAudio::OpenError);
+ return false;
+ }
+
+ // Buffer interface
+ if (SL_RESULT_SUCCESS != (*m_playerObject)->GetInterface(m_playerObject,
+ SL_IID_BUFFERQUEUE,
+ &m_bufferQueueItf)) {
+ setError(QAudio::FatalError);
+ return false;
+ }
+
+ if (SL_RESULT_SUCCESS != (*m_bufferQueueItf)->RegisterCallback(m_bufferQueueItf,
+ bufferQueueCallback,
+ this)) {
+ setError(QAudio::FatalError);
+ return false;
+ }
+
+ // Play interface
+ if (SL_RESULT_SUCCESS != (*m_playerObject)->GetInterface(m_playerObject,
+ SL_IID_PLAY,
+ &m_playItf)) {
+ setError(QAudio::FatalError);
+ return false;
+ }
+
+ if (SL_RESULT_SUCCESS != (*m_playItf)->RegisterCallback(m_playItf, playCallback, this)) {
+ setError(QAudio::FatalError);
+ return false;
+ }
+
+ if (SL_RESULT_SUCCESS != (*m_playItf)->SetCallbackEventsMask(m_playItf, m_eventMask)) {
+ setError(QAudio::FatalError);
+ return false;
+ }
+
+ // Volume interface
+ if (SL_RESULT_SUCCESS != (*m_playerObject)->GetInterface(m_playerObject,
+ SL_IID_VOLUME,
+ &m_volumeItf)) {
+ setError(QAudio::FatalError);
+ return false;
+ }
+
+ setVolume(m_volume);
+
+ const int lowLatencyBufferSize = QOpenSLESEngine::getLowLatencyBufferSize(m_format);
+ const int defaultBufferSize = QOpenSLESEngine::getDefaultBufferSize(m_format);
+
+ if (defaultBufferSize <= 0) {
+ qWarning() << "Unable to get minimum buffer size, returned" << defaultBufferSize;
+ setError(QAudio::FatalError);
+ return false;
+ }
+
+ // Buffer size
+ if (m_bufferSize <= 0) {
+ m_bufferSize = defaultBufferSize;
+ } else if (QOpenSLESEngine::supportsLowLatency()) {
+ if (m_bufferSize < lowLatencyBufferSize)
+ m_bufferSize = lowLatencyBufferSize;
+ } else if (m_bufferSize < defaultBufferSize) {
+ m_bufferSize = defaultBufferSize;
+ }
+
+ if (!m_buffers)
+ m_buffers = new char[BufferCount * m_bufferSize];
+
+ setError(QAudio::NoError);
+ m_startRequiresInit = false;
+
+ return true;
+}
+
+void QAndroidAudioSink::destroyPlayer()
+{
+ if (m_state != QAudio::StoppedState)
+ stopPlayer();
+
+ if (m_playerObject) {
+ (*m_playerObject)->Destroy(m_playerObject);
+ m_playerObject = nullptr;
+ }
+
+ if (m_outputMixObject) {
+ (*m_outputMixObject)->Destroy(m_outputMixObject);
+ m_outputMixObject = nullptr;
+ }
+
+ if (!m_pullMode && m_audioSource) {
+ m_audioSource->close();
+ delete m_audioSource;
+ m_audioSource = nullptr;
+ }
+
+ delete [] m_buffers;
+ m_buffers = nullptr;
+ m_processedBytes = 0;
+ m_nextBuffer = 0;
+ m_availableBuffers.storeRelease(BufferCount);
+ m_playItf = nullptr;
+ m_volumeItf = nullptr;
+ m_bufferQueueItf = nullptr;
+ m_startRequiresInit = true;
+}
+
+void QAndroidAudioSink::stopPlayer()
+{
+ setState(QAudio::StoppedState);
+
+ 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...
+ if (m_playItf)
+ (*m_playItf)->SetPlayState(m_playItf, SL_PLAYSTATE_STOPPED);
+
+ if (m_bufferQueueItf && SL_RESULT_SUCCESS != (*m_bufferQueueItf)->Clear(m_bufferQueueItf))
+ qWarning() << "Unable to clear buffer";
+}
+
+void QAndroidAudioSink::startPlayer()
+{
+ if (QOpenSLESEngine::printDebugInfo())
+ openSlDebugInfo();
+
+ if (SL_RESULT_SUCCESS != (*m_playItf)->SetPlayState(m_playItf, SL_PLAYSTATE_PLAYING)) {
+ setError(QAudio::FatalError);
+ destroyPlayer();
+ }
+}
+
+qint64 QAndroidAudioSink::writeData(const char *data, qint64 len)
+{
+ if (!len)
+ return 0;
+
+ if (len > m_bufferSize)
+ len = m_bufferSize;
+
+ // Acquire one slot in the buffer
+ const int before = m_availableBuffers.fetchAndAddAcquire(-1);
+
+ // If there where no vacant slots, then we just overdrew the buffer account...
+ if (before < 1) {
+ m_availableBuffers.fetchAndAddRelease(1);
+ return 0;
+ }
+
+ const int index = m_nextBuffer * m_bufferSize;
+ ::memcpy(m_buffers + index, data, len);
+ const SLuint32 res = (*m_bufferQueueItf)->Enqueue(m_bufferQueueItf,
+ m_buffers + index,
+ len);
+
+ // If we where unable to enqueue a new buffer, give back the acquired slot.
+ if (res == SL_RESULT_BUFFER_INSUFFICIENT) {
+ m_availableBuffers.fetchAndAddRelease(1);
+ return 0;
+ }
+
+ if (res != SL_RESULT_SUCCESS) {
+ setError(QAudio::FatalError);
+ destroyPlayer();
+ return -1;
+ }
+
+ m_processedBytes += len;
+ setState(QAudio::ActiveState);
+ setError(QAudio::NoError);
+ m_nextBuffer = (m_nextBuffer + 1) % BufferCount;
+
+ return len;
+}
+
+inline void QAndroidAudioSink::setState(QAudio::State state)
+{
+ if (m_state == state)
+ return;
+
+ m_state = state;
+ Q_EMIT stateChanged(m_state);
+}
+
+inline void QAndroidAudioSink::setError(QAudio::Error error)
+{
+ if (m_error == error)
+ return;
+
+ m_error = error;
+ Q_EMIT errorChanged(m_error);
+}
+
+inline SLmillibel QAndroidAudioSink::adjustVolume(qreal vol)
+{
+ if (qFuzzyIsNull(vol))
+ return SL_MILLIBEL_MIN;
+
+ if (qFuzzyCompare(vol, qreal(1.0)))
+ return 0;
+
+ return QAudio::convertVolume(vol, QAudio::LinearVolumeScale, QAudio::DecibelVolumeScale) * 100;
+}
+
+QT_END_NAMESPACE
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/android/qandroidaudiosource.cpp b/src/multimedia/android/qandroidaudiosource.cpp
new file mode 100644
index 000000000..3a7332fd1
--- /dev/null
+++ b/src/multimedia/android/qandroidaudiosource.cpp
@@ -0,0 +1,470 @@
+// 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 <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
+#define DEFAULT_PERIOD_TIME_MS 50
+#define MINIMUM_PERIOD_TIME_MS 5
+
+#ifdef ANDROID
+static bool hasRecordingPermission()
+{
+ QMicrophonePermission permission;
+
+ const bool permitted = qApp->checkPermission(permission) == Qt::PermissionStatus::Granted;
+ if (!permitted)
+ qCWarning(qLcAndroidAudioSource, "Missing microphone permission!");
+
+ return permitted;
+}
+
+static void bufferQueueCallback(SLAndroidSimpleBufferQueueItf, void *context)
+#else
+static void bufferQueueCallback(SLBufferQueueItf, void *context)
+#endif
+{
+ // Process buffer in main thread
+ QMetaObject::invokeMethod(reinterpret_cast<QAndroidAudioSource*>(context), "processBuffer");
+}
+
+QAndroidAudioSource::QAndroidAudioSource(const QByteArray &device, QObject *parent)
+ : QPlatformAudioSource(parent)
+ , m_device(device)
+ , m_engine(QOpenSLESEngine::instance())
+ , m_recorderObject(0)
+ , m_recorder(0)
+ , m_bufferQueue(0)
+ , m_pullMode(true)
+ , m_processedBytes(0)
+ , m_audioSource(0)
+ , m_bufferIODevice(0)
+ , m_errorState(QAudio::NoError)
+ , m_deviceState(QAudio::StoppedState)
+ , m_lastNotifyTime(0)
+ , m_volume(1.0)
+ , m_bufferSize(0)
+ , m_buffers(new QByteArray[NUM_BUFFERS])
+ , m_currentBuffer(0)
+{
+#ifdef ANDROID
+ if (qstrcmp(device, QT_ANDROID_PRESET_CAMCORDER) == 0)
+ m_recorderPreset = SL_ANDROID_RECORDING_PRESET_CAMCORDER;
+ else if (qstrcmp(device, QT_ANDROID_PRESET_VOICE_RECOGNITION) == 0)
+ m_recorderPreset = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
+ else if (qstrcmp(device, QT_ANDROID_PRESET_VOICE_COMMUNICATION) == 0)
+ m_recorderPreset = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
+ else
+ m_recorderPreset = SL_ANDROID_RECORDING_PRESET_GENERIC;
+#endif
+}
+
+QAndroidAudioSource::~QAndroidAudioSource()
+{
+ if (m_recorderObject)
+ (*m_recorderObject)->Destroy(m_recorderObject);
+ delete[] m_buffers;
+}
+
+QAudio::Error QAndroidAudioSource::error() const
+{
+ return m_errorState;
+}
+
+QAudio::State QAndroidAudioSource::state() const
+{
+ return m_deviceState;
+}
+
+void QAndroidAudioSource::setFormat(const QAudioFormat &format)
+{
+ if (m_deviceState == QAudio::StoppedState)
+ m_format = format;
+}
+
+QAudioFormat QAndroidAudioSource::format() const
+{
+ return m_format;
+}
+
+void QAndroidAudioSource::start(QIODevice *device)
+{
+ if (m_deviceState != QAudio::StoppedState)
+ stopRecording();
+
+ if (!m_pullMode && m_bufferIODevice) {
+ m_bufferIODevice->close();
+ delete m_bufferIODevice;
+ m_bufferIODevice = 0;
+ }
+
+ m_pullMode = true;
+ m_audioSource = device;
+
+ if (startRecording()) {
+ m_deviceState = QAudio::ActiveState;
+ } else {
+ m_deviceState = QAudio::StoppedState;
+ Q_EMIT errorChanged(m_errorState);
+ }
+
+ Q_EMIT stateChanged(m_deviceState);
+}
+
+QIODevice *QAndroidAudioSource::start()
+{
+ if (m_deviceState != QAudio::StoppedState)
+ stopRecording();
+
+ m_audioSource = 0;
+
+ if (!m_pullMode && m_bufferIODevice) {
+ m_bufferIODevice->close();
+ delete m_bufferIODevice;
+ }
+
+ m_pullMode = false;
+ m_pushBuffer.clear();
+ m_bufferIODevice = new QBuffer(&m_pushBuffer, this);
+ m_bufferIODevice->open(QIODevice::ReadOnly);
+
+ if (startRecording()) {
+ m_deviceState = QAudio::IdleState;
+ } else {
+ m_deviceState = QAudio::StoppedState;
+ Q_EMIT errorChanged(m_errorState);
+ m_bufferIODevice->close();
+ delete m_bufferIODevice;
+ m_bufferIODevice = 0;
+ }
+
+ Q_EMIT stateChanged(m_deviceState);
+ return m_bufferIODevice;
+}
+
+bool QAndroidAudioSource::startRecording()
+{
+ if (!hasRecordingPermission())
+ return false;
+
+ m_processedBytes = 0;
+ m_lastNotifyTime = 0;
+
+ SLresult result;
+
+ // configure audio source
+ SLDataLocator_IODevice loc_dev = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
+ SL_DEFAULTDEVICEID_AUDIOINPUT, NULL };
+ SLDataSource audioSrc = { &loc_dev, NULL };
+
+ // configure audio sink
+#ifdef ANDROID
+ SLDataLocator_AndroidSimpleBufferQueue loc_bq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
+ NUM_BUFFERS };
+#else
+ SLDataLocator_BufferQueue loc_bq = { SL_DATALOCATOR_BUFFERQUEUE, NUM_BUFFERS };
+#endif
+
+ SLAndroidDataFormat_PCM_EX format_pcm = QOpenSLESEngine::audioFormatToSLFormatPCM(m_format);
+ SLDataSink audioSnk = { &loc_bq, &format_pcm };
+
+ // create audio recorder
+ // (requires the RECORD_AUDIO permission)
+#ifdef ANDROID
+ const SLInterfaceID id[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION };
+ const SLboolean req[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
+#else
+ const SLInterfaceID id[1] = { SL_IID_BUFFERQUEUE };
+ const SLboolean req[1] = { SL_BOOLEAN_TRUE };
+#endif
+
+ result = (*m_engine->slEngine())->CreateAudioRecorder(m_engine->slEngine(), &m_recorderObject,
+ &audioSrc, &audioSnk,
+ sizeof(req) / sizeof(SLboolean), id, req);
+ if (result != SL_RESULT_SUCCESS) {
+ m_errorState = QAudio::OpenError;
+ return false;
+ }
+
+#ifdef ANDROID
+ // configure recorder source
+ SLAndroidConfigurationItf configItf;
+ result = (*m_recorderObject)->GetInterface(m_recorderObject, SL_IID_ANDROIDCONFIGURATION,
+ &configItf);
+ if (result != SL_RESULT_SUCCESS) {
+ m_errorState = QAudio::OpenError;
+ return false;
+ }
+
+ result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET,
+ &m_recorderPreset, sizeof(SLuint32));
+
+ SLuint32 presetValue = SL_ANDROID_RECORDING_PRESET_NONE;
+ SLuint32 presetSize = 2*sizeof(SLuint32); // intentionally too big
+ result = (*configItf)->GetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET,
+ &presetSize, (void*)&presetValue);
+
+ if (result != SL_RESULT_SUCCESS || presetValue == SL_ANDROID_RECORDING_PRESET_NONE) {
+ m_errorState = QAudio::OpenError;
+ return false;
+ }
+#endif
+
+ // realize the audio recorder
+ result = (*m_recorderObject)->Realize(m_recorderObject, SL_BOOLEAN_FALSE);
+ if (result != SL_RESULT_SUCCESS) {
+ m_errorState = QAudio::OpenError;
+ return false;
+ }
+
+ // get the record interface
+ result = (*m_recorderObject)->GetInterface(m_recorderObject, SL_IID_RECORD, &m_recorder);
+ if (result != SL_RESULT_SUCCESS) {
+ m_errorState = QAudio::FatalError;
+ return false;
+ }
+
+ // get the buffer queue interface
+#ifdef ANDROID
+ SLInterfaceID bufferqueueItfID = SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
+#else
+ SLInterfaceID bufferqueueItfID = SL_IID_BUFFERQUEUE;
+#endif
+ result = (*m_recorderObject)->GetInterface(m_recorderObject, bufferqueueItfID, &m_bufferQueue);
+ if (result != SL_RESULT_SUCCESS) {
+ m_errorState = QAudio::FatalError;
+ return false;
+ }
+
+ // register callback on the buffer queue
+ result = (*m_bufferQueue)->RegisterCallback(m_bufferQueue, bufferQueueCallback, this);
+ if (result != SL_RESULT_SUCCESS) {
+ m_errorState = QAudio::FatalError;
+ return false;
+ }
+
+ if (m_bufferSize <= 0) {
+ m_bufferSize = m_format.bytesForDuration(DEFAULT_PERIOD_TIME_MS * 1000);
+ } else {
+ int minimumBufSize = m_format.bytesForDuration(MINIMUM_PERIOD_TIME_MS * 1000);
+ if (m_bufferSize < minimumBufSize)
+ m_bufferSize = minimumBufSize;
+ }
+
+ // enqueue empty buffers to be filled by the recorder
+ for (int i = 0; i < NUM_BUFFERS; ++i) {
+ m_buffers[i].resize(m_bufferSize);
+
+ result = (*m_bufferQueue)->Enqueue(m_bufferQueue, m_buffers[i].data(), m_bufferSize);
+ if (result != SL_RESULT_SUCCESS) {
+ m_errorState = QAudio::FatalError;
+ return false;
+ }
+ }
+
+ // start recording
+ result = (*m_recorder)->SetRecordState(m_recorder, SL_RECORDSTATE_RECORDING);
+ if (result != SL_RESULT_SUCCESS) {
+ m_errorState = QAudio::FatalError;
+ return false;
+ }
+
+ m_errorState = QAudio::NoError;
+
+ return true;
+}
+
+void QAndroidAudioSource::stop()
+{
+ if (m_deviceState == QAudio::StoppedState)
+ return;
+
+ m_deviceState = QAudio::StoppedState;
+
+ stopRecording();
+
+ m_errorState = QAudio::NoError;
+ Q_EMIT stateChanged(m_deviceState);
+}
+
+void QAndroidAudioSource::stopRecording()
+{
+ flushBuffers();
+
+ (*m_recorder)->SetRecordState(m_recorder, SL_RECORDSTATE_STOPPED);
+ (*m_bufferQueue)->Clear(m_bufferQueue);
+
+ (*m_recorderObject)->Destroy(m_recorderObject);
+ m_recorderObject = 0;
+
+ for (int i = 0; i < NUM_BUFFERS; ++i)
+ m_buffers[i].clear();
+ m_currentBuffer = 0;
+
+ if (!m_pullMode && m_bufferIODevice) {
+ m_bufferIODevice->close();
+ delete m_bufferIODevice;
+ m_bufferIODevice = 0;
+ m_pushBuffer.clear();
+ }
+}
+
+void QAndroidAudioSource::suspend()
+{
+ if (m_deviceState == QAudio::ActiveState) {
+ m_deviceState = QAudio::SuspendedState;
+ emit stateChanged(m_deviceState);
+
+ (*m_recorder)->SetRecordState(m_recorder, SL_RECORDSTATE_PAUSED);
+ }
+}
+
+void QAndroidAudioSource::resume()
+{
+ if (m_deviceState == QAudio::SuspendedState || m_deviceState == QAudio::IdleState) {
+ (*m_recorder)->SetRecordState(m_recorder, SL_RECORDSTATE_RECORDING);
+
+ m_deviceState = QAudio::ActiveState;
+ emit stateChanged(m_deviceState);
+ }
+}
+
+void QAndroidAudioSource::processBuffer()
+{
+ if (m_deviceState == QAudio::StoppedState || m_deviceState == QAudio::SuspendedState)
+ return;
+
+ if (m_deviceState != QAudio::ActiveState) {
+ m_errorState = QAudio::NoError;
+ m_deviceState = QAudio::ActiveState;
+ emit stateChanged(m_deviceState);
+ }
+
+ 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(),
+ processedBuffer->size());
+
+ m_currentBuffer = (m_currentBuffer + 1) % NUM_BUFFERS;
+
+ // If the buffer queue is empty (shouldn't happen), stop recording.
+#ifdef ANDROID
+ SLAndroidSimpleBufferQueueState state;
+#else
+ SLBufferQueueState state;
+#endif
+ result = (*m_bufferQueue)->GetState(m_bufferQueue, &state);
+ if (result != SL_RESULT_SUCCESS || state.count == 0) {
+ stop();
+ m_errorState = QAudio::FatalError;
+ Q_EMIT errorChanged(m_errorState);
+ }
+}
+
+void QAndroidAudioSource::writeDataToDevice(const char *data, int size)
+{
+ m_processedBytes += size;
+
+ QByteArray outData;
+
+ // Apply volume
+ if (m_volume < 1.0f) {
+ outData.resize(size);
+ QAudioHelperInternal::qMultiplySamples(m_volume, m_format, data, outData.data(), size);
+ } else {
+ outData.append(data, size);
+ }
+
+ if (m_pullMode) {
+ // write buffer to the QIODevice
+ if (m_audioSource->write(outData) < 0) {
+ stop();
+ m_errorState = QAudio::IOError;
+ Q_EMIT errorChanged(m_errorState);
+ }
+ } else {
+ // emits readyRead() so user will call read() on QIODevice to get some audio data
+ if (m_bufferIODevice != 0) {
+ m_pushBuffer.append(outData);
+ Q_EMIT m_bufferIODevice->readyRead();
+ }
+ }
+}
+
+void QAndroidAudioSource::flushBuffers()
+{
+ SLmillisecond recorderPos;
+ (*m_recorder)->GetPosition(m_recorder, &recorderPos);
+ qint64 devicePos = processedUSecs();
+
+ qint64 delta = recorderPos * 1000 - devicePos;
+
+ if (delta > 0) {
+ const int writeSize = qMin(m_buffers[m_currentBuffer].size(),
+ m_format.bytesForDuration(delta));
+ writeDataToDevice(m_buffers[m_currentBuffer].constData(), writeSize);
+ }
+}
+
+qsizetype QAndroidAudioSource::bytesReady() const
+{
+ if (m_deviceState == QAudio::ActiveState || m_deviceState == QAudio::SuspendedState)
+ return m_bufferIODevice ? m_bufferIODevice->bytesAvailable() : m_bufferSize;
+
+ return 0;
+}
+
+void QAndroidAudioSource::setBufferSize(qsizetype value)
+{
+ m_bufferSize = value;
+}
+
+qsizetype QAndroidAudioSource::bufferSize() const
+{
+ return m_bufferSize;
+}
+
+qint64 QAndroidAudioSource::processedUSecs() const
+{
+ return m_format.durationForBytes(m_processedBytes);
+}
+
+void QAndroidAudioSource::setVolume(qreal vol)
+{
+ m_volume = vol;
+}
+
+qreal QAndroidAudioSource::volume() const
+{
+ return m_volume;
+}
+
+void QAndroidAudioSource::reset()
+{
+ stop();
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/android/qandroidaudiosource_p.h b/src/multimedia/android/qandroidaudiosource_p.h
new file mode 100644
index 000000000..13578509c
--- /dev/null
+++ b/src/multimedia/android/qandroidaudiosource_p.h
@@ -0,0 +1,101 @@
+// 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
+
+//
+// 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 <QElapsedTimer>
+#include <SLES/OpenSLES.h>
+
+#ifdef ANDROID
+#include <SLES/OpenSLES_Android.h>
+
+#define QT_ANDROID_PRESET_MIC "mic"
+#define QT_ANDROID_PRESET_CAMCORDER "camcorder"
+#define QT_ANDROID_PRESET_VOICE_RECOGNITION "voicerecognition"
+#define QT_ANDROID_PRESET_VOICE_COMMUNICATION "voicecommunication"
+
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QOpenSLESEngine;
+class QIODevice;
+class QBuffer;
+
+class QAndroidAudioSource : public QPlatformAudioSource
+{
+ Q_OBJECT
+
+public:
+ QAndroidAudioSource(const QByteArray &device, QObject *parent);
+ ~QAndroidAudioSource();
+
+ void start(QIODevice *device);
+ QIODevice *start();
+ 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 setFormat(const QAudioFormat &format);
+ QAudioFormat format() const;
+
+ void setVolume(qreal volume);
+ qreal volume() const;
+
+public Q_SLOTS:
+ void processBuffer();
+
+private:
+ bool startRecording();
+ void stopRecording();
+ void writeDataToDevice(const char *data, int size);
+ void flushBuffers();
+
+ QByteArray m_device;
+ QOpenSLESEngine *m_engine;
+ SLObjectItf m_recorderObject;
+ SLRecordItf m_recorder;
+#ifdef ANDROID
+ SLuint32 m_recorderPreset;
+ SLAndroidSimpleBufferQueueItf m_bufferQueue;
+#else
+ SLBufferQueueItf m_bufferQueue;
+#endif
+
+ bool m_pullMode;
+ qint64 m_processedBytes;
+ QIODevice *m_audioSource;
+ QBuffer *m_bufferIODevice;
+ QByteArray m_pushBuffer;
+ QAudioFormat m_format;
+ QAudio::Error m_errorState;
+ QAudio::State m_deviceState;
+ qint64 m_lastNotifyTime;
+ qreal m_volume;
+ int m_bufferSize;
+ QByteArray *m_buffers;
+ int m_currentBuffer;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOPENSLESAUDIOINPUT_H
diff --git a/src/multimedia/android/qandroidmediadevices.cpp b/src/multimedia/android/qandroidmediadevices.cpp
new file mode 100644
index 000000000..7688da079
--- /dev/null
+++ b/src/multimedia/android/qandroidmediadevices.cpp
@@ -0,0 +1,113 @@
+// 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");
+}
+
+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");
+}
+
+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/android/qopenslesengine.cpp b/src/multimedia/android/qopenslesengine.cpp
new file mode 100644
index 000000000..738161ab7
--- /dev/null
+++ b/src/multimedia/android/qopenslesengine.cpp
@@ -0,0 +1,378 @@
+// 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>
+
+#define MINIMUM_PERIOD_TIME_MS 5
+#define DEFAULT_PERIOD_TIME_MS 50
+
+#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()
+ : m_engineObject(0)
+ , m_engine(0)
+ , m_checkedInputFormats(false)
+{
+ SLresult result;
+
+ result = slCreateEngine(&m_engineObject, 0, 0, 0, 0, 0);
+ CheckError("Failed to create engine");
+
+ result = (*m_engineObject)->Realize(m_engineObject, SL_BOOLEAN_FALSE);
+ CheckError("Failed to realize engine");
+
+ result = (*m_engineObject)->GetInterface(m_engineObject, SL_IID_ENGINE, &m_engine);
+ CheckError("Failed to get engine interface");
+}
+
+QOpenSLESEngine::~QOpenSLESEngine()
+{
+ if (m_engineObject)
+ (*m_engineObject)->Destroy(m_engineObject);
+}
+
+QOpenSLESEngine *QOpenSLESEngine::instance()
+{
+ return openslesEngine();
+}
+
+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)
+{
+ SLAndroidDataFormat_PCM_EX format_pcm;
+ format_pcm.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
+ format_pcm.numChannels = format.channelCount();
+ format_pcm.sampleRate = format.sampleRate() * 1000;
+ format_pcm.bitsPerSample = format.bytesPerSample() * 8;
+ format_pcm.containerSize = format.bytesPerSample() * 8;
+ format_pcm.channelMask = getChannelMask(format_pcm.numChannels);
+ format_pcm.endianness = (QSysInfo::ByteOrder == QSysInfo::LittleEndian ?
+ SL_BYTEORDER_LITTLEENDIAN :
+ SL_BYTEORDER_BIGENDIAN);
+
+ 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)
+{
+ QList<QAudioDevice> devices;
+ QJniObject devs;
+ if (mode == QAudioDevice::Input) {
+ devs = QJniObject::callStaticObjectMethod(
+ "org/qtproject/qt/android/multimedia/QtAudioDeviceManager",
+ "getAudioInputDevices",
+ "()[Ljava/lang/String;");
+ } else if (mode == QAudioDevice::Output) {
+ devs = QJniObject::callStaticObjectMethod(
+ "org/qtproject/qt/android/multimedia/QtAudioDeviceManager",
+ "getAudioOutputDevices",
+ "()[Ljava/lang/String;");
+ }
+ if (devs.isValid()) {
+ QJniEnvironment env;
+ jobjectArray devsArray = static_cast<jobjectArray>(devs.object());
+ const jint size = env->GetArrayLength(devsArray);
+ for (int i = 0; i < size; ++i) {
+ QString val = QJniObject(env->GetObjectArrayElement(devsArray, i)).toString();
+ int pos = val.indexOf(QStringLiteral(":"));
+ devices << (new QOpenSLESDeviceInfo(
+ val.left(pos).toUtf8(), val.mid(pos+1), mode))->create();
+ }
+ }
+ return devices;
+}
+
+bool QOpenSLESEngine::setAudioOutput(const QByteArray &deviceId)
+{
+ return QJniObject::callStaticMethod<jboolean>(
+ "org/qtproject/qt/android/multimedia/QtAudioDeviceManager",
+ "setAudioOutput",
+ deviceId.toInt());
+}
+
+static bool hasRecordPermission()
+{
+ return qApp->checkPermission(QMicrophonePermission{}) == Qt::PermissionStatus::Granted;
+}
+
+QList<int> QOpenSLESEngine::supportedChannelCounts(QAudioDevice::Mode mode) const
+{
+ if (mode == QAudioDevice::Input) {
+ if (!m_checkedInputFormats)
+ const_cast<QOpenSLESEngine *>(this)->checkSupportedInputFormats();
+ return m_supportedInputChannelCounts;
+ } else {
+ return QList<int>() << 1 << 2;
+ }
+}
+
+QList<int> QOpenSLESEngine::supportedSampleRates(QAudioDevice::Mode mode) const
+{
+ if (mode == QAudioDevice::Input) {
+ if (!m_checkedInputFormats)
+ const_cast<QOpenSLESEngine *>(this)->checkSupportedInputFormats();
+ return m_supportedInputSampleRates;
+ } else {
+ return QList<int>() << 8000 << 11025 << 12000 << 16000 << 22050 << 24000
+ << 32000 << 44100 << 48000 << 64000 << 88200 << 96000 << 192000;
+ }
+}
+
+int QOpenSLESEngine::getOutputValue(QOpenSLESEngine::OutputValue type, int defaultValue)
+{
+ static int sampleRate = 0;
+ static int framesPerBuffer = 0;
+
+ if (type == FramesPerBuffer && framesPerBuffer != 0)
+ return framesPerBuffer;
+
+ if (type == SampleRate && sampleRate != 0)
+ return sampleRate;
+
+ QJniObject ctx(QNativeInterface::QAndroidApplication::context());
+ if (!ctx.isValid())
+ return defaultValue;
+
+
+ QJniObject audioServiceString = ctx.getStaticObjectField("android/content/Context",
+ "AUDIO_SERVICE",
+ "Ljava/lang/String;");
+ QJniObject am = ctx.callObjectMethod("getSystemService",
+ "(Ljava/lang/String;)Ljava/lang/Object;",
+ audioServiceString.object());
+ if (!am.isValid())
+ return defaultValue;
+
+ auto sampleRateField = QJniObject::getStaticObjectField("android/media/AudioManager",
+ "PROPERTY_OUTPUT_SAMPLE_RATE",
+ "Ljava/lang/String;");
+ auto framesPerBufferField = QJniObject::getStaticObjectField(
+ "android/media/AudioManager",
+ "PROPERTY_OUTPUT_FRAMES_PER_BUFFER",
+ "Ljava/lang/String;");
+
+ auto sampleRateString = am.callObjectMethod("getProperty",
+ "(Ljava/lang/String;)Ljava/lang/String;",
+ sampleRateField.object());
+ auto framesPerBufferString = am.callObjectMethod("getProperty",
+ "(Ljava/lang/String;)Ljava/lang/String;",
+ framesPerBufferField.object());
+
+ if (!sampleRateString.isValid() || !framesPerBufferString.isValid())
+ return defaultValue;
+
+ framesPerBuffer = framesPerBufferString.toString().toInt();
+ sampleRate = sampleRateString.toString().toInt();
+
+ if (type == FramesPerBuffer)
+ return framesPerBuffer;
+
+ if (type == SampleRate)
+ return sampleRate;
+
+ return defaultValue;
+}
+
+int QOpenSLESEngine::getDefaultBufferSize(const QAudioFormat &format)
+{
+ if (!format.isValid())
+ return 0;
+
+ const int channelConfig = [&format]() -> int
+ {
+ if (format.channelCount() == 1)
+ return 4; /* MONO */
+ else if (format.channelCount() == 2)
+ return 12; /* STEREO */
+ else if (format.channelCount() > 2)
+ return 1052; /* SURROUND */
+ else
+ return 1; /* DEFAULT */
+ }();
+
+ const int audioFormat = [&format]() -> int
+ {
+ const int sdkVersion = QNativeInterface::QAndroidApplication::sdkVersion();
+ if (format.sampleFormat() == QAudioFormat::Float && sdkVersion >= 21)
+ return 4; /* PCM_FLOAT */
+ else if (format.sampleFormat() == QAudioFormat::UInt8)
+ return 3; /* PCM_8BIT */
+ else if (format.sampleFormat() == QAudioFormat::Int16)
+ return 2; /* PCM_16BIT*/
+ else
+ return 1; /* DEFAULT */
+ }();
+
+ const int sampleRate = format.sampleRate();
+ const int minBufferSize = QJniObject::callStaticMethod<jint>("android/media/AudioTrack",
+ "getMinBufferSize",
+ "(III)I",
+ sampleRate,
+ channelConfig,
+ audioFormat);
+ return minBufferSize > 0 ? minBufferSize : format.bytesForDuration(DEFAULT_PERIOD_TIME_MS);
+}
+
+int QOpenSLESEngine::getLowLatencyBufferSize(const QAudioFormat &format)
+{
+ return format.bytesForFrames(QOpenSLESEngine::getOutputValue(QOpenSLESEngine::FramesPerBuffer,
+ format.framesForDuration(MINIMUM_PERIOD_TIME_MS)));
+}
+
+bool QOpenSLESEngine::supportsLowLatency()
+{
+ static int isSupported = -1;
+
+ if (isSupported != -1)
+ return (isSupported == 1);
+
+ QJniObject ctx(QNativeInterface::QAndroidApplication::context());
+ if (!ctx.isValid())
+ return false;
+
+ QJniObject pm = ctx.callObjectMethod("getPackageManager", "()Landroid/content/pm/PackageManager;");
+ if (!pm.isValid())
+ return false;
+
+ QJniObject audioFeatureField = QJniObject::getStaticObjectField(
+ "android/content/pm/PackageManager",
+ "FEATURE_AUDIO_LOW_LATENCY",
+ "Ljava/lang/String;");
+ if (!audioFeatureField.isValid())
+ return false;
+
+ isSupported = pm.callMethod<jboolean>("hasSystemFeature",
+ "(Ljava/lang/String;)Z",
+ audioFeatureField.object());
+ return (isSupported == 1);
+}
+
+bool QOpenSLESEngine::printDebugInfo()
+{
+ return qEnvironmentVariableIsSet("QT_OPENSL_INFO");
+}
+
+void QOpenSLESEngine::checkSupportedInputFormats()
+{
+ m_supportedInputChannelCounts = QList<int>() << 1;
+ m_supportedInputSampleRates.clear();
+
+ SLAndroidDataFormat_PCM_EX defaultFormat;
+ defaultFormat.formatType = SL_DATAFORMAT_PCM;
+ defaultFormat.numChannels = 1;
+ defaultFormat.sampleRate = SL_SAMPLINGRATE_44_1;
+ defaultFormat.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_32;
+ defaultFormat.containerSize = SL_PCMSAMPLEFORMAT_FIXED_32;
+ 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,
+ SL_SAMPLINGRATE_12,
+ SL_SAMPLINGRATE_16,
+ SL_SAMPLINGRATE_22_05,
+ SL_SAMPLINGRATE_24,
+ SL_SAMPLINGRATE_32,
+ SL_SAMPLINGRATE_44_1,
+ SL_SAMPLINGRATE_48,
+ SL_SAMPLINGRATE_64,
+ SL_SAMPLINGRATE_88_2,
+ SL_SAMPLINGRATE_96,
+ SL_SAMPLINGRATE_192 };
+
+
+ // Test sampling rates
+ for (size_t i = 0 ; i < std::size(rates); ++i) {
+ SLAndroidDataFormat_PCM_EX format = defaultFormat;
+ format.sampleRate = rates[i];
+
+ if (inputFormatIsSupported(format))
+ m_supportedInputSampleRates.append(rates[i] / 1000);
+
+ }
+
+ // Test if stereo is supported
+ {
+ SLAndroidDataFormat_PCM_EX format = defaultFormat;
+ format.numChannels = 2;
+ format.channelMask = SL_ANDROID_MAKE_INDEXED_CHANNEL_MASK(SL_SPEAKER_FRONT_LEFT
+ | SL_SPEAKER_FRONT_RIGHT);
+ if (inputFormatIsSupported(format))
+ m_supportedInputChannelCounts.append(2);
+ }
+
+ m_checkedInputFormats = true;
+}
+
+bool QOpenSLESEngine::inputFormatIsSupported(SLAndroidDataFormat_PCM_EX format)
+{
+ SLresult result;
+ SLObjectItf recorder = 0;
+ SLDataLocator_IODevice loc_dev = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
+ SL_DEFAULTDEVICEID_AUDIOINPUT, NULL };
+ SLDataSource audioSrc = { &loc_dev, NULL };
+
+ 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);
+
+ if (result == SL_RESULT_SUCCESS) {
+ (*recorder)->Destroy(recorder);
+ return true;
+ }
+
+ return 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/audio.pri b/src/multimedia/audio/audio.pri
deleted file mode 100644
index 388124205..000000000
--- a/src/multimedia/audio/audio.pri
+++ /dev/null
@@ -1,50 +0,0 @@
-INCLUDEPATH += audio
-
-PUBLIC_HEADERS += \
- audio/qaudio.h \
- audio/qaudiobuffer.h \
- audio/qaudioformat.h \
- audio/qaudioinput.h \
- audio/qaudiooutput.h \
- audio/qaudiodeviceinfo.h \
- audio/qaudiosystemplugin.h \
- audio/qaudiosystem.h \
- audio/qsoundeffect.h \
- audio/qsound.h \
- audio/qaudioprobe.h \
- audio/qaudiodecoder.h
-
-PRIVATE_HEADERS += \
- audio/qaudiobuffer_p.h \
- audio/qaudiodevicefactory_p.h \
- audio/qwavedecoder_p.h \
- audio/qsamplecache_p.h \
- audio/qaudiohelpers_p.h \
- audio/qaudiosystempluginext_p.h
-
-SOURCES += \
- audio/qaudio.cpp \
- audio/qaudioformat.cpp \
- audio/qaudiodeviceinfo.cpp \
- audio/qaudiooutput.cpp \
- audio/qaudioinput.cpp \
- audio/qaudiosystemplugin.cpp \
- audio/qaudiosystem.cpp \
- audio/qaudiodevicefactory.cpp \
- audio/qsoundeffect.cpp \
- audio/qwavedecoder_p.cpp \
- audio/qsamplecache_p.cpp \
- audio/qsound.cpp \
- audio/qaudiobuffer.cpp \
- audio/qaudioprobe.cpp \
- audio/qaudiodecoder.cpp \
- audio/qaudiohelpers.cpp
-
-qtConfig(pulseaudio) {
- QMAKE_USE_FOR_PRIVATE += pulseaudio
- PRIVATE_HEADERS += audio/qsoundeffect_pulse_p.h
- SOURCES += audio/qsoundeffect_pulse_p.cpp
-} else {
- PRIVATE_HEADERS += audio/qsoundeffect_qaudio_p.h
- SOURCES += audio/qsoundeffect_qaudio_p.cpp
-}
diff --git a/src/multimedia/audio/qaudio.h b/src/multimedia/audio/qaudio.h
index 90a8c236f..5ae994b9f 100644
--- a/src/multimedia/audio/qaudio.h
+++ b/src/multimedia/audio/qaudio.h
@@ -1,48 +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
#ifndef QAUDIO_H
#define QAUDIO_H
+#if 0
+#pragma qt_class(QAudio)
+#endif
+
#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qmultimedia.h>
#include <QtCore/qmetatype.h>
@@ -52,25 +18,15 @@ 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, InterruptedState };
- enum Mode { AudioInput, AudioOutput };
-
- enum Role {
- UnknownRole,
- MusicRole,
- VideoRole,
- VoiceCommunicationRole,
- AlarmRole,
- NotificationRole,
- RingtoneRole,
- AccessibilityRole,
- SonificationRole,
- GameRole,
- CustomRole
- };
+ enum State { ActiveState, SuspendedState, StoppedState, IdleState };
enum VolumeScale {
LinearVolumeScale,
@@ -79,23 +35,19 @@ namespace QAudio
DecibelVolumeScale
};
- Q_MULTIMEDIA_EXPORT qreal convertVolume(qreal volume, VolumeScale from, VolumeScale to);
+ 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::Mode mode);
-Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug dbg, QAudio::Role role);
-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
-Q_DECLARE_METATYPE(QAudio::Error)
-Q_DECLARE_METATYPE(QAudio::State)
-Q_DECLARE_METATYPE(QAudio::Mode)
-Q_DECLARE_METATYPE(QAudio::Role)
-Q_DECLARE_METATYPE(QAudio::VolumeScale)
-
#endif // QAUDIO_H
diff --git a/src/multimedia/audio/qaudiobuffer.cpp b/src/multimedia/audio/qaudiobuffer.cpp
index 999f280b3..69adcc5b7 100644
--- a/src/multimedia/audio/qaudiobuffer.cpp
+++ b/src/multimedia/audio/qaudiobuffer.cpp
@@ -1,185 +1,27 @@
-/****************************************************************************
-**
-** 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"
-#include "qaudiobuffer_p.h"
#include <QObject>
#include <QDebug>
QT_BEGIN_NAMESPACE
-
-static void qRegisterAudioBufferMetaTypes()
-{
- qRegisterMetaType<QAudioBuffer>();
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterAudioBufferMetaTypes)
-
-
class QAudioBufferPrivate : public QSharedData
{
public:
- QAudioBufferPrivate(QAbstractAudioBuffer *provider)
- : mProvider(provider)
- , mCount(1)
- {
- }
-
- ~QAudioBufferPrivate()
- {
- if (mProvider)
- mProvider->release();
- }
-
- void ref()
- {
- mCount.ref();
- }
-
- void deref()
- {
- if (!mCount.deref())
- delete this;
- }
-
- QAudioBufferPrivate *clone();
-
- static QAudioBufferPrivate *acquire(QAudioBufferPrivate *other)
- {
- if (!other)
- return nullptr;
-
- // Ref the other (if there are extant data() pointers, they will
- // also point here - it's a feature, not a bug, like QByteArray)
- other->ref();
- return other;
- }
-
- QAbstractAudioBuffer *mProvider;
- QAtomicInt mCount;
-};
-
-// Private class to go in .cpp file
-class QMemoryAudioBufferProvider : public QAbstractAudioBuffer {
-public:
- QMemoryAudioBufferProvider(const void *data, int frameCount, const QAudioFormat &format, qint64 startTime)
- : mStartTime(startTime)
- , mFrameCount(frameCount)
- , mFormat(format)
- {
- int numBytes = format.bytesForFrames(frameCount);
- if (numBytes > 0) {
- mBuffer = malloc(numBytes);
- if (!mBuffer) {
- // OOM, if that's likely
- mStartTime = -1;
- mFrameCount = 0;
- mFormat = QAudioFormat();
- } else {
- // Allocated, see if we have data to copy
- if (data) {
- memcpy(mBuffer, data, numBytes);
- } else {
- // We have to fill with the zero value..
- switch (format.sampleType()) {
- case QAudioFormat::SignedInt:
- // Signed int means 0x80, 0x8000 is zero
- // XXX this is not right for > 8 bits(0x8080 vs 0x8000)
- memset(mBuffer, 0x80, numBytes);
- break;
- default:
- memset(mBuffer, 0x0, numBytes);
- }
- }
- }
- } else
- mBuffer = nullptr;
- }
-
- ~QMemoryAudioBufferProvider()
+ QAudioBufferPrivate(const QAudioFormat &f, const QByteArray &d, qint64 start)
+ : format(f), data(d), startTime(start)
{
- if (mBuffer)
- free(mBuffer);
}
- void release() override {delete this;}
- QAudioFormat format() const override {return mFormat;}
- qint64 startTime() const override {return mStartTime;}
- int frameCount() const override {return mFrameCount;}
-
- void *constData() const override {return mBuffer;}
-
- void *writableData() override {return mBuffer;}
- QAbstractAudioBuffer *clone() const override
- {
- return new QMemoryAudioBufferProvider(mBuffer, mFrameCount, mFormat, mStartTime);
- }
-
- void *mBuffer;
- qint64 mStartTime;
- int mFrameCount;
- QAudioFormat mFormat;
+ QAudioFormat format;
+ QByteArray data;
+ qint64 startTime;
};
-QAudioBufferPrivate *QAudioBufferPrivate::clone()
-{
- // We want to create a single bufferprivate with a
- // single qaab
- // This should only be called when the count is > 1
- Q_ASSERT(mCount.loadRelaxed() > 1);
-
- if (mProvider) {
- QAbstractAudioBuffer *abuf = mProvider->clone();
-
- if (!abuf) {
- abuf = new QMemoryAudioBufferProvider(mProvider->constData(), mProvider->frameCount(), mProvider->format(), mProvider->startTime());
- }
-
- if (abuf) {
- return new QAudioBufferPrivate(abuf);
- }
- }
-
- return nullptr;
-}
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QAudioBufferPrivate);
/*!
\class QAbstractAudioBuffer
@@ -191,38 +33,29 @@ QAudioBufferPrivate *QAudioBufferPrivate::clone()
\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.
+
+ To access the data stored inside the buffer, use the data() or constData() methods.
+
+ Audio buffers are explicitly shared, in most cases, you should call detach() before
+ modifying the data.
*/
-// ^ Mostly useful with probe or decoder
/*!
Create a new, empty, invalid buffer.
*/
-QAudioBuffer::QAudioBuffer()
- : d(nullptr)
-{
-}
+QAudioBuffer::QAudioBuffer() noexcept = default;
/*!
- \internal
- Create a new audio buffer from the supplied \a provider. This
- constructor is typically only used when handling certain hardware
- or media framework specific buffers, and generally isn't useful
- in application code.
+ Creates a new audio buffer from \a other. Audio buffers are explicitly shared,
+ you should call detach() on the buffer to make a copy that can then be modified.
*/
-QAudioBuffer::QAudioBuffer(QAbstractAudioBuffer *provider)
- : d(new QAudioBufferPrivate(provider))
-{
-}
-/*!
- Creates a new audio buffer from \a other. Generally
- this will have copy-on-write semantics - a copy will
- only be made when it has to be.
- */
-QAudioBuffer::QAudioBuffer(const QAudioBuffer &other)
-{
- d = QAudioBufferPrivate::acquire(other.d);
-}
+QAudioBuffer::QAudioBuffer(const QAudioBuffer &other) noexcept = default;
/*!
Creates a new audio buffer from the supplied \a data, in the
@@ -240,11 +73,9 @@ QAudioBuffer::QAudioBuffer(const QAudioBuffer &other)
*/
QAudioBuffer::QAudioBuffer(const QByteArray &data, const QAudioFormat &format, qint64 startTime)
{
- if (format.isValid()) {
- int frameCount = format.framesForBytes(data.size());
- d = new QAudioBufferPrivate(new QMemoryAudioBufferProvider(data.constData(), frameCount, format, startTime));
- } else
- d = nullptr;
+ if (!format.isValid() || !data.size())
+ return;
+ d = new QAudioBufferPrivate(format, data, startTime);
}
/*!
@@ -258,43 +89,55 @@ QAudioBuffer::QAudioBuffer(const QByteArray &data, const QAudioFormat &format, q
*/
QAudioBuffer::QAudioBuffer(int numFrames, const QAudioFormat &format, qint64 startTime)
{
- if (format.isValid())
- d = new QAudioBufferPrivate(new QMemoryAudioBufferProvider(nullptr, numFrames, format, startTime));
- else
- d = nullptr;
+ if (!format.isValid() || !numFrames)
+ return;
+
+ QByteArray data(format.bytesForFrames(numFrames), '\0');
+ d = new QAudioBufferPrivate(format, data, startTime);
}
/*!
+ \fn QAudioBuffer::QAudioBuffer(QAudioBuffer &&other)
+
+ Constructs a QAudioBuffer by moving from \a other.
+*/
+
+/*!
+ \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.
+*/
+
+/*!
Assigns the \a other buffer to this.
*/
-QAudioBuffer &QAudioBuffer::operator =(const QAudioBuffer &other)
-{
- if (this->d != other.d) {
- if (d)
- d->deref();
- d = QAudioBufferPrivate::acquire(other.d);
- }
- return *this;
-}
+QAudioBuffer &QAudioBuffer::operator=(const QAudioBuffer &other) = default;
/*!
Destroys this audio buffer.
*/
-QAudioBuffer::~QAudioBuffer()
-{
- if (d)
- d->deref();
-}
+QAudioBuffer::~QAudioBuffer() = default;
+
+/*! \fn bool QAudioBuffer::isValid() const noexcept
-/*!
Returns true if this is a valid buffer. A valid buffer
has more than zero frames in it and a valid format.
*/
-bool QAudioBuffer::isValid() const
+
+/*!
+ Detaches this audio buffers from other copies that might share data with it.
+*/
+void QAudioBuffer::detach()
{
- if (!d || !d->mProvider)
- return false;
- return d->mProvider->format().isValid() && (d->mProvider->frameCount() > 0);
+ if (!d)
+ return;
+ d = new QAudioBufferPrivate(*d);
}
/*!
@@ -304,11 +147,11 @@ bool QAudioBuffer::isValid() const
the \l duration() or \l byteCount() are calculated
from the \l frameCount().
*/
-QAudioFormat QAudioBuffer::format() const
+QAudioFormat QAudioBuffer::format() const noexcept
{
- if (!isValid())
+ if (!d)
return QAudioFormat();
- return d->mProvider->format();
+ return d->format;
}
/*!
@@ -317,11 +160,11 @@ QAudioFormat QAudioBuffer::format() const
An audio frame is an interleaved set of one sample per channel
for the same instant in time.
*/
-int QAudioBuffer::frameCount() const
+qsizetype QAudioBuffer::frameCount() const noexcept
{
- if (!isValid())
+ if (!d)
return 0;
- return d->mProvider->frameCount();
+ return d->format.framesForBytes(d->data.size());
}
/*!
@@ -335,21 +178,17 @@ int QAudioBuffer::frameCount() const
\sa frameCount()
*/
-int QAudioBuffer::sampleCount() const
+qsizetype QAudioBuffer::sampleCount() const noexcept
{
- if (!isValid())
- return 0;
-
return frameCount() * format().channelCount();
}
/*!
Returns the size of this buffer, in bytes.
*/
-int QAudioBuffer::byteCount() const
+qsizetype QAudioBuffer::byteCount() const noexcept
{
- const QAudioFormat f(format());
- return format().bytesForFrames(frameCount());
+ return d ? d->data.size() : 0;
}
/*!
@@ -357,7 +196,7 @@ int QAudioBuffer::byteCount() const
This depends on the \l format(), and the \l frameCount().
*/
-qint64 QAudioBuffer::duration() const
+qint64 QAudioBuffer::duration() const noexcept
{
return format().durationForFrames(frameCount());
}
@@ -367,23 +206,23 @@ qint64 QAudioBuffer::duration() const
If this buffer is not part of a stream, this will return -1.
*/
-qint64 QAudioBuffer::startTime() const
+qint64 QAudioBuffer::startTime() const noexcept
{
- if (!isValid())
+ if (!d)
return -1;
- return d->mProvider->startTime();
+ return d->startTime;
}
/*!
+ \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:
@@ -391,22 +230,23 @@ qint64 QAudioBuffer::startTime() const
\endcode
*/
-const void* QAudioBuffer::constData() const
+
+const void *QAudioBuffer::constData() const noexcept
{
- if (!isValid())
+ if (!d)
return nullptr;
- return d->mProvider->constData();
+ return d->data.constData();
}
/*!
+ \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
@@ -414,192 +254,73 @@ const void* QAudioBuffer::constData() const
const quint16 *data = buffer->data<quint16>();
\endcode
*/
-const void* QAudioBuffer::data() const
+
+const void *QAudioBuffer::data() const noexcept
{
- if (!isValid())
+ if (!d)
return nullptr;
- return d->mProvider->constData();
+ 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 QAudioBuffers can share the actual sample data, calling
- this function will result in a deep copy being made if there
- are any other buffers using the sample. You should avoid calling
- this unless you really need to modify the data.
-
- This pointer will remain valid until the underlying storage is
- detached. In particular, if you obtain a pointer, and then
- copy this audio buffer, changing data through this pointer may
- change both buffer instances. Calling \l data() on either instance
- will again cause a deep copy to be made, which may invalidate
- the pointers returned from this function previously.
+ 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 (!isValid())
+ if (!d)
return nullptr;
-
- if (d->mCount.loadRelaxed() != 1) {
- // Can't share a writable buffer
- // so we need to detach
- QAudioBufferPrivate *newd = d->clone();
-
- // This shouldn't happen
- if (!newd)
- return nullptr;
-
- d->deref();
- d = newd;
- }
-
- // We're (now) the only user of this qaab, so
- // see if it's writable directly
- void *buffer = d->mProvider->writableData();
- if (buffer) {
- return buffer;
- }
-
- // Wasn't writable, so turn it into a memory provider
- QAbstractAudioBuffer *memBuffer = new QMemoryAudioBufferProvider(constData(), frameCount(), format(), startTime());
-
- if (memBuffer) {
- d->mProvider->release();
- d->mCount.storeRelaxed(1);
- d->mProvider = memBuffer;
-
- return memBuffer->writableData();
- }
-
- return nullptr;
+ return d->data.data();
}
-// Template helper classes worth documenting
-
/*!
- \class QAudioBuffer::StereoFrameDefault
- \internal
-
- Just a trait class for the default value.
-*/
-
-/*!
- \class QAudioBuffer::StereoFrame
- \brief The StereoFrame class provides a simple wrapper for a stereo audio frame.
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_audio
-
- This templatized structure lets you treat a block of individual samples as an
- interleaved stereo stream frame. This is most useful when used with the templatized
- \l {QAudioBuffer::data()}{data()} functions of QAudioBuffer. Generally the data
- is accessed as a pointer, so no copying should occur.
-
- There are some predefined instantiations of this template for working with common
- stereo sample depths in a convenient way.
-
- This frame structure has \e left and \e right members for accessing individual channel data.
-
- For example:
- \code
- // Assuming 'buffer' is an unsigned 16 bit stereo buffer..
- QAudioBuffer::S16U *frames = buffer->data<QAudioBuffer::S16U>();
- for (int i=0; i < buffer->frameCount(); i++) {
- qSwap(frames[i].left, frames[i].right);
- }
- \endcode
+ \typedef QAudioBuffer::S16S
- \sa QAudioBuffer::S8U, QAudioBuffer::S8S, QAudioBuffer::S16S, QAudioBuffer::S16U, QAudioBuffer::S32F
+ This is a predefined specialization for a signed stereo 16 bit sample. Each
+ channel is a \e {signed short}.
*/
/*!
- \fn template <typename T> QAudioBuffer::StereoFrame<T>::StereoFrame()
+ \typedef QAudioBuffer::U8M
- Constructs a new frame with the "silent" value for this
- sample format (0 for signed formats and floats, 0x8* for unsigned formats).
+ This is a predefined specialization for an unsigned 8 bit mono sample.
*/
-
/*!
- \fn template <typename T> QAudioBuffer::StereoFrame<T>::StereoFrame(T leftSample, T rightSample)
-
- Constructs a new frame with the supplied \a leftSample and \a rightSample values.
-*/
-
+ \typedef QAudioBuffer::S16M
+ This is a predefined specialization for a signed 16 bit mono sample.
+i*/
/*!
- \fn template <typename T> QAudioBuffer::StereoFrame<T>::operator=(const StereoFrame &other)
-
- Assigns \a other to this frame.
- */
-
-
-/*!
- \fn template <typename T> QAudioBuffer::StereoFrame<T>::average() const
-
- Returns the arithmetic average of the left and right samples.
- */
-
-/*! \fn template <typename T> QAudioBuffer::StereoFrame<T>::clear()
-
- Sets the values of this frame to the "silent" value.
-*/
-
-/*!
- \variable QAudioBuffer::StereoFrame::left
- \brief the left sample
-*/
-
-/*!
- \variable QAudioBuffer::StereoFrame::right
- \brief the right sample
-*/
-
-/*!
- \typedef QAudioBuffer::S8U
-
- This is a predefined specialization for an unsigned stereo 8 bit sample. Each
- channel is an \e {unsigned char}.
+ \typedef QAudioBuffer::S32M
+ This is a predefined specialization for a signed 32 bit mono sample.
*/
/*!
- \typedef QAudioBuffer::S8S
-
- This is a predefined specialization for a signed stereo 8 bit sample. Each
- channel is a \e {signed char}.
+ \typedef QAudioBuffer::F32M
+ This is a predefined specialization for a 32 bit float mono sample.
*/
/*!
- \typedef QAudioBuffer::S16U
-
- This is a predefined specialization for an unsigned stereo 16 bit sample. Each
- channel is an \e {unsigned short}.
+ \typedef QAudioBuffer::U8S
+ This is a predifined specialization for an unsiged 8 bit stereo sample.
*/
/*!
- \typedef QAudioBuffer::S16S
-
- This is a predefined specialization for a signed stereo 16 bit sample. Each
- channel is a \e {signed short}.
+ \typedef QAudioBuffer::S32S
+ This is a predifined specialization for a siged 32 bit stereo sample.
*/
/*!
- \typedef QAudioBuffer::S32F
-
- This is a predefined specialization for an 32 bit float sample. Each
- channel is a \e float.
+ \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 bed387462..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
@@ -43,89 +7,149 @@
#include <QtCore/qshareddata.h>
#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qmultimedia.h>
-#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qtaudio.h>
#include <QtMultimedia/qaudioformat.h>
QT_BEGIN_NAMESPACE
-class QAbstractAudioBuffer;
-class QAudioBufferPrivate;
-class Q_MULTIMEDIA_EXPORT QAudioBuffer
+namespace QtPrivate {
+template <QAudioFormat::SampleFormat> struct AudioSampleFormatHelper
+{
+};
+
+template <> struct AudioSampleFormatHelper<QAudioFormat::UInt8>
+{
+ using value_type = unsigned char;
+ static constexpr value_type Default = 128;
+};
+
+template <> struct AudioSampleFormatHelper<QAudioFormat::Int16>
+{
+ using value_type = short;
+ static constexpr value_type Default = 0;
+};
+
+template <> struct AudioSampleFormatHelper<QAudioFormat::Int32>
{
+ using value_type = int;
+ static constexpr value_type Default = 0;
+};
+
+template <> struct AudioSampleFormatHelper<QAudioFormat::Float>
+{
+ using value_type = float;
+ static constexpr value_type Default = 0.;
+};
+
+}
+
+template <QAudioFormat::ChannelConfig config, QAudioFormat::SampleFormat format>
+struct QAudioFrame
+{
+private:
+ // popcount in qalgorithms.h is unfortunately not constexpr on MSVC.
+ // Use this here as a fallback
+ static constexpr int constexprPopcount(quint32 i)
+ {
+ i = i - ((i >> 1) & 0x55555555); // add pairs of bits
+ i = (i & 0x33333333) + ((i >> 2) & 0x33333333); // quads
+ i = (i + (i >> 4)) & 0x0F0F0F0F; // groups of 8
+ return (i * 0x01010101) >> 24; // horizontal sum of bytes
+ }
+ static constexpr int nChannels = constexprPopcount(config);
public:
- QAudioBuffer();
- QAudioBuffer(QAbstractAudioBuffer *provider);
- QAudioBuffer(const QAudioBuffer &other);
- QAudioBuffer(const QByteArray &data, const QAudioFormat &format, qint64 startTime = -1);
- QAudioBuffer(int numFrames, const QAudioFormat &format, qint64 startTime = -1); // Initialized to empty
+ using value_type = typename QtPrivate::AudioSampleFormatHelper<format>::value_type;
+ value_type channels[nChannels];
+ static constexpr int positionToIndex(QAudioFormat::AudioChannelPosition pos)
+ {
+ if (!(config & (1u << pos)))
+ return -1;
+
+ uint maskedChannels = config & ((1u << pos) - 1);
+ return qPopulationCount(maskedChannels);
+ }
- QAudioBuffer& operator=(const QAudioBuffer &other);
- ~QAudioBuffer();
+ value_type value(QAudioFormat::AudioChannelPosition pos) const {
+ int idx = positionToIndex(pos);
+ if (idx < 0)
+ return QtPrivate::AudioSampleFormatHelper<format>::Default;
+ return channels[idx];
+ }
+ void setValue(QAudioFormat::AudioChannelPosition pos, value_type val) {
+ int idx = positionToIndex(pos);
+ if (idx < 0)
+ return;
+ channels[idx] = val;
+ }
+ value_type operator[](QAudioFormat::AudioChannelPosition pos) const {
+ return value(pos);
+ }
+ constexpr void clear() {
+ for (int i = 0; i < nChannels; ++i)
+ channels[i] = QtPrivate::AudioSampleFormatHelper<format>::Default;
+ }
+};
+
+template <QAudioFormat::SampleFormat Format>
+using QAudioFrameMono = QAudioFrame<QAudioFormat::ChannelConfigMono, Format>;
+
+template <QAudioFormat::SampleFormat Format>
+using QAudioFrameStereo = QAudioFrame<QAudioFormat::ChannelConfigStereo, Format>;
+
+template <QAudioFormat::SampleFormat Format>
+using QAudioFrame2Dot1 = QAudioFrame<QAudioFormat::ChannelConfig2Dot1, Format>;
- bool isValid() const;
+template <QAudioFormat::SampleFormat Format>
+using QAudioFrameSurround5Dot1 = QAudioFrame<QAudioFormat::ChannelConfigSurround5Dot1, Format>;
- QAudioFormat format() const;
+template <QAudioFormat::SampleFormat Format>
+using QAudioFrameSurround7Dot1 = QAudioFrame<QAudioFormat::ChannelConfigSurround7Dot1, Format>;
- int frameCount() const;
- int sampleCount() const;
- int byteCount() const;
- qint64 duration() const;
- qint64 startTime() const;
+class QAudioBufferPrivate;
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QAudioBufferPrivate, Q_MULTIMEDIA_EXPORT)
- // Data modification
- // void clear();
- // Other ideas
- // operator *=
- // operator += (need to be careful about different formats)
+class Q_MULTIMEDIA_EXPORT QAudioBuffer
+{
+public:
+ QAudioBuffer() noexcept;
+ QAudioBuffer(const QAudioBuffer &other) noexcept;
+ QAudioBuffer(const QByteArray &data, const QAudioFormat &format, qint64 startTime = -1);
+ QAudioBuffer(int numFrames, const QAudioFormat &format, qint64 startTime = -1); // Initialized to empty
+ ~QAudioBuffer();
- // Data access
- const void* constData() const; // Does not detach, preferred
- const void* data() const; // Does not detach
- void *data(); // detaches
+ QAudioBuffer& operator=(const QAudioBuffer &other);
- // Structures for easier access to stereo data
- template <typename T> struct StereoFrameDefault { enum { Default = 0 }; };
+ QAudioBuffer(QAudioBuffer &&other) noexcept = default;
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QAudioBuffer)
+ void swap(QAudioBuffer &other) noexcept
+ { d.swap(other.d); }
- template <typename T> struct StereoFrame {
+ bool isValid() const noexcept { return d != nullptr; };
- StereoFrame()
- : left(T(StereoFrameDefault<T>::Default))
- , right(T(StereoFrameDefault<T>::Default))
- {
- }
+ void detach();
- StereoFrame(T leftSample, T rightSample)
- : left(leftSample)
- , right(rightSample)
- {
- }
+ QAudioFormat format() const noexcept;
- StereoFrame& operator=(const StereoFrame &other)
- {
- // Two straight assigns is probably
- // cheaper than a conditional check on
- // self assignment
- left = other.left;
- right = other.right;
- return *this;
- }
+ qsizetype frameCount() const noexcept;
+ qsizetype sampleCount() const noexcept;
+ qsizetype byteCount() const noexcept;
- T left;
- T right;
+ qint64 duration() const noexcept;
+ qint64 startTime() const noexcept;
- T average() const {return (left + right) / 2;}
- void clear() {left = right = T(StereoFrameDefault<T>::Default);}
- };
+ // Structures for easier access to data
+ typedef QAudioFrameMono<QAudioFormat::UInt8> U8M;
+ typedef QAudioFrameMono<QAudioFormat::Int16> S16M;
+ typedef QAudioFrameMono<QAudioFormat::Int32> S32M;
+ typedef QAudioFrameMono<QAudioFormat::Float> F32M;
- typedef StereoFrame<unsigned char> S8U;
- typedef StereoFrame<signed char> S8S;
- typedef StereoFrame<unsigned short> S16U;
- typedef StereoFrame<signed short> S16S;
- typedef StereoFrame<float> S32F;
+ typedef QAudioFrameStereo<QAudioFormat::UInt8> U8S;
+ typedef QAudioFrameStereo<QAudioFormat::Int16> S16S;
+ typedef QAudioFrameStereo<QAudioFormat::Int32> S32S;
+ typedef QAudioFrameStereo<QAudioFormat::Float> F32S;
template <typename T> const T* constData() const {
return static_cast<const T*>(constData());
@@ -137,12 +161,12 @@ public:
return static_cast<T*>(data());
}
private:
- QAudioBufferPrivate *d;
-};
-
-template <> struct QAudioBuffer::StereoFrameDefault<unsigned char> { enum { Default = 128 }; };
-template <> struct QAudioBuffer::StereoFrameDefault<unsigned short> { enum { Default = 32768 }; };
+ const void* constData() const noexcept;
+ const void* data() const noexcept;
+ void *data();
+ QExplicitlySharedDataPointer<QAudioBufferPrivate> d;
+};
QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudiobuffer_p.h b/src/multimedia/audio/qaudiobuffer_p.h
deleted file mode 100644
index e770989f2..000000000
--- a/src/multimedia/audio/qaudiobuffer_p.h
+++ /dev/null
@@ -1,96 +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 QAUDIOBUFFER_P_H
-#define QAUDIOBUFFER_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 <qtmultimediaglobal.h>
-#include <qmultimedia.h>
-
-#include "qaudioformat.h"
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QAbstractAudioBuffer {
-public:
- virtual ~QAbstractAudioBuffer() {}
-
- // Lifetime management
- virtual void release() = 0;
-
- // Format related
- virtual QAudioFormat format() const = 0;
- virtual qint64 startTime() const = 0;
- virtual int frameCount() const = 0;
-
- // R/O Data
- virtual void *constData() const = 0;
-
- // For writable data we do this:
- // If we only have one reference to the provider,
- // call writableData(). If that does not return 0,
- // then we're finished. If it does return 0, then we call
- // writableClone() to get a new buffer and then release
- // the old clone if that succeeds. If it fails, we create
- // a memory clone from the constData and release the old buffer.
- // If writableClone() succeeds, we then call writableData() on it
- // and that should be good.
-
- virtual void *writableData() = 0;
- virtual QAbstractAudioBuffer *clone() const = 0;
-};
-
-
-QT_END_NAMESPACE
-
-#endif // QAUDIOBUFFER_P_H
diff --git a/src/multimedia/audio/qaudiobufferinput.cpp b/src/multimedia/audio/qaudiobufferinput.cpp
new file mode 100644
index 000000000..e43066f10
--- /dev/null
+++ b/src/multimedia/audio/qaudiobufferinput.cpp
@@ -0,0 +1,184 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qaudiobufferinput.h"
+#include "qplatformaudiobufferinput_p.h"
+#include "qmediainputencoderinterface_p.h"
+#include "qmediaframeinput_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QAudioBufferInputPrivate : public QMediaFrameInputPrivate
+{
+public:
+ QAudioBufferInputPrivate(QAudioBufferInput *q) : q(q) { }
+
+ bool sendAudioBuffer(const QAudioBuffer &audioBuffer)
+ {
+ return sendMediaFrame(
+ [&]() { emit m_platfromAudioBufferInput->newAudioBuffer(audioBuffer); });
+ }
+
+ void initialize(const QAudioFormat &format = {})
+ {
+ m_platfromAudioBufferInput = std::make_unique<QPlatformAudioBufferInput>(format);
+ addUpdateSignal(m_platfromAudioBufferInput.get(),
+ &QPlatformAudioBufferInput::encoderUpdated);
+ }
+
+ void uninitialize()
+ {
+ m_platfromAudioBufferInput.reset();
+
+ if (captureSession())
+ captureSession()->setAudioBufferInput(nullptr);
+ }
+
+ QMediaCaptureSession *session() const { return m_captureSession; }
+
+ QPlatformAudioBufferInput *platfromAudioBufferInput() const
+ {
+ return m_platfromAudioBufferInput.get();
+ }
+
+private:
+ void updateCaptureSessionConnections(QMediaCaptureSession *prevSession,
+ QMediaCaptureSession *newSession) override
+ {
+ if (prevSession)
+ removeUpdateSignal(prevSession, &QMediaCaptureSession::audioOutputChanged);
+
+ if (newSession)
+ addUpdateSignal(newSession, &QMediaCaptureSession::audioOutputChanged);
+ }
+
+ bool checkIfCanSendMediaFrame() const override
+ {
+ if (auto encoderInterface = m_platfromAudioBufferInput->encoderInterface())
+ return encoderInterface->canPushFrame();
+
+ // Not implemented yet
+ // return captureSession()->audioOutput() != nullptr;
+ return false;
+ }
+
+ void emitReadyToSendMediaFrame() override { emit q->readyToSendAudioBuffer(); }
+
+private:
+ QAudioBufferInput *q = nullptr;
+ QMediaCaptureSession *m_captureSession = nullptr;
+ std::unique_ptr<QPlatformAudioBufferInput> m_platfromAudioBufferInput;
+};
+
+/*!
+ \class QAudioBufferInput
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \ingroup multimedia_audio
+ \since 6.8
+
+ \brief The QAudioBufferInput class is used for providing custom audio buffers
+ to \l QMediaRecorder through \l QMediaCaptureSession.
+
+ \sa QMediaRecorder, QMediaCaptureSession
+*/
+
+/*!
+ Constructs a new QAudioBufferInput object with \a parent.
+*/
+QAudioBufferInput::QAudioBufferInput(QObject *parent) : QAudioBufferInput({}, parent) { }
+
+/*!
+ Constructs a new QAudioBufferInput object with audio \a format and \a parent.
+
+ The specified \a format will work as a hint for the initialization of the matching
+ audio encoder upon invoking \l QMediaRecorder::record().
+ If the format is not specified or not valid, the audio encoder will be initialized
+ upon sending the first audio buffer.
+
+ We recommend specifying the format if you know in advance what kind of audio buffers
+ you're going to send.
+*/
+QAudioBufferInput::QAudioBufferInput(const QAudioFormat &format, QObject *parent)
+ : QObject(*new QAudioBufferInputPrivate(this), parent)
+{
+ Q_D(QAudioBufferInput);
+ d->initialize(format);
+}
+
+/*!
+ Destroys the object.
+ */
+QAudioBufferInput::~QAudioBufferInput()
+{
+ Q_D(QAudioBufferInput);
+ d->uninitialize();
+}
+
+/*!
+ Sends \l QAudioBuffer to \l QMediaRecorder through \l QMediaCaptureSession.
+
+ Returns \c true if the specified \a audioBuffer has been sent successfully
+ to the destination. Returns \c false, if the buffer hasn't been sent,
+ which can happen if the instance is not assigned to
+ \l QMediaCaptureSession, the session doesn't have a media recorder,
+ the media recorder is not started or its queue is full.
+ The \l readyToSendAudioBuffer() signal will be emitted as soon as
+ the destination is able to handle a new audio buffer.
+
+ Sending of an empty audio buffer is treated by \l QMediaRecorder
+ as an end of the input stream. QMediaRecorder stops the recording
+ automatically if \l QMediaRecorder::autoStop is \c true and
+ all the inputs have reported the end of the stream.
+*/
+bool QAudioBufferInput::sendAudioBuffer(const QAudioBuffer &audioBuffer)
+{
+ Q_D(QAudioBufferInput);
+ return d->sendAudioBuffer(audioBuffer);
+}
+
+/*!
+ Returns the audio format that was specified upon construction of the audio buffer input.
+*/
+QAudioFormat QAudioBufferInput::format() const
+{
+ Q_D(const QAudioBufferInput);
+ return d->platfromAudioBufferInput()->audioFormat();
+}
+
+/*!
+ Returns the capture session this audio buffer input is connected to, or
+ a \c nullptr if the audio buffer input is not connected to a capture session.
+
+ Use QMediaCaptureSession::setAudioBufferInput() to connect
+ the audio buffer input to a session.
+*/
+QMediaCaptureSession *QAudioBufferInput::captureSession() const
+{
+ Q_D(const QAudioBufferInput);
+ return d->captureSession();
+}
+
+void QAudioBufferInput::setCaptureSession(QMediaCaptureSession *captureSession)
+{
+ Q_D(QAudioBufferInput);
+ d->setCaptureSession(captureSession);
+}
+
+QPlatformAudioBufferInput *QAudioBufferInput::platformAudioBufferInput() const
+{
+ Q_D(const QAudioBufferInput);
+ return d->platfromAudioBufferInput();
+}
+
+/*!
+ \fn void QAudioBufferInput::readyToSendAudioBuffer()
+
+ Signals that a new audio buffer can be sent to the audio buffer input.
+ After receiving the signal, if you have audio date to be sent, invoke \l sendAudioBuffer
+ once or in a loop until it returns \c false.
+
+ \sa sendAudioBuffer()
+*/
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudiobufferinput.h b/src/multimedia/audio/qaudiobufferinput.h
new file mode 100644
index 000000000..f48db186a
--- /dev/null
+++ b/src/multimedia/audio/qaudiobufferinput.h
@@ -0,0 +1,48 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QAUDIOBUFFERINPUT_H
+#define QAUDIOBUFFERINPUT_H
+
+#include <QtMultimedia/qtmultimediaexports.h>
+#include <QtMultimedia/qaudiobuffer.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPlatformAudioBufferInput;
+class QAudioBufferInputPrivate;
+class QMediaCaptureSession;
+
+class Q_MULTIMEDIA_EXPORT QAudioBufferInput : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QAudioBufferInput(QObject *parent = nullptr);
+
+ explicit QAudioBufferInput(const QAudioFormat &format, QObject *parent = nullptr);
+
+ ~QAudioBufferInput() override;
+
+ bool sendAudioBuffer(const QAudioBuffer &audioBuffer);
+
+ QAudioFormat format() const;
+
+ QMediaCaptureSession *captureSession() const;
+
+Q_SIGNALS:
+ void readyToSendAudioBuffer();
+
+private:
+ void setCaptureSession(QMediaCaptureSession *captureSession);
+
+ QPlatformAudioBufferInput *platformAudioBufferInput() const;
+
+ friend class QMediaCaptureSession;
+ Q_DISABLE_COPY(QAudioBufferInput)
+ Q_DECLARE_PRIVATE(QAudioBufferInput)
+};
+
+QT_END_NAMESPACE
+
+#endif // QAUDIOBUFFERINPUT_H
diff --git a/src/multimedia/audio/qaudiobufferoutput.cpp b/src/multimedia/audio/qaudiobufferoutput.cpp
new file mode 100644
index 000000000..50389c49a
--- /dev/null
+++ b/src/multimedia/audio/qaudiobufferoutput.cpp
@@ -0,0 +1,78 @@
+// 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 "qaudiobufferoutput_p.h"
+#include "qmediaplayer.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAudioBufferOutput
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \ingroup multimedia_audio
+ \since 6.8
+
+ \brief The QAudioBufferOutput class is used for capturing audio data provided by \l QMediaPlayer.
+
+ QAudioBufferOutput can be set to QMediaPlayer in order to receive audio buffers
+ decoded by the media player. The received audio data can be used for any
+ processing or visualization.
+
+ \sa QMediaPlayer, QMediaPlayer::setAudioBufferOutput, QAudioBuffer
+*/
+
+/*!
+ Constructs a new QAudioBufferOutput object with \a parent.
+
+ The audio format of output audio buffers will depend on
+ the source media file and the inner audio decoder in \l QMediaPlayer.
+*/
+QAudioBufferOutput::QAudioBufferOutput(QObject *parent)
+ : QObject(*new QAudioBufferOutputPrivate, parent)
+{
+}
+
+/*!
+ Constructs a new QAudioBufferOutput object with audio \a format and \a parent.
+
+ If the specified \a format is valid, it will be the format of output
+ audio buffers. Otherwise, the format of output audio buffers
+ will depend on the source media file and the inner audio decoder in \l QMediaPlayer.
+*/
+QAudioBufferOutput::QAudioBufferOutput(const QAudioFormat &format, QObject *parent)
+ : QObject(*new QAudioBufferOutputPrivate(format), parent)
+{
+}
+
+/*!
+ Destroys the audio buffer output object.
+*/
+QAudioBufferOutput::~QAudioBufferOutput()
+{
+ Q_D(QAudioBufferOutput);
+
+ if (d->mediaPlayer)
+ d->mediaPlayer->setAudioBufferOutput(nullptr);
+}
+
+/*!
+ Gets the audio format specified in the constructor.
+
+ If the format is valid, it specifies the format of output oudio buffers.
+*/
+QAudioFormat QAudioBufferOutput::format() const
+{
+ Q_D(const QAudioBufferOutput);
+ return d->format;
+}
+
+/*!
+ \fn void QAudioBufferOutput::audioBufferReceived(const QAudioBuffer &buffer)
+
+ Signals that a new audio \a buffer has been received from \l QMediaPlayer.
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qaudiobufferoutput.cpp"
diff --git a/src/multimedia/audio/qaudiobufferoutput.h b/src/multimedia/audio/qaudiobufferoutput.h
new file mode 100644
index 000000000..2e4fab1a4
--- /dev/null
+++ b/src/multimedia/audio/qaudiobufferoutput.h
@@ -0,0 +1,37 @@
+// 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 QAUDIOBUFFEROUTPUT_H
+#define QAUDIOBUFFEROUTPUT_H
+
+#include <QtMultimedia/qtmultimediaexports.h>
+#include <QtMultimedia/qaudiobuffer.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAudioBufferOutputPrivate;
+
+class Q_MULTIMEDIA_EXPORT QAudioBufferOutput : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QAudioBufferOutput(QObject *parent = nullptr);
+
+ explicit QAudioBufferOutput(const QAudioFormat &format, QObject *parent = nullptr);
+
+ ~QAudioBufferOutput() override;
+
+ QAudioFormat format() const;
+
+Q_SIGNALS:
+ void audioBufferReceived(const QAudioBuffer &buffer);
+
+private:
+ Q_DISABLE_COPY(QAudioBufferOutput)
+ Q_DECLARE_PRIVATE(QAudioBufferOutput)
+};
+
+QT_END_NAMESPACE
+
+#endif // QAUDIOBUFFEROUTPUT_H
diff --git a/src/multimedia/audio/qaudiobufferoutput_p.h b/src/multimedia/audio/qaudiobufferoutput_p.h
new file mode 100644
index 000000000..2f9c11bd1
--- /dev/null
+++ b/src/multimedia/audio/qaudiobufferoutput_p.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QAUDIOBUFFEROUTPUT_P_H
+#define QAUDIOBUFFEROUTPUT_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 "qaudiobufferoutput.h"
+
+QT_BEGIN_NAMESPACE
+
+class QMediaPlayer;
+
+class QAudioBufferOutputPrivate : public QObjectPrivate
+{
+public:
+ QAudioBufferOutputPrivate(const QAudioFormat &format = {}) : format(std::move(format)) { }
+
+ static QMediaPlayer *exchangeMediaPlayer(QAudioBufferOutput &output, QMediaPlayer *player)
+ {
+ auto outputPrivate = static_cast<QAudioBufferOutputPrivate *>(output.d_func());
+ return std::exchange(outputPrivate->mediaPlayer, player);
+ }
+
+ QAudioFormat format;
+ QMediaPlayer *mediaPlayer = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QAUDIOBUFFEROUTPUT_P_H
diff --git a/src/multimedia/audio/qaudiodecoder.cpp b/src/multimedia/audio/qaudiodecoder.cpp
index 0286e9a85..f555f46ed 100644
--- a/src/multimedia/audio/qaudiodecoder.cpp
+++ b/src/multimedia/audio/qaudiodecoder.cpp
@@ -1,192 +1,104 @@
-/****************************************************************************
-**
-** 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 "qaudiodecoder.h"
-#include "qmediaobject_p.h"
-#include <qmediaservice.h>
-#include "qaudiodecodercontrol.h"
-#include <private/qmediaserviceprovider_p.h>
+#include <private/qaudiodecoder_p.h>
+#include <private/qmultimediautils_p.h>
+#include <private/qplatformaudiodecoder_p.h>
+#include <private/qplatformmediaintegration_p.h>
#include <QtCore/qcoreevent.h>
-#include <QtCore/qmetaobject.h>
-#include <QtCore/qtimer.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qmetaobject.h>
#include <QtCore/qpointer.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qurl.h>
QT_BEGIN_NAMESPACE
/*!
\class QAudioDecoder
- \brief The QAudioDecoder class allows decoding audio.
+ \brief The QAudioDecoder class implements decoding audio.
\inmodule QtMultimedia
\ingroup multimedia
\ingroup multimedia_audio
\preliminary
- The QAudioDecoder class is a high level class for decoding local
+ The QAudioDecoder class is a high level class for decoding
audio media files. It is similar to the QMediaPlayer class except
that audio is provided back through this API rather than routed
- directly to audio hardware, and playlists and network and streaming
- based media is not supported.
+ directly to audio hardware.
\sa QAudioBuffer
*/
-static void qRegisterAudioDecoderMetaTypes()
-{
- qRegisterMetaType<QAudioDecoder::State>("QAudioDecoder::State");
- qRegisterMetaType<QAudioDecoder::Error>("QAudioDecoder::Error");
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterAudioDecoderMetaTypes)
-
-class QAudioDecoderPrivate : public QMediaObjectPrivate
-{
- Q_DECLARE_NON_CONST_PUBLIC(QAudioDecoder)
-
-public:
- QAudioDecoderPrivate()
- : provider(nullptr)
- , control(nullptr)
- , state(QAudioDecoder::StoppedState)
- , error(QAudioDecoder::NoError)
- {}
-
- QMediaServiceProvider *provider;
- QAudioDecoderControl *control;
- QAudioDecoder::State state;
- QAudioDecoder::Error error;
- QString errorString;
-
- void _q_stateChanged(QAudioDecoder::State state);
- void _q_error(int error, const QString &errorString);
-};
-
-void QAudioDecoderPrivate::_q_stateChanged(QAudioDecoder::State ps)
+/*!
+ Construct an QAudioDecoder instance with \a parent.
+*/
+QAudioDecoder::QAudioDecoder(QObject *parent) : QObject{ *new QAudioDecoderPrivate, parent }
{
- Q_Q(QAudioDecoder);
+ QT6_ONLY(Q_UNUSED(unused))
- if (ps != state) {
- state = ps;
+ Q_D(QAudioDecoder);
- emit q->stateChanged(ps);
+ auto maybeDecoder = QPlatformMediaIntegration::instance()->createAudioDecoder(this);
+ if (maybeDecoder) {
+ d->decoder.reset(maybeDecoder.value());
+ } else {
+ qWarning() << "Failed to initialize QAudioDecoder" << maybeDecoder.error();
}
}
-void QAudioDecoderPrivate::_q_error(int error, const QString &errorString)
-{
- Q_Q(QAudioDecoder);
-
- this->error = QAudioDecoder::Error(error);
- this->errorString = errorString;
-
- emit q->error(this->error);
-}
+/*!
+ Destroys the audio decoder object.
+*/
+QAudioDecoder::~QAudioDecoder() = default;
/*!
- Construct an QAudioDecoder instance
- parented to \a parent.
+ Returns true is audio decoding is supported on this platform.
*/
-QAudioDecoder::QAudioDecoder(QObject *parent)
- : QMediaObject(*new QAudioDecoderPrivate,
- parent,
- QMediaServiceProvider::defaultServiceProvider()->requestService(Q_MEDIASERVICE_AUDIODECODER))
+bool QAudioDecoder::isSupported() const
{
- Q_D(QAudioDecoder);
+ Q_D(const QAudioDecoder);
- d->provider = QMediaServiceProvider::defaultServiceProvider();
- if (d->service) {
- d->control = qobject_cast<QAudioDecoderControl*>(d->service->requestControl(QAudioDecoderControl_iid));
- if (d->control != nullptr) {
- connect(d->control, SIGNAL(stateChanged(QAudioDecoder::State)), SLOT(_q_stateChanged(QAudioDecoder::State)));
- connect(d->control, SIGNAL(error(int,QString)), SLOT(_q_error(int,QString)));
-
- connect(d->control, SIGNAL(formatChanged(QAudioFormat)), SIGNAL(formatChanged(QAudioFormat)));
- connect(d->control, SIGNAL(sourceChanged()), SIGNAL(sourceChanged()));
- connect(d->control, SIGNAL(bufferReady()), this, SIGNAL(bufferReady()));
- connect(d->control ,SIGNAL(bufferAvailableChanged(bool)), this, SIGNAL(bufferAvailableChanged(bool)));
- connect(d->control ,SIGNAL(finished()), this, SIGNAL(finished()));
- connect(d->control ,SIGNAL(positionChanged(qint64)), this, SIGNAL(positionChanged(qint64)));
- connect(d->control ,SIGNAL(durationChanged(qint64)), this, SIGNAL(durationChanged(qint64)));
- }
- }
- if (!d->control) {
- d->error = ServiceMissingError;
- d->errorString = tr("The QAudioDecoder object does not have a valid service");
- }
+ return bool(d->decoder);
}
-
/*!
- Destroys the audio decoder object.
+ \property QAudioDecoder::isDecoding
+ \brief \c true if the decoder is currently running and decoding audio data.
*/
-QAudioDecoder::~QAudioDecoder()
+bool QAudioDecoder::isDecoding() const
{
- Q_D(QAudioDecoder);
-
- if (d->service) {
- if (d->control)
- d->service->releaseControl(d->control);
-
- d->provider->releaseService(d->service);
- }
-}
+ Q_D(const QAudioDecoder);
-QAudioDecoder::State QAudioDecoder::state() const
-{
- return d_func()->state;
+ return d->decoder && d->decoder->isDecoding();
}
/*!
- Returns the current error state.
-*/
+ Returns the current error state of the QAudioDecoder.
+*/
QAudioDecoder::Error QAudioDecoder::error() const
{
- return d_func()->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
{
- return d_func()->errorString;
+ Q_D(const QAudioDecoder);
+ if (!d->decoder)
+ return tr("QAudioDecoder not supported.");
+ return d->decoder->errorString();
}
/*!
@@ -205,18 +117,12 @@ void QAudioDecoder::start()
{
Q_D(QAudioDecoder);
- if (d->control == nullptr) {
- QMetaObject::invokeMethod(this, "_q_error", Qt::QueuedConnection,
- Q_ARG(int, QAudioDecoder::ServiceMissingError),
- Q_ARG(QString, tr("The QAudioDecoder object does not have a valid service")));
+ if (!d->decoder)
return;
- }
// Reset error conditions
- d->error = NoError;
- d->errorString.clear();
-
- d->control->start();
+ d->decoder->clearError();
+ d->decoder->start();
}
/*!
@@ -226,8 +132,8 @@ void QAudioDecoder::stop()
{
Q_D(QAudioDecoder);
- if (d->control != nullptr)
- d->control->stop();
+ if (d->decoder)
+ d->decoder->stop();
}
/*!
@@ -235,12 +141,10 @@ void QAudioDecoder::stop()
If \l setSourceDevice was called, this will
be empty.
*/
-QString QAudioDecoder::sourceFilename() const
+QUrl QAudioDecoder::source() const
{
Q_D(const QAudioDecoder);
- if (d->control)
- return d->control->sourceFilename();
- return QString();
+ return d->unresolvedUrl;
}
/*!
@@ -252,24 +156,28 @@ QString QAudioDecoder::sourceFilename() const
You can only specify either a source filename or
a source QIODevice. Setting one will unset the other.
*/
-void QAudioDecoder::setSourceFilename(const QString &fileName)
+void QAudioDecoder::setSource(const QUrl &fileName)
{
Q_D(QAudioDecoder);
- if (d->control != nullptr)
- d_func()->control->setSourceFilename(fileName);
+ if (!d->decoder)
+ return;
+
+ d->decoder->clearError();
+ d->unresolvedUrl = fileName;
+ d->decoder->setSourceDevice(nullptr);
+ QUrl url = qMediaFromUserInput(fileName);
+ d->decoder->setSource(url);
}
/*!
Returns the current source QIODevice, if one was set.
- If \l setSourceFilename() was called, this will be 0.
+ If \l setSource() was called, this will be a nullptr.
*/
QIODevice *QAudioDecoder::sourceDevice() const
{
Q_D(const QAudioDecoder);
- if (d->control)
- return d->control->sourceDevice();
- return nullptr;
+ return d->decoder ? d->decoder->sourceDevice() : nullptr;
}
/*!
@@ -284,24 +192,24 @@ QIODevice *QAudioDecoder::sourceDevice() const
void QAudioDecoder::setSourceDevice(QIODevice *device)
{
Q_D(QAudioDecoder);
-
- if (d->control != nullptr)
- d_func()->control->setSourceDevice(device);
+ if (d->decoder) {
+ d->unresolvedUrl = QUrl{};
+ d->decoder->setSourceDevice(device);
+ }
}
/*!
- Returns the current audio format of the decoded stream.
+ Returns the audio format the decoder is set to.
- Any buffers returned should have this format.
+ \note This may be different than the format of the decoded
+ samples, if the audio format was set to an invalid one.
\sa setAudioFormat(), formatChanged()
*/
QAudioFormat QAudioDecoder::audioFormat() const
{
Q_D(const QAudioDecoder);
- if (d->control)
- return d->control->audioFormat();
- return QAudioFormat();
+ return d->decoder ? d->decoder->audioFormat() : QAudioFormat{};
}
/*!
@@ -319,45 +227,20 @@ QAudioFormat QAudioDecoder::audioFormat() const
If you wish to reset the decoded format to that of the original
audio file, you can specify an invalid \a format.
+
+ \warning Setting a desired audio format is not yet supported
+ on the Android backend. It does work with the default FFMPEG
+ backend.
*/
void QAudioDecoder::setAudioFormat(const QAudioFormat &format)
{
- Q_D(QAudioDecoder);
-
- if (state() != QAudioDecoder::StoppedState)
+ if (isDecoding())
return;
- if (d->control != nullptr)
- d_func()->control->setAudioFormat(format);
-}
-
-/*!
- \internal
-*/
-
-bool QAudioDecoder::bind(QObject *obj)
-{
- return QMediaObject::bind(obj);
-}
-
-/*!
- \internal
-*/
-
-void QAudioDecoder::unbind(QObject *obj)
-{
- QMediaObject::unbind(obj);
-}
+ Q_D(QAudioDecoder);
-/*!
- Returns the level of support an audio decoder has for a \a mimeType and a set of \a codecs.
-*/
-QMultimedia::SupportEstimate QAudioDecoder::hasSupport(const QString &mimeType,
- const QStringList& codecs)
-{
- return QMediaServiceProvider::defaultServiceProvider()->hasSupport(QByteArray(Q_MEDIASERVICE_AUDIODECODER),
- mimeType,
- codecs);
+ if (d->decoder)
+ d->decoder->setAudioFormat(format);
}
/*!
@@ -368,9 +251,7 @@ QMultimedia::SupportEstimate QAudioDecoder::hasSupport(const QString &mimeType,
bool QAudioDecoder::bufferAvailable() const
{
Q_D(const QAudioDecoder);
- if (d->control)
- return d->control->bufferAvailable();
- return false;
+ return d->decoder && d->decoder->bufferAvailable();
}
/*!
@@ -381,9 +262,7 @@ bool QAudioDecoder::bufferAvailable() const
qint64 QAudioDecoder::position() const
{
Q_D(const QAudioDecoder);
- if (d->control)
- return d->control->position();
- return -1;
+ return d->decoder ? d->decoder->position() : -1;
}
/*!
@@ -394,9 +273,7 @@ qint64 QAudioDecoder::position() const
qint64 QAudioDecoder::duration() const
{
Q_D(const QAudioDecoder);
- if (d->control)
- return d->control->duration();
- return -1;
+ return d->decoder ? d->decoder->duration() : -1;
}
/*!
@@ -412,26 +289,11 @@ qint64 QAudioDecoder::duration() const
QAudioBuffer QAudioDecoder::read() const
{
Q_D(const QAudioDecoder);
-
- if (d->control) {
- return d->control->read();
- } else {
- return QAudioBuffer();
- }
+ return d->decoder ? d->decoder->read() : QAudioBuffer{};
}
// Enums
/*!
- \enum QAudioDecoder::State
-
- Defines the current state of a media player.
-
- \value StoppedState The decoder is not decoding. Decoding will
- start at the start of the media.
- \value DecodingState The audio player is currently decoding media.
-*/
-
-/*!
\enum QAudioDecoder::Error
Defines a media player error condition.
@@ -440,12 +302,12 @@ QAudioBuffer QAudioDecoder::read() const
\value ResourceError A media resource couldn't be resolved.
\value FormatError The format of a media resource isn't supported.
\value AccessDeniedError There are not the appropriate permissions to play a media resource.
- \value ServiceMissingError A valid playback service was not found, playback cannot proceed.
+ \value NotSupportedError QAudioDecoder is not supported on this platform
*/
// Signals
/*!
- \fn QAudioDecoder::error(QAudioDecoder::Error error)
+ \fn void QAudioDecoder::error(QAudioDecoder::Error error)
Signals that an \a error condition has occurred.
@@ -453,17 +315,11 @@ QAudioBuffer QAudioDecoder::read() const
*/
/*!
- \fn void QAudioDecoder::stateChanged(State state)
-
- Signal the \a state of the decoder object has changed.
-*/
-
-/*!
\fn void QAudioDecoder::sourceChanged()
Signals that the current source of the decoder has changed.
- \sa sourceFilename(), sourceDevice()
+ \sa source(), sourceDevice()
*/
/*!
@@ -517,26 +373,9 @@ QAudioBuffer QAudioDecoder::read() const
\sa positionChanged()
*/
-
// Properties
/*!
- \property QAudioDecoder::state
- \brief the audio decoder's playback state.
-
- By default this property is QAudioDecoder::Stopped
-
- \sa start(), stop()
-*/
-
-/*!
- \property QAudioDecoder::error
- \brief a string describing the last error condition.
-
- \sa error()
-*/
-
-/*!
- \property QAudioDecoder::sourceFilename
+ \property QAudioDecoder::source
\brief the active filename being decoded by the decoder object.
*/
diff --git a/src/multimedia/audio/qaudiodecoder.h b/src/multimedia/audio/qaudiodecoder.h
index 4ba107946..9044b6617 100644
--- a/src/multimedia/audio/qaudiodecoder.h
+++ b/src/multimedia/audio/qaudiodecoder.h
@@ -1,89 +1,43 @@
-/****************************************************************************
-**
-** 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 <QtMultimedia/qmediaobject.h>
+#include <QtCore/qobject.h>
#include <QtMultimedia/qmediaenumdebug.h>
-
#include <QtMultimedia/qaudiobuffer.h>
QT_BEGIN_NAMESPACE
class QAudioDecoderPrivate;
-class Q_MULTIMEDIA_EXPORT QAudioDecoder : public QMediaObject
+class Q_MULTIMEDIA_EXPORT QAudioDecoder : public QObject
{
Q_OBJECT
- Q_PROPERTY(QString sourceFilename READ sourceFilename WRITE setSourceFilename NOTIFY sourceChanged)
- Q_PROPERTY(State state READ state NOTIFY stateChanged)
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(bool isDecoding READ isDecoding NOTIFY isDecodingChanged)
Q_PROPERTY(QString error READ errorString)
Q_PROPERTY(bool bufferAvailable READ bufferAvailable NOTIFY bufferAvailableChanged)
- Q_ENUMS(State)
- Q_ENUMS(Error)
-
public:
- enum State
- {
- StoppedState,
- DecodingState
- };
-
enum Error
{
NoError,
ResourceError,
FormatError,
AccessDeniedError,
- ServiceMissingError
+ NotSupportedError
};
+ Q_ENUM(Error)
explicit QAudioDecoder(QObject *parent = nullptr);
~QAudioDecoder();
- static QMultimedia::SupportEstimate hasSupport(const QString &mimeType, const QStringList& codecs = QStringList());
+ bool isSupported() const;
+ bool isDecoding() const;
- State state() const;
-
- QString sourceFilename() const;
- void setSourceFilename(const QString &fileName);
+ QUrl source() const;
+ void setSource(const QUrl &fileName);
QIODevice* sourceDevice() const;
void setSourceDevice(QIODevice *device);
@@ -108,8 +62,8 @@ Q_SIGNALS:
void bufferAvailableChanged(bool);
void bufferReady();
void finished();
+ void isDecodingChanged(bool);
- void stateChanged(QAudioDecoder::State newState);
void formatChanged(const QAudioFormat &format);
void error(QAudioDecoder::Error error);
@@ -119,23 +73,16 @@ Q_SIGNALS:
void positionChanged(qint64 position);
void durationChanged(qint64 duration);
-public:
- bool bind(QObject *) override;
- void unbind(QObject *) override;
-
private:
Q_DISABLE_COPY(QAudioDecoder)
Q_DECLARE_PRIVATE(QAudioDecoder)
- Q_PRIVATE_SLOT(d_func(), void _q_stateChanged(QAudioDecoder::State))
- Q_PRIVATE_SLOT(d_func(), void _q_error(int, const QString &))
+
+ // ### Qt7: remove unused member
+ QT6_ONLY(void *unused = nullptr;) // for ABI compatibility
};
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QAudioDecoder::State)
-Q_DECLARE_METATYPE(QAudioDecoder::Error)
-
-Q_MEDIA_ENUM_DEBUG(QAudioDecoder, State)
Q_MEDIA_ENUM_DEBUG(QAudioDecoder, Error)
#endif // QAUDIODECODER_H
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
new file mode 100644
index 000000000..4b1e182cb
--- /dev/null
+++ b/src/multimedia/audio/qaudiodevice.cpp
@@ -0,0 +1,373 @@
+// 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"
+#include <private/qplatformmediadevices_p.h>
+#include <private/qplatformmediaintegration_p.h>
+
+#include <QtCore/qmap.h>
+
+QT_BEGIN_NAMESPACE
+
+QAudioDevicePrivate::~QAudioDevicePrivate() = default;
+
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QAudioDevicePrivate);
+
+/*!
+ \class QAudioDevice
+ \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.
+
+ A QAudioDevice is used by Qt to construct
+ classes that communicate with the device -- such as
+ QAudioSource, and QAudioSink. It is also used to determine the
+ input or output device to use in a capture session or during media playback.
+
+ You can also query each device for the formats it supports. A
+ format in this context is a set consisting of a channel count, sample rate, and sample type. A
+ format is represented by the QAudioFormat class.
+
+ The values supported by the device for each of these parameters can be
+ fetched with minimumChannelCount(), maximumChannelCount(),
+ 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(). For instance:
+
+ \snippet multimedia-snippets/audio.cpp Audio output setup
+
+ The set of available devices can be retrieved from the QMediaDevices class.
+
+ For instance:
+
+ \snippet multimedia-snippets/audio.cpp Dumping audio formats
+
+ In this code sample, we loop through all devices that are able to output
+ sound, i.e., play an audio stream in a supported format. For each device we
+ find, we simply print the deviceName().
+
+ \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
+*/
+
+/*!
+ Constructs a null QAudioDevice object.
+*/
+QAudioDevice::QAudioDevice() = default;
+
+/*!
+ Constructs a copy of \a other.
+*/
+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.
+*/
+QAudioDevice::~QAudioDevice() = default;
+
+/*!
+ Sets the QAudioDevice object to be equal to \a other.
+*/
+QAudioDevice &QAudioDevice::operator=(const QAudioDevice &other) = default;
+
+/*!
+ \fn QAudioDevice& QAudioDevice::operator=(QAudioDevice &&other)
+
+ Moves \a other into this QAudioDevice object.
+*/
+
+/*!
+ Returns true if this QAudioDevice class represents the
+ same audio device as \a other.
+*/
+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 && d->isDefault == other.d->isDefault)
+ return true;
+ return false;
+}
+
+/*!
+ Returns true if this QAudioDevice class represents a
+ different audio device than \a other
+*/
+bool QAudioDevice::operator!=(const QAudioDevice &other) const
+{
+ return !operator==(other);
+}
+
+/*!
+ Returns whether this QAudioDevice object holds a valid device definition.
+*/
+bool QAudioDevice::isNull() const
+{
+ return d == nullptr;
+}
+
+/*!
+ \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.
+
+ They are a unique identifier for the audio device.
+*/
+QByteArray QAudioDevice::id() const
+{
+ return isNull() ? QByteArray() : d->id;
+}
+
+/*!
+ \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.
+*/
+QString QAudioDevice::description() const
+{
+ return isNull() ? QString() : d->description;
+}
+
+/*!
+ \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
+{
+ return d ? d->isDefault : false;
+}
+
+/*!
+ Returns true if the supplied \a settings are supported by the audio
+ device described by this QAudioDevice.
+*/
+bool QAudioDevice::isFormatSupported(const QAudioFormat &settings) const
+{
+ if (isNull())
+ return false;
+ if (settings.sampleRate() < d->minimumSampleRate
+ || settings.sampleRate() > d->maximumSampleRate)
+ return false;
+ if (settings.channelCount() < d->minimumChannelCount
+ || settings.channelCount() > d->maximumChannelCount)
+ return false;
+ if (!d->supportedSampleFormats.contains(settings.sampleFormat()))
+ return false;
+ return true;
+}
+
+/*!
+ Returns the default audio format settings for this device.
+
+ These settings are provided by the platform/audio plugin being used.
+
+ They are also dependent on the \l {QtAudio}::Mode being used.
+
+ A typical audio system would provide something like:
+ \list
+ \li Input settings: 48000Hz mono 16 bit.
+ \li Output settings: 48000Hz stereo 16 bit.
+ \endlist
+*/
+QAudioFormat QAudioDevice::preferredFormat() const
+{
+ return isNull() ? QAudioFormat() : d->preferredFormat;
+}
+
+/*!
+ Returns the minimum supported sample rate (in Hertz).
+*/
+int QAudioDevice::minimumSampleRate() const
+{
+ return isNull() ? 0 : d->minimumSampleRate;
+}
+
+/*!
+ Returns the maximum supported sample rate (in Hertz).
+*/
+int QAudioDevice::maximumSampleRate() const
+{
+ return isNull() ? 0 : d->maximumSampleRate;
+}
+
+/*!
+ Returns the minimum number of supported channel counts.
+
+ This is typically 1 for mono sound, or 2 for stereo sound.
+*/
+int QAudioDevice::minimumChannelCount() const
+{
+ return isNull() ? 0 : d->minimumChannelCount;
+}
+
+/*!
+ Returns the maximum number of supported channel counts.
+
+ This is typically 1 for mono sound, or 2 for stereo sound.
+*/
+int QAudioDevice::maximumChannelCount() const
+{
+ return isNull() ? 0 : d->maximumChannelCount;
+}
+
+/*!
+ Returns a list of supported sample types.
+*/
+QList<QAudioFormat::SampleFormat> QAudioDevice::supportedSampleFormats() const
+{
+ return isNull() ? QList<QAudioFormat::SampleFormat>() : d->supportedSampleFormats;
+}
+
+/*!
+ Returns the channel configuration of the device.
+*/
+QAudioFormat::ChannelConfig QAudioDevice::channelConfiguration() const
+{
+ return isNull() ? QAudioFormat::ChannelConfigUnknown : d->channelConfiguration;
+}
+
+/*!
+ \fn QAudioDevicePrivate QAudioDevice::handle() const
+ \internal
+*/
+/*!
+ \internal
+*/
+QAudioDevice::QAudioDevice(QAudioDevicePrivate *p) : d(p) { }
+
+/*!
+ \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
+{
+ return d ? d->mode : Null;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, QAudioDevice::Mode mode)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace();
+ switch (mode) {
+ case QAudioDevice::Input:
+ dbg << "QAudioDevice::Input";
+ break;
+ case QAudioDevice::Output:
+ dbg << "QAudioDevice::Output";
+ break;
+ case QAudioDevice::Null:
+ dbg << "QAudioDevice::Null";
+ break;
+ }
+ return dbg;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qaudiodevice.cpp"
diff --git a/src/multimedia/audio/qaudiodevice.h b/src/multimedia/audio/qaudiodevice.h
new file mode 100644
index 000000000..abd1b654c
--- /dev/null
+++ b/src/multimedia/audio/qaudiodevice.h
@@ -0,0 +1,84 @@
+// 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
+#define QAUDIODEVICEINFO_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qlist.h>
+
+#include <QtMultimedia/qtmultimediaglobal.h>
+
+#include <QtMultimedia/qtaudio.h>
+#include <QtMultimedia/qaudioformat.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAudioDevicePrivate;
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QAudioDevicePrivate, Q_MULTIMEDIA_EXPORT)
+
+class Q_MULTIMEDIA_EXPORT QAudioDevice
+{
+ Q_GADGET
+ Q_PROPERTY(QByteArray id READ id CONSTANT)
+ Q_PROPERTY(QString description READ description CONSTANT)
+ Q_PROPERTY(bool isDefault READ isDefault CONSTANT)
+ Q_PROPERTY(Mode mode READ mode CONSTANT)
+public:
+ enum Mode {
+ Null,
+ Input,
+ Output
+ };
+ Q_ENUM(Mode)
+
+ QAudioDevice();
+ QAudioDevice(const QAudioDevice& other);
+ ~QAudioDevice();
+
+ QAudioDevice(QAudioDevice &&other) noexcept = default;
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QAudioDevice)
+ void swap(QAudioDevice &other) noexcept
+ { d.swap(other.d); }
+
+ QAudioDevice& operator=(const QAudioDevice& other);
+
+ bool operator==(const QAudioDevice &other) const;
+ bool operator!=(const QAudioDevice &other) const;
+
+ bool isNull() const;
+
+ QByteArray id() const;
+ QString description() const;
+
+ bool isDefault() const;
+ QAudioDevice::Mode mode() const;
+
+ bool isFormatSupported(const QAudioFormat &format) const;
+ QAudioFormat preferredFormat() const;
+
+ int minimumSampleRate() const;
+ int maximumSampleRate() const;
+ int minimumChannelCount() const;
+ int maximumChannelCount() const;
+ QList<QAudioFormat::SampleFormat> supportedSampleFormats() const;
+ QAudioFormat::ChannelConfig channelConfiguration() const;
+
+ const QAudioDevicePrivate *handle() const { return d.get(); }
+private:
+ friend class QAudioDevicePrivate;
+ QAudioDevice(QAudioDevicePrivate *p);
+ QExplicitlySharedDataPointer<QAudioDevicePrivate> d;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug dbg, QAudioDevice::Mode mode);
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QAUDIODEVICEINFO_H
diff --git a/src/multimedia/audio/qaudiodevice_p.h b/src/multimedia/audio/qaudiodevice_p.h
new file mode 100644
index 000000000..c59856d72
--- /dev/null
+++ b/src/multimedia/audio/qaudiodevice_p.h
@@ -0,0 +1,62 @@
+// 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
+#define QAUDIODEVICEINFO_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/qaudiodevice.h>
+#include <QtCore/private/qglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_MULTIMEDIA_EXPORT QAudioDevicePrivate : public QSharedData
+{
+public:
+ QAudioDevicePrivate(const QByteArray &i, QAudioDevice::Mode m)
+ : id(i),
+ mode(m)
+ {}
+ virtual ~QAudioDevicePrivate();
+ QByteArray id;
+ QAudioDevice::Mode mode = QAudioDevice::Output;
+ bool isDefault = false;
+
+ QAudioFormat preferredFormat;
+ QString description;
+ int minimumSampleRate = 0;
+ int maximumSampleRate = 0;
+ 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); }
+};
+
+QT_END_NAMESPACE
+
+#endif // QAUDIODEVICEINFO_H
diff --git a/src/multimedia/audio/qaudiodevicefactory.cpp b/src/multimedia/audio/qaudiodevicefactory.cpp
deleted file mode 100644
index cf770c468..000000000
--- a/src/multimedia/audio/qaudiodevicefactory.cpp
+++ /dev/null
@@ -1,259 +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 "qaudiosystem.h"
-#include "qaudiosystemplugin.h"
-#include "qaudiosystempluginext_p.h"
-
-#include "qmediapluginloader_p.h"
-#include "qaudiodevicefactory_p.h"
-
-QT_BEGIN_NAMESPACE
-
-static QString defaultKey()
-{
- return QStringLiteral("default");
-}
-
-#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
-Q_GLOBAL_STATIC_WITH_ARGS(QMediaPluginLoader, audioLoader,
- (QAudioSystemFactoryInterface_iid, QLatin1String("audio"), Qt::CaseInsensitive))
-#endif
-
-class QNullDeviceInfo : public QAbstractAudioDeviceInfo
-{
-public:
- QAudioFormat preferredFormat() const override { qWarning()<<"using null deviceinfo, none available"; return QAudioFormat(); }
- bool isFormatSupported(const QAudioFormat& ) const override { return false; }
- QAudioFormat nearestFormat(const QAudioFormat& ) const { return QAudioFormat(); }
- QString deviceName() const override { return QString(); }
- QStringList supportedCodecs() override { return QStringList(); }
- QList<int> supportedSampleRates() override { return QList<int>(); }
- QList<int> supportedChannelCounts() override { return QList<int>(); }
- QList<int> supportedSampleSizes() override { return QList<int>(); }
- QList<QAudioFormat::Endian> supportedByteOrders() override { return QList<QAudioFormat::Endian>(); }
- QList<QAudioFormat::SampleType> supportedSampleTypes() override { return QList<QAudioFormat::SampleType>(); }
-};
-
-class QNullInputDevice : public QAbstractAudioInput
-{
-public:
- void start(QIODevice*) override { qWarning()<<"using null input device, none available";}
- QIODevice *start() override { qWarning()<<"using null input device, none available"; return nullptr; }
- void stop() override {}
- void reset() override {}
- void suspend() override {}
- void resume() override {}
- int bytesReady() const override { return 0; }
- int periodSize() const override { return 0; }
- void setBufferSize(int ) override {}
- int bufferSize() const override { return 0; }
- void setNotifyInterval(int ) override {}
- int notifyInterval() const override { return 0; }
- qint64 processedUSecs() const override { return 0; }
- qint64 elapsedUSecs() const override { return 0; }
- QAudio::Error error() const override { return QAudio::OpenError; }
- QAudio::State state() const override { return QAudio::StoppedState; }
- void setFormat(const QAudioFormat&) override {}
- QAudioFormat format() const override { return QAudioFormat(); }
- void setVolume(qreal) override {}
- qreal volume() const override {return 1.0f;}
-};
-
-class QNullOutputDevice : public QAbstractAudioOutput
-{
-public:
- void start(QIODevice*) override {qWarning()<<"using null output device, none available";}
- QIODevice *start() override { qWarning()<<"using null output device, none available"; return nullptr; }
- void stop() override {}
- void reset() override {}
- void suspend() override {}
- void resume() override {}
- int bytesFree() const override { return 0; }
- int periodSize() const override { return 0; }
- void setBufferSize(int ) override {}
- int bufferSize() const override { return 0; }
- void setNotifyInterval(int ) override {}
- int notifyInterval() const override { return 0; }
- qint64 processedUSecs() const override { return 0; }
- qint64 elapsedUSecs() const override { return 0; }
- QAudio::Error error() const override { return QAudio::OpenError; }
- QAudio::State state() const override { return QAudio::StoppedState; }
- void setFormat(const QAudioFormat&) override {}
- QAudioFormat format() const override { return QAudioFormat(); }
-};
-
-QList<QAudioDeviceInfo> QAudioDeviceFactory::availableDevices(QAudio::Mode mode)
-{
- QList<QAudioDeviceInfo> devices;
-#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
- QMediaPluginLoader* l = audioLoader();
- const auto keys = l->keys();
- for (const QString& key : keys) {
- QAudioSystemFactoryInterface* plugin = qobject_cast<QAudioSystemFactoryInterface*>(l->instance(key));
- if (plugin) {
- const auto availableDevices = plugin->availableDevices(mode);
- for (const QByteArray& handle : availableDevices)
- devices << QAudioDeviceInfo(key, handle, mode);
- }
- }
-#endif
-
- return devices;
-}
-
-QAudioDeviceInfo QAudioDeviceFactory::defaultDevice(QAudio::Mode mode)
-{
-#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
- QMediaPluginLoader* l = audioLoader();
-
- // Check if there is a default plugin.
- QAudioSystemFactoryInterface *plugin = qobject_cast<QAudioSystemFactoryInterface *>(l->instance(defaultKey()));
- if (plugin) {
- // Check if the plugin has the extension interface.
- QAudioSystemPluginExtension *pluginExt = qobject_cast<QAudioSystemPluginExtension *>(l->instance(defaultKey()));
- // Ask for the default device.
- if (pluginExt) {
- const QByteArray &device = pluginExt->defaultDevice(mode);
- if (!device.isEmpty())
- return QAudioDeviceInfo(defaultKey(), device, mode);
- }
-
- // If there were no default devices, e.g., if the plugin did not implement the extent-ion interface,
- // then just pick the first device that's available.
- const auto &devices = plugin->availableDevices(mode);
- if (!devices.isEmpty())
- return QAudioDeviceInfo(defaultKey(), devices.first(), mode);
- }
-
- // If no plugin is marked as default, check the other plugins.
- // Note: We're going to prioritize plugins that report a default device.
- const auto &keys = l->keys();
- QAudioDeviceInfo fallbackDevice;
- for (const auto &key : keys) {
- if (key == defaultKey())
- continue;
- QAudioSystemFactoryInterface* plugin = qobject_cast<QAudioSystemFactoryInterface*>(l->instance(key));
- if (plugin) {
- // Check if the plugin has the extent-ion interface.
- QAudioSystemPluginExtension *pluginExt = qobject_cast<QAudioSystemPluginExtension *>(l->instance(key));
- if (pluginExt) {
- const QByteArray &device = pluginExt->defaultDevice(mode);
- if (!device.isEmpty())
- return QAudioDeviceInfo(key, device, mode);
- } else if (fallbackDevice.isNull()) {
- const auto &devices = plugin->availableDevices(mode);
- if (!devices.isEmpty())
- fallbackDevice = QAudioDeviceInfo(key, devices.first(), mode);
- }
- }
- }
-
-#endif
-
- return QAudioDeviceInfo();
-}
-
-QAbstractAudioDeviceInfo* QAudioDeviceFactory::audioDeviceInfo(const QString &realm, const QByteArray &handle, QAudio::Mode mode)
-{
- QAbstractAudioDeviceInfo *rc = nullptr;
-
-#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
- QAudioSystemFactoryInterface* plugin =
- qobject_cast<QAudioSystemFactoryInterface*>(audioLoader()->instance(realm));
-
- if (plugin)
- rc = plugin->createDeviceInfo(handle, mode);
-#endif
-
- return rc == nullptr ? new QNullDeviceInfo() : rc;
-}
-
-QAbstractAudioInput* QAudioDeviceFactory::createDefaultInputDevice(QAudioFormat const &format)
-{
- return createInputDevice(defaultDevice(QAudio::AudioInput), format);
-}
-
-QAbstractAudioOutput* QAudioDeviceFactory::createDefaultOutputDevice(QAudioFormat const &format)
-{
- return createOutputDevice(defaultDevice(QAudio::AudioOutput), format);
-}
-
-QAbstractAudioInput* QAudioDeviceFactory::createInputDevice(QAudioDeviceInfo const& deviceInfo, QAudioFormat const &format)
-{
- if (deviceInfo.isNull())
- return new QNullInputDevice();
-
-#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
- QAudioSystemFactoryInterface* plugin =
- qobject_cast<QAudioSystemFactoryInterface*>(audioLoader()->instance(deviceInfo.realm()));
-
- if (plugin) {
- QAbstractAudioInput* p = plugin->createInput(deviceInfo.handle());
- if (p) p->setFormat(format);
- return p;
- }
-#endif
-
- return new QNullInputDevice();
-}
-
-QAbstractAudioOutput* QAudioDeviceFactory::createOutputDevice(QAudioDeviceInfo const& deviceInfo, QAudioFormat const &format)
-{
- if (deviceInfo.isNull())
- return new QNullOutputDevice();
-
-#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
- QAudioSystemFactoryInterface* plugin =
- qobject_cast<QAudioSystemFactoryInterface*>(audioLoader()->instance(deviceInfo.realm()));
-
- if (plugin) {
- QAbstractAudioOutput* p = plugin->createOutput(deviceInfo.handle());
- if (p) p->setFormat(format);
- return p;
- }
-#endif
-
- return new QNullOutputDevice();
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/multimedia/audio/qaudiodevicefactory_p.h b/src/multimedia/audio/qaudiodevicefactory_p.h
deleted file mode 100644
index 238be46a7..000000000
--- a/src/multimedia/audio/qaudiodevicefactory_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 QAUDIODEVICEFACTORY_P_H
-#define QAUDIODEVICEFACTORY_P_H
-
-#include <QtCore/qbytearray.h>
-#include <QtCore/qlist.h>
-
-#include <qtmultimediaglobal.h>
-#include <qmultimedia.h>
-
-#include "qaudiodeviceinfo.h"
-
-QT_BEGIN_NAMESPACE
-
-
-class QAbstractAudioInput;
-class QAbstractAudioOutput;
-class QAbstractAudioDeviceInfo;
-
-class QAudioDeviceFactory
-{
-public:
- static QList<QAudioDeviceInfo> availableDevices(QAudio::Mode mode);
-
- static QAudioDeviceInfo defaultDevice(QAudio::Mode mode);
-
- static QAbstractAudioDeviceInfo* audioDeviceInfo(const QString &realm, const QByteArray &handle, QAudio::Mode mode);
-
- static QAbstractAudioInput* createDefaultInputDevice(QAudioFormat const &format);
- static QAbstractAudioOutput* createDefaultOutputDevice(QAudioFormat const &format);
-
- static QAbstractAudioInput* createInputDevice(QAudioDeviceInfo const &device, QAudioFormat const &format);
- static QAbstractAudioOutput* createOutputDevice(QAudioDeviceInfo const &device, QAudioFormat const &format);
-
- static QAbstractAudioInput* createNullInput();
- static QAbstractAudioOutput* createNullOutput();
-};
-
-QT_END_NAMESPACE
-
-#endif // QAUDIODEVICEFACTORY_P_H
-
diff --git a/src/multimedia/audio/qaudiodeviceinfo.cpp b/src/multimedia/audio/qaudiodeviceinfo.cpp
deleted file mode 100644
index 051ef8b3f..000000000
--- a/src/multimedia/audio/qaudiodeviceinfo.cpp
+++ /dev/null
@@ -1,476 +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 "qaudiodevicefactory_p.h"
-#include "qaudiosystem.h"
-#include "qaudiodeviceinfo.h"
-
-#include <QtCore/qmap.h>
-
-QT_BEGIN_NAMESPACE
-
-static void qRegisterAudioDeviceInfoMetaTypes()
-{
- qRegisterMetaType<QAudioDeviceInfo>();
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterAudioDeviceInfoMetaTypes)
-
-class QAudioDeviceInfoPrivate : public QSharedData
-{
-public:
- QAudioDeviceInfoPrivate()
- : mode(QAudio::AudioOutput)
- , info(nullptr)
- {
- }
-
- QAudioDeviceInfoPrivate(const QString &r, const QByteArray &h, QAudio::Mode m):
- realm(r), handle(h), mode(m)
- {
- if (!handle.isEmpty())
- info = QAudioDeviceFactory::audioDeviceInfo(realm, handle, mode);
- else
- info = nullptr;
- }
-
- QAudioDeviceInfoPrivate(const QAudioDeviceInfoPrivate &other):
- QSharedData(other),
- realm(other.realm), handle(other.handle), mode(other.mode)
- {
- info = QAudioDeviceFactory::audioDeviceInfo(realm, handle, mode);
- }
-
- QAudioDeviceInfoPrivate& operator=(const QAudioDeviceInfoPrivate &other)
- {
- delete info;
-
- realm = other.realm;
- handle = other.handle;
- mode = other.mode;
- info = QAudioDeviceFactory::audioDeviceInfo(realm, handle, mode);
- return *this;
- }
-
- ~QAudioDeviceInfoPrivate()
- {
- delete info;
- }
-
- QString realm;
- QByteArray handle;
- QAudio::Mode mode;
- QAbstractAudioDeviceInfo* info;
-};
-
-
-/*!
- \class QAudioDeviceInfo
- \brief The QAudioDeviceInfo class provides an interface to query audio devices and their functionality.
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_audio
-
- QAudioDeviceInfo lets you query for audio devices--such as sound
- cards and USB headsets--that are currently available on the system.
- The audio devices available are dependent on the platform or audio plugins installed.
-
- A QAudioDeviceInfo is used by Qt to construct
- classes that communicate with the device--such as
- QAudioInput, and QAudioOutput.
-
- You can also query each device for the formats it supports. A
- format in this context is a set consisting of a specific byte
- order, channel, codec, frequency, sample rate, and sample type. A
- format is represented by the QAudioFormat class.
-
- The values supported by the device for each of these
- parameters can be fetched with
- supportedByteOrders(), supportedChannelCounts(), supportedCodecs(),
- supportedSampleRates(), supportedSampleSizes(), and
- supportedSampleTypes(). The combinations supported are dependent on the platform,
- audio plugins installed and 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:
-
- \snippet multimedia-snippets/audio.cpp Setting audio format
-
- The static
- functions defaultInputDevice(), defaultOutputDevice(), and
- availableDevices() let you get a list of all available
- devices. Devices are fetched according to the value of mode
- this is specified by the \l {QAudio}::Mode enum.
- The QAudioDeviceInfo returned are only valid for the \l {QAudio}::Mode.
-
- For instance:
-
- \snippet multimedia-snippets/audio.cpp Dumping audio formats
-
- In this code sample, we loop through all devices that are able to output
- sound, i.e., play an audio stream in a supported format. For each device we
- find, we simply print the deviceName().
-
- \sa QAudioOutput, QAudioInput
-*/
-
-/*!
- Constructs an empty QAudioDeviceInfo object.
-*/
-QAudioDeviceInfo::QAudioDeviceInfo():
- d(new QAudioDeviceInfoPrivate)
-{
-}
-
-/*!
- Constructs a copy of \a other.
-*/
-QAudioDeviceInfo::QAudioDeviceInfo(const QAudioDeviceInfo& other):
- d(other.d)
-{
-}
-
-/*!
- Destroy this audio device info.
-*/
-QAudioDeviceInfo::~QAudioDeviceInfo()
-{
-}
-
-/*!
- Sets the QAudioDeviceInfo object to be equal to \a other.
-*/
-QAudioDeviceInfo& QAudioDeviceInfo::operator=(const QAudioDeviceInfo &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Returns true if this QAudioDeviceInfo class represents the
- same audio device as \a other.
-*/
-bool QAudioDeviceInfo::operator ==(const QAudioDeviceInfo &other) const
-{
- if (d == other.d)
- return true;
- if (d->realm == other.d->realm
- && d->mode == other.d->mode
- && d->handle == other.d->handle
- && deviceName() == other.deviceName())
- return true;
- return false;
-}
-
-/*!
- Returns true if this QAudioDeviceInfo class represents a
- different audio device than \a other
-*/
-bool QAudioDeviceInfo::operator !=(const QAudioDeviceInfo &other) const
-{
- return !operator==(other);
-}
-
-/*!
- Returns whether this QAudioDeviceInfo object holds a valid device definition.
-*/
-bool QAudioDeviceInfo::isNull() const
-{
- return d->info == nullptr;
-}
-
-/*!
- Returns the human readable name of the audio device.
-
- Device names vary depending on the platform/audio plugin being used.
-
- They are a unique string identifier for the audio device.
-
- eg. default, Intel, U0x46d0x9a4
-*/
-QString QAudioDeviceInfo::deviceName() const
-{
- return isNull() ? QString() : d->info->deviceName();
-}
-
-/*!
- Returns true if the supplied \a settings are supported by the audio
- device described by this QAudioDeviceInfo.
-*/
-bool QAudioDeviceInfo::isFormatSupported(const QAudioFormat &settings) const
-{
- return isNull() ? false : d->info->isFormatSupported(settings);
-}
-
-/*!
- Returns the default audio format settings for this device.
-
- These settings are provided by the platform/audio plugin being used.
-
- They are also dependent on the \l {QAudio}::Mode being used.
-
- A typical audio system would provide something like:
- \list
- \li Input settings: 8000Hz mono 8 bit.
- \li Output settings: 44100Hz stereo 16 bit little endian.
- \endlist
-*/
-QAudioFormat QAudioDeviceInfo::preferredFormat() const
-{
- return isNull() ? QAudioFormat() : d->info->preferredFormat();
-}
-
-/*!
- Returns the closest QAudioFormat to the supplied \a settings that the system supports.
-
- These settings are provided by the platform/audio plugin being used.
-
- They are also dependent on the \l {QAudio}::Mode being used.
-*/
-QAudioFormat QAudioDeviceInfo::nearestFormat(const QAudioFormat &settings) const
-{
- if (isFormatSupported(settings))
- return settings;
-
- QAudioFormat nearest = settings;
-
- QList<QString> testCodecs = supportedCodecs();
- QList<int> testChannels = supportedChannelCounts();
- QList<QAudioFormat::Endian> testByteOrders = supportedByteOrders();
- QList<QAudioFormat::SampleType> testSampleTypes;
- QList<QAudioFormat::SampleType> sampleTypesAvailable = supportedSampleTypes();
- QMap<int,int> testSampleRates;
- QList<int> sampleRatesAvailable = supportedSampleRates();
- QMap<int,int> testSampleSizes;
- QList<int> sampleSizesAvailable = supportedSampleSizes();
-
- // Get sorted lists for checking
- if (testCodecs.contains(settings.codec())) {
- testCodecs.removeAll(settings.codec());
- testCodecs.insert(0, settings.codec());
- }
- testChannels.removeAll(settings.channelCount());
- testChannels.insert(0, settings.channelCount());
- testByteOrders.removeAll(settings.byteOrder());
- testByteOrders.insert(0, settings.byteOrder());
-
- if (sampleTypesAvailable.contains(settings.sampleType()))
- testSampleTypes.append(settings.sampleType());
- if (sampleTypesAvailable.contains(QAudioFormat::SignedInt))
- testSampleTypes.append(QAudioFormat::SignedInt);
- if (sampleTypesAvailable.contains(QAudioFormat::UnSignedInt))
- testSampleTypes.append(QAudioFormat::UnSignedInt);
- if (sampleTypesAvailable.contains(QAudioFormat::Float))
- testSampleTypes.append(QAudioFormat::Float);
-
- if (sampleSizesAvailable.contains(settings.sampleSize()))
- testSampleSizes.insert(0,settings.sampleSize());
- sampleSizesAvailable.removeAll(settings.sampleSize());
- for (int size : qAsConst(sampleSizesAvailable)) {
- int larger = (size > settings.sampleSize()) ? size : settings.sampleSize();
- int smaller = (size > settings.sampleSize()) ? settings.sampleSize() : size;
- bool isMultiple = ( 0 == (larger % smaller));
- int diff = larger - smaller;
- testSampleSizes.insert((isMultiple ? diff : diff+100000), size);
- }
- if (sampleRatesAvailable.contains(settings.sampleRate()))
- testSampleRates.insert(0,settings.sampleRate());
- sampleRatesAvailable.removeAll(settings.sampleRate());
- for (int sampleRate : qAsConst(sampleRatesAvailable)) {
- int larger = (sampleRate > settings.sampleRate()) ? sampleRate : settings.sampleRate();
- int smaller = (sampleRate > settings.sampleRate()) ? settings.sampleRate() : sampleRate;
- bool isMultiple = ( 0 == (larger % smaller));
- int diff = larger - smaller;
- testSampleRates.insert((isMultiple ? diff : diff+100000), sampleRate);
- }
-
- // Try to find nearest
- for (const QString &codec : qAsConst(testCodecs)) {
- nearest.setCodec(codec);
- for (QAudioFormat::Endian order : qAsConst(testByteOrders)) {
- nearest.setByteOrder(order);
- for (QAudioFormat::SampleType sample : qAsConst(testSampleTypes)) {
- nearest.setSampleType(sample);
- for (int sampleSize : qAsConst(testSampleSizes)) {
- nearest.setSampleSize(sampleSize);
- for (int channel : qAsConst(testChannels)) {
- nearest.setChannelCount(channel);
- for (int sampleRate : qAsConst(testSampleRates)) {
- nearest.setSampleRate(sampleRate);
- if (isFormatSupported(nearest))
- return nearest;
- }
- }
- }
- }
- }
- }
- //Fallback
- return preferredFormat();
-}
-
-/*!
- Returns a list of supported codecs.
-
- All platform and plugin implementations should provide support for:
-
- "audio/pcm" - Linear PCM
-
- For writing plugins to support additional codecs refer to:
-
- http://www.iana.org/assignments/media-types/audio/
-*/
-QStringList QAudioDeviceInfo::supportedCodecs() const
-{
- return isNull() ? QStringList() : d->info->supportedCodecs();
-}
-
-/*!
- Returns a list of supported sample rates (in Hertz).
-
-*/
-QList<int> QAudioDeviceInfo::supportedSampleRates() const
-{
- return isNull() ? QList<int>() : d->info->supportedSampleRates();
-}
-
-/*!
- Returns a list of supported channel counts.
-
- This is typically 1 for mono sound, or 2 for stereo sound.
-
-*/
-QList<int> QAudioDeviceInfo::supportedChannelCounts() const
-{
- return isNull() ? QList<int>() : d->info->supportedChannelCounts();
-}
-
-/*!
- Returns a list of supported sample sizes (in bits).
-
- Typically this will include 8 and 16 bit sample sizes.
-
-*/
-QList<int> QAudioDeviceInfo::supportedSampleSizes() const
-{
- return isNull() ? QList<int>() : d->info->supportedSampleSizes();
-}
-
-/*!
- Returns a list of supported byte orders.
-*/
-QList<QAudioFormat::Endian> QAudioDeviceInfo::supportedByteOrders() const
-{
- return isNull() ? QList<QAudioFormat::Endian>() : d->info->supportedByteOrders();
-}
-
-/*!
- Returns a list of supported sample types.
-*/
-QList<QAudioFormat::SampleType> QAudioDeviceInfo::supportedSampleTypes() const
-{
- return isNull() ? QList<QAudioFormat::SampleType>() : d->info->supportedSampleTypes();
-}
-
-/*!
- Returns the information for the default input audio device.
- All platform and audio plugin implementations provide a default audio device to use.
-*/
-QAudioDeviceInfo QAudioDeviceInfo::defaultInputDevice()
-{
- return QAudioDeviceFactory::defaultDevice(QAudio::AudioInput);
-}
-
-/*!
- Returns the information for the default output audio device.
- All platform and audio plugin implementations provide a default audio device to use.
-*/
-QAudioDeviceInfo QAudioDeviceInfo::defaultOutputDevice()
-{
- return QAudioDeviceFactory::defaultDevice(QAudio::AudioOutput);
-}
-
-/*!
- Returns a list of audio devices that support \a mode.
-*/
-QList<QAudioDeviceInfo> QAudioDeviceInfo::availableDevices(QAudio::Mode mode)
-{
- return QAudioDeviceFactory::availableDevices(mode);
-}
-
-
-/*!
- \internal
-*/
-QAudioDeviceInfo::QAudioDeviceInfo(const QString &realm, const QByteArray &handle, QAudio::Mode mode):
- d(new QAudioDeviceInfoPrivate(realm, handle, mode))
-{
-}
-
-/*!
- Returns the key that represents the audio plugin.
-
- \since 5.14
- \sa QAudioSystemPlugin
-*/
-QString QAudioDeviceInfo::realm() const
-{
- return d->realm;
-}
-
-/*!
- \internal
-*/
-QByteArray QAudioDeviceInfo::handle() const
-{
- return d->handle;
-}
-
-
-/*!
- \internal
-*/
-QAudio::Mode QAudioDeviceInfo::mode() const
-{
- return d->mode;
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/multimedia/audio/qaudiodeviceinfo.h b/src/multimedia/audio/qaudiodeviceinfo.h
deleted file mode 100644
index 015c8bad7..000000000
--- a/src/multimedia/audio/qaudiodeviceinfo.h
+++ /dev/null
@@ -1,109 +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 QAUDIODEVICEINFO_H
-#define QAUDIODEVICEINFO_H
-
-#include <QtCore/qobject.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qlist.h>
-
-#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qmultimedia.h>
-
-#include <QtMultimedia/qaudio.h>
-#include <QtMultimedia/qaudioformat.h>
-
-QT_BEGIN_NAMESPACE
-
-
-class QAudioDeviceFactory;
-
-class QAudioDeviceInfoPrivate;
-class Q_MULTIMEDIA_EXPORT QAudioDeviceInfo
-{
- friend class QAudioDeviceFactory;
-
-public:
- QAudioDeviceInfo();
- QAudioDeviceInfo(const QAudioDeviceInfo& other);
- ~QAudioDeviceInfo();
-
- QAudioDeviceInfo& operator=(const QAudioDeviceInfo& other);
-
- bool operator==(const QAudioDeviceInfo &other) const;
- bool operator!=(const QAudioDeviceInfo &other) const;
-
- bool isNull() const;
-
- QString deviceName() const;
-
- bool isFormatSupported(const QAudioFormat &format) const;
- QAudioFormat preferredFormat() const;
- QAudioFormat nearestFormat(const QAudioFormat &format) const;
-
- QStringList supportedCodecs() const;
- QList<int> supportedSampleRates() const;
- QList<int> supportedChannelCounts() const;
- QList<int> supportedSampleSizes() const;
- QList<QAudioFormat::Endian> supportedByteOrders() const;
- QList<QAudioFormat::SampleType> supportedSampleTypes() const;
- QString realm() const;
-
- static QAudioDeviceInfo defaultInputDevice();
- static QAudioDeviceInfo defaultOutputDevice();
-
- static QList<QAudioDeviceInfo> availableDevices(QAudio::Mode mode);
-
-private:
- QAudioDeviceInfo(const QString &realm, const QByteArray &handle, QAudio::Mode mode);
- QByteArray handle() const;
- QAudio::Mode mode() const;
-
- QSharedDataPointer<QAudioDeviceInfoPrivate> d;
-};
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QAudioDeviceInfo)
-
-#endif // QAUDIODEVICEINFO_H
diff --git a/src/multimedia/audio/qaudioformat.cpp b/src/multimedia/audio/qaudioformat.cpp
index be3561084..9f51759b5 100644
--- a/src/multimedia/audio/qaudioformat.cpp
+++ b/src/multimedia/audio/qaudioformat.cpp
@@ -1,99 +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 <QDebug>
#include <qaudioformat.h>
-
+#include <qalgorithms.h>
QT_BEGIN_NAMESPACE
-static void qRegisterAudioFormatMetaTypes()
-{
- qRegisterMetaType<QAudioFormat>();
- qRegisterMetaType<QAudioFormat::SampleType>();
- qRegisterMetaType<QAudioFormat::Endian>();
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterAudioFormatMetaTypes)
-
-class QAudioFormatPrivate : public QSharedData
-{
-public:
- QAudioFormatPrivate()
- {
- sampleRate = -1;
- channels = -1;
- sampleSize = -1;
- byteOrder = QAudioFormat::Endian(QSysInfo::ByteOrder);
- sampleType = QAudioFormat::Unknown;
- }
-
- QAudioFormatPrivate(const QAudioFormatPrivate &other):
- QSharedData(other),
- codec(other.codec),
- byteOrder(other.byteOrder),
- sampleType(other.sampleType),
- sampleRate(other.sampleRate),
- channels(other.channels),
- sampleSize(other.sampleSize)
- {
- }
-
- QAudioFormatPrivate& operator=(const QAudioFormatPrivate &other)
- {
- codec = other.codec;
- byteOrder = other.byteOrder;
- sampleType = other.sampleType;
- sampleRate = other.sampleRate;
- channels = other.channels;
- sampleSize = other.sampleSize;
-
- return *this;
- }
-
- QString codec;
- QAudioFormat::Endian byteOrder;
- QAudioFormat::SampleType sampleType;
- int sampleRate;
- int channels;
- int sampleSize;
-};
-
/*!
\class QAudioFormat
\brief The QAudioFormat class stores audio stream parameter information.
@@ -102,15 +14,12 @@ public:
\ingroup multimedia
\ingroup multimedia_audio
- An audio format specifies how data in an audio stream is arranged,
- i.e, how the stream is to be interpreted. The encoding itself is
- specified by the codec() used for the stream.
+ An audio format specifies how data in a raw audio stream is arranged. For
+ example, how the stream is to be interpreted.
- In addition to the encoding, QAudioFormat contains other
- parameters that further specify how the audio sample data is arranged.
- These are the frequency, the number of channels, the sample size,
- the sample type, and the byte order. The following table describes
- these in more detail.
+ QAudioFormat contains parameters that specify how the audio sample data
+ is arranged. These are the frequency, the number of channels, and the
+ sample format. The following table describes these in more detail.
\table
\header
@@ -122,241 +31,231 @@ public:
\row
\li Number of channels
\li The number of audio channels (typically one for mono
- or two for stereo)
- \row
- \li Sample size
- \li How much data is stored in each sample (typically 8
- or 16 bits)
+ or two for stereo). These are the amount of consecutive
+ samples that together form one frame in the stream
\row
- \li Sample type
- \li Numerical representation of sample (typically signed integer,
- unsigned integer or float)
- \row
- \li Byte order
- \li Byte ordering of sample (typically little endian, big endian)
+ \li Sample format
+ \li The format of the audio samples in the stream
\endtable
- This class is typically used in conjunction with QAudioInput or
- QAudioOutput to allow you to specify the parameters of the audio
+ This class is used in conjunction with QAudioSource or
+ QAudioSink to allow you to specify the parameters of the audio
stream being read or written, or with QAudioBuffer when dealing with
samples in memory.
You can obtain audio formats compatible with the audio device used
- through functions in QAudioDeviceInfo. This class also lets you
+ through functions in QAudioDevice. This class also lets you
query available parameter values for a device, so that you can set
- the parameters yourself. See the \l QAudioDeviceInfo class
+ the parameters yourself. See the \l QAudioDevice class
description for details. You need to know the format of the audio
streams you wish to play or record.
- In the common case of interleaved linear PCM data, the codec will
- be "audio/pcm", and the samples for all channels will be interleaved.
+ Samples for all channels will be interleaved.
One sample for each channel for the same instant in time is referred
to as a frame in Qt Multimedia (and other places).
*/
/*!
- Construct a new audio format.
+ \fn QAudioFormat::QAudioFormat()
+
+ Constructs a new audio format.
Values are initialized as follows:
\list
- \li sampleRate() = -1
- \li channelCount() = -1
- \li sampleSize() = -1
- \li byteOrder() = QAudioFormat::Endian(QSysInfo::ByteOrder)
- \li sampleType() = QAudioFormat::Unknown
- \c codec() = ""
+ \li sampleRate() = 0
+ \li channelCount() = 0
+ \li sampleFormat() = QAudioFormat::Unknown
\endlist
*/
-QAudioFormat::QAudioFormat():
- d(new QAudioFormatPrivate)
-{
-}
/*!
+ \fn QAudioFormat::QAudioFormat(const QAudioFormat &other)
+
Construct a new audio format using \a other.
*/
-QAudioFormat::QAudioFormat(const QAudioFormat &other):
- d(other.d)
-{
-}
/*!
+ \fn QAudioFormat::~QAudioFormat()
+
Destroy this audio format.
*/
-QAudioFormat::~QAudioFormat()
-{
-}
/*!
- Assigns \a other to this QAudioFormat implementation.
+ \fn bool QAudioFormat::operator==(const QAudioFormat &a, const QAudioFormat &b)
+
+ Returns \c true if audio format \a a is equal to \a b, otherwise returns \c false.
*/
-QAudioFormat& QAudioFormat::operator=(const QAudioFormat &other)
-{
- d = other.d;
- return *this;
-}
/*!
- Returns true if this QAudioFormat is equal to the \a other
- QAudioFormat; otherwise returns false.
+ \fn bool QAudioFormat::operator!=(const QAudioFormat &a, const QAudioFormat &b)
- All elements of QAudioFormat are used for the comparison.
+ Returns \c true if audio format \a a is not equal to \a b, otherwise returns \c false.
*/
-bool QAudioFormat::operator==(const QAudioFormat &other) const
-{
- return d->sampleRate == other.d->sampleRate &&
- d->channels == other.d->channels &&
- d->sampleSize == other.d->sampleSize &&
- d->byteOrder == other.d->byteOrder &&
- d->codec == other.d->codec &&
- d->sampleType == other.d->sampleType;
-}
/*!
- Returns true if this QAudioFormat is not equal to the \a other
- QAudioFormat; otherwise returns false.
+ \fn bool QAudioFormat::isValid() const
- All elements of QAudioFormat are used for the comparison.
+ Returns \c true if all of the parameters are valid.
*/
-bool QAudioFormat::operator!=(const QAudioFormat& other) const
-{
- return !(*this == other);
-}
/*!
- Returns true if all of the parameters are valid.
+ \fn void QAudioFormat::setSampleRate(int samplerate)
+
+ Sets the sample rate to \a samplerate in Hertz.
*/
-bool QAudioFormat::isValid() const
-{
- return d->sampleRate != -1 && d->channels != -1 && d->sampleSize != -1 &&
- d->sampleType != QAudioFormat::Unknown && !d->codec.isEmpty();
-}
/*!
- Sets the sample rate to \a samplerate Hertz.
+ \fn int QAudioFormat::sampleRate() const
+ Returns the current sample rate in Hertz.
*/
-void QAudioFormat::setSampleRate(int samplerate)
-{
- d->sampleRate = samplerate;
-}
/*!
- Returns the current sample rate in Hertz.
-
+ \enum QAudioFormat::AudioChannelPosition
+
+ Describes the possible audio channel positions. These follow the standard
+ definition used in the 22.2 surround sound configuration.
+
+ \value UnknownPosition Unknown position
+ \value FrontLeft
+ \value FrontRight
+ \value FrontCenter
+ \value LFE Low Frequency Effect channel (Subwoofer)
+ \value BackLeft
+ \value BackRight
+ \value FrontLeftOfCenter
+ \value FrontRightOfCenter
+ \value BackCenter
+ \value LFE2
+ \value SideLeft
+ \value SideRight
+ \value TopFrontLeft
+ \value TopFrontRight
+ \value TopFrontCenter
+ \value TopCenter
+ \value TopBackLeft
+ \value TopBackRight
+ \value TopSideLeft
+ \value TopSideRight
+ \value TopBackCenter
+ \value BottomFrontCenter
+ \value BottomFrontLeft
+ \value BottomFrontRight
*/
-int QAudioFormat::sampleRate() const
-{
- return d->sampleRate;
-}
-
/*!
- Sets the channel count to \a channels.
-
+ \variable QAudioFormat::NChannelPositions
+ \internal
*/
-void QAudioFormat::setChannelCount(int channels)
-{
- d->channels = channels;
-}
/*!
- Returns the current channel count value.
-
+ \enum QAudioFormat::ChannelConfig
+
+ This enum describes a standardized audio channel layout. The most common
+ configurations are Mono, Stereo, 2.1 (stereo plus low frequency), 5.1 surround,
+ 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 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.
*/
-int QAudioFormat::channelCount() const
-{
- return d->channels;
-}
/*!
- Sets the sample size to the \a sampleSize specified, in bits.
+ Sets the channel configuration to \a config.
+
+ Sets the channel configuration of the audio format to one of the standard
+ audio channel configurations.
- This is typically 8 or 16, but some systems may support higher sample sizes.
+ \note that this will also modify the channel count.
*/
-void QAudioFormat::setSampleSize(int sampleSize)
+void QAudioFormat::setChannelConfig(ChannelConfig config) noexcept
{
- d->sampleSize = sampleSize;
+ m_channelConfig = config;
+ if (config != ChannelConfigUnknown)
+ m_channelCount = qPopulationCount(config);
}
/*!
- Returns the current sample size value, in bits.
-
- \sa bytesPerFrame()
+ Returns the position of a certain audio \a channel inside an audio frame
+ for the given format.
+ Returns -1 if the channel does not exist for this format or the channel
+ configuration is unknown.
*/
-int QAudioFormat::sampleSize() const
+int QAudioFormat::channelOffset(AudioChannelPosition channel) const noexcept
{
- return d->sampleSize;
+ if (!(m_channelConfig & (1u << channel)))
+ return -1;
+
+ uint maskedChannels = m_channelConfig & ((1u << channel) - 1);
+ return qPopulationCount(maskedChannels);
}
/*!
- Sets the codec to \a codec.
-
- The parameter to this function should be one of the types
- reported by the QAudioDeviceInfo::supportedCodecs() function
- for the audio device you are working with.
+ \fn void QAudioFormat::setChannelCount(int channels)
- \sa QAudioDeviceInfo::supportedCodecs()
+ Sets the channel count to \a channels. Setting this also sets the channel
+ config to ChannelConfigUnknown.
*/
-void QAudioFormat::setCodec(const QString &codec)
-{
- d->codec = codec;
-}
/*!
- Returns the current codec identifier.
+ \fn template <typename... Args> QAudioFormat::ChannelConfig QAudioFormat::channelConfig(Args... channels)
- \sa QAudioDeviceInfo::supportedCodecs()
+ Returns the current channel configuration for the given \a channels.
*/
-QString QAudioFormat::codec() const
-{
- return d->codec;
-}
-
/*!
- Sets the byteOrder to \a byteOrder.
+ \fn QAudioFormat::ChannelConfig QAudioFormat::channelConfig() const noexcept
+
+ Returns the current channel configuration.
*/
-void QAudioFormat::setByteOrder(QAudioFormat::Endian byteOrder)
-{
- d->byteOrder = byteOrder;
-}
/*!
- Returns the current byteOrder value.
+ \fn int QAudioFormat::channelCount() const
+
+ Returns the current channel count value.
+
*/
-QAudioFormat::Endian QAudioFormat::byteOrder() const
-{
- return d->byteOrder;
-}
/*!
- Sets the sampleType to \a sampleType.
+ \fn void QAudioFormat::setSampleFormat(SampleFormat format)
+
+ Sets the sample format to \a format.
+
+ \sa QAudioFormat::SampleFormat
*/
-void QAudioFormat::setSampleType(QAudioFormat::SampleType sampleType)
-{
- d->sampleType = sampleType;
-}
/*!
- Returns the current SampleType value.
+ \fn QAudioFormat::SampleFormat QAudioFormat::sampleFormat() const
+ Returns the current sample format.
+
+ \sa setSampleFormat()
*/
-QAudioFormat::SampleType QAudioFormat::sampleType() const
-{
- return d->sampleType;
-}
/*!
- Returns the number of bytes required for this audio format for \a duration microseconds.
+ Returns the number of bytes required for this audio format for \a microseconds.
Returns 0 if this format is not valid.
- Note that some rounding may occur if \a duration is not an exact fraction of the
+ Note that some rounding may occur if \a microseconds is not an exact fraction of the
sampleRate().
\sa durationForBytes()
*/
-qint32 QAudioFormat::bytesForDuration(qint64 duration) const
+qint32 QAudioFormat::bytesForDuration(qint64 microseconds) const
{
- return bytesPerFrame() * framesForDuration(duration);
+ return bytesPerFrame() * framesForDuration(microseconds);
}
/*!
@@ -371,6 +270,10 @@ qint32 QAudioFormat::bytesForDuration(qint64 duration) const
*/
qint64 QAudioFormat::durationForBytes(qint32 bytes) const
{
+ // avoid compiler warnings about unused variables. [[maybe_unused]] in the header
+ // gives compiler errors on older gcc versions
+ Q_UNUSED(reserved);
+
if (!isValid() || bytes <= 0)
return 0;
@@ -409,17 +312,17 @@ qint32 QAudioFormat::framesForBytes(qint32 byteCount) const
}
/*!
- Returns the number of frames required to represent \a duration microseconds in this format.
+ Returns the number of frames required to represent \a microseconds in this format.
- Note that some rounding may occur if \a duration is not an exact fraction of the
+ Note that some rounding may occur if \a microseconds is not an exact fraction of the
\l sampleRate().
*/
-qint32 QAudioFormat::framesForDuration(qint64 duration) const
+qint32 QAudioFormat::framesForDuration(qint64 microseconds) const
{
if (!isValid())
return 0;
- return qint32((duration * sampleRate()) / 1000000LL);
+ return qint32((microseconds * sampleRate()) / 1000000LL);
}
/*!
@@ -434,85 +337,142 @@ qint64 QAudioFormat::durationForFrames(qint32 frameCount) const
}
/*!
- Returns the number of bytes required to represent one frame (a sample in each channel) in this format.
+ \fn int QAudioFormat::bytesPerFrame() const
+
+ Returns the number of bytes required to represent one frame
+ (a sample in each channel) in this format.
Returns 0 if this format is invalid.
*/
-int QAudioFormat::bytesPerFrame() const
-{
- if (!isValid())
- return 0;
-
- return (sampleSize() * channelCount()) / 8;
-}
/*!
- \enum QAudioFormat::SampleType
+ \fn int QAudioFormat::bytesPerSample() const
+ Returns the number of bytes required to represent one sample in this format.
- \value Unknown Not Set
- \value SignedInt Samples are signed integers
- \value UnSignedInt Samples are unsigned intergers
- \value Float Samples are floats
+ Returns 0 if this format is invalid.
*/
/*!
- \enum QAudioFormat::Endian
-
- \value BigEndian Samples are big endian byte order
- \value LittleEndian Samples are little endian byte order
+ Normalizes the \a sample value to a number between -1 and 1.
+ The method depends on the QaudioFormat.
*/
+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.;
+ case Int16:
+ 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();
+ case Float:
+ return *reinterpret_cast<const float *>(sample);
+ case Unknown:
+ case NSampleFormats:
+ break;
+ }
-#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug dbg, QAudioFormat::Endian endian)
+ return 0.;
+}
+
+/*!
+ 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)
{
- QDebugStateSaver saver(dbg);
- dbg.nospace();
- switch (endian) {
- case QAudioFormat::BigEndian:
- dbg << "BigEndian";
- break;
- case QAudioFormat::LittleEndian:
- dbg << "LittleEndian";
- break;
+ 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 dbg;
+ return config;
}
-QDebug operator<<(QDebug dbg, QAudioFormat::SampleType type)
+/*!
+ \enum QAudioFormat::SampleFormat
+
+ Qt will always expect and use samples in the endianness of the host platform.
+ When processing audio data from external sources yourself, ensure you convert
+ them to the correct endianness before writing them to a QAudioSink or
+ QAudioBuffer.
+
+ \value Unknown Not Set
+ \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
+ \omitvalue NSampleFormats
+*/
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, QAudioFormat::SampleFormat type)
{
QDebugStateSaver saver(dbg);
dbg.nospace();
switch (type) {
- case QAudioFormat::SignedInt:
- dbg << "SignedInt";
- break;
- case QAudioFormat::UnSignedInt:
- dbg << "UnSignedInt";
- break;
- case QAudioFormat::Float:
- dbg << "Float";
- break;
- default:
- dbg << "Unknown";
- break;
+ case QAudioFormat::UInt8:
+ dbg << "UInt8";
+ break;
+ case QAudioFormat::Int16:
+ dbg << "Int16";
+ break;
+ case QAudioFormat::Int32:
+ dbg << "Int32";
+ break;
+ case QAudioFormat::Float:
+ dbg << "Float";
+ break;
+ default:
+ dbg << "Unknown";
+ break;
}
return dbg;
}
QDebug operator<<(QDebug dbg, const QAudioFormat &f)
{
- QDebugStateSaver saver(dbg);
- dbg.nospace();
- dbg << "QAudioFormat(" << f.sampleRate() << "Hz, "
- << f.sampleSize() << "bit, channelCount=" << f.channelCount()
- << ", sampleType=" << f.sampleType() << ", byteOrder=" << f.byteOrder()
- << ", codec=" << f.codec() << ')';
-
+ 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 97779ea2c..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
@@ -45,72 +9,152 @@
#include <QtCore/qshareddata.h>
#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qmultimedia.h>
QT_BEGIN_NAMESPACE
class QAudioFormatPrivate;
-class Q_MULTIMEDIA_EXPORT QAudioFormat
+namespace QtPrivate {
+template <typename... Args>
+constexpr int channelConfig(Args... values) {
+ return (0 | ... | (1u << values));
+}
+}
+
+class QAudioFormat
{
public:
- enum SampleType { Unknown, SignedInt, UnSignedInt, Float };
- enum Endian { BigEndian = QSysInfo::BigEndian, LittleEndian = QSysInfo::LittleEndian };
-
- QAudioFormat();
- QAudioFormat(const QAudioFormat &other);
- ~QAudioFormat();
-
- QAudioFormat& operator=(const QAudioFormat &other);
- bool operator==(const QAudioFormat &other) const;
- bool operator!=(const QAudioFormat &other) const;
-
- bool isValid() const;
-
- void setSampleRate(int sampleRate);
- int sampleRate() const;
-
- void setChannelCount(int channelCount);
- int channelCount() const;
-
- void setSampleSize(int sampleSize);
- int sampleSize() const;
-
- void setCodec(const QString &codec);
- QString codec() const;
-
- void setByteOrder(QAudioFormat::Endian byteOrder);
- QAudioFormat::Endian byteOrder() const;
-
- void setSampleType(QAudioFormat::SampleType sampleType);
- QAudioFormat::SampleType sampleType() const;
+ enum SampleFormat : quint16 {
+ Unknown,
+ UInt8,
+ Int16,
+ Int32,
+ Float,
+ NSampleFormats
+ };
+
+ // This matches the speaker positions of a 22.2 audio layout. Stereo, Surround 5.1 and Surround 7.1 are subsets of these
+ enum AudioChannelPosition {
+ UnknownPosition,
+ FrontLeft,
+ FrontRight,
+ FrontCenter,
+ LFE,
+ BackLeft,
+ BackRight,
+ FrontLeftOfCenter,
+ FrontRightOfCenter,
+ BackCenter,
+ SideLeft,
+ SideRight,
+ TopCenter,
+ TopFrontLeft,
+ TopFrontCenter,
+ TopFrontRight,
+ TopBackLeft,
+ TopBackCenter,
+ TopBackRight,
+ LFE2,
+ TopSideLeft,
+ TopSideRight,
+ 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),
+ ChannelConfigSurround7Dot1 = QtPrivate::channelConfig(FrontLeft, FrontRight, FrontCenter, LFE, BackLeft, BackRight, SideLeft, SideRight),
+ };
+
+ template <typename... Args>
+ static constexpr ChannelConfig channelConfig(Args... channels)
+ {
+ return ChannelConfig(QtPrivate::channelConfig(channels...));
+ }
+
+ constexpr bool isValid() const noexcept
+ {
+ return m_sampleRate > 0 && m_channelCount > 0 && m_sampleFormat != Unknown;
+ }
+
+ constexpr void setSampleRate(int sampleRate) noexcept { m_sampleRate = sampleRate; }
+ constexpr int sampleRate() const noexcept { return m_sampleRate; }
+
+ Q_MULTIMEDIA_EXPORT void setChannelConfig(ChannelConfig config) noexcept;
+ constexpr ChannelConfig channelConfig() const noexcept { return m_channelConfig; }
+
+ constexpr void setChannelCount(int channelCount) noexcept { m_channelConfig = ChannelConfigUnknown; m_channelCount = channelCount; }
+ constexpr int channelCount() const noexcept { return m_channelCount; }
+
+ Q_MULTIMEDIA_EXPORT int channelOffset(AudioChannelPosition channel) const noexcept;
+
+ constexpr void setSampleFormat(SampleFormat f) noexcept { m_sampleFormat = f; }
+ constexpr SampleFormat sampleFormat() const noexcept { return m_sampleFormat; }
// Helper functions
- qint32 bytesForDuration(qint64 duration) const;
- qint64 durationForBytes(qint32 byteCount) const;
-
- qint32 bytesForFrames(qint32 frameCount) const;
- qint32 framesForBytes(qint32 byteCount) const;
-
- qint32 framesForDuration(qint64 duration) const;
- qint64 durationForFrames(qint32 frameCount) const;
-
- int bytesPerFrame() const;
+ Q_MULTIMEDIA_EXPORT qint32 bytesForDuration(qint64 microseconds) const;
+ Q_MULTIMEDIA_EXPORT qint64 durationForBytes(qint32 byteCount) const;
+
+ Q_MULTIMEDIA_EXPORT qint32 bytesForFrames(qint32 frameCount) const;
+ Q_MULTIMEDIA_EXPORT qint32 framesForBytes(qint32 byteCount) const;
+
+ Q_MULTIMEDIA_EXPORT qint32 framesForDuration(qint64 microseconds) const;
+ Q_MULTIMEDIA_EXPORT qint64 durationForFrames(qint32 frameCount) const;
+
+ constexpr int bytesPerFrame() const { return bytesPerSample()*channelCount(); }
+ constexpr int bytesPerSample() const noexcept
+ {
+ switch (m_sampleFormat) {
+ case Unknown:
+ case NSampleFormats: return 0;
+ case UInt8: return 1;
+ case Int16: return 2;
+ case Int32:
+ case Float: return 4;
+ }
+ return 0;
+ }
+
+ Q_MULTIMEDIA_EXPORT float normalizedSampleValue(const void *sample) const;
+
+ friend bool operator==(const QAudioFormat &a, const QAudioFormat &b)
+ {
+ return a.m_sampleRate == b.m_sampleRate &&
+ a.m_channelCount == b.m_channelCount &&
+ a.m_sampleFormat == b.m_sampleFormat;
+ }
+ friend bool operator!=(const QAudioFormat &a, const QAudioFormat &b)
+ {
+ return !(a == b);
+ }
+
+ static Q_MULTIMEDIA_EXPORT ChannelConfig defaultChannelConfigForChannelCount(int channelCount);
private:
- QSharedDataPointer<QAudioFormatPrivate> d;
+ SampleFormat m_sampleFormat = SampleFormat::Unknown;
+ short m_channelCount = 0;
+ ChannelConfig m_channelConfig = ChannelConfigUnknown;
+ int m_sampleRate = 0;
+ quint64 reserved = 0;
};
#ifndef QT_NO_DEBUG_STREAM
Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, const QAudioFormat &);
-Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, QAudioFormat::SampleType);
-Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, QAudioFormat::Endian);
+Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, QAudioFormat::SampleFormat);
#endif
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QAudioFormat)
-Q_DECLARE_METATYPE(QAudioFormat::SampleType)
-Q_DECLARE_METATYPE(QAudioFormat::Endian)
#endif // QAUDIOFORMAT_H
diff --git a/src/multimedia/audio/qaudiohelpers.cpp b/src/multimedia/audio/qaudiohelpers.cpp
index fae591477..c2d8681c6 100644
--- a/src/multimedia/audio/qaudiohelpers.cpp
+++ b/src/multimedia/audio/qaudiohelpers.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 "qaudiohelpers_p.h"
@@ -43,49 +7,6 @@
QT_BEGIN_NAMESPACE
-// Base implementation of 24 bits number.
-// Used to adjust 3 bytes values by a factor.
-// TODO: Uses little-endian only.
-class Int24
-{
-public:
- quint8 data[3];
- Int24(qint32 v) {
- data[0] = v & 0xFF;
- data[1] = (v & 0xFF00) >> 8;
- data[2] = (v & 0xFF0000) >> 16;
- }
- template<class T>
- T multiply(qreal factor, T v = 0) const {
- v |= data[0];
- v |= data[1] << 8;
- v |= data[2] << 16;
- v *= factor;
- return v;
- }
-};
-
-class qint24: public Int24
-{
-public:
- qint24(qint32 v): Int24(v) {}
- qint24 operator*(qreal factor) const {
- // Checks if it is a signed value.
- qint32 v = (data[2] & 0x80) ? 0xFF000000 : 0;
- return multiply(factor, v);
- }
-};
-
-class quint24: public Int24
-{
-public:
- quint24(quint32 v): Int24(v) {}
- quint24 operator*(qreal factor) const {
- return multiply<quint32>(factor);
- }
-};
-
-
namespace QAudioHelperInternal
{
@@ -102,20 +23,8 @@ template<class T> void adjustSamples(qreal factor, const void *src, void *dst, i
template<class T> struct signedVersion {};
template<> struct signedVersion<quint8>
{
- typedef qint8 TS;
- enum {offset = 0x80};
-};
-
-template<> struct signedVersion<quint16>
-{
- typedef qint16 TS;
- enum {offset = 0x8000};
-};
-
-template<> struct signedVersion<quint32>
-{
- typedef qint32 TS;
- enum {offset = 0x80000000};
+ using TS = qint8;
+ static constexpr int offset = 0x80;
};
template<class T> void adjustUnsignedSamples(qreal factor, const void *src, void *dst, int samples)
@@ -129,34 +38,24 @@ template<class T> void adjustUnsignedSamples(qreal factor, const void *src, void
void qMultiplySamples(qreal factor, const QAudioFormat &format, const void* src, void* dest, int len)
{
- int samplesCount = len / (format.sampleSize()/8);
+ const int samplesCount = len / qMax(1, format.bytesPerSample());
- switch ( format.sampleSize() ) {
- case 8:
- if (format.sampleType() == QAudioFormat::SignedInt)
- QAudioHelperInternal::adjustSamples<qint8>(factor,src,dest,samplesCount);
- else if (format.sampleType() == QAudioFormat::UnSignedInt)
- QAudioHelperInternal::adjustUnsignedSamples<quint8>(factor,src,dest,samplesCount);
+ switch (format.sampleFormat()) {
+ case QAudioFormat::Unknown:
+ case QAudioFormat::NSampleFormats:
+ return;
+ case QAudioFormat::UInt8:
+ QAudioHelperInternal::adjustUnsignedSamples<quint8>(factor,src,dest,samplesCount);
+ break;
+ case QAudioFormat::Int16:
+ QAudioHelperInternal::adjustSamples<qint16>(factor,src,dest,samplesCount);
break;
- case 16:
- if (format.sampleType() == QAudioFormat::SignedInt)
- QAudioHelperInternal::adjustSamples<qint16>(factor,src,dest,samplesCount);
- else if (format.sampleType() == QAudioFormat::UnSignedInt)
- QAudioHelperInternal::adjustUnsignedSamples<quint16>(factor,src,dest,samplesCount);
+ case QAudioFormat::Int32:
+ QAudioHelperInternal::adjustSamples<qint32>(factor,src,dest,samplesCount);
break;
- case 24:
- if (format.sampleType() == QAudioFormat::SignedInt)
- QAudioHelperInternal::adjustSamples<qint24>(factor,src,dest,samplesCount);
- else if (format.sampleType() == QAudioFormat::UnSignedInt)
- QAudioHelperInternal::adjustSamples<quint24>(factor,src,dest,samplesCount);
+ case QAudioFormat::Float:
+ QAudioHelperInternal::adjustSamples<float>(factor,src,dest,samplesCount);
break;
- default:
- if (format.sampleType() == QAudioFormat::SignedInt)
- QAudioHelperInternal::adjustSamples<qint32>(factor,src,dest,samplesCount);
- else if (format.sampleType() == QAudioFormat::UnSignedInt)
- QAudioHelperInternal::adjustUnsignedSamples<quint32>(factor,src,dest,samplesCount);
- else if (format.sampleType() == QAudioFormat::Float)
- QAudioHelperInternal::adjustSamples<float>(factor,src,dest,samplesCount);
}
}
}
diff --git a/src/multimedia/audio/qaudiohelpers_p.h b/src/multimedia/audio/qaudiohelpers_p.h
index c59e01cad..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,6 +16,7 @@
//
#include <qaudioformat.h>
+#include <private/qglobal_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/multimedia/audio/qaudioinput.cpp b/src/multimedia/audio/qaudioinput.cpp
index 872dce819..dc7d7335f 100644
--- a/src/multimedia/audio/qaudioinput.cpp
+++ b/src/multimedia/audio/qaudioinput.cpp
@@ -1,413 +1,192 @@
-/****************************************************************************
-**
-** 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 "qaudio.h"
-#include "qaudiodeviceinfo.h"
-#include "qaudiosystem.h"
-#include "qaudioinput.h"
-
-#include "qaudiodevicefactory_p.h"
-
-QT_BEGIN_NAMESPACE
+// 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
-/*!
- \class QAudioInput
- \brief The QAudioInput class provides an interface for receiving audio data from an audio input device.
-
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_audio
-
- You can construct an audio input with the system's
- \l{QAudioDeviceInfo::defaultInputDevice()}{default audio input
- device}. It is also possible to create QAudioInput with a
- specific QAudioDeviceInfo. When you create the audio input, you
- should also send in the QAudioFormat to be used for the recording
- (see the QAudioFormat class description for details).
-
- To record to a file:
-
- QAudioInput lets you record audio with an audio input device. The
- default constructor of this class will use the systems default
- audio device, but you can also specify a QAudioDeviceInfo for a
- specific device. You also need to pass in the QAudioFormat in
- which you wish to record.
-
- Starting up the QAudioInput is simply a matter of calling start()
- with a QIODevice opened for writing. For instance, to record to a
- file, you can:
-
- \snippet multimedia-snippets/audio.cpp Audio input class members
-
- \snippet multimedia-snippets/audio.cpp Audio input setup
-
- This will start recording if the format specified is supported by
- the input device (you can check this with
- QAudioDeviceInfo::isFormatSupported(). In case there are any
- snags, use the error() function to check what went wrong. We stop
- recording in the \c stopRecording() slot.
-
- \snippet multimedia-snippets/audio.cpp Audio input stop recording
-
- At any point in time, QAudioInput 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
- suspend(), resume(), stop(), reset(), and start(). The current
- state is reported by state(). QAudioOutput will also signal you
- when the state changes (stateChanged()).
+#include <qaudioinput.h>
+#include <qaudiodevice.h>
+#include <qmediadevices.h>
+#include <private/qplatformaudioinput_p.h>
+#include <private/qplatformmediaintegration_p.h>
- QAudioInput provides several ways of measuring the time that has
- passed since the start() of the recording. The \c processedUSecs()
- function returns the length of the stream in microseconds written,
- i.e., it leaves out the times the audio input was suspended or idle.
- The elapsedUSecs() function returns the time elapsed since start() was called regardless of
- which states the QAudioInput 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 QAudioInput will enter the \l{QAudio::}{StoppedState} when
- an error is encountered. Connect to the stateChanged() signal to
- handle the error:
-
- \snippet multimedia-snippets/audio.cpp Audio input state changed
-
- \sa QAudioOutput, QAudioDeviceInfo
-*/
+#include <utility>
/*!
- Construct a new audio input and attach it to \a parent.
- The default audio input device is used with the output
- \a format parameters.
-*/
+ \qmltype AudioInput
+ \instantiates QAudioInput
+ \brief An audio input to be used for capturing audio in a capture session.
-QAudioInput::QAudioInput(const QAudioFormat &format, QObject *parent):
- QObject(parent)
-{
- d = QAudioDeviceFactory::createDefaultInputDevice(format);
- connect(d, SIGNAL(notify()), SIGNAL(notify()));
- connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State)));
-}
+ \inqmlmodule QtMultimedia
+ \ingroup multimedia_qml
+ \ingroup multimedia_audio_qml
-/*!
- Construct a new audio input and attach it to \a parent.
- The device referenced by \a audioDevice is used with the input
- \a format parameters.
-*/
+ \qml
+ CaptureSession {
+ id: playMusic
+ audioInput: AudioInput {
+ volume: slider.value
+ }
+ recorder: MediaRecorder { ... }
+ }
+ Slider {
+ id: slider
+ from: 0.
+ to: 1.
+ }
+ \endqml
-QAudioInput::QAudioInput(const QAudioDeviceInfo &audioDevice, const QAudioFormat &format, QObject *parent):
- QObject(parent)
-{
- d = QAudioDeviceFactory::createInputDevice(audioDevice, format);
- connect(d, SIGNAL(notify()), SIGNAL(notify()));
- connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State)));
-}
+ You can use AudioInput together with a QtMultiMedia::CaptureSession to capture audio from an
+ audio input device.
-/*!
- Destroy this audio input.
+ \sa Camera, AudioOutput
*/
-QAudioInput::~QAudioInput()
-{
- delete d;
-}
-
/*!
- Starts transferring audio data from the system's audio input to the \a device.
- The \a device must have been opened in the \l{QIODevice::WriteOnly}{WriteOnly},
- \l{QIODevice::Append}{Append} or \l{QIODevice::ReadWrite}{ReadWrite} modes.
-
- If the QAudioInput is able to successfully get audio data, state() returns
- either QAudio::ActiveState or QAudio::IdleState, error() returns QAudio::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.
-
- \sa QIODevice
-*/
-
-void QAudioInput::start(QIODevice* device)
-{
- d->start(device);
-}
-
-/*!
- Returns a pointer to the internal QIODevice being used to transfer data from
- the system's audio input. The device will already be open and
- \l{QIODevice::read()}{read()} can read data directly from it.
-
- \note The pointer will become invalid after the stream is stopped or
- if you start another stream.
-
- If the QAudioInput is able to access the system's audio device, state() returns
- QAudio::IdleState, error() returns QAudio::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.
+ \class QAudioInput
+ \brief Represents an input channel for audio.
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \ingroup multimedia_audio
- \sa QIODevice
+ This class represents an input channel that can be used together with
+ QMediaCaptureSession. It enables the selection of the physical input device
+ to be used, muting the channel, and changing the channel's volume.
*/
-QIODevice* QAudioInput::start()
+QAudioInput::QAudioInput(QObject *parent) : QAudioInput(QMediaDevices::defaultAudioInput(), parent)
{
- return d->start();
}
-/*!
- Returns the QAudioFormat being used.
-*/
-
-QAudioFormat QAudioInput::format() const
+QAudioInput::QAudioInput(const QAudioDevice &device, QObject *parent)
+ : QObject(parent)
{
- return d->format();
+ 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();
+ }
}
-/*!
- Stops the audio input, detaching from the system resource.
-
- Sets error() to QAudio::NoError, state() to QAudio::StoppedState and
- emit stateChanged() signal.
-*/
-
-void QAudioInput::stop()
+QAudioInput::~QAudioInput()
{
- d->stop();
+ setDisconnectFunction({});
+ delete d;
}
/*!
- Drops all audio data in the buffers, resets buffers to zero.
-*/
+ \qmlproperty real QtMultimedia::AudioInput::volume
-void QAudioInput::reset()
-{
- d->reset();
-}
+ The volume is scaled linearly, ranging from \c 0 (silence) to \c 1 (full volume).
+ \note values outside this range will be clamped.
-/*!
- Stops processing audio data, preserving buffered audio data.
+ By default the volume is \c 1.
- Sets error() to QAudio::NoError, state() to QAudio::SuspendedState and
- emit stateChanged() signal.
+ 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 QtAudio::convertVolume()
*/
-
-void QAudioInput::suspend()
-{
- d->suspend();
-}
-
/*!
- Resumes processing audio data after a suspend().
+ \property QAudioInput::volume
- 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.
+ The property returns the volume of the audio input.
*/
-
-void QAudioInput::resume()
+float QAudioInput::volume() const
{
- d->resume();
+ return d->volume;
}
-/*!
- Sets the audio buffer size to \a value bytes.
-
- Note: This function can be called anytime before start(), calls to this
- are ignored after start(). It should not be assumed that the buffer size
- set is the actual buffer size used, calling bufferSize() anytime after start()
- will return the actual buffer size being used.
-
-*/
-
-void QAudioInput::setBufferSize(int value)
+void QAudioInput::setVolume(float volume)
{
- d->setBufferSize(value);
+ volume = qBound(0., volume, 1.);
+ if (d->volume == volume)
+ return;
+ d->volume = volume;
+ d->setVolume(volume);
+ emit volumeChanged(volume);
}
/*!
- Returns the audio buffer size in bytes.
+ \qmlproperty bool QtMultimedia::AudioInput::muted
- If called before start(), returns platform default value.
- If called before start() but setBufferSize() was called prior, returns value set by setBufferSize().
- If called after start(), returns the actual buffer size being used. This may not be what was set previously
- by setBufferSize().
+ This property holds whether the audio input is muted.
+ Defaults to \c{false}.
*/
-int QAudioInput::bufferSize() const
-{
- return d->bufferSize();
-}
-
/*!
- Returns the amount of audio data available to read in bytes.
+ \property QAudioInput::muted
+ \brief The muted state of the current media.
- Note: returned value is only valid while in QAudio::ActiveState or QAudio::IdleState
- state, otherwise returns zero.
+ The value will be \c true if the input is muted; otherwise \c false.
*/
-
-int QAudioInput::bytesReady() const
+bool QAudioInput::isMuted() const
{
- /*
- -If not ActiveState|IdleState, return 0
- -return amount of audio data available to read
- */
- return d->bytesReady();
+ return d->muted;
}
-/*!
- Returns the period size in bytes.
-
- Note: This is the recommended read size in bytes.
-*/
-
-int QAudioInput::periodSize() const
+void QAudioInput::setMuted(bool muted)
{
- return d->periodSize();
+ if (d->muted == muted)
+ return;
+ d->muted = muted;
+ d->setMuted(muted);
+ emit mutedChanged(muted);
}
/*!
- Sets the interval for notify() signal to be emitted.
- This is based on the \a ms of audio data processed
- not on actual real-time.
- The minimum resolution of the timer is platform specific and values
- should be checked with notifyInterval() to confirm actual value
- being used.
-*/
+ \qmlproperty AudioDevice QtMultimedia::AudioInput::device
-void QAudioInput::setNotifyInterval(int ms)
-{
- d->setNotifyInterval(ms);
-}
+ This property describes the audio device connected to this input.
-/*!
- Returns the notify interval in milliseconds.
+ 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.
*/
-int QAudioInput::notifyInterval() const
-{
- return d->notifyInterval();
-}
-
/*!
- Sets the input volume to \a volume.
+ \property QAudioInput::device
+ \brief The audio device connected to this input.
- The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this
- range will be clamped.
+ 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.
- If the device does not support adjusting the input
- volume then \a volume will be ignored and the input
- volume will remain at 1.0.
-
- The default volume is \c 1.0.
-
- Note: Adjustments to the volume will change the volume of this audio stream, not the global volume.
+ You can select the system default audio input by setting this property to
+ a default constructed QAudioDevice object.
*/
-void QAudioInput::setVolume(qreal volume)
+QAudioDevice QAudioInput::device() const
{
- qreal v = qBound(qreal(0.0), volume, qreal(1.0));
- d->setVolume(v);
+ return d->device;
}
-/*!
- Returns the input volume.
-
- If the device does not support adjusting the input volume
- the returned value will be 1.0.
-*/
-qreal QAudioInput::volume() const
-{
- return d->volume();
-}
-
-/*!
- Returns the amount of audio data processed since start()
- was called in microseconds.
-*/
-
-qint64 QAudioInput::processedUSecs() const
+void QAudioInput::setDevice(const QAudioDevice &device)
{
- return d->processedUSecs();
+ 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();
}
/*!
- Returns the microseconds since start() was called, including time in Idle and
- Suspend states.
+ \internal
*/
-
-qint64 QAudioInput::elapsedUSecs() const
-{
- return d->elapsedUSecs();
-}
-
-/*!
- Returns the error state.
-*/
-
-QAudio::Error QAudioInput::error() const
+void QAudioInput::setDisconnectFunction(std::function<void()> disconnectFunction)
{
- return d->error();
+ if (d->disconnectFunction) {
+ auto df = d->disconnectFunction;
+ d->disconnectFunction = {};
+ df();
+ }
+ d->disconnectFunction = std::move(disconnectFunction);
}
-/*!
- Returns the state of audio processing.
-*/
-
-QAudio::State QAudioInput::state() const
-{
- return d->state();
-}
-
-/*!
- \fn QAudioInput::stateChanged(QAudio::State state)
- This signal is emitted when the device \a state has changed.
-*/
-
-/*!
- \fn QAudioInput::notify()
- This signal is emitted when x ms of audio data has been processed
- the interval set by setNotifyInterval(x).
-*/
-
-QT_END_NAMESPACE
-
#include "moc_qaudioinput.cpp"
-
diff --git a/src/multimedia/audio/qaudioinput.h b/src/multimedia/audio/qaudioinput.h
index b17fd4d79..6f4f6b099 100644
--- a/src/multimedia/audio/qaudioinput.h
+++ b/src/multimedia/audio/qaudioinput.h
@@ -1,109 +1,54 @@
-/****************************************************************************
-**
-** 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 QAUDIOINPUTDEVICE_H
+#define QAUDIOINPUTDEVICE_H
-#ifndef QAUDIOINPUT_H
-#define QAUDIOINPUT_H
-
-#include <QtCore/qiodevice.h>
-
+#include <QtCore/qobject.h>
#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qmultimedia.h>
-
-#include <QtMultimedia/qaudio.h>
-#include <QtMultimedia/qaudioformat.h>
-#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qtaudio.h>
+#include <functional>
QT_BEGIN_NAMESPACE
-
-
-class QAbstractAudioInput;
+class QAudioDevice;
+class QPlatformAudioInput;
class Q_MULTIMEDIA_EXPORT QAudioInput : public QObject
{
Q_OBJECT
+ Q_PROPERTY(QAudioDevice device READ device WRITE setDevice NOTIFY deviceChanged)
+ Q_PROPERTY(float volume READ volume WRITE setVolume NOTIFY volumeChanged)
+ Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
public:
- explicit QAudioInput(const QAudioFormat &format = QAudioFormat(), QObject *parent = nullptr);
- explicit QAudioInput(const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format = QAudioFormat(), QObject *parent = nullptr);
+ explicit QAudioInput(QObject *parent = nullptr);
+ explicit QAudioInput(const QAudioDevice &deviceInfo, QObject *parent = nullptr);
~QAudioInput();
- QAudioFormat format() const;
-
- void start(QIODevice *device);
- QIODevice* start();
-
- void stop();
- void reset();
- void suspend();
- void resume();
+ QAudioDevice device() const;
+ float volume() const;
+ bool isMuted() const;
- void setBufferSize(int bytes);
- int bufferSize() const;
-
- int bytesReady() const;
- int periodSize() const;
-
- void setNotifyInterval(int milliSeconds);
- int notifyInterval() const;
-
- void setVolume(qreal volume);
- qreal volume() const;
-
- qint64 processedUSecs() const;
- qint64 elapsedUSecs() const;
-
- QAudio::Error error() const;
- QAudio::State state() const;
+public Q_SLOTS:
+ void setDevice(const QAudioDevice &device);
+ void setVolume(float volume);
+ void setMuted(bool muted);
Q_SIGNALS:
- void stateChanged(QAudio::State state);
- void notify();
+ void deviceChanged();
+ void volumeChanged(float volume);
+ void mutedChanged(bool muted);
private:
+ QPlatformAudioInput *handle() const { return d; }
+ void setDisconnectFunction(std::function<void()> disconnectFunction);
+ friend class QMediaCaptureSession;
Q_DISABLE_COPY(QAudioInput)
-
- QAbstractAudioInput* d;
+ QPlatformAudioInput *d = nullptr;
};
QT_END_NAMESPACE
-#endif // QAUDIOINPUT_H
+#endif // QAUDIOINPUTDEVICE_H
diff --git a/src/multimedia/audio/qaudiooutput.cpp b/src/multimedia/audio/qaudiooutput.cpp
index e37da9bdf..3bb52a4d2 100644
--- a/src/multimedia/audio/qaudiooutput.cpp
+++ b/src/multimedia/audio/qaudiooutput.cpp
@@ -1,429 +1,209 @@
-/****************************************************************************
-**
-** 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 "qaudio.h"
-#include "qaudiodeviceinfo.h"
-#include "qaudiosystem.h"
-#include "qaudiooutput.h"
-
-#include "qaudiodevicefactory_p.h"
-
-
-QT_BEGIN_NAMESPACE
+// 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
-/*!
- \class QAudioOutput
- \brief The QAudioOutput class provides an interface for sending audio data to an audio output device.
-
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_audio
-
- You can construct an audio output with the system's
- \l{QAudioDeviceInfo::defaultOutputDevice()}{default audio output
- device}. It is also possible to create QAudioOutput with a
- specific QAudioDeviceInfo. When you create the audio output, you
- should also send in the QAudioFormat to be used for the playback
- (see the QAudioFormat class description for details).
-
- To play a file:
-
- Starting to play an audio stream is simply a matter of calling
- start() with a QIODevice. QAudioOutput will then fetch the data it
- needs from the io device. So playing back an audio file is as
- simple as:
-
- \snippet multimedia-snippets/audio.cpp Audio output class members
-
- \snippet multimedia-snippets/audio.cpp Audio output setup
-
- The file will start playing assuming that the audio system and
- output device support it. If you run out of luck, check what's
- up with the error() function.
-
- After the file has finished playing, we need to stop the device:
-
- \snippet multimedia-snippets/audio.cpp Audio output state changed
-
- At any given time, the QAudioOutput will be in one of four states:
- active, suspended, stopped, or idle. These states are described
- by the QAudio::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().
-
- While the stream is playing, you can set a notify interval in
- milliseconds with setNotifyInterval(). This interval specifies the
- time between two emissions of the notify() signal. This is
- relative to the position in the stream, i.e., if the QAudioOutput
- is in the SuspendedState or the IdleState, the notify() signal is
- not emitted. A typical use-case would be to update a
- \l{QSlider}{slider} that allows seeking in the stream.
- If you want the time since playback started regardless of which
- states the audio output has been in, elapsedUSecs() is the function for you.
-
- 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.
- You can check for errors by connecting to the stateChanged()
- signal:
-
- \snippet multimedia-snippets/audio.cpp Audio output state changed
-
- \sa QAudioInput, QAudioDeviceInfo
-*/
+#include <qaudiooutput.h>
+#include <qaudiodevice.h>
+#include <qmediadevices.h>
+#include <private/qplatformaudiooutput_p.h>
+#include <private/qplatformmediaintegration_p.h>
/*!
- Construct a new audio output and attach it to \a parent.
- The default audio output device is used with the output
- \a format parameters.
-*/
-QAudioOutput::QAudioOutput(const QAudioFormat &format, QObject *parent):
- QObject(parent)
-{
- d = QAudioDeviceFactory::createDefaultOutputDevice(format);
- connect(d, SIGNAL(notify()), SIGNAL(notify()));
- connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State)));
-}
+ \qmltype AudioOutput
+ \instantiates QAudioOutput
+ \brief An audio output to be used for playback or monitoring of a capture session.
-/*!
- Construct a new audio output and attach it to \a parent.
- The device referenced by \a audioDevice is used with the output
- \a format parameters.
-*/
-QAudioOutput::QAudioOutput(const QAudioDeviceInfo &audioDevice, const QAudioFormat &format, QObject *parent):
- QObject(parent)
-{
- d = QAudioDeviceFactory::createOutputDevice(audioDevice, format);
- connect(d, SIGNAL(notify()), SIGNAL(notify()));
- connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State)));
-}
-
-/*!
- Destroys this audio output.
+ \inqmlmodule QtMultimedia
+ \ingroup multimedia_qml
+ \ingroup multimedia_audio_qml
- This will release any system resources used and free any buffers.
-*/
-QAudioOutput::~QAudioOutput()
-{
- delete d;
-}
+ \qml
+ MediaPlayer {
+ id: playMusic
+ source: "music.wav"
+ audioOutput: AudioOutput {
+ volume: slider.value
+ }
+ }
+ Slider {
+ id: slider
+ from: 0.
+ to: 1.
+ }
+ \endqml
-/*!
- Returns the QAudioFormat being used.
+ 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
*/
-QAudioFormat QAudioOutput::format() const
-{
- return d->format();
-}
/*!
- Starts transferring audio data from the \a device to the system's audio output.
- The \a device must have been opened in the \l{QIODevice::ReadOnly}{ReadOnly} or
- \l{QIODevice::ReadWrite}{ReadWrite} modes.
-
- If the QAudioOutput is able to successfully output audio data, state() returns
- QAudio::ActiveState, error() returns QAudio::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.
+ \class QAudioOutput
+ \brief Represents an output channel for audio.
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \ingroup multimedia_audio
+ \since 6.0
- \sa QIODevice
+ This class represents an output channel that can be used together with
+ QMediaPlayer or QMediaCaptureSession. It enables the selection of the
+ physical output device to be used, muting the channel, and changing the
+ channel's volume.
*/
-void QAudioOutput::start(QIODevice* device)
+QAudioOutput::QAudioOutput(QObject *parent)
+ : QAudioOutput(QMediaDevices::defaultAudioOutput(), parent)
{
- d->start(device);
}
-/*!
- Returns a pointer to the internal QIODevice being used to transfer data to
- the system's audio output. The device will already be open and
- \l{QIODevice::write()}{write()} can write data directly to it.
-
- \note The pointer will become invalid after the stream is stopped or
- if you start another stream.
-
- If the QAudioOutput is able to access the system's audio device, state() returns
- QAudio::IdleState, error() returns QAudio::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.
-
- \sa QIODevice
-*/
-QIODevice* QAudioOutput::start()
+QAudioOutput::QAudioOutput(const QAudioDevice &device, QObject *parent)
+ : QObject(parent)
{
- return d->start();
+ 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();
+ }
}
-/*!
- Stops the audio output, detaching from the system resource.
-
- Sets error() to QAudio::NoError, state() to QAudio::StoppedState and
- emit stateChanged() signal.
-*/
-void QAudioOutput::stop()
+QAudioOutput::~QAudioOutput()
{
- d->stop();
+ setDisconnectFunction({});
+ delete d;
}
/*!
- Drops all audio data in the buffers, resets buffers to zero.
+ \qmlproperty real QtMultimedia::AudioOutput::volume
-*/
-void QAudioOutput::reset()
-{
- d->reset();
-}
+ This property holds the volume of the audio output.
-/*!
- Stops processing audio data, preserving buffered audio data.
+ 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.
- Sets error() to QAudio::NoError, state() to QAudio::SuspendedState and
- emits stateChanged() signal.
-*/
-void QAudioOutput::suspend()
-{
- d->suspend();
-}
+ The default volume is \c{1.0}.
-/*!
- Resumes processing audio data after a suspend().
+ 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.
- 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.
+ See \l {QtAudio::convertVolume()}{QtMultimedia.convertVolume()}
+ for more details.
*/
-void QAudioOutput::resume()
-{
- d->resume();
-}
/*!
- Returns the number of free bytes available in the audio buffer.
+ \property QAudioOutput::volume
+ \brief The current volume.
- \note The returned value is only valid while in QAudio::ActiveState or QAudio::IdleState
- state, otherwise returns zero.
-*/
-int QAudioOutput::bytesFree() const
-{
- return d->bytesFree();
-}
+ The volume is scaled linearly, ranging from \c 0 (silence) to \c 1
+ (full volume).
+ \note values outside this range will be clamped.
-/*!
- Returns the period size in bytes. This is the amount of data required each period
- to prevent buffer underrun, and to ensure uninterrupted playback.
+ By default the volume is \c 1.
- \note It is recommended to provide at least enough data for a full period with each
- write operation.
-*/
-int QAudioOutput::periodSize() const
-{
- return d->periodSize();
-}
-
-/*!
- Sets the audio buffer size to \a value in bytes.
+ 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.
- \note This function can be called anytime before start(). Calls to this
- are ignored after start(). It should not be assumed that the buffer size
- set is the actual buffer size used - call bufferSize() anytime after start()
- to return the actual buffer size being used.
+ \sa QtAudio::convertVolume()
*/
-void QAudioOutput::setBufferSize(int value)
+float QAudioOutput::volume() const
{
- d->setBufferSize(value);
+ return d->volume;
}
-/*!
- Returns the audio buffer size in bytes.
-
- If called before start(), returns platform default value.
- If called before start() but setBufferSize() was called prior, returns value set by setBufferSize().
- If called after start(), returns the actual buffer size being used. This may not be what was set previously
- by setBufferSize().
-
-*/
-int QAudioOutput::bufferSize() const
+void QAudioOutput::setVolume(float volume)
{
- return d->bufferSize();
+ volume = qBound(0., volume, 1.);
+ if (d->volume == volume)
+ return;
+ d->volume = volume;
+ d->setVolume(volume);
+ emit volumeChanged(volume);
}
/*!
- Sets the interval for notify() signal to be emitted.
- This is based on the \a ms of audio data processed,
- not on wall clock time.
- The minimum resolution of the timer is platform specific and values
- should be checked with notifyInterval() to confirm the actual value
- being used.
-*/
-void QAudioOutput::setNotifyInterval(int ms)
-{
- d->setNotifyInterval(ms);
-}
+ \qmlproperty bool QtMultimedia::AudioOutput::muted
-/*!
- Returns the notify interval in milliseconds.
-*/
-int QAudioOutput::notifyInterval() const
-{
- return d->notifyInterval();
-}
+ This property holds whether the audio output is muted.
-/*!
- Returns the amount of audio data processed since start()
- was called (in microseconds).
+ Defaults to \c{false}.
*/
-qint64 QAudioOutput::processedUSecs() const
-{
- return d->processedUSecs();
-}
/*!
- Returns the microseconds since start() was called, including time in Idle and
- Suspend states.
-*/
-qint64 QAudioOutput::elapsedUSecs() const
-{
- return d->elapsedUSecs();
-}
+ \property QAudioOutput::muted
+ \brief The muted state of the current media.
-/*!
- Returns the error state.
+ The value will be \c true if the output is muted; otherwise \c{false}.
*/
-QAudio::Error QAudioOutput::error() const
+bool QAudioOutput::isMuted() const
{
- return d->error();
+ return d->muted;
}
-/*!
- Returns the state of audio processing.
-*/
-QAudio::State QAudioOutput::state() const
+void QAudioOutput::setMuted(bool muted)
{
- return d->state();
+ if (d->muted == muted)
+ return;
+ d->muted = muted;
+ d->setMuted(muted);
+ emit mutedChanged(muted);
}
/*!
- Sets the output volume to \a volume.
-
- The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this
- range will be clamped.
+ \qmlproperty AudioDevice QtMultimedia::AudioOutput::device
- The default volume is \c 1.0.
+ This property describes the audio device connected to this output.
- Note: Adjustments to the volume will change the volume of this audio stream, not the global volume.
-
- UI volume controls should usually be scaled nonlinearly. 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.
+ 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.
*/
-void QAudioOutput::setVolume(qreal volume)
-{
- qreal v = qBound(qreal(0.0), volume, qreal(1.0));
- d->setVolume(v);
-}
/*!
- Returns the volume between 0.0 and 1.0 inclusive.
+ \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.
*/
-qreal QAudioOutput::volume() const
+QAudioDevice QAudioOutput::device() const
{
- return d->volume();
+ return d->device;
}
-/*!
- Returns the audio category of this audio stream.
-
- Some platforms can group audio streams into categories
- and manage their volumes independently, or display them
- in a system mixer control. You can set this property to
- allow the platform to distinguish the purpose of your streams.
-
- \sa setCategory()
-*/
-QString QAudioOutput::category() const
+void QAudioOutput::setDevice(const QAudioDevice &device)
{
- return d->category();
+ 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();
}
/*!
- Sets the audio category of this audio stream to \a category.
-
- Some platforms can group audio streams into categories
- and manage their volumes independently, or display them
- in a system mixer control. You can set this property to
- allow the platform to distinguish the purpose of your streams.
-
- Not all platforms support audio stream categorization. In this
- case, the function call will be ignored.
-
- Changing an audio output stream's category while it is opened
- will not take effect until it is reopened.
- \sa category()
+ \internal
*/
-void QAudioOutput::setCategory(const QString &category)
+void QAudioOutput::setDisconnectFunction(std::function<void()> disconnectFunction)
{
- d->setCategory(category);
+ if (d->disconnectFunction) {
+ auto df = d->disconnectFunction;
+ d->disconnectFunction = {};
+ df();
+ }
+ d->disconnectFunction = std::move(disconnectFunction);
}
-/*!
- \fn QAudioOutput::stateChanged(QAudio::State state)
- This signal is emitted when the device \a state has changed.
- This is the current state of the audio output.
-*/
-
-/*!
- \fn QAudioOutput::notify()
- This signal is emitted when a certain interval of milliseconds
- of audio data has been processed. The interval is set by
- setNotifyInterval().
-*/
-
-QT_END_NAMESPACE
-
#include "moc_qaudiooutput.cpp"
diff --git a/src/multimedia/audio/qaudiooutput.h b/src/multimedia/audio/qaudiooutput.h
index 5f466d8e1..643d19f94 100644
--- a/src/multimedia/audio/qaudiooutput.h
+++ b/src/multimedia/audio/qaudiooutput.h
@@ -1,112 +1,55 @@
-/****************************************************************************
-**
-** 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 QAUDIOOUTPUTDEVICE_H
+#define QAUDIOOUTPUTDEVICE_H
-#ifndef QAUDIOOUTPUT_H
-#define QAUDIOOUTPUT_H
-
-#include <QtCore/qiodevice.h>
-
+#include <QtCore/qobject.h>
#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qmultimedia.h>
-
-#include <QtMultimedia/qaudio.h>
-#include <QtMultimedia/qaudioformat.h>
-#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qtaudio.h>
+#include <functional>
QT_BEGIN_NAMESPACE
-
-
-class QAbstractAudioOutput;
+class QAudioDevice;
+class QPlatformAudioOutput;
class Q_MULTIMEDIA_EXPORT QAudioOutput : public QObject
{
Q_OBJECT
+ Q_PROPERTY(QAudioDevice device READ device WRITE setDevice NOTIFY deviceChanged)
+ Q_PROPERTY(float volume READ volume WRITE setVolume NOTIFY volumeChanged)
+ Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
public:
- explicit QAudioOutput(const QAudioFormat &format = QAudioFormat(), QObject *parent = nullptr);
- explicit QAudioOutput(const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format = QAudioFormat(), QObject *parent = nullptr);
+ explicit QAudioOutput(QObject *parent = nullptr);
+ explicit QAudioOutput(const QAudioDevice &device, QObject *parent = nullptr);
~QAudioOutput();
- QAudioFormat format() const;
-
- void start(QIODevice *device);
- QIODevice* start();
-
- void stop();
- void reset();
- void suspend();
- void resume();
+ QAudioDevice device() const;
+ float volume() const;
+ bool isMuted() const;
- void setBufferSize(int bytes);
- int bufferSize() const;
-
- int bytesFree() const;
- int periodSize() const;
-
- void setNotifyInterval(int milliSeconds);
- int notifyInterval() const;
-
- qint64 processedUSecs() const;
- qint64 elapsedUSecs() const;
-
- QAudio::Error error() const;
- QAudio::State state() const;
-
- void setVolume(qreal);
- qreal volume() const;
-
- QString category() const;
- void setCategory(const QString &category);
+public Q_SLOTS:
+ void setDevice(const QAudioDevice &device);
+ void setVolume(float volume);
+ void setMuted(bool muted);
Q_SIGNALS:
- void stateChanged(QAudio::State state);
- void notify();
+ void deviceChanged();
+ void volumeChanged(float volume);
+ void mutedChanged(bool muted);
private:
+ QPlatformAudioOutput *handle() const { return d; }
+ void setDisconnectFunction(std::function<void()> disconnectFunction);
+ friend class QMediaCaptureSession;
+ friend class QMediaPlayer;
Q_DISABLE_COPY(QAudioOutput)
-
- QAbstractAudioOutput* d;
+ QPlatformAudioOutput *d = nullptr;
};
QT_END_NAMESPACE
-#endif // QAUDIOOUTPUT_H
+#endif // QAUDIOOUTPUTDEVICE_H
diff --git a/src/multimedia/audio/qaudioprobe.cpp b/src/multimedia/audio/qaudioprobe.cpp
deleted file mode 100644
index 7fb57242f..000000000
--- a/src/multimedia/audio/qaudioprobe.cpp
+++ /dev/null
@@ -1,205 +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$
-**
-****************************************************************************/
-
-/*!
- \class QAudioProbe
- \inmodule QtMultimedia
-
- \ingroup multimedia
- \ingroup multimedia_audio
-
- \brief The QAudioProbe class allows you to monitor audio being played or recorded.
-
- \snippet multimedia-snippets/qaudioprobe.cpp desc
-
- \sa QVideoProbe, QMediaPlayer, QCamera
-*/
-
-#include "qaudioprobe.h"
-#include "qmediaaudioprobecontrol.h"
-#include "qmediaservice.h"
-#include "qmediarecorder.h"
-#include "qsharedpointer.h"
-#include "qpointer.h"
-
-QT_BEGIN_NAMESPACE
-
-class QAudioProbePrivate {
-public:
- QPointer<QMediaObject> source;
- QPointer<QMediaAudioProbeControl> probee;
-};
-
-/*!
- Creates a new QAudioProbe class with a \a parent. After setting the
- source to monitor with \l setSource(), the \l audioBufferProbed()
- signal will be emitted when audio buffers are flowing in the
- source media object.
- */
-QAudioProbe::QAudioProbe(QObject *parent)
- : QObject(parent)
- , d(new QAudioProbePrivate)
-{
-}
-
-/*!
- Destroys this probe and disconnects from any
- media object.
- */
-QAudioProbe::~QAudioProbe()
-{
- if (d->source) {
- // Disconnect
- if (d->probee) {
- disconnect(d->probee.data(), SIGNAL(audioBufferProbed(QAudioBuffer)), this, SIGNAL(audioBufferProbed(QAudioBuffer)));
- disconnect(d->probee.data(), SIGNAL(flush()), this, SIGNAL(flush()));
- }
- d->source.data()->service()->releaseControl(d->probee.data());
- }
-}
-
-/*!
- Sets the media object to monitor to \a source.
-
- If \a source is zero, this probe will be deactivated
- and this function wil return true.
-
- If the media object does not support monitoring
- audio, this function will return false.
-
- The previous object will no longer be monitored.
- Passing in the same object will be ignored, but
- monitoring will continue.
- */
-bool QAudioProbe::setSource(QMediaObject *source)
-{
- // Need to:
- // 1) disconnect from current source if necessary
- // 2) see if new one has the probe control
- // 3) connect if so
-
- // in case source was destroyed but probe control is still valid
- if (!d->source && d->probee) {
- disconnect(d->probee.data(), SIGNAL(audioBufferProbed(QAudioBuffer)), this, SIGNAL(audioBufferProbed(QAudioBuffer)));
- disconnect(d->probee.data(), SIGNAL(flush()), this, SIGNAL(flush()));
- d->probee.clear();
- }
-
- if (source != d->source.data()) {
- if (d->source) {
- Q_ASSERT(d->probee);
- disconnect(d->probee.data(), SIGNAL(audioBufferProbed(QAudioBuffer)), this, SIGNAL(audioBufferProbed(QAudioBuffer)));
- disconnect(d->probee.data(), SIGNAL(flush()), this, SIGNAL(flush()));
- d->source.data()->service()->releaseControl(d->probee.data());
- d->source.clear();
- d->probee.clear();
- }
-
- if (source) {
- QMediaService *service = source->service();
- if (service) {
- d->probee = service->requestControl<QMediaAudioProbeControl*>();
- }
-
- if (d->probee) {
- connect(d->probee.data(), SIGNAL(audioBufferProbed(QAudioBuffer)), this, SIGNAL(audioBufferProbed(QAudioBuffer)));
- connect(d->probee.data(), SIGNAL(flush()), this, SIGNAL(flush()));
- d->source = source;
- }
- }
- }
-
- return (!source || d->probee != nullptr);
-}
-
-/*!
- Starts monitoring the given \a mediaRecorder.
-
- Returns true on success.
-
- If there is no mediaObject associated with \a mediaRecorder, or if it is
- zero, this probe will be deactivated and this function wil return true.
-
- If the media recorder instance does not support monitoring
- audio, this function will return false.
-
- Any previously monitored objects will no longer be monitored.
- Passing in the same (valid) object will be ignored, but
- monitoring will continue.
- */
-bool QAudioProbe::setSource(QMediaRecorder *mediaRecorder)
-{
- QMediaObject *source = mediaRecorder ? mediaRecorder->mediaObject() : nullptr;
- bool result = setSource(source);
-
- if (!mediaRecorder)
- return true;
-
- if (mediaRecorder && !source)
- return false;
-
- return result;
-}
-
-/*!
- Returns true if this probe is monitoring something, or false otherwise.
-
- The source being monitored does not need to be active.
- */
-bool QAudioProbe::isActive() const
-{
- return d->probee != nullptr;
-}
-
-/*!
- \fn QAudioProbe::audioBufferProbed(const QAudioBuffer &buffer)
-
- This signal should be emitted when an audio \a buffer is processed in the
- media service.
-*/
-
-
-/*!
- \fn QAudioProbe::flush()
-
- This signal should be emitted when it is required to release all buffers.
- Application must release all outstanding references to audio buffers.
-*/
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudioprobe.h b/src/multimedia/audio/qaudioprobe.h
deleted file mode 100644
index e0d5619d2..000000000
--- a/src/multimedia/audio/qaudioprobe.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 QAUDIOPROBE_H
-#define QAUDIOPROBE_H
-
-#include <QtCore/qobject.h>
-#include <QtMultimedia/qaudiobuffer.h>
-
-QT_BEGIN_NAMESPACE
-
-class QMediaObject;
-class QMediaRecorder;
-
-class QAudioProbePrivate;
-class Q_MULTIMEDIA_EXPORT QAudioProbe : public QObject
-{
- Q_OBJECT
-public:
- explicit QAudioProbe(QObject *parent = nullptr);
- ~QAudioProbe();
-
- bool setSource(QMediaObject *source);
- bool setSource(QMediaRecorder *source);
-
- bool isActive() const;
-
-Q_SIGNALS:
- void audioBufferProbed(const QAudioBuffer &buffer);
- void flush();
-
-private:
- QAudioProbePrivate *d;
-};
-
-QT_END_NAMESPACE
-
-#endif // QAUDIOPROBE_H
diff --git a/src/multimedia/audio/qaudiosink.cpp b/src/multimedia/audio/qaudiosink.cpp
new file mode 100644
index 000000000..12263d32a
--- /dev/null
+++ b/src/multimedia/audio/qaudiosink.cpp
@@ -0,0 +1,339 @@
+// 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"
+#include "qaudiodevice.h"
+#include "qaudiosystem_p.h"
+#include "qaudiosink.h"
+
+#include <private/qplatformmediadevices_p.h>
+#include <private/qplatformmediaintegration_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAudioSink
+ \brief The QAudioSink class provides an interface for sending audio data to
+ an audio output device.
+
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \ingroup multimedia_audio
+
+ You can construct an audio output with the system's
+ default audio output device. It is also possible to
+ create QAudioSink with a specific QAudioDevice. When
+ you create the audio output, you should also send in
+ the QAudioFormat to be used for the playback (see
+ the QAudioFormat class description for details).
+
+ To play a file:
+
+ Starting to play an audio stream is simply a matter of calling
+ start() with a QIODevice. QAudioSink will then fetch the data it
+ needs from the io device. So playing back an audio file is as
+ simple as:
+
+ \snippet multimedia-snippets/audio.cpp Audio output class members
+
+ \snippet multimedia-snippets/audio.cpp Audio output setup
+
+ The file will start playing assuming that the audio system and
+ output device support it. If you run out of luck, check what's
+ up with the error() function.
+
+ After the file has finished playing, we need to stop the device:
+
+ \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 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{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:
+
+ \snippet multimedia-snippets/audio.cpp Audio output state changed
+
+ \sa QAudioSource, QAudioDevice
+*/
+
+/*!
+ Construct a new audio output and attach it to \a parent.
+ The default audio output device is used with the output
+ \a format parameters.
+*/
+QAudioSink::QAudioSink(const QAudioFormat &format, QObject *parent)
+ : QAudioSink({}, format, parent)
+{
+}
+
+/*!
+ Construct a new audio output and attach it to \a parent.
+ The device referenced by \a audioDevice is used with the output
+ \a format parameters.
+*/
+QAudioSink::QAudioSink(const QAudioDevice &audioDevice, const QAudioFormat &format, QObject *parent):
+ QObject(parent)
+{
+ 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.
+*/
+QAudioSink::~QAudioSink()
+{
+ delete d;
+}
+
+/*!
+ Returns the QAudioFormat being used.
+
+*/
+QAudioFormat QAudioSink::format() const
+{
+ return d ? d->format() : QAudioFormat();
+}
+
+/*!
+ Starts transferring audio data from the \a device to the system's audio output.
+ The \a device must have been opened in the \l{QIODevice::ReadOnly}{ReadOnly} or
+ \l{QIODevice::ReadWrite}{ReadWrite} modes.
+
+ If the QAudioSink is able to successfully output audio data, state() returns
+ QtAudio::ActiveState, error() returns QtAudio::NoError
+ 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);
+}
+
+/*!
+ Returns a pointer to the internal QIODevice being used to transfer data to
+ the system's audio output. The device will already be open and
+ \l{QIODevice::write()}{write()} can write data directly to it.
+
+ \note The pointer will become invalid after the stream is stopped or
+ if you start another stream.
+
+ If the QAudioSink is able to access the system's audio device, state() returns
+ QtAudio::IdleState, error() returns QtAudio::NoError
+ 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();
+}
+
+/*!
+ Stops the audio output, detaching from the system resource.
+
+ Sets error() to QtAudio::NoError, state() to QtAudio::StoppedState and
+ emit stateChanged() signal.
+*/
+void QAudioSink::stop()
+{
+ if (d)
+ d->stop();
+}
+
+/*!
+ Drops all audio data in the buffers, resets buffers to zero.
+
+*/
+void QAudioSink::reset()
+{
+ if (d)
+ d->reset();
+}
+
+/*!
+ Stops processing audio data, preserving buffered audio data.
+
+ Sets error() to QtAudio::NoError, state() to QtAudio::SuspendedState and
+ emits stateChanged() signal.
+*/
+void QAudioSink::suspend()
+{
+ if (d)
+ d->suspend();
+}
+
+/*!
+ Resumes processing audio data after a suspend().
+
+ 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()
+{
+ if (d)
+ d->resume();
+}
+
+/*!
+ Returns the number of free bytes available in the audio buffer.
+
+ \note The returned value is only valid while in QtAudio::ActiveState or QtAudio::IdleState
+ state, otherwise returns zero.
+*/
+qsizetype QAudioSink::bytesFree() const
+{
+ return d ? d->bytesFree() : 0;
+}
+
+/*!
+ Sets the audio buffer size to \a value in bytes.
+
+ \note This function can be called anytime before start(). Calls to this
+ are ignored after start(). It should not be assumed that the buffer size
+ set is the actual buffer size used - call bufferSize() anytime after start()
+ to return the actual buffer size being used.
+*/
+void QAudioSink::setBufferSize(qsizetype value)
+{
+ if (d)
+ d->setBufferSize(value);
+}
+
+/*!
+ Returns the audio buffer size in bytes.
+
+ If called before start(), returns platform default value.
+ If called before start() but setBufferSize() was called prior, returns value set by setBufferSize().
+ If called after start(), returns the actual buffer size being used. This may not be what was set previously
+ by setBufferSize().
+
+*/
+qsizetype QAudioSink::bufferSize() const
+{
+ return d ? d->bufferSize() : 0;
+}
+
+/*!
+ Returns the amount of audio data processed since start()
+ was called (in microseconds).
+*/
+qint64 QAudioSink::processedUSecs() const
+{
+ return d ? d->processedUSecs() : 0;
+}
+
+/*!
+ Returns the microseconds since start() was called, including time in Idle and
+ Suspend states.
+*/
+qint64 QAudioSink::elapsedUSecs() const
+{
+ return state() == QAudio::StoppedState ? 0 : d->elapsedTime.nsecsElapsed()/1000;
+}
+
+/*!
+ Returns the error state.
+*/
+QtAudio::Error QAudioSink::error() const
+{
+ return d ? d->error() : QAudio::OpenError;
+}
+
+/*!
+ Returns the state of audio processing.
+*/
+QtAudio::State QAudioSink::state() const
+{
+ return d ? d->state() : QAudio::StoppedState;
+}
+
+/*!
+ Sets the output volume to \a volume.
+
+ The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume).
+ Values outside this range will be clamped.
+
+ The default volume is \c 1.0.
+
+ \note Adjustments to the volume will change the volume of this audio stream,
+ not the global volume.
+
+ 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
+ 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);
+}
+
+/*!
+ Returns the volume between 0.0 and 1.0 inclusive.
+*/
+qreal QAudioSink::volume() const
+{
+ return d ? d->volume() : 1.0;
+}
+
+/*!
+ \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
+
+#include "moc_qaudiosink.cpp"
diff --git a/src/multimedia/audio/qaudiosink.h b/src/multimedia/audio/qaudiosink.h
new file mode 100644
index 000000000..e071e6fbc
--- /dev/null
+++ b/src/multimedia/audio/qaudiosink.h
@@ -0,0 +1,74 @@
+// 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
+#define QAUDIOOUTPUT_H
+
+#include <QtCore/qiodevice.h>
+
+#include <QtMultimedia/qtmultimediaglobal.h>
+
+#include <QtMultimedia/qtaudio.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <QtMultimedia/qaudiodevice.h>
+
+
+QT_BEGIN_NAMESPACE
+
+
+
+class QPlatformAudioSink;
+
+class Q_MULTIMEDIA_EXPORT QAudioSink : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit QAudioSink(const QAudioFormat &format = QAudioFormat(), QObject *parent = nullptr);
+ explicit QAudioSink(const QAudioDevice &audioDeviceInfo, const QAudioFormat &format = QAudioFormat(), QObject *parent = nullptr);
+ ~QAudioSink();
+
+ bool isNull() const { return !d; }
+
+ QAudioFormat format() const;
+
+ void start(QIODevice *device);
+ QIODevice* start();
+
+ void stop();
+ void reset();
+ void suspend();
+ void resume();
+
+ void setBufferSize(qsizetype bytes);
+ qsizetype bufferSize() const;
+
+ qsizetype bytesFree() const;
+
+ qint64 processedUSecs() const;
+ qint64 elapsedUSecs() 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)
+
+ QPlatformAudioSink* d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QAUDIOOUTPUT_H
diff --git a/src/multimedia/audio/qaudiosource.cpp b/src/multimedia/audio/qaudiosource.cpp
new file mode 100644
index 000000000..1ed5e82bc
--- /dev/null
+++ b/src/multimedia/audio/qaudiosource.cpp
@@ -0,0 +1,369 @@
+// 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"
+#include "qaudiodevice.h"
+#include "qaudiosystem_p.h"
+#include "qaudiosource.h"
+
+#include <private/qplatformmediadevices_p.h>
+#include <private/qplatformmediaintegration_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAudioSource
+ \brief The QAudioSource class provides an interface for receiving audio data from an audio input device.
+
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \ingroup multimedia_audio
+
+ You can construct an audio input with the system's
+ default audio input device. It is also possible to
+ create QAudioSource with a specific QAudioDevice. When
+ you create the audio input, you should also send in the
+ QAudioFormat to be used for the recording (see the QAudioFormat
+ class description for details).
+
+ To record to a file:
+
+ QAudioSource lets you record audio with an audio input device. The
+ default constructor of this class will use the systems default
+ audio device, but you can also specify a QAudioDevice for a
+ specific device. You also need to pass in the QAudioFormat in
+ which you wish to record.
+
+ Starting up the QAudioSource is simply a matter of calling start()
+ with a QIODevice opened for writing. For instance, to record to a
+ file, you can:
+
+ \snippet multimedia-snippets/audio.cpp Audio input class members
+
+ \snippet multimedia-snippets/audio.cpp Audio input setup
+
+ This will start recording if the format specified is supported by
+ the input device (you can check this with
+ QAudioDevice::isFormatSupported(). In case there are any
+ snags, use the error() function to check what went wrong. We stop
+ recording in the \c stopRecording() slot.
+
+ \snippet multimedia-snippets/audio.cpp Audio input stop recording
+
+ At any point in time, QAudioSource will be in one of four states:
+ active, suspended, stopped, or idle. These states are specified by
+ 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()).
+
+ QAudioSource provides several ways of measuring the time that has
+ passed since the start() of the recording. The \c processedUSecs()
+ function returns the length of the stream in microseconds written,
+ i.e., it leaves out the times the audio input was suspended or idle.
+ The elapsedUSecs() function returns the time elapsed since start() was called regardless of
+ 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 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:
+
+ \snippet multimedia-snippets/audio.cpp Audio input state changed
+
+ \sa QAudioSink, QAudioDevice
+*/
+
+/*!
+ Construct a new audio input and attach it to \a parent.
+ The default audio input device is used with the output
+ \a format parameters.
+*/
+
+QAudioSource::QAudioSource(const QAudioFormat &format, QObject *parent)
+ : QAudioSource({}, format, parent)
+{
+}
+
+/*!
+ Construct a new audio input and attach it to \a parent.
+ The device referenced by \a audioDevice is used with the input
+ \a format parameters.
+*/
+
+QAudioSource::QAudioSource(const QAudioDevice &audioDevice, const QAudioFormat &format, QObject *parent):
+ QObject(parent)
+{
+ 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.
+*/
+
+QAudioSource::~QAudioSource()
+{
+ delete d;
+}
+
+/*!
+ Starts transferring audio data from the system's audio input to the \a device.
+ The \a device must have been opened in the \l{QIODevice::WriteOnly}{WriteOnly},
+ \l{QIODevice::Append}{Append} or \l{QIODevice::ReadWrite}{ReadWrite} modes.
+
+ If the QAudioSource is able to successfully get audio data, state() returns
+ 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 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);
+}
+
+/*!
+ Returns a pointer to the internal QIODevice being used to transfer data from
+ the system's audio input. The device will already be open and
+ \l{QIODevice::read()}{read()} can read data directly from it.
+
+ \note The pointer will become invalid after the stream is stopped or
+ if you start another stream.
+
+ If the QAudioSource is able to access the system's audio device, state() returns
+ QtAudio::IdleState, error() returns QtAudio::NoError
+ 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();
+}
+
+/*!
+ Returns the QAudioFormat being used.
+*/
+
+QAudioFormat QAudioSource::format() const
+{
+ return d ? d->format() : QAudioFormat();
+}
+
+/*!
+ Stops the audio input, detaching from the system resource.
+
+ Sets error() to QtAudio::NoError, state() to QtAudio::StoppedState and
+ emit stateChanged() signal.
+*/
+
+void QAudioSource::stop()
+{
+ if (d)
+ d->stop();
+}
+
+/*!
+ Drops all audio data in the buffers, resets buffers to zero.
+*/
+
+void QAudioSource::reset()
+{
+ if (d)
+ d->reset();
+}
+
+/*!
+ Stops processing audio data, preserving buffered audio data.
+
+ Sets error() to QtAudio::NoError, state() to QtAudio::SuspendedState and
+ emit stateChanged() signal.
+*/
+
+void QAudioSource::suspend()
+{
+ if (d)
+ d->suspend();
+}
+
+/*!
+ Resumes processing audio data after a suspend().
+
+ 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()
+{
+ if (d)
+ d->resume();
+}
+
+/*!
+ Sets the audio buffer size to \a value bytes.
+
+ Note: This function can be called anytime before start(), calls to this
+ are ignored after start(). It should not be assumed that the buffer size
+ set is the actual buffer size used, calling bufferSize() anytime after start()
+ will return the actual buffer size being used.
+
+*/
+
+void QAudioSource::setBufferSize(qsizetype value)
+{
+ if (d)
+ d->setBufferSize(value);
+}
+
+/*!
+ Returns the audio buffer size in bytes.
+
+ If called before start(), returns platform default value.
+ If called before start() but setBufferSize() was called prior, returns value set by setBufferSize().
+ If called after start(), returns the actual buffer size being used. This may not be what was set previously
+ by setBufferSize().
+
+*/
+
+qsizetype QAudioSource::bufferSize() const
+{
+ return d ? d->bufferSize() : 0;
+}
+
+/*!
+ Returns the amount of audio data available to read in bytes.
+
+ Note: returned value is only valid while in QtAudio::ActiveState or QtAudio::IdleState
+ state, otherwise returns zero.
+*/
+
+qsizetype QAudioSource::bytesAvailable() const
+{
+ /*
+ -If not ActiveState|IdleState, return 0
+ -return amount of audio data available to read
+ */
+ return d ? d->bytesReady() : 0;
+}
+
+/*!
+ Sets the input volume to \a volume.
+
+ The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this
+ range will be clamped.
+
+ If the device does not support adjusting the input
+ volume then \a volume will be ignored and the input
+ volume will remain at 1.0.
+
+ The default volume is \c 1.0.
+
+ Note: Adjustments to the volume will change the volume of this audio stream, not the global volume.
+*/
+void QAudioSource::setVolume(qreal volume)
+{
+ if (!d)
+ return;
+ qreal v = qBound(qreal(0.0), volume, qreal(1.0));
+ d->setVolume(v);
+}
+
+/*!
+ Returns the input volume.
+
+ If the device does not support adjusting the input volume
+ the returned value will be 1.0.
+*/
+qreal QAudioSource::volume() const
+{
+ return d ? d->volume() : 1.0;
+}
+
+/*!
+ Returns the amount of audio data processed since start()
+ was called in microseconds.
+*/
+
+qint64 QAudioSource::processedUSecs() const
+{
+ return d ? d->processedUSecs() : 0;
+}
+
+/*!
+ Returns the microseconds since start() was called, including time in Idle and
+ Suspend states.
+*/
+
+#include <qdebug.h>
+
+qint64 QAudioSource::elapsedUSecs() const
+{
+ return state() == QAudio::StoppedState ? 0 : d->elapsedTime.nsecsElapsed()/1000;
+}
+
+/*!
+ Returns the error state.
+*/
+
+QtAudio::Error QAudioSource::error() const
+{
+ return d ? d->error() : QAudio::OpenError;
+}
+
+/*!
+ Returns the state of audio processing.
+*/
+
+QtAudio::State QAudioSource::state() const
+{
+ return d ? d->state() : QAudio::StoppedState;
+}
+
+/*!
+ \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
+
+#include "moc_qaudiosource.cpp"
+
diff --git a/src/multimedia/audio/qaudiosource.h b/src/multimedia/audio/qaudiosource.h
new file mode 100644
index 000000000..f0ad0ceb5
--- /dev/null
+++ b/src/multimedia/audio/qaudiosource.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 QAUDIOINPUT_H
+#define QAUDIOINPUT_H
+
+#include <QtCore/qiodevice.h>
+
+#include <QtMultimedia/qtmultimediaglobal.h>
+
+#include <QtMultimedia/qtaudio.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <QtMultimedia/qaudiodevice.h>
+
+
+QT_BEGIN_NAMESPACE
+
+class QPlatformAudioSource;
+
+class Q_MULTIMEDIA_EXPORT QAudioSource : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit QAudioSource(const QAudioFormat &format = QAudioFormat(), QObject *parent = nullptr);
+ explicit QAudioSource(const QAudioDevice &audioDeviceInfo, const QAudioFormat &format = QAudioFormat(), QObject *parent = nullptr);
+ ~QAudioSource();
+
+ bool isNull() const { return !d; }
+
+ QAudioFormat format() const;
+
+ void start(QIODevice *device);
+ QIODevice* start();
+
+ void stop();
+ void reset();
+ void suspend();
+ void resume();
+
+ void setBufferSize(qsizetype bytes);
+ qsizetype bufferSize() const;
+
+ qsizetype bytesAvailable() const;
+
+ void setVolume(qreal volume);
+ qreal volume() const;
+
+ qint64 processedUSecs() const;
+ qint64 elapsedUSecs() 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)
+
+ QPlatformAudioSource *d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QAUDIOINPUT_H
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 b11993e55..355771f6b 100644
--- a/src/multimedia/audio/qaudiosystem.cpp
+++ b/src/multimedia/audio/qaudiosystem.cpp
@@ -1,376 +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) 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 "qaudiosystem.h"
+#include "qaudiosystem_p.h"
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QAbstractAudioDeviceInfo
- \brief The QAbstractAudioDeviceInfo class is a base class for audio backends.
-
- \ingroup multimedia
- \ingroup multimedia_audio
- \inmodule QtMultimedia
-
- This class implements the audio functionality for
- QAudioDeviceInfo, i.e., QAudioDeviceInfo keeps a
- QAbstractAudioDeviceInfo and routes function calls to it. For a
- description of the functionality that QAbstractAudioDeviceInfo
- implements, you can read the class and functions documentation of
- QAudioDeviceInfo.
-
- \sa QAudioDeviceInfo
- \sa QAbstractAudioOutput, QAbstractAudioInput
-*/
-
-/*!
- \fn virtual QAudioFormat QAbstractAudioDeviceInfo::preferredFormat() const
- Returns the recommended settings to use.
-*/
-
-/*!
- \fn virtual bool QAbstractAudioDeviceInfo::isFormatSupported(const QAudioFormat& format) const
- Returns true if \a format is available from audio device.
-*/
-
-/*!
- \fn virtual QString QAbstractAudioDeviceInfo::deviceName() const
- Returns the audio device name.
-*/
-
-/*!
- \fn virtual QStringList QAbstractAudioDeviceInfo::supportedCodecs()
- Returns the list of currently available codecs.
-*/
-
-/*!
- \fn virtual QList<int> QAbstractAudioDeviceInfo::supportedSampleRates()
- Returns the list of currently available sample rates.
-*/
-
-/*!
- \fn virtual QList<int> QAbstractAudioDeviceInfo::supportedChannelCounts()
- Returns the list of currently available channels.
-*/
-
-/*!
- \fn virtual QList<int> QAbstractAudioDeviceInfo::supportedSampleSizes()
- Returns the list of currently available sample sizes.
-*/
-
-/*!
- \fn virtual QList<QAudioFormat::Endian> QAbstractAudioDeviceInfo::supportedByteOrders()
- Returns the list of currently available byte orders.
-*/
-
-/*!
- \fn virtual QList<QAudioFormat::SampleType> QAbstractAudioDeviceInfo::supportedSampleTypes()
- Returns the list of currently available sample types.
-*/
-
-/*!
- \class QAbstractAudioOutput
- \brief The QAbstractAudioOutput class is a base class for audio backends.
-
- \ingroup multimedia
- \inmodule QtMultimedia
-
- QAbstractAudioOutput implements audio functionality for
- QAudioOutput, i.e., QAudioOutput routes function calls to
- QAbstractAudioOutput. For a description of the functionality that
- is implemented, see the QAudioOutput class and function
- descriptions.
-
- \sa QAudioOutput
-*/
-
-/*!
- \fn virtual void QAbstractAudioOutput::start(QIODevice* device)
- Uses the \a device as the QIODevice to transfer data.
-*/
-
-/*!
- \fn virtual QIODevice* QAbstractAudioOutput::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 virtual void QAbstractAudioOutput::stop()
- Stops the audio output.
-*/
-
-/*!
- \fn virtual void QAbstractAudioOutput::reset()
- Drops all audio data in the buffers, resets buffers to zero.
-*/
-
-/*!
- \fn virtual void QAbstractAudioOutput::suspend()
- Stops processing audio data, preserving buffered audio data.
-*/
-
-/*!
- \fn virtual void QAbstractAudioOutput::resume()
- Resumes processing audio data after a suspend()
-*/
-
-/*!
- \fn virtual int QAbstractAudioOutput::bytesFree() const
- Returns the free space available in bytes in the audio buffer.
-*/
-
-/*!
- \fn virtual int QAbstractAudioOutput::periodSize() const
- Returns the period size in bytes.
-*/
-
-/*!
- \fn virtual void QAbstractAudioOutput::setBufferSize(int value)
- Sets the audio buffer size to \a value in bytes.
-*/
-
-/*!
- \fn virtual int QAbstractAudioOutput::bufferSize() const
- Returns the audio buffer size in bytes.
-*/
-
-/*!
- \fn virtual void QAbstractAudioOutput::setNotifyInterval(int ms)
- Sets the interval for notify() signal to be emitted. This is based on the \a ms
- of audio data processed not on actual real-time. The resolution of the timer
- is platform specific.
-*/
-
-/*!
- \fn virtual int QAbstractAudioOutput::notifyInterval() const
- Returns the notify interval in milliseconds.
-*/
-
-/*!
- \fn virtual qint64 QAbstractAudioOutput::processedUSecs() const
- Returns the amount of audio data processed since start() was called in milliseconds.
-*/
-
-/*!
- \fn virtual qint64 QAbstractAudioOutput::elapsedUSecs() const
- Returns the milliseconds since start() was called, including time in Idle and suspend states.
-*/
+#include <private/qplatformmediadevices_p.h>
-/*!
- \fn virtual QAudio::Error QAbstractAudioOutput::error() const
- Returns the error state.
-*/
-
-/*!
- \fn virtual QAudio::State QAbstractAudioOutput::state() const
- Returns the state of audio processing.
-*/
-
-/*!
- \fn virtual void QAbstractAudioOutput::setFormat(const QAudioFormat& fmt)
- Set the QAudioFormat to use to \a fmt.
- Setting the format is only allowable while in QAudio::StoppedState.
-*/
-
-/*!
- \fn virtual QAudioFormat QAbstractAudioOutput::format() const
- Returns the QAudioFormat being used.
-*/
-
-/*!
- \fn virtual void QAbstractAudioOutput::setVolume(qreal volume)
- Sets the volume.
- Where \a volume is between 0.0 and 1.0.
-*/
-
-/*!
- \fn virtual qreal QAbstractAudioOutput::volume() const
- Returns the volume in the range 0.0 and 1.0.
-*/
-
-/*!
- \fn QAbstractAudioOutput::errorChanged(QAudio::Error error)
- This signal is emitted when the \a error state has changed.
-*/
-
-/*!
- \fn QAbstractAudioOutput::stateChanged(QAudio::State state)
- This signal is emitted when the device \a state has changed.
-*/
-
-/*!
- \fn QAbstractAudioOutput::notify()
- This signal is emitted when x ms of audio data has been processed
- the interval set by setNotifyInterval(x).
-*/
-
-
-/*!
- \class QAbstractAudioInput
- \brief The QAbstractAudioInput class provides access for QAudioInput to access the audio
- device provided by the plugin.
-
- \ingroup multimedia
- \inmodule QtMultimedia
-
- QAudioDeviceInput keeps an instance of QAbstractAudioInput and
- routes calls to functions of the same name to QAbstractAudioInput.
- This means that it is QAbstractAudioInput that implements the
- audio functionality. For a description of the functionality, see
- the QAudioInput class description.
-
- \sa QAudioInput
-*/
-
-/*!
- \fn virtual void QAbstractAudioInput::start(QIODevice* device)
- Uses the \a device as the QIODevice to transfer data.
-*/
-
-/*!
- \fn virtual QIODevice* QAbstractAudioInput::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 virtual void QAbstractAudioInput::stop()
- Stops the audio input.
-*/
-
-/*!
- \fn virtual void QAbstractAudioInput::reset()
- Drops all audio data in the buffers, resets buffers to zero.
-*/
-
-/*!
- \fn virtual void QAbstractAudioInput::suspend()
- Stops processing audio data, preserving buffered audio data.
-*/
-
-/*!
- \fn virtual void QAbstractAudioInput::resume()
- Resumes processing audio data after a suspend().
-*/
-
-/*!
- \fn virtual int QAbstractAudioInput::bytesReady() const
- Returns the amount of audio data available to read in bytes.
-*/
-
-/*!
- \fn virtual int QAbstractAudioInput::periodSize() const
- Returns the period size in bytes.
-*/
-
-/*!
- \fn virtual void QAbstractAudioInput::setBufferSize(int value)
- Sets the audio buffer size to \a value in milliseconds.
-*/
-
-/*!
- \fn virtual int QAbstractAudioInput::bufferSize() const
- Returns the audio buffer size in milliseconds.
-*/
-
-/*!
- \fn virtual void QAbstractAudioInput::setNotifyInterval(int ms)
- Sets the interval for notify() signal to be emitted. This is based
- on the \a ms of audio data processed not on actual real-time.
- The resolution of the timer is platform specific.
-*/
-
-/*!
- \fn virtual int QAbstractAudioInput::notifyInterval() const
- Returns the notify interval in milliseconds.
-*/
-
-/*!
- \fn virtual qint64 QAbstractAudioInput::processedUSecs() const
- Returns the amount of audio data processed since start() was called in milliseconds.
-*/
-
-/*!
- \fn virtual qint64 QAbstractAudioInput::elapsedUSecs() const
- Returns the milliseconds since start() was called, including time in Idle and suspend states.
-*/
-
-/*!
- \fn virtual QAudio::Error QAbstractAudioInput::error() const
- Returns the error state.
-*/
-
-/*!
- \fn virtual QAudio::State QAbstractAudioInput::state() const
- Returns the state of audio processing.
-*/
-
-/*!
- \fn virtual void QAbstractAudioInput::setFormat(const QAudioFormat& fmt)
- Set the QAudioFormat to use to \a fmt.
- Setting the format is only allowable while in QAudio::StoppedState.
-*/
-
-/*!
- \fn virtual QAudioFormat QAbstractAudioInput::format() const
- Returns the QAudioFormat being used
-*/
+QT_BEGIN_NAMESPACE
-/*!
- \fn QAbstractAudioInput::errorChanged(QAudio::Error error)
- This signal is emitted when the \a error state has changed.
-*/
+QAudioStateChangeNotifier::QAudioStateChangeNotifier(QObject *parent) : QObject(parent) { }
-/*!
- \fn QAbstractAudioInput::stateChanged(QAudio::State state)
- This signal is emitted when the device \a state has changed.
-*/
+QPlatformAudioSink::QPlatformAudioSink(QObject *parent) : QAudioStateChangeNotifier(parent) { }
-/*!
- \fn QAbstractAudioInput::notify()
- This signal is emitted when x ms of audio data has been processed
- the interval set by setNotifyInterval(x).
-*/
+qreal QPlatformAudioSink::volume() const
+{
+ return 1.0;
+}
+QPlatformAudioSource::QPlatformAudioSource(QObject *parent) : QAudioStateChangeNotifier(parent) { }
QT_END_NAMESPACE
-#include "moc_qaudiosystem.cpp"
+#include "moc_qaudiosystem_p.cpp"
diff --git a/src/multimedia/audio/qaudiosystem.h b/src/multimedia/audio/qaudiosystem.h
deleted file mode 100644
index c326460fe..000000000
--- a/src/multimedia/audio/qaudiosystem.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 QAUDIOSYSTEM_H
-#define QAUDIOSYSTEM_H
-
-#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qmultimedia.h>
-
-#include <QtMultimedia/qaudio.h>
-#include <QtMultimedia/qaudioformat.h>
-#include <QtMultimedia/qaudiodeviceinfo.h>
-
-QT_BEGIN_NAMESPACE
-
-class QIODevice;
-
-class Q_MULTIMEDIA_EXPORT QAbstractAudioDeviceInfo : public QObject
-{
- Q_OBJECT
-
-public:
- virtual QAudioFormat preferredFormat() const = 0;
- virtual bool isFormatSupported(const QAudioFormat &format) const = 0;
- virtual QString deviceName() const = 0;
- virtual QStringList supportedCodecs() = 0;
- virtual QList<int> supportedSampleRates() = 0;
- virtual QList<int> supportedChannelCounts() = 0;
- virtual QList<int> supportedSampleSizes() = 0;
- virtual QList<QAudioFormat::Endian> supportedByteOrders() = 0;
- virtual QList<QAudioFormat::SampleType> supportedSampleTypes() = 0;
-};
-
-class Q_MULTIMEDIA_EXPORT QAbstractAudioOutput : public QObject
-{
- Q_OBJECT
-
-public:
- virtual void start(QIODevice *device) = 0;
- virtual QIODevice* start() = 0;
- virtual void stop() = 0;
- virtual void reset() = 0;
- virtual void suspend() = 0;
- virtual void resume() = 0;
- virtual int bytesFree() const = 0;
- virtual int periodSize() const = 0;
- virtual void setBufferSize(int value) = 0;
- virtual int bufferSize() const = 0;
- virtual void setNotifyInterval(int milliSeconds) = 0;
- virtual int notifyInterval() const = 0;
- virtual qint64 processedUSecs() const = 0;
- virtual qint64 elapsedUSecs() const = 0;
- virtual QAudio::Error error() const = 0;
- virtual QAudio::State state() const = 0;
- virtual void setFormat(const QAudioFormat& fmt) = 0;
- virtual QAudioFormat format() const = 0;
- virtual void setVolume(qreal) {}
- virtual qreal volume() const { return 1.0; }
- virtual QString category() const { return QString(); }
- virtual void setCategory(const QString &) { }
-
-Q_SIGNALS:
- void errorChanged(QAudio::Error error);
- void stateChanged(QAudio::State state);
- void notify();
-};
-
-class Q_MULTIMEDIA_EXPORT QAbstractAudioInput : public QObject
-{
- Q_OBJECT
-
-public:
- virtual void start(QIODevice *device) = 0;
- virtual QIODevice* start() = 0;
- virtual void stop() = 0;
- virtual void reset() = 0;
- virtual void suspend() = 0;
- virtual void resume() = 0;
- virtual int bytesReady() const = 0;
- virtual int periodSize() const = 0;
- virtual void setBufferSize(int value) = 0;
- virtual int bufferSize() const = 0;
- virtual void setNotifyInterval(int milliSeconds) = 0;
- virtual int notifyInterval() const = 0;
- virtual qint64 processedUSecs() const = 0;
- virtual qint64 elapsedUSecs() const = 0;
- virtual QAudio::Error error() const = 0;
- virtual QAudio::State state() const = 0;
- virtual void setFormat(const QAudioFormat& fmt) = 0;
- virtual QAudioFormat format() const = 0;
- virtual void setVolume(qreal) = 0;
- virtual qreal volume() const = 0;
-
-Q_SIGNALS:
- void errorChanged(QAudio::Error error);
- void stateChanged(QAudio::State state);
- void notify();
-};
-
-QT_END_NAMESPACE
-
-#endif // QAUDIOSYSTEM_H
diff --git a/src/multimedia/audio/qaudiosystem_p.h b/src/multimedia/audio/qaudiosystem_p.h
new file mode 100644
index 000000000..4a0650e80
--- /dev/null
+++ b/src/multimedia/audio/qaudiosystem_p.h
@@ -0,0 +1,96 @@
+// 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
+
+//
+// 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 <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <QtMultimedia/qaudiodevice.h>
+
+#include <QtCore/qelapsedtimer.h>
+#include <QtCore/private/qglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+
+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;
+ virtual void reset() = 0;
+ virtual void suspend() = 0;
+ virtual void resume() = 0;
+ virtual qsizetype bytesFree() const = 0;
+ virtual void setBufferSize(qsizetype value) = 0;
+ virtual qsizetype bufferSize() const = 0;
+ virtual qint64 processedUSecs() const = 0;
+ virtual QAudio::Error error() const = 0;
+ virtual QAudio::State state() const = 0;
+ virtual void setFormat(const QAudioFormat& fmt) = 0;
+ virtual QAudioFormat format() const = 0;
+ virtual void setVolume(qreal) {}
+ virtual qreal volume() const;
+
+ QElapsedTimer elapsedTime;
+};
+
+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;
+ virtual void reset() = 0;
+ virtual void suspend() = 0;
+ virtual void resume() = 0;
+ virtual qsizetype bytesReady() const = 0;
+ virtual void setBufferSize(qsizetype value) = 0;
+ virtual qsizetype bufferSize() const = 0;
+ virtual qint64 processedUSecs() const = 0;
+ virtual QAudio::Error error() const = 0;
+ virtual QAudio::State state() const = 0;
+ virtual void setFormat(const QAudioFormat& fmt) = 0;
+ virtual QAudioFormat format() const = 0;
+ virtual void setVolume(qreal) = 0;
+ virtual qreal volume() const = 0;
+
+ QElapsedTimer elapsedTime;
+};
+
+QT_END_NAMESPACE
+
+#endif // QAUDIOSYSTEM_H
diff --git a/src/multimedia/audio/qaudiosystemplugin.cpp b/src/multimedia/audio/qaudiosystemplugin.cpp
deleted file mode 100644
index cb5628477..000000000
--- a/src/multimedia/audio/qaudiosystemplugin.cpp
+++ /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$
-**
-****************************************************************************/
-
-
-#include "qaudiosystemplugin.h"
-#include "qaudiosystempluginext_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QAudioSystemFactoryInterface::~QAudioSystemFactoryInterface()
-{
-}
-
-QAudioSystemPluginExtension::~QAudioSystemPluginExtension()
-{
-}
-
-/*!
- \class QAudioSystemPlugin
- \brief The QAudioSystemPlugin class provides an abstract base for audio plugins.
-
- \ingroup multimedia
- \ingroup multimedia_audio
- \inmodule QtMultimedia
-
- Writing a audio plugin is achieved by subclassing this base class,
- reimplementing the pure virtual functions availableDevices(),
- createInput(), createOutput() and createDeviceInfo() then exporting
- the class with the Q_PLUGIN_METADATA() macro.
-
- The json file containing the meta data should contain a list of keys
- matching the plugin. Add "default" to your list of keys available
- to override the default audio device to be provided by your plugin.
-
- \code
- { "Keys": [ "default" ] }
- \endcode
-
- Unit tests are available to help in debugging new plugins.
-
- \sa QAbstractAudioDeviceInfo, QAbstractAudioOutput, QAbstractAudioInput
-
- Qt comes with plugins for Windows (WinMM and WASAPI), Linux (ALSA and PulseAudio), \macos / iOS
- (CoreAudio), Android (OpenSL ES) and QNX.
-
- If no audio plugins are available, a fallback dummy backend will be used.
- This should print out warnings if this is the case when you try and use QAudioInput
- or QAudioOutput. To fix this problem, make sure the dependencies for the Qt plugins are
- installed on the system and reconfigure Qt (e.g. alsa-devel package on Linux), or create your
- own plugin with a default key to always override the dummy fallback. The easiest way to
- determine if you have only a dummy backend is to get a list of available audio devices.
-
- QAudioDeviceInfo::availableDevices(QAudio::AudioOutput).size() = 0 (dummy backend)
-*/
-
-/*!
- \fn QAudioSystemPlugin::QAudioSystemPlugin(QObject* parent)
-
- Constructs a new audio plugin with \a parent.
- This is invoked automatically by the Q_PLUGIN_METADATA() macro.
-*/
-
-QAudioSystemPlugin::QAudioSystemPlugin(QObject* parent) :
- QObject(parent)
-{}
-
-/*!
- \fn QAudioSystemPlugin::~QAudioSystemPlugin()
-
- Destroys the audio plugin.
- You never have to call this explicitly. Qt destroys a plugin automatically when it is no longer used.
-*/
-
-QAudioSystemPlugin::~QAudioSystemPlugin()
-{}
-
-/*!
- \fn QList<QByteArray> QAudioSystemPlugin::availableDevices(QAudio::Mode mode) const
- Returns a list of available audio devices for \a mode
-*/
-
-/*!
- \fn QAbstractAudioInput* QAudioSystemPlugin::createInput(const QByteArray& device)
- Returns a pointer to a QAbstractAudioInput created using \a device identifier
-*/
-
-/*!
- \fn QAbstractAudioOutput* QAudioSystemPlugin::createOutput(const QByteArray& device)
- Returns a pointer to a QAbstractAudioOutput created using \a device identifier
-
-*/
-
-/*!
- \fn QAbstractAudioDeviceInfo* QAudioSystemPlugin::createDeviceInfo(const QByteArray& device, QAudio::Mode mode)
- Returns a pointer to a QAbstractAudioDeviceInfo created using \a device and \a mode
-
-*/
-
-
-QT_END_NAMESPACE
-
-#include "moc_qaudiosystemplugin.cpp"
diff --git a/src/multimedia/audio/qaudiosystemplugin.h b/src/multimedia/audio/qaudiosystemplugin.h
deleted file mode 100644
index 18079e9d9..000000000
--- a/src/multimedia/audio/qaudiosystemplugin.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 QAUDIOSYSTEMPLUGIN_H
-#define QAUDIOSYSTEMPLUGIN_H
-
-#include <QtCore/qstring.h>
-#include <QtCore/qplugin.h>
-
-#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qmultimedia.h>
-
-#include <QtMultimedia/qaudioformat.h>
-#include <QtMultimedia/qaudiodeviceinfo.h>
-#include <QtMultimedia/qaudiosystem.h>
-
-QT_BEGIN_NAMESPACE
-
-struct Q_MULTIMEDIA_EXPORT QAudioSystemFactoryInterface
-{
- virtual QList<QByteArray> availableDevices(QAudio::Mode) const = 0;
- virtual QAbstractAudioInput* createInput(const QByteArray& device) = 0;
- virtual QAbstractAudioOutput* createOutput(const QByteArray& device) = 0;
- virtual QAbstractAudioDeviceInfo* createDeviceInfo(const QByteArray& device, QAudio::Mode mode) = 0;
- virtual ~QAudioSystemFactoryInterface();
-};
-
-#define QAudioSystemFactoryInterface_iid \
- "org.qt-project.qt.audiosystemfactory/5.0"
-Q_DECLARE_INTERFACE(QAudioSystemFactoryInterface, QAudioSystemFactoryInterface_iid)
-
-class Q_MULTIMEDIA_EXPORT QAudioSystemPlugin : public QObject, public QAudioSystemFactoryInterface
-{
- Q_OBJECT
- Q_INTERFACES(QAudioSystemFactoryInterface)
-
-public:
- explicit QAudioSystemPlugin(QObject *parent = nullptr);
- ~QAudioSystemPlugin();
-
- QList<QByteArray> availableDevices(QAudio::Mode) const override = 0;
- QAbstractAudioInput* createInput(const QByteArray& device) override = 0;
- QAbstractAudioOutput* createOutput(const QByteArray& device) override = 0;
- QAbstractAudioDeviceInfo* createDeviceInfo(const QByteArray& device, QAudio::Mode mode) override = 0;
-};
-
-QT_END_NAMESPACE
-
-#endif // QAUDIOSYSTEMPLUGIN_H
diff --git a/src/multimedia/audio/qaudiosystempluginext_p.h b/src/multimedia/audio/qaudiosystempluginext_p.h
deleted file mode 100644
index 6493b7f77..000000000
--- a/src/multimedia/audio/qaudiosystempluginext_p.h
+++ /dev/null
@@ -1,71 +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 QAUDIOSYSTEMPLUGINEXT_P_H
-#define QAUDIOSYSTEMPLUGINEXT_P_H
-
-#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qaudio.h>
-#include <QtCore/qplugin.h>
-
-QT_BEGIN_NAMESPACE
-
-//
-// 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.
-//
-
-struct Q_MULTIMEDIA_EXPORT QAudioSystemPluginExtension
-{
- virtual QByteArray defaultDevice(QAudio::Mode) const = 0;
- virtual ~QAudioSystemPluginExtension();
-};
-
-#define QAudioSystemPluginExtension_iid "org.qt-project.qt.audiosystempluginextension"
-Q_DECLARE_INTERFACE(QAudioSystemPluginExtension, QAudioSystemPluginExtension_iid)
-
-QT_END_NAMESPACE
-
-#endif // QAUDIOSYSTEMPLUGINEXT_P_H
diff --git a/src/multimedia/audio/qsamplecache_p.cpp b/src/multimedia/audio/qsamplecache_p.cpp
index b293946cc..805ab534e 100644
--- a/src/multimedia/audio/qsamplecache_p.cpp
+++ b/src/multimedia/audio/qsamplecache_p.cpp
@@ -1,51 +1,17 @@
-/****************************************************************************
-**
-** 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_p.h"
+#include "qwavedecoder.h"
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>
#include <QtCore/QDebug>
-//#define QT_SAMPLECACHE_DEBUG
+#include <QtCore/qloggingcategory.h>
+
+Q_STATIC_LOGGING_CATEGORY(qLcSampleCache, "qt.multimedia.samplecache")
#include <mutex>
@@ -105,8 +71,6 @@ QSampleCache::QSampleCache(QObject *parent)
, m_loadingRefCount(0)
{
m_loadingThread.setObjectName(QLatin1String("QSampleCache::LoadingThread"));
- connect(&m_loadingThread, SIGNAL(finished()), this, SIGNAL(isLoadingChanged()));
- connect(&m_loadingThread, SIGNAL(started()), this, SIGNAL(isLoadingChanged()));
}
QNetworkAccessManager& QSampleCache::networkAccessManager()
@@ -166,22 +130,25 @@ 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();
- if (!m_loadingThread.isRunning())
- m_loadingThread.start();
-
-#ifdef QT_SAMPLECACHE_DEBUG
- qDebug() << "QSampleCache: request sample [" << url << "]";
-#endif
+ qCDebug(qLcSampleCache) << "QSampleCache: request sample [" << url << "]";
std::unique_lock<QRecursiveMutex> locker(m_mutex);
QMap<QUrl, QSample*>::iterator it = m_samples.find(url);
QSample* sample;
if (it == m_samples.end()) {
+ 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;
}
@@ -198,9 +165,7 @@ void QSampleCache::setCapacity(qint64 capacity)
const std::lock_guard<QRecursiveMutex> locker(m_mutex);
if (m_capacity == capacity)
return;
-#ifdef QT_SAMPLECACHE_DEBUG
- qDebug() << "QSampleCache: capacity changes from " << m_capacity << "to " << capacity;
-#endif
+ qCDebug(qLcSampleCache) << "QSampleCache: capacity changes from " << m_capacity << "to " << capacity;
if (m_capacity > 0 && capacity <= 0) { //memory management strategy changed
for (QMap<QUrl, QSample*>::iterator it = m_samples.begin(); it != m_samples.end();) {
QSample* sample = *it;
@@ -233,9 +198,7 @@ void QSampleCache::refresh(qint64 usageChange)
if (m_capacity <= 0 || m_usage <= m_capacity)
return;
-#ifdef QT_SAMPLECACHE_DEBUG
qint64 recoveredSize = 0;
-#endif
//free unused samples to keep usage under capacity limit.
for (QMap<QUrl, QSample*>::iterator it = m_samples.begin(); it != m_samples.end();) {
@@ -244,20 +207,16 @@ void QSampleCache::refresh(qint64 usageChange)
++it;
continue;
}
-#ifdef QT_SAMPLECACHE_DEBUG
recoveredSize += sample->m_soundData.size();
-#endif
unloadSample(sample);
it = m_samples.erase(it);
if (m_usage <= m_capacity)
return;
}
-#ifdef QT_SAMPLECACHE_DEBUG
- qDebug() << "QSampleCache: refresh(" << usageChange
+ qCDebug(qLcSampleCache) << "QSampleCache: refresh(" << usageChange
<< ") recovered size =" << recoveredSize
<< "new usage =" << m_usage;
-#endif
if (m_usage > m_capacity)
qWarning() << "QSampleCache: usage[" << m_usage << " out of limit[" << m_capacity << "]";
@@ -278,9 +237,7 @@ QSample::~QSample()
m_parent->removeUnreferencedSample(this);
QMutexLocker locker(&m_mutex);
-#ifdef QT_SAMPLECACHE_DEBUG
- qDebug() << "~QSample" << this << ": deleted [" << m_url << "]" << QThread::currentThread();
-#endif
+ qCDebug(qLcSampleCache) << "~QSample" << this << ": deleted [" << m_url << "]" << QThread::currentThread();
cleanup();
}
@@ -315,9 +272,7 @@ bool QSampleCache::notifyUnreferencedSample(QSample* sample)
void QSample::release()
{
QMutexLocker locker(&m_mutex);
-#ifdef QT_SAMPLECACHE_DEBUG
- qDebug() << "Sample:: release" << this << QThread::currentThread() << m_ref;
-#endif
+ qCDebug(qLcSampleCache) << "Sample:: release" << this << QThread::currentThread() << m_ref;
if (--m_ref == 0) {
locker.unlock();
m_parent->notifyUnreferencedSample(this);
@@ -328,10 +283,15 @@ void QSample::release()
// must be called locked.
void QSample::cleanup()
{
- if (m_waveDecoder)
+ qCDebug(qLcSampleCache) << "QSample: cleanup";
+ 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;
@@ -346,14 +306,14 @@ void QSample::addRef()
// Called in loading thread
void QSample::readSample()
{
+#if QT_CONFIG(thread)
Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String("QSampleCache::LoadingThread"));
- QMutexLocker m(&m_mutex);
-#ifdef QT_SAMPLECACHE_DEBUG
- qDebug() << "QSample: readSample";
#endif
+ QMutexLocker m(&m_mutex);
qint64 read = m_waveDecoder->read(m_soundData.data() + m_sampleReadLength,
qMin(m_waveDecoder->bytesAvailable(),
qint64(m_waveDecoder->size() - m_sampleReadLength)));
+ qCDebug(qLcSampleCache) << "QSample: readSample" << read;
if (read > 0)
m_sampleReadLength += read;
if (m_sampleReadLength < m_waveDecoder->size())
@@ -365,16 +325,17 @@ void QSample::readSample()
// Called in loading thread
void QSample::decoderReady()
{
+#if QT_CONFIG(thread)
Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String("QSampleCache::LoadingThread"));
- QMutexLocker m(&m_mutex);
-#ifdef QT_SAMPLECACHE_DEBUG
- qDebug() << "QSample: decoder ready";
#endif
+ QMutexLocker m(&m_mutex);
+ qCDebug(qLcSampleCache) << "QSample: decoder ready";
m_parent->refresh(m_waveDecoder->size());
m_soundData.resize(m_waveDecoder->size());
m_sampleReadLength = 0;
qint64 read = m_waveDecoder->read(m_soundData.data(), m_waveDecoder->size());
+ qCDebug(qLcSampleCache) << " bytes read" << read;
if (read > 0)
m_sampleReadLength += read;
if (m_sampleReadLength >= m_waveDecoder->size())
@@ -392,26 +353,42 @@ 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"));
-#ifdef QT_SAMPLECACHE_DEBUG
- qDebug() << "QSample: load [" << m_url << "]";
#endif
- m_stream = m_parent->networkAccessManager().get(QNetworkRequest(m_url));
- connect(m_stream, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), SLOT(decoderError()));
+ qCDebug(qLcSampleCache) << "QSample: load [" << m_url << "]";
+ QNetworkReply *reply = m_parent->networkAccessManager().get(QNetworkRequest(m_url));
+ m_stream = reply;
+ connect(reply, &QNetworkReply::errorOccurred, this, &QSample::loadingError);
m_waveDecoder = new QWaveDecoder(m_stream);
- connect(m_waveDecoder, SIGNAL(formatKnown()), SLOT(decoderReady()));
- connect(m_waveDecoder, SIGNAL(parsingError()), SLOT(decoderError()));
- connect(m_waveDecoder, SIGNAL(readyRead()), SLOT(readSample()));
+ connect(m_waveDecoder, &QWaveDecoder::formatKnown, this, &QSample::decoderReady);
+ connect(m_waveDecoder, &QWaveDecoder::parsingError, this, &QSample::decoderError);
+ connect(m_waveDecoder, &QIODevice::readyRead, this, &QSample::readSample);
+
+ 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"));
- QMutexLocker m(&m_mutex);
-#ifdef QT_SAMPLECACHE_DEBUG
- qDebug() << "QSample: decoder error";
#endif
+ QMutexLocker m(&m_mutex);
+ qCDebug(qLcSampleCache) << "QSample: decoder error";
cleanup();
m_state = QSample::Error;
qobject_cast<QSampleCache*>(m_parent)->loadingRelease();
@@ -421,11 +398,11 @@ 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"));
-#ifdef QT_SAMPLECACHE_DEBUG
- qDebug() << "QSample: load ready";
#endif
m_audioFormat = m_waveDecoder->audioFormat();
+ qCDebug(qLcSampleCache) << "QSample: load ready format:" << m_audioFormat;
cleanup();
m_state = QSample::Ready;
qobject_cast<QSampleCache*>(m_parent)->loadingRelease();
diff --git a/src/multimedia/audio/qsamplecache_p.h b/src/multimedia/audio/qsamplecache_p.h
index 4c2384743..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();
@@ -136,9 +102,6 @@ public:
bool isLoading() const;
bool isCached(const QUrl& url) const;
-Q_SIGNALS:
- void isLoadingChanged();
-
private:
QMap<QUrl, QSample*> m_samples;
QSet<QSample*> m_staleSamples;
diff --git a/src/multimedia/audio/qsound.cpp b/src/multimedia/audio/qsound.cpp
deleted file mode 100644
index cbd336457..000000000
--- a/src/multimedia/audio/qsound.cpp
+++ /dev/null
@@ -1,244 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui 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$
-**
-****************************************************************************/
-
-#include "qsound.h"
-#include "qsoundeffect.h"
-#include "qcoreapplication.h"
-
-
-/*!
- \class QSound
- \brief The QSound class provides a method to play .wav sound files.
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_audio
-
- Qt provides the most commonly required audio operation in GUI
- applications: asynchronously playing a sound file. This is most
- easily accomplished using the static play() function:
-
- \snippet multimedia-snippets/qsound.cpp 0
-
- Alternatively, create a QSound object from the sound file first
- and then call the play() slot:
-
- \snippet multimedia-snippets/qsound.cpp 1
-
- In both cases, the file may either be a local file or in a
- \l{The Qt Resource System}{resource}.
-
- Once created a QSound object can be queried for its fileName() and
- total number of loops() (i.e. the number of times the sound will
- play). The number of repetitions can be altered using the
- setLoops() function. While playing the sound, the loopsRemaining()
- function returns the remaining number of repetitions. Use the
- isFinished() function to determine whether the sound has finished
- playing.
-
- Sounds played using a QSound object may use more memory than the
- static play() function, but it may also play more immediately
- (depending on the underlying platform audio facilities).
-
- If you require finer control over playing sounds, consider the
- \l QSoundEffect or \l QAudioOutput classes.
-
- \sa QSoundEffect
-*/
-
-/*!
- \enum QSound::Loop
-
- \value Infinite Can be used as a parameter to \l setLoops() to loop infinitely.
-*/
-
-
-/*!
- Plays the sound stored in the file specified by the given \a filename.
-
- The file can either be a local file or in a \l{The Qt Resource System}{resource}.
-
- \sa stop(), loopsRemaining(), isFinished()
-*/
-void QSound::play(const QString &filename)
-{
- // Object destruction is generally handled via deleteOnComplete
- // Unexpected cases will be handled via parenting of QSound objects to qApp
- QSound *sound = new QSound(filename, qApp);
- sound->connect(sound->m_soundEffect, &QSoundEffect::playingChanged,
- sound, &QSound::deleteOnComplete);
- sound->play();
-}
-
-/*!
- Constructs a QSound object from the file specified by the given \a
- filename and with the given \a parent.
-
- The file can either be a local file or in a \l{The Qt Resource System}{resource}.
-
- \sa play()
-*/
-QSound::QSound(const QString &filename, QObject *parent)
- : QObject(parent)
-{
- m_soundEffect = new QSoundEffect(this);
- const bool isQrc = filename.startsWith(QLatin1String("qrc:"), Qt::CaseInsensitive);
- const QUrl url = isQrc ? QUrl(filename) : QUrl::fromLocalFile(filename);
- m_soundEffect->setSource(url);
-}
-
-/*!
- Destroys this sound object. If the sound is not finished playing,
- the stop() function is called before the sound object is
- destroyed.
-
- \sa stop(), isFinished()
-*/
-QSound::~QSound()
-{
- if (!isFinished())
- stop();
-}
-
-/*!
- Returns true if the sound has finished playing; otherwise returns false.
-*/
-bool QSound::isFinished() const
-{
- return !m_soundEffect->isPlaying();
-}
-
-/*!
- \overload
-
- Starts playing the sound specified by this QSound object.
-
- The function returns immediately. Depending on the platform audio
- facilities, other sounds may stop or be mixed with the new
- sound. The sound can be played again at any time, possibly mixing
- or replacing previous plays of the sound.
-
- \sa fileName()
-*/
-void QSound::play()
-{
- m_soundEffect->play();
-}
-
-/*!
- Returns the number of times the sound will play.
- Return value of \c QSound::Infinite indicates infinite number of loops
-
- \sa loopsRemaining(), setLoops()
-*/
-int QSound::loops() const
-{
- // retain old API value for infinite loops
- int loopCount = m_soundEffect->loopCount();
- if (loopCount == QSoundEffect::Infinite)
- loopCount = Infinite;
-
- return loopCount;
-}
-
-/*!
- Returns the remaining number of times the sound will loop (for all
- positive values this value decreases each time the sound is played).
- Return value of \c QSound::Infinite indicates infinite number of loops
-
- \sa loops(), isFinished()
-*/
-int QSound::loopsRemaining() const
-{
- // retain old API value for infinite loops
- int loopsRemaining = m_soundEffect->loopsRemaining();
- if (loopsRemaining == QSoundEffect::Infinite)
- loopsRemaining = Infinite;
-
- return loopsRemaining;
-}
-
-/*!
- \fn void QSound::setLoops(int number)
-
- Sets the sound to repeat the given \a number of times when it is
- played.
-
- Note that passing the value \c QSound::Infinite will cause the sound to loop
- indefinitely.
-
- \sa loops()
-*/
-void QSound::setLoops(int n)
-{
- if (n == Infinite)
- n = QSoundEffect::Infinite;
-
- m_soundEffect->setLoopCount(n);
-}
-
-/*!
- Returns the filename associated with this QSound object.
-
- \sa QSound()
-*/
-QString QSound::fileName() const
-{
- return m_soundEffect->source().toLocalFile();
-}
-
-/*!
- Stops the sound playing.
-
- \sa play()
-*/
-void QSound::stop()
-{
- m_soundEffect->stop();
-}
-
-/*!
- \internal
-*/
-void QSound::deleteOnComplete()
-{
- if (!m_soundEffect->isPlaying())
- deleteLater();
-}
-
-#include "moc_qsound.cpp"
diff --git a/src/multimedia/audio/qsound.h b/src/multimedia/audio/qsound.h
deleted file mode 100644
index 972847c37..000000000
--- a/src/multimedia/audio/qsound.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 QSOUND_H
-#define QSOUND_H
-
-#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtCore/qobject.h>
-
-QT_BEGIN_NAMESPACE
-
-class QSoundEffect;
-
-class Q_MULTIMEDIA_EXPORT QSound : public QObject
-{
- Q_OBJECT
-public:
- enum Loop
- {
- Infinite = -1
- };
-
- static void play(const QString &filename);
-
- explicit QSound(const QString &filename, QObject *parent = nullptr);
- ~QSound();
-
- int loops() const;
- int loopsRemaining() const;
- void setLoops(int);
- QString fileName() const;
-
- bool isFinished() const;
-
-public Q_SLOTS:
- void play();
- void stop();
-
-private Q_SLOTS:
- void deleteOnComplete();
-
-private:
- QSoundEffect *m_soundEffect = nullptr;
-};
-
-QT_END_NAMESPACE
-
-
-#endif // QSOUND_H
diff --git a/src/multimedia/audio/qsoundeffect.cpp b/src/multimedia/audio/qsoundeffect.cpp
index 09085dca9..c403648f9 100644
--- a/src/multimedia/audio/qsoundeffect.cpp
+++ b/src/multimedia/audio/qsoundeffect.cpp
@@ -1,53 +1,265 @@
-/****************************************************************************
-**
-** 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"
-
-#if QT_CONFIG(pulseaudio)
-#include "qsoundeffect_pulse_p.h"
-#else
-#include "qsoundeffect_qaudio_p.h"
-#endif
+#include "qsamplecache_p.h"
+#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_STATIC_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:
+ QSoundEffectPrivate(QSoundEffect *q, const QAudioDevice &audioDevice = QAudioDevice());
+ ~QSoundEffectPrivate() override = default;
+
+ qint64 readData(char *data, qint64 len) override;
+ qint64 writeData(const char *data, qint64 len) override;
+ qint64 size() const override {
+ if (m_sample->state() != QSample::Ready)
+ return 0;
+ return m_loopCount == QSoundEffect::Infinite ? 0 : m_loopCount * m_audioBuffer.byteCount();
+ }
+ qint64 bytesAvailable() const override {
+ if (m_sample->state() != QSample::Ready)
+ return 0;
+ 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;
+ }
+ bool atEnd() const override {
+ return m_runningCount == 0;
+ }
+
+ void setLoopsRemaining(int loopsRemaining);
+ void setStatus(QSoundEffect::Status status);
+ void setPlaying(bool playing);
+
+public Q_SLOTS:
+ void sampleReady();
+ void decoderError();
+ void stateChanged(QAudio::State);
+
+public:
+ QSoundEffect *q_ptr;
+ QUrl m_url;
+ int m_loopCount = 1;
+ int m_runningCount = 0;
+ bool m_playing = false;
+ 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;
+ qint64 m_offset = 0;
+ QAudioDevice m_audioDevice;
+};
+
+QSoundEffectPrivate::QSoundEffectPrivate(QSoundEffect *q, const QAudioDevice &audioDevice)
+ : QIODevice(q)
+ , q_ptr(q)
+ , m_audioDevice(audioDevice)
+{
+ open(QIODevice::ReadOnly);
+
+ QPlatformMediaIntegration::instance()->mediaDevices()->prepareAudio();
+}
+
+void QSoundEffectPrivate::sampleReady()
+{
+ if (m_status == QSoundEffect::Error)
+ return;
+
+ qCDebug(qLcSoundEffect) << this << "sampleReady: sample size:" << m_sample->data().size();
+ 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_audioSink->setVolume(m_volume);
+ else
+ m_audioSink->setVolume(0);
+ }
+ m_sampleReady = true;
+ setStatus(QSoundEffect::Ready);
+
+ if (m_playing && m_audioSink->state() == QAudio::StoppedState) {
+ qCDebug(qLcSoundEffect) << this << "starting playback on audiooutput";
+ m_audioSink->start(this);
+ }
+}
+
+void QSoundEffectPrivate::decoderError()
+{
+ qWarning("QSoundEffect(qaudio): Error decoding source %ls", qUtf16Printable(m_url.toString()));
+ disconnect(m_sample.get(), &QSample::ready, this, &QSoundEffectPrivate::sampleReady);
+ disconnect(m_sample.get(), &QSample::error, this, &QSoundEffectPrivate::decoderError);
+ m_playing = false;
+ setStatus(QSoundEffect::Error);
+}
+
+void QSoundEffectPrivate::stateChanged(QAudio::State state)
+{
+ qCDebug(qLcSoundEffect) << this << "stateChanged " << state;
+ if ((state == QAudio::IdleState && m_runningCount == 0) || state == QAudio::StoppedState)
+ q_ptr->stop();
+}
+
+qint64 QSoundEffectPrivate::readData(char *data, qint64 len)
+{
+ qCDebug(qLcSoundEffect) << this << "readData" << len << m_runningCount;
+ if (!len)
+ return 0;
+ if (m_sample->state() != QSample::Ready)
+ return 0;
+ if (m_runningCount == 0 || !m_playing)
+ return 0;
+
+ qint64 bytesWritten = 0;
+
+ const int sampleSize = m_audioBuffer.byteCount();
+ const char *sampleData = m_audioBuffer.constData<char>();
+
+ while (len && m_runningCount) {
+ int toWrite = qMin(sampleSize - m_offset, len);
+ memcpy(data, sampleData + m_offset, toWrite);
+ bytesWritten += toWrite;
+ data += toWrite;
+ len -= toWrite;
+ m_offset += toWrite;
+ if (m_offset >= sampleSize) {
+ if (m_runningCount > 0 && m_runningCount != QSoundEffect::Infinite)
+ setLoopsRemaining(m_runningCount - 1);
+ m_offset = 0;
+ }
+ }
+
+ return bytesWritten;
+}
+
+qint64 QSoundEffectPrivate::writeData(const char *data, qint64 len)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(len);
+ return 0;
+}
+
+void QSoundEffectPrivate::setLoopsRemaining(int loopsRemaining)
+{
+ if (m_runningCount == loopsRemaining)
+ return;
+ qCDebug(qLcSoundEffect) << this << "setLoopsRemaining " << loopsRemaining;
+ m_runningCount = loopsRemaining;
+ emit q_ptr->loopsRemainingChanged();
+}
+
+void QSoundEffectPrivate::setStatus(QSoundEffect::Status status)
+{
+ qCDebug(qLcSoundEffect) << this << "setStatus" << status;
+ if (m_status == status)
+ return;
+ bool oldLoaded = q_ptr->isLoaded();
+ m_status = status;
+ emit q_ptr->statusChanged();
+ if (oldLoaded != q_ptr->isLoaded())
+ emit q_ptr->loadedChanged();
+}
+
+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_audioSink && playing)
+ m_audioSink->start(this);
+
+ emit q_ptr->playingChanged();
+}
+
/*!
\class QSoundEffect
\brief The QSoundEffect class provides a way to play low latency sound effects.
@@ -94,8 +306,8 @@ QT_BEGIN_NAMESPACE
a generally lower latency way, and is suitable for "feedback" type sounds in
response to user actions (e.g. virtual keyboard sounds, positive or negative
feedback for popup dialogs, or game sounds). If low latency is not important,
- consider using the MediaPlayer or Audio types instead, since they support a wider
- variety of media formats and are less resource intensive.
+ consider using the MediaPlayer type instead, since it support a wider
+ variety of media formats and is less resource intensive.
Typically the sound effect should be reused, which allows all the
parsing and preparation to be done ahead of time, and only triggered
@@ -111,33 +323,20 @@ QT_BEGIN_NAMESPACE
sound effects.
*/
-static QSoundEffectPrivate *initPrivate(QSoundEffect *self, QSoundEffectPrivate *d)
-{
- QObject::connect(d, &QSoundEffectPrivate::loopsRemainingChanged, self, &QSoundEffect::loopsRemainingChanged);
- QObject::connect(d, &QSoundEffectPrivate::volumeChanged, self, &QSoundEffect::volumeChanged);
- QObject::connect(d, &QSoundEffectPrivate::mutedChanged, self, &QSoundEffect::mutedChanged);
- QObject::connect(d, &QSoundEffectPrivate::loadedChanged, self, &QSoundEffect::loadedChanged);
- QObject::connect(d, &QSoundEffectPrivate::playingChanged, self, &QSoundEffect::playingChanged);
- QObject::connect(d, &QSoundEffectPrivate::statusChanged, self, &QSoundEffect::statusChanged);
- QObject::connect(d, &QSoundEffectPrivate::categoryChanged, self, &QSoundEffect::categoryChanged);
-
- return d;
-}
/*!
Creates a QSoundEffect with the given \a parent.
*/
QSoundEffect::QSoundEffect(QObject *parent)
- : QObject(parent)
- , d(initPrivate(this, new QSoundEffectPrivate(this)))
+ : QSoundEffect(QAudioDevice(), parent)
{
}
/*!
Creates a QSoundEffect with the given \a audioDevice and \a parent.
*/
-QSoundEffect::QSoundEffect(const QAudioDeviceInfo &audioDevice, QObject *parent)
+QSoundEffect::QSoundEffect(const QAudioDevice &audioDevice, QObject *parent)
: QObject(parent)
- , d(initPrivate(this, new QSoundEffectPrivate(audioDevice, this)))
+ , d(new QSoundEffectPrivate(this, audioDevice))
{
}
@@ -146,7 +345,10 @@ QSoundEffect::QSoundEffect(const QAudioDeviceInfo &audioDevice, QObject *parent)
*/
QSoundEffect::~QSoundEffect()
{
- d->release();
+ stop();
+ d->m_audioSink.reset();
+ d->m_sample.reset();
+ delete d;
}
/*!
@@ -156,7 +358,15 @@ QSoundEffect::~QSoundEffect()
*/
QStringList QSoundEffect::supportedMimeTypes()
{
- return QSoundEffectPrivate::supportedMimeTypes();
+ // Only return supported mime types if we have a audio device available
+ const QList<QAudioDevice> devices = QMediaDevices::audioOutputs();
+ if (devices.isEmpty())
+ return QStringList();
+
+ return QStringList() << QLatin1String("audio/x-wav")
+ << QLatin1String("audio/wav")
+ << QLatin1String("audio/wave")
+ << QLatin1String("audio/x-pn-wav");
}
/*!
@@ -178,16 +388,62 @@ QStringList QSoundEffect::supportedMimeTypes()
/*! Returns the URL of the current source to play */
QUrl QSoundEffect::source() const
{
- return d->source();
+ return d->m_url;
}
/*! Set the current URL to play to \a url. */
void QSoundEffect::setSource(const QUrl &url)
{
- if (d->source() == url)
+ qCDebug(qLcSoundEffect) << this << "setSource current=" << d->m_url << ", to=" << url;
+ if (d->m_url == url)
return;
- d->setSource(url);
+ Q_ASSERT(d->m_url != url);
+
+ stop();
+
+ d->m_url = url;
+
+ d->m_sampleReady = false;
+
+ if (url.isEmpty()) {
+ d->setStatus(QSoundEffect::Null);
+ return;
+ }
+
+ if (!url.isValid()) {
+ d->setStatus(QSoundEffect::Error);
+ return;
+ }
+
+ if (d->m_sample) {
+ if (!d->m_sampleReady) {
+ disconnect(d->m_sample.get(), &QSample::error, d, &QSoundEffectPrivate::decoderError);
+ disconnect(d->m_sample.get(), &QSample::ready, d, &QSoundEffectPrivate::sampleReady);
+ }
+ d->m_sample.reset();
+ }
+
+ 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.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:
+ d->sampleReady();
+ break;
+ case QSample::Error:
+ d->decoderError();
+ break;
+ default:
+ break;
+ }
emit sourceChanged();
}
@@ -218,7 +474,7 @@ void QSoundEffect::setSource(const QUrl &url)
*/
int QSoundEffect::loopCount() const
{
- return d->loopCount();
+ return d->m_loopCount;
}
/*!
@@ -245,14 +501,35 @@ void QSoundEffect::setLoopCount(int loopCount)
}
if (loopCount == 0)
loopCount = 1;
- if (d->loopCount() == loopCount)
+ if (d->m_loopCount == loopCount)
return;
- d->setLoopCount(loopCount);
+ d->m_loopCount = loopCount;
+ if (d->m_playing)
+ d->setLoopsRemaining(loopCount);
emit loopCountChanged();
}
/*!
+ \property QSoundEffect::audioDevice
+
+ Returns the QAudioDevice instance.
+*/
+QAudioDevice QSoundEffect::audioDevice()
+{
+ return d->m_audioDevice;
+}
+
+void QSoundEffect::setAudioDevice(const QAudioDevice &device)
+{
+ if (d->m_audioDevice == device)
+ return;
+ // ### recreate the QAudioSink if needed
+ d->m_audioDevice = device;
+ emit audioDeviceChanged();
+}
+
+/*!
\qmlproperty int QtMultimedia::SoundEffect::loopsRemaining
This property contains the number of loops remaining before the sound effect
@@ -266,7 +543,7 @@ void QSoundEffect::setLoopCount(int loopCount)
*/
int QSoundEffect::loopsRemaining() const
{
- return d->loopsRemaining();
+ return d->m_runningCount;
}
@@ -280,9 +557,9 @@ int QSoundEffect::loopsRemaining() const
The default volume is \c 1.0.
- UI volume controls should usually be scaled nonlinearly. For example, using a logarithmic scale
+ 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 {QtMultimedia::QtMultimedia::convertVolume()}{QtMultimedia.convertVolume()}
+ from a volume control. See \l {QtAudio::convertVolume()}{convertVolume()}
for more details.
*/
/*!
@@ -294,9 +571,12 @@ int QSoundEffect::loopsRemaining() const
/*!
Returns the current volume of this sound effect, from 0.0 (silent) to 1.0 (maximum volume).
*/
-qreal QSoundEffect::volume() const
+float QSoundEffect::volume() const
{
- return d->volume();
+ if (d->m_audioSink && !d->m_muted)
+ return d->m_audioSink->volume();
+
+ return d->m_volume;
}
/*!
@@ -307,17 +587,22 @@ qreal QSoundEffect::volume() const
The default volume is \c 1.0.
- UI volume controls should usually be scaled nonlinearly. For example, using a logarithmic scale
+ 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(qreal volume)
+void QSoundEffect::setVolume(float volume)
{
- volume = qBound(qreal(0.0), volume, qreal(1.0));
- if (qFuzzyCompare(d->volume(), volume))
+ volume = qBound(0.0f, volume, 1.0f);
+ if (d->m_volume == volume)
return;
- d->setVolume(volume);
+ d->m_volume = volume;
+
+ if (d->m_audioSink && !d->m_muted)
+ d->m_audioSink->setVolume(volume);
+
+ emit volumeChanged();
}
/*!
@@ -335,7 +620,7 @@ void QSoundEffect::setVolume(qreal volume)
/*! Returns whether this sound effect is muted */
bool QSoundEffect::isMuted() const
{
- return d->isMuted();
+ return d->m_muted;
}
/*!
@@ -347,10 +632,16 @@ bool QSoundEffect::isMuted() const
*/
void QSoundEffect::setMuted(bool muted)
{
- if (d->isMuted() == muted)
+ if (d->m_muted == muted)
return;
- d->setMuted(muted);
+ 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();
}
/*!
@@ -365,7 +656,7 @@ void QSoundEffect::setMuted(bool muted)
*/
bool QSoundEffect::isLoaded() const
{
- return d->isLoaded();
+ return d->m_status == QSoundEffect::Ready;
}
/*!
@@ -386,7 +677,14 @@ bool QSoundEffect::isLoaded() const
*/
void QSoundEffect::play()
{
- d->play();
+ d->m_offset = 0;
+ d->setLoopsRemaining(d->m_loopCount);
+ qCDebug(qLcSoundEffect) << this << "play" << d->m_loopCount << d->m_runningCount;
+ if (d->m_status == QSoundEffect::Null || d->m_status == QSoundEffect::Error) {
+ d->setStatus(QSoundEffect::Null);
+ return;
+ }
+ d->setPlaying(true);
}
/*!
@@ -403,7 +701,7 @@ void QSoundEffect::play()
/*! Returns true if the sound effect is currently playing, or false otherwise */
bool QSoundEffect::isPlaying() const
{
- return d->isPlaying();
+ return d->m_playing;
}
/*!
@@ -443,72 +741,9 @@ bool QSoundEffect::isPlaying() const
*/
QSoundEffect::Status QSoundEffect::status() const
{
- return d->status();
-}
-
-/*!
- \qmlproperty string QtMultimedia::SoundEffect::category
-
- This property contains the \e category of this sound effect.
-
- Some platforms can perform different audio routing
- for different categories, or may allow the user to
- set different volume levels for different categories.
-
- This setting will be ignored on platforms that do not
- support audio categories.
-*/
-/*!
- \property QSoundEffect::category
-
- This property contains the \e category of this sound effect.
-
- Some platforms can perform different audio routing
- for different categories, or may allow the user to
- set different volume levels for different categories.
-
- This setting will be ignored on platforms that do not
- support audio categories.
-*/
-/*!
- Returns the current \e category for this sound effect.
-
- Some platforms can perform different audio routing
- for different categories, or may allow the user to
- set different volume levels for different categories.
-
- This setting will be ignored on platforms that do not
- support audio categories.
-
- \sa setCategory()
-*/
-QString QSoundEffect::category() const
-{
- return d->category();
-}
-
-/*!
- Sets the \e category of this sound effect to \a category.
-
- Some platforms can perform different audio routing
- for different categories, or may allow the user to
- set different volume levels for different categories.
-
- This setting will be ignored on platforms that do not
- support audio categories.
-
- If this setting is changed while a sound effect is playing
- it will only take effect when the sound effect has stopped
- playing.
-
- \sa category()
- */
-void QSoundEffect::setCategory(const QString &category)
-{
- d->setCategory(category);
+ return d->m_status;
}
-
/*!
\qmlmethod QtMultimedia::SoundEffect::stop()
@@ -523,7 +758,12 @@ void QSoundEffect::setCategory(const QString &category)
*/
void QSoundEffect::stop()
{
- d->stop();
+ if (!d->m_playing)
+ return;
+ qCDebug(qLcSoundEffect) << "stop()";
+ d->m_offset = 0;
+
+ d->setPlaying(false);
}
/* Signals */
@@ -537,8 +777,6 @@ void QSoundEffect::stop()
\qmlsignal QtMultimedia::SoundEffect::sourceChanged()
The \c sourceChanged signal is emitted when the source has been changed.
-
- The corresponding handler is \c onSourceChanged.
*/
/*!
\fn void QSoundEffect::loadedChanged()
@@ -549,8 +787,6 @@ void QSoundEffect::stop()
\qmlsignal QtMultimedia::SoundEffect::loadedChanged()
The \c loadedChanged signal is emitted when the loading state has changed.
-
- The corresponding handler is \c onLoadedChanged.
*/
/*!
@@ -562,8 +798,6 @@ void QSoundEffect::stop()
\qmlsignal QtMultimedia::SoundEffect::loopCountChanged()
The \c loopCountChanged signal is emitted when the initial number of loops has changed.
-
- The corresponding handler is \c onLoopCountChanged.
*/
/*!
@@ -575,8 +809,6 @@ void QSoundEffect::stop()
\qmlsignal QtMultimedia::SoundEffect::loopsRemainingChanged()
The \c loopsRemainingChanged signal is emitted when the remaining number of loops has changed.
-
- The corresponding handler is \c onLoopsRemainingChanged.
*/
/*!
@@ -588,8 +820,6 @@ void QSoundEffect::stop()
\qmlsignal QtMultimedia::SoundEffect::volumeChanged()
The \c volumeChanged signal is emitted when the volume has changed.
-
- The corresponding handler is \c onVolumeChanged.
*/
/*!
@@ -601,8 +831,6 @@ void QSoundEffect::stop()
\qmlsignal QtMultimedia::SoundEffect::mutedChanged()
The \c mutedChanged signal is emitted when the mute state has changed.
-
- The corresponding handler is \c onMutedChanged.
*/
/*!
@@ -614,8 +842,6 @@ void QSoundEffect::stop()
\qmlsignal QtMultimedia::SoundEffect::playingChanged()
The \c playingChanged signal is emitted when the playing property has changed.
-
- The corresponding handler is \c onPlayingChanged.
*/
/*!
@@ -627,24 +853,8 @@ void QSoundEffect::stop()
\qmlsignal QtMultimedia::SoundEffect::statusChanged()
The \c statusChanged signal is emitted when the status property has changed.
-
- The corresponding handler is \c onStatusChanged.
*/
-/*!
- \fn void QSoundEffect::categoryChanged()
-
- The \c categoryChanged signal is emitted when the category property has changed.
-*/
-/*!
- \qmlsignal QtMultimedia::SoundEffect::categoryChanged()
-
- The \c categoryChanged signal is emitted when the category property has changed.
-
- The corresponding handler is \c onCategoryChanged.
-*/
-
-
QT_END_NAMESPACE
#include "moc_qsoundeffect.cpp"
diff --git a/src/multimedia/audio/qsoundeffect.h b/src/multimedia/audio/qsoundeffect.h
index 1185afe07..eeafc4c9f 100644
--- a/src/multimedia/audio/qsoundeffect.h
+++ b/src/multimedia/audio/qsoundeffect.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 QSOUNDEFFECT_H
#define QSOUNDEFFECT_H
#include <QtMultimedia/qtmultimediaglobal.h>
+#include <QtMultimedia/qaudio.h>
#include <QtCore/qobject.h>
#include <QtCore/qurl.h>
#include <QtCore/qstringlist.h>
@@ -50,7 +15,7 @@ QT_BEGIN_NAMESPACE
class QSoundEffectPrivate;
-class QAudioDeviceInfo;
+class QAudioDevice;
class Q_MULTIMEDIA_EXPORT QSoundEffect : public QObject
{
@@ -59,19 +24,18 @@ class Q_MULTIMEDIA_EXPORT QSoundEffect : public QObject
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
Q_PROPERTY(int loops READ loopCount WRITE setLoopCount NOTIFY loopCountChanged)
Q_PROPERTY(int loopsRemaining READ loopsRemaining NOTIFY loopsRemainingChanged)
- Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged)
+ Q_PROPERTY(float volume READ volume WRITE setVolume NOTIFY volumeChanged)
Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
Q_PROPERTY(bool playing READ isPlaying NOTIFY playingChanged)
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
- Q_PROPERTY(QString category READ category WRITE setCategory NOTIFY categoryChanged)
- Q_ENUMS(Loop)
- Q_ENUMS(Status)
+ Q_PROPERTY(QAudioDevice audioDevice READ audioDevice WRITE setAudioDevice NOTIFY audioDeviceChanged)
public:
enum Loop
{
Infinite = -2
};
+ Q_ENUM(Loop)
enum Status
{
@@ -80,9 +44,10 @@ public:
Ready,
Error
};
+ Q_ENUM(Status)
explicit QSoundEffect(QObject *parent = nullptr);
- explicit QSoundEffect(const QAudioDeviceInfo &audioDevice, QObject *parent = nullptr);
+ explicit QSoundEffect(const QAudioDevice &audioDevice, QObject *parent = nullptr);
~QSoundEffect();
static QStringList supportedMimeTypes();
@@ -94,8 +59,11 @@ public:
int loopsRemaining() const;
void setLoopCount(int loopCount);
- qreal volume() const;
- void setVolume(qreal volume);
+ QAudioDevice audioDevice();
+ void setAudioDevice(const QAudioDevice &device);
+
+ float volume() const;
+ void setVolume(float volume);
bool isMuted() const;
void setMuted(bool muted);
@@ -105,9 +73,6 @@ public:
bool isPlaying() const;
Status status() const;
- QString category() const;
- void setCategory(const QString &category);
-
Q_SIGNALS:
void sourceChanged();
void loopCountChanged();
@@ -117,7 +82,7 @@ Q_SIGNALS:
void loadedChanged();
void playingChanged();
void statusChanged();
- void categoryChanged();
+ void audioDeviceChanged();
public Q_SLOTS:
void play();
diff --git a/src/multimedia/audio/qsoundeffect_pulse_p.cpp b/src/multimedia/audio/qsoundeffect_pulse_p.cpp
deleted file mode 100644
index 51cdde026..000000000
--- a/src/multimedia/audio/qsoundeffect_pulse_p.cpp
+++ /dev/null
@@ -1,1214 +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 purely as an
-// implementation detail. 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 <QtCore/qcoreapplication.h>
-#include <qaudioformat.h>
-#include <QTime>
-#include <QTimer>
-
-#include "qsoundeffect_pulse_p.h"
-
-#include <private/qaudiohelpers_p.h>
-#include <private/qmediaresourcepolicy_p.h>
-#include <private/qmediaresourceset_p.h>
-#include <QAudioDeviceInfo>
-#include <unistd.h>
-
-//#define QT_PA_DEBUG
-
-QT_BEGIN_NAMESPACE
-
-namespace
-{
-inline 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 = (format.byteOrder() == QAudioFormat::BigEndian);
-
- if (format.sampleType() == QAudioFormat::UnSignedInt) {
- if (format.sampleSize() == 8)
- spec.format = PA_SAMPLE_U8;
- } else if (format.sampleType() == QAudioFormat::SignedInt) {
- if (format.sampleSize() == 16) {
- spec.format = isBigEndian ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
- } else if (format.sampleSize() == 24) {
- spec.format = isBigEndian ? PA_SAMPLE_S24BE : PA_SAMPLE_S24LE;
- } else if (format.sampleSize() == 32) {
- spec.format = isBigEndian ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
- }
- } else if (format.sampleType() == QAudioFormat::Float) {
- if (format.sampleSize() == 32)
- spec.format = isBigEndian ? PA_SAMPLE_FLOAT32BE : PA_SAMPLE_FLOAT32LE;
- }
-
- return spec;
-}
-
-class PulseDaemon : public QObject
-{
- Q_OBJECT
-public:
- PulseDaemon()
- {
- prepare();
- }
-
- ~PulseDaemon()
- {
- release();
- }
-
- inline void ref()
- {
- m_ref.ref();
- prepare();
- }
-
- inline void deref()
- {
- if (!m_ref.deref())
- release();
- }
-
- inline void lock()
- {
- if (m_mainLoop) {
- if (++m_lockCount == 1)
- pa_threaded_mainloop_lock(m_mainLoop);
- }
- }
-
- inline void unlock()
- {
- if (m_mainLoop) {
- if (--m_lockCount == 0)
- pa_threaded_mainloop_unlock(m_mainLoop);
- }
- }
-
- inline pa_context *context() const
- {
- return m_context;
- }
-
-Q_SIGNALS:
- void contextReady();
- void contextFailed();
-
-private Q_SLOTS:
- void onContextFailed()
- {
- release();
-
- // Try to reconnect later
- QTimer::singleShot(30000, this, &PulseDaemon::prepare);
-
- emit contextFailed();
- }
-
- void prepare()
- {
- if (m_prepared)
- return;
-
- m_context = nullptr;
- 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);
- 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");
- unlock();
- pa_threaded_mainloop_free(m_mainLoop);
- m_mainLoop = nullptr;
- onContextFailed();
- return;
- }
-
- pa_context_set_state_callback(m_context, context_state_callback, this);
-
- const QByteArray srvStrEnv = qgetenv("QT_PULSE_SERVER_STRING");
- const char *srvStr = srvStrEnv.isNull() ? nullptr : srvStrEnv.constData();
- pa_context_flags_t flags = qEnvironmentVariableIsSet("QT_PULSE_NOAUTOSPAWN") ? PA_CONTEXT_NOAUTOSPAWN : (pa_context_flags_t)0;
-
- if (pa_context_connect(m_context, srvStr, flags, nullptr) < 0) {
- qWarning("PulseAudioService: pa_context_connect() failed");
- pa_context_unref(m_context);
- unlock();
- pa_threaded_mainloop_free(m_mainLoop);
- m_mainLoop = nullptr;
- m_context = nullptr;
- return;
- }
- unlock();
-
- m_prepared = true;
- }
-
-private:
- void release()
- {
- if (!m_prepared)
- return;
-
- if (m_context) {
- lock();
- pa_context_disconnect(m_context);
- unlock();
- }
-
- if (m_mainLoop) {
- pa_threaded_mainloop_stop(m_mainLoop);
- pa_threaded_mainloop_free(m_mainLoop);
- m_mainLoop = nullptr;
- }
-
- if (m_context) {
- pa_context_unref(m_context);
- m_context = nullptr;
- }
-
- m_prepared = false;
- }
-
- static void context_state_callback(pa_context *c, void *userdata)
- {
- PulseDaemon *self = reinterpret_cast<PulseDaemon*>(userdata);
- switch (pa_context_get_state(c)) {
- case PA_CONTEXT_CONNECTING:
- case PA_CONTEXT_AUTHORIZING:
- case PA_CONTEXT_SETTING_NAME:
- break;
- case PA_CONTEXT_READY:
- QMetaObject::invokeMethod(self, "contextReady", Qt::QueuedConnection);
- break;
- case PA_CONTEXT_FAILED:
- QMetaObject::invokeMethod(self, "onContextFailed", Qt::QueuedConnection);
- break;
- default:
- break;
- }
- }
-
- bool m_prepared = false;
- pa_context *m_context = nullptr;
- pa_threaded_mainloop *m_mainLoop = nullptr;
- pa_mainloop_api *m_mainLoopApi = nullptr;
- uint m_lockCount = 0;
- QAtomicInt m_ref;
-};
-
-}
-
-Q_GLOBAL_STATIC(PulseDaemon, pulseDaemon)
-Q_GLOBAL_STATIC(QSampleCache, sampleCache)
-
-namespace
-{
-class PulseDaemonLocker
-{
-public:
- PulseDaemonLocker()
- {
- pulseDaemon()->lock();
- }
-
- ~PulseDaemonLocker()
- {
- pulseDaemon()->unlock();
- }
-};
-}
-
-class QSoundEffectRef
-{
-public:
- QSoundEffectRef(QSoundEffectPrivate *target)
- : m_target(target)
- {
-#ifdef QT_PA_DEBUG
- qDebug() << "QSoundEffectRef(" << this << ") ctor";
-#endif
- }
-
- QSoundEffectRef *getRef()
- {
-#ifdef QT_PA_DEBUG
- qDebug() << "QSoundEffectRef(" << this << ") getRef";
-#endif
- QMutexLocker locker(&m_mutex);
- m_ref++;
- return this;
- }
-
- void release()
- {
-#ifdef QT_PA_DEBUG
- qDebug() << "QSoundEffectRef(" << this << ") Release";
-#endif
- m_mutex.lock();
- --m_ref;
- if (m_ref == 0) {
- m_mutex.unlock();
-#ifdef QT_PA_DEBUG
- qDebug() << "QSoundEffectRef(" << this << ") deleted";
-#endif
- delete this;
- return;
- }
- m_mutex.unlock();
- }
-
- QSoundEffectPrivate* soundEffect() const
- {
- QMutexLocker locker(&m_mutex);
- return m_target;
- }
-
- void notifyDeleted()
- {
-#ifdef QT_PA_DEBUG
- qDebug() << "QSoundEffectRef(" << this << ") notifyDeleted";
-#endif
- QMutexLocker locker(&m_mutex);
- m_target = nullptr;
- }
-
-private:
- int m_ref = 1;
- mutable QMutex m_mutex;
- QSoundEffectPrivate *m_target = nullptr;
-};
-
-QSoundEffectPrivate::QSoundEffectPrivate(QObject* parent):
- QObject(parent)
-{
- pulseDaemon()->ref();
-
- m_ref = new QSoundEffectRef(this);
- if (pulseDaemon()->context())
- pa_sample_spec_init(&m_pulseSpec);
-
- m_resources = QMediaResourcePolicy::createResourceSet<QMediaPlayerResourceSetInterface>();
- Q_ASSERT(m_resources);
- m_resourcesAvailable = m_resources->isAvailable();
- connect(m_resources, &QMediaPlayerResourceSetInterface::availabilityChanged,
- this, &QSoundEffectPrivate::handleAvailabilityChanged);
-}
-
-QSoundEffectPrivate::QSoundEffectPrivate(const QAudioDeviceInfo &audioDevice, QObject *parent)
- : QSoundEffectPrivate(parent)
-{
- m_sinkName = audioDevice.deviceName();
-}
-
-void QSoundEffectPrivate::handleAvailabilityChanged(bool available)
-{
- m_resourcesAvailable = available;
-#ifdef DEBUG_RESOURCE
- qDebug() << Q_FUNC_INFO << "Resource availability changed " << m_resourcesAvailable;
-#endif
- if (!m_resourcesAvailable)
- stop();
-}
-
-void QSoundEffectPrivate::release()
-{
-#ifdef QT_PA_DEBUG
- qDebug() << this << "release";
-#endif
- m_ref->notifyDeleted();
- unloadPulseStream();
- if (m_sample) {
- m_sample->release();
- m_sample = nullptr;
- }
-
- this->deleteLater();
-}
-
-QString QSoundEffectPrivate::category() const
-{
- return m_category;
-}
-
-void QSoundEffectPrivate::setCategory(const QString &category)
-{
- if (m_category != category) {
- m_category = category;
-
- PulseDaemonLocker locker;
-
- if (m_playing || m_playQueued) {
- // Currently playing, we need to disconnect when
- // playback stops
- m_reloadCategory = true;
- } else if (m_pulseStream) {
- // We have to disconnect and reconnect
- unloadPulseStream();
- createPulseStream();
- } else {
- // Well, next time we create the pulse stream
- // it should be set
- }
-
- emit categoryChanged();
- }
-}
-
-QSoundEffectPrivate::~QSoundEffectPrivate()
-{
- QMediaResourcePolicy::destroyResourceSet(m_resources);
- m_resources = nullptr;
- m_ref->release();
-
- pulseDaemon()->deref();
-}
-
-QStringList QSoundEffectPrivate::supportedMimeTypes()
-{
- QStringList supportedTypes;
- supportedTypes << QLatin1String("audio/x-wav") << QLatin1String("audio/vnd.wave") ;
- return supportedTypes;
-}
-
-QUrl QSoundEffectPrivate::source() const
-{
- return m_source;
-}
-
-void QSoundEffectPrivate::setSource(const QUrl &url)
-{
- Q_ASSERT(m_source != url);
-#ifdef QT_PA_DEBUG
- qDebug() << this << "setSource =" << url;
-#endif
-
- PulseDaemonLocker locker;
-
- // Make sure the stream is empty before loading a new source (otherwise whatever is there will
- // be played before the new source)
- emptyStream();
-
- stop();
-
- if (m_sample) {
- if (!m_sampleReady) {
- disconnect(m_sample, &QSample::error, this, &QSoundEffectPrivate::decoderError);
- disconnect(m_sample, &QSample::ready, this, &QSoundEffectPrivate::sampleReady);
- }
- m_sample->release();
- m_sample = nullptr;
- }
-
- m_source = url;
- m_sampleReady = false;
-
- setLoopsRemaining(0);
- if (m_pulseStream && !pa_stream_is_corked(m_pulseStream)) {
- pa_stream_set_write_callback(m_pulseStream, nullptr, nullptr);
- pa_stream_set_underflow_callback(m_pulseStream, nullptr, nullptr);
- pa_operation *op = pa_stream_cork(m_pulseStream, 1, nullptr, nullptr);
- if (op)
- pa_operation_unref(op);
- else
- qWarning("QSoundEffect(pulseaudio): failed to cork stream");
- }
- setPlaying(false);
-
- if (url.isEmpty()) {
- setStatus(QSoundEffect::Null);
- return;
- }
-
- setStatus(QSoundEffect::Loading);
- m_sample = sampleCache()->requestSample(url);
- connect(m_sample, &QSample::error, this, &QSoundEffectPrivate::decoderError);
- connect(m_sample, &QSample::ready, this, &QSoundEffectPrivate::sampleReady);
- switch(m_sample->state()) {
- case QSample::Ready:
- sampleReady();
- break;
- case QSample::Error:
- decoderError();
- break;
- default:
- break;
- }
-}
-
-int QSoundEffectPrivate::loopCount() const
-{
- return m_loopCount;
-}
-
-int QSoundEffectPrivate::loopsRemaining() const
-{
- return m_runningCount;
-}
-
-void QSoundEffectPrivate::setLoopCount(int loopCount)
-{
- if (loopCount == 0)
- loopCount = 1;
- m_loopCount = loopCount;
- if (m_playing) {
- PulseDaemonLocker locker;
- setLoopsRemaining(loopCount);
- }
-}
-
-qreal QSoundEffectPrivate::volume() const
-{
- QMutexLocker locker(&m_volumeLock);
- return m_volume;
-}
-
-static void volume_stream_flush_callback(pa_stream *s, int success, void *userdata)
-{
- Q_UNUSED(s);
- QSoundEffectRef *ref = reinterpret_cast<QSoundEffectRef *>(userdata);
- QSoundEffectPrivate *self = ref->soundEffect();
- ref->release();
- if (!self)
- return;
-
- if (!success)
- qWarning("QSoundEffect(pulseaudio): failed to drain");
-
- QMetaObject::invokeMethod(self, "prepare", Qt::QueuedConnection);
-}
-
-void QSoundEffectPrivate::setVolume(qreal volume)
-{
- QMutexLocker locker(&m_volumeLock);
-
- if (qFuzzyCompare(m_volume, volume))
- return;
-
- m_volume = qBound(qreal(0), volume, qreal(1));
- locker.unlock();
- if (!m_playing && m_pulseStream)
- pa_stream_flush(m_pulseStream, volume_stream_flush_callback, m_ref->getRef());
- emit volumeChanged();
-}
-
-bool QSoundEffectPrivate::isMuted() const
-{
- QMutexLocker locker(&m_volumeLock);
- return m_muted;
-}
-
-void QSoundEffectPrivate::setMuted(bool muted)
-{
- m_volumeLock.lock();
- m_muted = muted;
- m_volumeLock.unlock();
-
- emit mutedChanged();
-}
-
-bool QSoundEffectPrivate::isLoaded() const
-{
- return m_status == QSoundEffect::Ready;
-}
-
-bool QSoundEffectPrivate::isPlaying() const
-{
- return m_playing;
-}
-
-QSoundEffect::Status QSoundEffectPrivate::status() const
-{
- return m_status;
-}
-
-void QSoundEffectPrivate::setPlaying(bool playing)
-{
-#ifdef QT_PA_DEBUG
- qDebug() << this << "setPlaying(" << playing << ")";
-#endif
- if (m_playing == playing)
- return;
- if (!playing)
- m_playQueued = false;
- m_playing = playing;
- emit playingChanged();
-}
-
-void QSoundEffectPrivate::setStatus(QSoundEffect::Status status)
-{
-#ifdef QT_PA_DEBUG
- qDebug() << this << "setStatus" << status;
-#endif
- if (m_status == status)
- return;
- bool oldLoaded = isLoaded();
- m_status = status;
- emit statusChanged();
- if (oldLoaded != isLoaded())
- emit loadedChanged();
-}
-
-void QSoundEffectPrivate::setLoopsRemaining(int loopsRemaining)
-{
-#ifdef QT_PA_DEBUG
- qDebug() << this << "setLoopsRemaining " << loopsRemaining;
-#endif
- if (m_runningCount == loopsRemaining)
- return;
- m_runningCount = loopsRemaining;
- emit loopsRemainingChanged();
-}
-
-void QSoundEffectPrivate::play()
-{
- if (!m_resourcesAvailable)
- return;
-
- playAvailable();
-}
-
-void QSoundEffectPrivate::playAvailable()
-{
-#ifdef QT_PA_DEBUG
- qDebug() << this << "play";
-#endif
- if (m_status == QSoundEffect::Null || m_status == QSoundEffect::Error || m_playQueued)
- return;
-
- PulseDaemonLocker locker;
-
- if (!m_pulseStream || m_status != QSoundEffect::Ready || m_stopping || m_emptying) {
-#ifdef QT_PA_DEBUG
- qDebug() << this << "play deferred";
-#endif
- m_playQueued = true;
- } else {
- if (m_playing) { //restart playing from the beginning
-#ifdef QT_PA_DEBUG
- qDebug() << this << "restart playing";
-#endif
- setLoopsRemaining(0);
- m_playQueued = true;
- Q_ASSERT(m_pulseStream);
- emptyStream(ReloadSampleWhenDone);
- return;
- }
- setLoopsRemaining(m_loopCount);
- playSample();
- }
-
- setPlaying(true);
-}
-
-void QSoundEffectPrivate::emptyStream(EmptyStreamOptions options)
-{
-#ifdef QT_PA_DEBUG
- qDebug() << this << "emptyStream";
-#endif
- if (!m_pulseStream || m_emptying)
- return;
-
- const bool reloadSample = options.testFlag(ReloadSampleWhenDone);
- pa_stream_success_cb_t flushCompleteCb = reloadSample ? stream_flush_reload_callback
- : stream_flush_callback;
-
- PulseDaemonLocker locker;
-
- m_emptying = true;
- pa_stream_set_write_callback(m_pulseStream, nullptr, nullptr);
- pa_stream_set_underflow_callback(m_pulseStream, nullptr, nullptr);
- pa_operation *op = pa_stream_flush(m_pulseStream, flushCompleteCb, m_ref->getRef());
- if (op)
- pa_operation_unref(op);
- else
- qWarning("QSoundEffect(pulseaudio): failed to flush stream");
-}
-
-void QSoundEffectPrivate::emptyComplete(void *stream, bool reload)
-{
-#ifdef QT_PA_DEBUG
- qDebug() << this << "emptyComplete";
-#endif
-
- PulseDaemonLocker locker;
-
- m_emptying = false;
-
- if ((pa_stream *)stream == m_pulseStream) {
- pa_operation *op = pa_stream_cork(m_pulseStream, 1,
- reload ? stream_cork_callback : nullptr, m_ref->getRef());
- if (op)
- pa_operation_unref(op);
- else
- qWarning("QSoundEffect(pulseaudio): failed to cork stream");
- }
-}
-
-void QSoundEffectPrivate::sampleReady()
-{
- PulseDaemonLocker locker;
-
- // The slot might be called right after a new call to setSource().
- // In this case, the sample has been reset and the slot is being called for the previous sample.
- // Just ignore it.
- if (Q_UNLIKELY(!m_sample || m_sample->state() != QSample::Ready))
- return;
-
-#ifdef QT_PA_DEBUG
- qDebug() << this << "sampleReady";
-#endif
- disconnect(m_sample, &QSample::error, this, &QSoundEffectPrivate::decoderError);
- disconnect(m_sample, &QSample::ready, this, &QSoundEffectPrivate::sampleReady);
- pa_sample_spec newFormatSpec = audioFormatToSampleSpec(m_sample->format());
-
- if (m_pulseStream && !pa_sample_spec_equal(&m_pulseSpec, &newFormatSpec)) {
- unloadPulseStream();
- }
- m_pulseSpec = newFormatSpec;
-
- m_sampleReady = true;
- m_position = 0;
-
- if (m_name.isNull())
- m_name = QString(QLatin1String("QtPulseSample-%1-%2")).arg(::getpid()).arg(quintptr(this)).toUtf8();
-
- if (m_pulseStream && pa_stream_get_state(m_pulseStream) == PA_STREAM_READY) {
-#ifdef QT_PA_DEBUG
- qDebug() << this << "reuse existing pulsestream";
-#endif
- const pa_buffer_attr *bufferAttr = pa_stream_get_buffer_attr(m_pulseStream);
- if (bufferAttr->prebuf > uint32_t(m_sample->data().size())) {
- pa_buffer_attr newBufferAttr;
- newBufferAttr = *bufferAttr;
- newBufferAttr.prebuf = m_sample->data().size();
- pa_operation *op = pa_stream_set_buffer_attr(m_pulseStream, &newBufferAttr, stream_adjust_prebuffer_callback, m_ref->getRef());
- if (op)
- pa_operation_unref(op);
- else
- qWarning("QSoundEffect(pulseaudio): failed to adjust pre-buffer attribute");
- } else {
- streamReady();
- }
- } else if (!m_pulseStream) {
- if (!pulseDaemon()->context() || pa_context_get_state(pulseDaemon()->context()) != PA_CONTEXT_READY) {
- connect(pulseDaemon(), &PulseDaemon::contextReady,
- this, &QSoundEffectPrivate::contextReady);
- return;
- }
- createPulseStream();
- }
-}
-
-void QSoundEffectPrivate::decoderError()
-{
- qWarning("QSoundEffect(pulseaudio): Error decoding source %ls", qUtf16Printable(m_source.toString()));
- disconnect(m_sample, &QSample::error, this, &QSoundEffectPrivate::decoderError);
- bool playingDirty = false;
- if (m_playing) {
- m_playing = false;
- playingDirty = true;
- }
- setStatus(QSoundEffect::Error);
- if (playingDirty)
- emit playingChanged();
-}
-
-void QSoundEffectPrivate::unloadPulseStream()
-{
-#ifdef QT_PA_DEBUG
- qDebug() << this << "unloadPulseStream";
-#endif
- m_sinkInputId = -1;
- PulseDaemonLocker locker;
- if (m_pulseStream) {
- pa_stream_set_state_callback(m_pulseStream, nullptr, nullptr);
- pa_stream_set_write_callback(m_pulseStream, nullptr, nullptr);
- pa_stream_set_underflow_callback(m_pulseStream, nullptr, nullptr);
- pa_stream_disconnect(m_pulseStream);
- pa_stream_unref(m_pulseStream);
- disconnect(pulseDaemon(), &PulseDaemon::contextFailed,
- this, &QSoundEffectPrivate::contextFailed);
- m_pulseStream = nullptr;
- m_reloadCategory = false; // category will be reloaded when we connect anyway
- }
-}
-
-void QSoundEffectPrivate::prepare()
-{
- if (!m_pulseStream || !m_sampleReady)
- return;
- PulseDaemonLocker locker;
-
- if (pa_stream_get_state(m_pulseStream) != PA_STREAM_READY)
- return;
-
- pa_stream_set_write_callback(m_pulseStream, stream_write_callback, this);
- pa_stream_set_underflow_callback(m_pulseStream, stream_underrun_callback, this);
- m_stopping = false;
- size_t writeBytes = size_t(qMin(m_pulseBufferSize, m_sample->data().size()));
-#ifdef QT_PA_DEBUG
- qDebug() << this << "prepare(): writable size =" << pa_stream_writable_size(m_pulseStream)
- << "actual writeBytes =" << writeBytes
- << "m_playQueued =" << m_playQueued;
-#endif
- m_position = writeToStream(m_sample->data().data(), writeBytes);
-
- if (m_playQueued) {
- m_playQueued = false;
- setLoopsRemaining(m_loopCount);
- playSample();
- }
-}
-
-void QSoundEffectPrivate::uploadSample()
-{
- // Always called on PulseAudio thread
-
- if (m_runningCount == 0) {
-#ifdef QT_PA_DEBUG
- qDebug() << this << "uploadSample: return due to 0 m_runningCount";
-#endif
- return;
- }
-
- if (Q_UNLIKELY(!m_pulseStream
- || pa_stream_get_state(m_pulseStream) != PA_STREAM_READY
- || !m_sampleReady)) {
- return;
- }
-
-#ifdef QT_PA_DEBUG
- qDebug() << this << "uploadSample: m_runningCount =" << m_runningCount;
-#endif
- if (m_position == m_sample->data().size()) {
- m_position = 0;
- if (m_runningCount > 0)
- setLoopsRemaining(m_runningCount - 1);
- if (m_runningCount == 0) {
- return;
- }
- }
-
- int writableSize = int(pa_stream_writable_size(m_pulseStream));
- int firstPartLength = qMin(m_sample->data().size() - m_position, writableSize);
-
- int writtenBytes = writeToStream(m_sample->data().data() + m_position,
- firstPartLength);
-
- m_position += writtenBytes;
- if (m_position == m_sample->data().size()) {
- m_position = 0;
- if (m_runningCount > 0)
- setLoopsRemaining(m_runningCount - 1);
- if (m_runningCount != 0 && firstPartLength < writableSize)
- {
- while (writtenBytes < writableSize) {
- int writeSize = qMin(writableSize - writtenBytes, m_sample->data().size());
- writtenBytes += writeToStream(m_sample->data().data(), writeSize);
-
- if (writeSize < m_sample->data().size()) {
- m_position = writeSize;
- break;
- }
- if (m_runningCount > 0)
- setLoopsRemaining(m_runningCount - 1);
- if (m_runningCount == 0)
- break;
- }
- }
- }
-#ifdef QT_PA_DEBUG
- qDebug() << this << "uploadSample: use direct write, writeable size =" << writableSize
- << "actual writtenBytes =" << writtenBytes;
-#endif
-}
-
-int QSoundEffectPrivate::writeToStream(const void *data, int size)
-{
- // Always called on PulseAudio thread
-
- if (size < 1)
- return 0;
-
- m_volumeLock.lock();
- qreal volume = m_muted ? 0 : m_volume;
- m_volumeLock.unlock();
- pa_free_cb_t writeDoneCb = stream_write_done_callback;
-
- if (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 = size;
- if (pa_stream_begin_write(m_pulseStream, &dest, &nbytes) < 0) {
- qWarning("QSoundEffect(pulseaudio): pa_stream_begin_write, error = %s",
- pa_strerror(pa_context_errno(pulseDaemon()->context())));
- return 0;
- }
-
- size = int(nbytes);
- QAudioHelperInternal::qMultiplySamples(volume, m_sample->format(), data, dest, size);
- data = dest;
- writeDoneCb = nullptr;
- }
-
- if (pa_stream_write(m_pulseStream, data, size, writeDoneCb, 0, PA_SEEK_RELATIVE) < 0) {
- qWarning("QSoundEffect(pulseaudio): pa_stream_write, error = %s",
- pa_strerror(pa_context_errno(pulseDaemon()->context())));
- return 0;
- }
-
- return size;
-}
-
-void QSoundEffectPrivate::playSample()
-{
- PulseDaemonLocker locker;
-
-#ifdef QT_PA_DEBUG
- qDebug() << this << "playSample";
-#endif
- Q_ASSERT(m_pulseStream);
- Q_ASSERT(pa_stream_get_state(m_pulseStream) == PA_STREAM_READY);
- pa_operation *o = pa_stream_cork(m_pulseStream, 0, nullptr, nullptr);
- if (o)
- pa_operation_unref(o);
-}
-
-void QSoundEffectPrivate::stop()
-{
-#ifdef QT_PA_DEBUG
- qDebug() << this << "stop";
-#endif
- if (!m_playing)
- return;
-
- PulseDaemonLocker locker;
-
- setPlaying(false);
-
- m_stopping = true;
- if (m_pulseStream) {
- emptyStream(ReloadSampleWhenDone);
- if (m_reloadCategory) {
- unloadPulseStream(); // upon play we reconnect anyway
- }
- }
- setLoopsRemaining(0);
- m_position = 0;
- m_playQueued = false;
- m_reloadCategory = false;
-}
-
-void QSoundEffectPrivate::underRun()
-{
- stop();
-}
-
-void QSoundEffectPrivate::streamReady()
-{
- PulseDaemonLocker locker;
-
- if (Q_UNLIKELY(!m_sample || m_sample->state() != QSample::Ready
- || !m_pulseStream || pa_stream_get_state(m_pulseStream) != PA_STREAM_READY)) {
- return;
- }
-
-#ifdef QT_PA_DEBUG
- qDebug() << this << "streamReady";
-#endif
-
- m_sinkInputId = pa_stream_get_index(m_pulseStream);
-#ifdef QT_PA_DEBUG
- const pa_buffer_attr *realBufAttr = pa_stream_get_buffer_attr(m_pulseStream);
- qDebug() << this << "m_sinkInputId =" << m_sinkInputId
- << "tlength =" << realBufAttr->tlength << "maxlength =" << realBufAttr->maxlength
- << "minreq = " << realBufAttr->minreq << "prebuf =" << realBufAttr->prebuf;
-#endif
- prepare();
- setStatus(QSoundEffect::Ready);
-}
-
-void QSoundEffectPrivate::createPulseStream()
-{
-#ifdef QT_PA_DEBUG
- qDebug() << this << "createPulseStream";
-#endif
-
- if (!pulseDaemon()->context())
- return;
-
- pa_proplist *propList = pa_proplist_new();
- if (!m_category.isNull())
- pa_proplist_sets(propList, PA_PROP_MEDIA_ROLE, m_category.toLatin1().constData());
- pa_stream *stream = pa_stream_new_with_proplist(pulseDaemon()->context(), m_name.constData(),
- &m_pulseSpec, nullptr, propList);
- pa_proplist_free(propList);
-
- connect(pulseDaemon(), &PulseDaemon::contextFailed,
- this, &QSoundEffectPrivate::contextFailed);
-
- if (stream == nullptr) {
- qWarning("QSoundEffect(pulseaudio): Failed to create stream");
- m_pulseStream = nullptr;
- setStatus(QSoundEffect::Error);
- setPlaying(false);
- return;
- }
- else {
- pa_stream_set_state_callback(stream, stream_state_callback, this);
- pa_stream_set_write_callback(stream, stream_write_callback, this);
- pa_stream_set_underflow_callback(stream, stream_underrun_callback, this);
- }
- m_pulseStream = stream;
-
- if (pa_stream_connect_playback(m_pulseStream,
- m_sinkName.isEmpty() ? nullptr : m_sinkName.toLatin1().constData(),
- nullptr, PA_STREAM_START_CORKED, nullptr, nullptr) < 0) {
- qWarning("QSoundEffect(pulseaudio): Failed to connect stream, error = %s",
- pa_strerror(pa_context_errno(pulseDaemon()->context())));
- }
-}
-
-void QSoundEffectPrivate::contextReady()
-{
- disconnect(pulseDaemon(), &PulseDaemon::contextReady,
- this, &QSoundEffectPrivate::contextReady);
- PulseDaemonLocker locker;
- createPulseStream();
-}
-
-void QSoundEffectPrivate::contextFailed()
-{
- unloadPulseStream();
- connect(pulseDaemon(), &PulseDaemon::contextReady,
- this, &QSoundEffectPrivate::contextReady);
-}
-
-void QSoundEffectPrivate::stream_write_callback(pa_stream *s, size_t length, void *userdata)
-{
- Q_UNUSED(length);
- Q_UNUSED(s);
-
- QSoundEffectPrivate *self = reinterpret_cast<QSoundEffectPrivate*>(userdata);
-#ifdef QT_PA_DEBUG
- qDebug() << self << "stream_write_callback";
-#endif
- self->uploadSample();
-}
-
-void QSoundEffectPrivate::stream_state_callback(pa_stream *s, void *userdata)
-{
- QSoundEffectPrivate *self = reinterpret_cast<QSoundEffectPrivate*>(userdata);
- switch (pa_stream_get_state(s)) {
- case PA_STREAM_READY:
- {
-#ifdef QT_PA_DEBUG
- qDebug() << self << "pulse stream ready";
-#endif
- if (Q_UNLIKELY(!self->m_sample || self->m_sample->state() != QSample::Ready))
- return;
-
- const pa_buffer_attr *bufferAttr = pa_stream_get_buffer_attr(self->m_pulseStream);
- self->m_pulseBufferSize = bufferAttr->tlength;
- if (bufferAttr->prebuf > uint32_t(self->m_sample->data().size())) {
- pa_buffer_attr newBufferAttr;
- newBufferAttr = *bufferAttr;
- newBufferAttr.prebuf = self->m_sample->data().size();
- pa_operation *op = pa_stream_set_buffer_attr(self->m_pulseStream, &newBufferAttr, stream_adjust_prebuffer_callback, self->m_ref->getRef());
- if (op)
- pa_operation_unref(op);
- else
- qWarning("QSoundEffect(pulseaudio): failed to adjust pre-buffer attribute");
- } else {
- QMetaObject::invokeMethod(self, "streamReady", Qt::QueuedConnection);
- }
- break;
- }
- case PA_STREAM_CREATING:
-#ifdef QT_PA_DEBUG
- qDebug() << self << "pulse stream creating";
-#endif
- break;
- case PA_STREAM_TERMINATED:
-#ifdef QT_PA_DEBUG
- qDebug() << self << "pulse stream terminated";
-#endif
- break;
-
- case PA_STREAM_FAILED:
- default:
- qWarning("QSoundEffect(pulseaudio): Error in pulse audio stream");
- break;
- }
-}
-
-void QSoundEffectPrivate::stream_adjust_prebuffer_callback(pa_stream *s, int success, void *userdata)
-{
-#ifdef QT_PA_DEBUG
- qDebug() << "stream_adjust_prebuffer_callback";
-#endif
- Q_UNUSED(s);
- QSoundEffectRef *ref = reinterpret_cast<QSoundEffectRef*>(userdata);
- QSoundEffectPrivate *self = ref->soundEffect();
- ref->release();
- if (!self)
- return;
-
- if (!success)
- qWarning("QSoundEffect(pulseaudio): failed to adjust pre-buffer attribute");
-#ifdef QT_PA_DEBUG
- qDebug() << self << "stream_adjust_prebuffer_callback";
-#endif
- QMetaObject::invokeMethod(self, "streamReady", Qt::QueuedConnection);
-}
-
-void QSoundEffectPrivate::stream_underrun_callback(pa_stream *s, void *userdata)
-{
- Q_UNUSED(s);
- QSoundEffectPrivate *self = reinterpret_cast<QSoundEffectPrivate*>(userdata);
-#ifdef QT_PA_DEBUG
- qDebug() << self << "stream_underrun_callback";
-#endif
- if (self->m_runningCount == 0 && !self->m_playQueued)
- QMetaObject::invokeMethod(self, "underRun", Qt::QueuedConnection);
-#ifdef QT_PA_DEBUG
- else
- qDebug() << "underun corked =" << pa_stream_is_corked(s);
-#endif
-}
-
-void QSoundEffectPrivate::stream_cork_callback(pa_stream *s, int success, void *userdata)
-{
-#ifdef QT_PA_DEBUG
- qDebug() << "stream_cork_callback";
-#endif
- Q_UNUSED(s);
- QSoundEffectRef *ref = reinterpret_cast<QSoundEffectRef*>(userdata);
- QSoundEffectPrivate *self = ref->soundEffect();
- ref->release();
- if (!self)
- return;
-
- if (!success)
- qWarning("QSoundEffect(pulseaudio): failed to stop");
-#ifdef QT_PA_DEBUG
- qDebug() << self << "stream_cork_callback";
-#endif
- QMetaObject::invokeMethod(self, "prepare", Qt::QueuedConnection);
-}
-
-void QSoundEffectPrivate::stream_flush_callback(pa_stream *s, int success, void *userdata)
-{
-#ifdef QT_PA_DEBUG
- qDebug() << "stream_flush_callback";
-#endif
- Q_UNUSED(s);
- QSoundEffectRef *ref = reinterpret_cast<QSoundEffectRef*>(userdata);
- QSoundEffectPrivate *self = ref->soundEffect();
- ref->release();
- if (!self)
- return;
-
- if (!success)
- qWarning("QSoundEffect(pulseaudio): failed to drain");
-
- QMetaObject::invokeMethod(self, "emptyComplete", Qt::QueuedConnection, Q_ARG(void*, s), Q_ARG(bool, false));
-}
-
-void QSoundEffectPrivate::stream_flush_reload_callback(pa_stream *s, int success, void *userdata)
-{
-#ifdef QT_PA_DEBUG
- qDebug() << "stream_flush_reload_callback";
-#endif
- Q_UNUSED(s);
- QSoundEffectRef *ref = reinterpret_cast<QSoundEffectRef*>(userdata);
- QSoundEffectPrivate *self = ref->soundEffect();
- ref->release();
- if (!self)
- return;
-
- if (!success)
- qWarning("QSoundEffect(pulseaudio): failed to drain");
-
- QMetaObject::invokeMethod(self, "emptyComplete", Qt::QueuedConnection, Q_ARG(void*, s), Q_ARG(bool, true));
-}
-
-void QSoundEffectPrivate::stream_write_done_callback(void *p)
-{
- Q_UNUSED(p);
-#ifdef QT_PA_DEBUG
- qDebug() << "stream_write_done_callback";
-#endif
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qsoundeffect_pulse_p.cpp"
-#include "qsoundeffect_pulse_p.moc"
diff --git a/src/multimedia/audio/qsoundeffect_pulse_p.h b/src/multimedia/audio/qsoundeffect_pulse_p.h
deleted file mode 100644
index e0073f0d5..000000000
--- a/src/multimedia/audio/qsoundeffect_pulse_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 QSOUNDEFFECT_PULSE_H
-#define QSOUNDEFFECT_PULSE_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 "qsoundeffect.h"
-
-#include <QtCore/qobject.h>
-#include <QtCore/qdatetime.h>
-#include <QtCore/qmutex.h>
-#include <qmediaplayer.h>
-#include <pulse/pulseaudio.h>
-#include "qsamplecache_p.h"
-
-#include <private/qmediaresourcepolicy_p.h>
-#include <private/qmediaresourceset_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QSoundEffectRef;
-
-class QSoundEffectPrivate : public QObject
-{
- Q_OBJECT
-public:
- explicit QSoundEffectPrivate(QObject* parent);
- explicit QSoundEffectPrivate(const QAudioDeviceInfo &audioDevice, QObject *parent);
- ~QSoundEffectPrivate();
-
- static QStringList supportedMimeTypes();
-
- QUrl source() const;
- void setSource(const QUrl &url);
- int loopCount() const;
- int loopsRemaining() const;
- void setLoopCount(int loopCount);
- qreal volume() const;
- void setVolume(qreal volume);
- bool isMuted() const;
- void setMuted(bool muted);
- bool isLoaded() const;
- bool isPlaying() const;
- QSoundEffect::Status status() const;
-
- void release();
-
- QString category() const;
- void setCategory(const QString &category);
-
-public Q_SLOTS:
- void play();
- void stop();
-
-Q_SIGNALS:
- void loopsRemainingChanged();
- void volumeChanged();
- void mutedChanged();
- void loadedChanged();
- void playingChanged();
- void statusChanged();
- void categoryChanged();
-
-private Q_SLOTS:
- void decoderError();
- void sampleReady();
- void uploadSample();
- void contextReady();
- void contextFailed();
- void underRun();
- void prepare();
- void streamReady();
- void emptyComplete(void *stream, bool reload);
-
- void handleAvailabilityChanged(bool available);
-
-private:
- void playAvailable();
- void playSample();
-
- enum EmptyStreamOption {
- ReloadSampleWhenDone = 0x1
- };
- Q_DECLARE_FLAGS(EmptyStreamOptions, EmptyStreamOption)
- void emptyStream(EmptyStreamOptions options = EmptyStreamOptions());
-
- void createPulseStream();
- void unloadPulseStream();
-
- int writeToStream(const void *data, int size);
-
- void setPlaying(bool playing);
- void setStatus(QSoundEffect::Status status);
- void setLoopsRemaining(int loopsRemaining);
-
- static void stream_write_callback(pa_stream *s, size_t length, void *userdata);
- static void stream_state_callback(pa_stream *s, void *userdata);
- static void stream_underrun_callback(pa_stream *s, void *userdata);
- static void stream_cork_callback(pa_stream *s, int success, void *userdata);
- static void stream_flush_callback(pa_stream *s, int success, void *userdata);
- static void stream_flush_reload_callback(pa_stream *s, int success, void *userdata);
- static void stream_write_done_callback(void *p);
- static void stream_adjust_prebuffer_callback(pa_stream *s, int success, void *userdata);
-
- pa_stream *m_pulseStream = nullptr;
- QString m_sinkName;
- int m_sinkInputId = -1;
- pa_sample_spec m_pulseSpec;
- int m_pulseBufferSize = 0;
-
- bool m_emptying = false;
- bool m_sampleReady = false;
- bool m_playing = false;
- QSoundEffect::Status m_status = QSoundEffect::Null;
- bool m_muted = false;
- bool m_playQueued = false;
- bool m_stopping = false;
- qreal m_volume = 1.0;
- int m_loopCount = 1;
- int m_runningCount = 0;
- QUrl m_source;
- QByteArray m_name;
- QString m_category;
- bool m_reloadCategory = false;
-
- QSample *m_sample = nullptr;
- int m_position = 0;
- QSoundEffectRef *m_ref = nullptr;
-
- bool m_resourcesAvailable = false;
-
- // Protects volume while PuseAudio is accessing it
- mutable QMutex m_volumeLock;
-
- QMediaPlayerResourceSetInterface *m_resources = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QSOUNDEFFECT_PULSE_H
diff --git a/src/multimedia/audio/qsoundeffect_qaudio_p.cpp b/src/multimedia/audio/qsoundeffect_qaudio_p.cpp
deleted file mode 100644
index 90d195d3f..000000000
--- a/src/multimedia/audio/qsoundeffect_qaudio_p.cpp
+++ /dev/null
@@ -1,457 +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 purely as an
-// implementation detail. 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 "qsoundeffect_qaudio_p.h"
-
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qiodevice.h>
-
-//#include <QDebug>
-//#define QT_QAUDIO_DEBUG 1
-
-QT_BEGIN_NAMESPACE
-
-Q_GLOBAL_STATIC(QSampleCache, sampleCache)
-
-QSoundEffectPrivate::QSoundEffectPrivate(QObject *parent):
- QObject(parent),
- d(new PrivateSoundSource(this))
-{
-}
-
-QSoundEffectPrivate::QSoundEffectPrivate(const QAudioDeviceInfo &audioDevice, QObject *parent)
- : QObject(parent)
- , d(new PrivateSoundSource(this, audioDevice))
-{
-}
-
-QSoundEffectPrivate::~QSoundEffectPrivate()
-{
-}
-
-void QSoundEffectPrivate::release()
-{
- stop();
- if (d->m_audioOutput) {
- d->m_audioOutput->stop();
- d->m_audioOutput->deleteLater();
- d->m_sample->release();
- }
- delete d;
- this->deleteLater();
-}
-
-QStringList QSoundEffectPrivate::supportedMimeTypes()
-{
- // Only return supported mime types if we have a audio device available
- const QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
- if (devices.size() <= 0)
- return QStringList();
-
- return QStringList() << QLatin1String("audio/x-wav")
- << QLatin1String("audio/wav")
- << QLatin1String("audio/wave")
- << QLatin1String("audio/x-pn-wav");
-}
-
-QUrl QSoundEffectPrivate::source() const
-{
- return d->m_url;
-}
-
-void QSoundEffectPrivate::setSource(const QUrl &url)
-{
-#ifdef QT_QAUDIO_DEBUG
- qDebug() << this << "setSource current=" << d->m_url << ", to=" << url;
-#endif
- Q_ASSERT(d->m_url != url);
-
- stop();
-
- d->m_url = url;
-
- d->m_sampleReady = false;
-
- if (url.isEmpty()) {
- setStatus(QSoundEffect::Null);
- return;
- }
-
- if (!url.isValid()) {
- setStatus(QSoundEffect::Error);
- return;
- }
-
- if (d->m_sample) {
- if (!d->m_sampleReady) {
- disconnect(d->m_sample, &QSample::error, d, &PrivateSoundSource::decoderError);
- disconnect(d->m_sample, &QSample::ready, d, &PrivateSoundSource::sampleReady);
- }
- d->m_sample->release();
- d->m_sample = nullptr;
- }
-
- if (d->m_audioOutput) {
- disconnect(d->m_audioOutput, &QAudioOutput::stateChanged, d, &PrivateSoundSource::stateChanged);
- d->m_audioOutput->stop();
- d->m_audioOutput->deleteLater();
- d->m_audioOutput = nullptr;
- }
-
- setStatus(QSoundEffect::Loading);
- d->m_sample = sampleCache()->requestSample(url);
- connect(d->m_sample, &QSample::error, d, &PrivateSoundSource::decoderError);
- connect(d->m_sample, &QSample::ready, d, &PrivateSoundSource::sampleReady);
-
- switch (d->m_sample->state()) {
- case QSample::Ready:
- d->sampleReady();
- break;
- case QSample::Error:
- d->decoderError();
- break;
- default:
- break;
- }
-}
-
-int QSoundEffectPrivate::loopCount() const
-{
- return d->m_loopCount;
-}
-
-int QSoundEffectPrivate::loopsRemaining() const
-{
- return d->m_runningCount;
-}
-
-void QSoundEffectPrivate::setLoopCount(int loopCount)
-{
-#ifdef QT_QAUDIO_DEBUG
- qDebug() << "setLoopCount " << loopCount;
-#endif
- if (loopCount == 0)
- loopCount = 1;
- d->m_loopCount = loopCount;
- if (d->m_playing)
- setLoopsRemaining(loopCount);
-}
-
-qreal QSoundEffectPrivate::volume() const
-{
- if (d->m_audioOutput && !d->m_muted)
- return d->m_audioOutput->volume();
-
- return d->m_volume;
-}
-
-void QSoundEffectPrivate::setVolume(qreal volume)
-{
- d->m_volume = volume;
-
- if (d->m_audioOutput && !d->m_muted)
- d->m_audioOutput->setVolume(volume);
-
- emit volumeChanged();
-}
-
-bool QSoundEffectPrivate::isMuted() const
-{
- return d->m_muted;
-}
-
-void QSoundEffectPrivate::setMuted(bool muted)
-{
- 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);
-
- d->m_muted = muted;
- emit mutedChanged();
-}
-
-bool QSoundEffectPrivate::isLoaded() const
-{
- return d->m_status == QSoundEffect::Ready;
-}
-
-
-bool QSoundEffectPrivate::isPlaying() const
-{
- return d->m_playing;
-}
-
-QSoundEffect::Status QSoundEffectPrivate::status() const
-{
- return d->m_status;
-}
-
-void QSoundEffectPrivate::play()
-{
- d->m_offset = 0;
- setLoopsRemaining(d->m_loopCount);
-#ifdef QT_QAUDIO_DEBUG
- qDebug() << this << "play";
-#endif
- if (d->m_status == QSoundEffect::Null || d->m_status == QSoundEffect::Error) {
- setStatus(QSoundEffect::Null);
- return;
- }
- setPlaying(true);
- if (d->m_audioOutput && d->m_audioOutput->state() == QAudio::StoppedState && d->m_sampleReady)
- d->m_audioOutput->start(d);
-}
-
-void QSoundEffectPrivate::stop()
-{
- if (!d->m_playing)
- return;
-#ifdef QT_QAUDIO_DEBUG
- qDebug() << "stop()";
-#endif
- d->m_offset = 0;
-
- setPlaying(false);
-
- if (d->m_audioOutput)
- d->m_audioOutput->stop();
-}
-
-void QSoundEffectPrivate::setStatus(QSoundEffect::Status status)
-{
-#ifdef QT_QAUDIO_DEBUG
- qDebug() << this << "setStatus" << status;
-#endif
- if (d->m_status == status)
- return;
- bool oldLoaded = isLoaded();
- d->m_status = status;
- emit statusChanged();
- if (oldLoaded != isLoaded())
- emit loadedChanged();
-}
-
-void QSoundEffectPrivate::setPlaying(bool playing)
-{
-#ifdef QT_QAUDIO_DEBUG
- qDebug() << this << "setPlaying(" << playing << ")";
-#endif
- if (d->m_playing == playing)
- return;
- d->m_playing = playing;
- emit playingChanged();
-}
-
-void QSoundEffectPrivate::setLoopsRemaining(int loopsRemaining)
-{
- if (d->m_runningCount == loopsRemaining)
- return;
-#ifdef QT_QAUDIO_DEBUG
- qDebug() << this << "setLoopsRemaining " << loopsRemaining;
-#endif
- d->m_runningCount = loopsRemaining;
- emit loopsRemainingChanged();
-}
-
-/* Categories are ignored */
-QString QSoundEffectPrivate::category() const
-{
- return d->m_category;
-}
-
-void QSoundEffectPrivate::setCategory(const QString &category)
-{
- if (d->m_category != category && !d->m_playing) {
- d->m_category = category;
- emit categoryChanged();
- }
-}
-
-PrivateSoundSource::PrivateSoundSource(QSoundEffectPrivate *s, const QAudioDeviceInfo &audioDevice)
- : QIODevice(s)
- , m_audioDevice(audioDevice)
-{
- soundeffect = s;
- m_category = QLatin1String("game");
- open(QIODevice::ReadOnly);
-}
-
-void PrivateSoundSource::sampleReady()
-{
- if (m_status == QSoundEffect::Error)
- return;
-
-#ifdef QT_QAUDIO_DEBUG
- qDebug() << this << "sampleReady "<<m_playing;
-#endif
- disconnect(m_sample, &QSample::error, this, &PrivateSoundSource::decoderError);
- disconnect(m_sample, &QSample::ready, this, &PrivateSoundSource::sampleReady);
- if (!m_audioOutput) {
- if (m_audioDevice.isNull())
- m_audioOutput = new QAudioOutput(m_sample->format());
- else
- m_audioOutput = new QAudioOutput(m_audioDevice, m_sample->format());
- connect(m_audioOutput, &QAudioOutput::stateChanged, this, &PrivateSoundSource::stateChanged);
- if (!m_muted)
- m_audioOutput->setVolume(m_volume);
- else
- m_audioOutput->setVolume(0);
- }
- m_sampleReady = true;
- soundeffect->setStatus(QSoundEffect::Ready);
-
- if (m_playing && m_audioOutput->state() == QAudio::StoppedState)
- m_audioOutput->start(this);
-}
-
-void PrivateSoundSource::decoderError()
-{
- qWarning("QSoundEffect(qaudio): Error decoding source %ls", qUtf16Printable(m_url.toString()));
- disconnect(m_sample, &QSample::ready, this, &PrivateSoundSource::sampleReady);
- disconnect(m_sample, &QSample::error, this, &PrivateSoundSource::decoderError);
- m_playing = false;
- soundeffect->setStatus(QSoundEffect::Error);
-}
-
-void PrivateSoundSource::stateChanged(QAudio::State state)
-{
-#ifdef QT_QAUDIO_DEBUG
- qDebug() << this << "stateChanged " << state;
-#endif
- if ((state == QAudio::IdleState && m_runningCount == 0)
- || (state == QAudio::StoppedState && m_audioOutput->error() != QAudio::NoError))
- emit soundeffect->stop();
-}
-
-qint64 PrivateSoundSource::readData(char *data, qint64 len)
-{
- if ((m_runningCount > 0 || m_runningCount == QSoundEffect::Infinite) && m_playing) {
-
- if (m_sample->state() != QSample::Ready)
- return 0;
-
- qint64 bytesWritten = 0;
-
- const int periodSize = m_audioOutput->periodSize();
- const int sampleSize = m_sample->data().size();
- const char* sampleData = m_sample->data().constData();
-
- // Some systems can have large buffers we only need a max of three
- int periodsFree = qMin(3, (int)(m_audioOutput->bytesFree()/periodSize));
- int dataOffset = 0;
-
-#ifdef QT_QAUDIO_DEBUG
- qDebug() << "bytesFree=" << m_audioOutput->bytesFree() << ", can fit " << periodsFree << " periodSize() chunks";
-#endif
-
- while ((periodsFree > 0) && (bytesWritten + periodSize <= len)) {
-
- if (sampleSize - m_offset >= periodSize) {
- // We can fit a whole period of data
- memcpy(data + dataOffset, sampleData + m_offset, periodSize);
- m_offset += periodSize;
- dataOffset += periodSize;
- bytesWritten += periodSize;
-#ifdef QT_QAUDIO_DEBUG
- qDebug() << "WHOLE PERIOD: bytesWritten=" << bytesWritten << ", offset=" << m_offset
- << ", filesize=" << sampleSize;
-#endif
- } else {
- // We are at end of sound, first write what is left of current sound
- memcpy(data + dataOffset, sampleData + m_offset, sampleSize - m_offset);
- bytesWritten += sampleSize - m_offset;
- int wrapLen = periodSize - (sampleSize - m_offset);
- if (wrapLen > sampleSize)
- wrapLen = sampleSize;
-#ifdef QT_QAUDIO_DEBUG
- qDebug() << "END OF SOUND: bytesWritten=" << bytesWritten << ", offset=" << m_offset
- << ", part1=" << (sampleSize-m_offset);
-#endif
- dataOffset += (sampleSize - m_offset);
- m_offset = 0;
-
- if (m_runningCount > 0 && m_runningCount != QSoundEffect::Infinite)
- soundeffect->setLoopsRemaining(m_runningCount-1);
-
- if (m_runningCount > 0 || m_runningCount == QSoundEffect::Infinite) {
- // There are still more loops of this sound to play, append the start of sound to make up full period
- memcpy(data + dataOffset, sampleData + m_offset, wrapLen);
- m_offset += wrapLen;
- dataOffset += wrapLen;
- bytesWritten += wrapLen;
-#ifdef QT_QAUDIO_DEBUG
- qDebug() << "APPEND START FOR FULL PERIOD: bytesWritten=" << bytesWritten << ", offset=" << m_offset
- << ", part2=" << wrapLen;
- qDebug() << "part1 + part2 should be a period " << periodSize;
-#endif
- }
- }
- if (m_runningCount == 0)
- break;
-
- periodsFree--;
- }
- return bytesWritten;
- }
-
- return 0;
-}
-
-qint64 PrivateSoundSource::writeData(const char *data, qint64 len)
-{
- Q_UNUSED(data);
- Q_UNUSED(len);
- return 0;
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qsoundeffect_qaudio_p.cpp"
diff --git a/src/multimedia/audio/qsoundeffect_qaudio_p.h b/src/multimedia/audio/qsoundeffect_qaudio_p.h
deleted file mode 100644
index a3a48f60d..000000000
--- a/src/multimedia/audio/qsoundeffect_qaudio_p.h
+++ /dev/null
@@ -1,151 +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 QSOUNDEFFECT_QAUDIO_H
-#define QSOUNDEFFECT_QAUDIO_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/qurl.h>
-#include "qaudiooutput.h"
-#include "qsamplecache_p.h"
-#include "qsoundeffect.h"
-
-QT_BEGIN_NAMESPACE
-
-class QSoundEffectPrivate;
-
-class PrivateSoundSource : public QIODevice
-{
- friend class QSoundEffectPrivate;
- Q_OBJECT
-public:
- PrivateSoundSource(QSoundEffectPrivate *s, const QAudioDeviceInfo &audioDevice = QAudioDeviceInfo());
- ~PrivateSoundSource() {}
-
- qint64 readData(char *data, qint64 len) override;
- qint64 writeData(const char *data, qint64 len) override;
-
-private Q_SLOTS:
- void sampleReady();
- void decoderError();
- void stateChanged(QAudio::State);
-
-private:
- QUrl m_url;
- int m_loopCount = 1;
- int m_runningCount = 0;
- bool m_playing = false;
- QSoundEffect::Status m_status = QSoundEffect::Null;
- QAudioOutput *m_audioOutput = nullptr;
- QSample *m_sample = nullptr;
- bool m_muted = false;
- qreal m_volume = 1.0;
- bool m_sampleReady = false;
- qint64 m_offset = 0;
- QString m_category;
- QAudioDeviceInfo m_audioDevice;
- QSoundEffectPrivate *soundeffect = nullptr;
-};
-
-
-class QSoundEffectPrivate : public QObject
-{
- friend class PrivateSoundSource;
- Q_OBJECT
-public:
-
- explicit QSoundEffectPrivate(QObject *parent);
- explicit QSoundEffectPrivate(const QAudioDeviceInfo &audioDevice, QObject *parent);
- ~QSoundEffectPrivate();
-
- static QStringList supportedMimeTypes();
-
- QUrl source() const;
- void setSource(const QUrl &url);
- int loopCount() const;
- int loopsRemaining() const;
- void setLoopCount(int loopCount);
- qreal volume() const;
- void setVolume(qreal volume);
- bool isMuted() const;
- void setMuted(bool muted);
- bool isLoaded() const;
- bool isPlaying() const;
- QSoundEffect::Status status() const;
-
- void release();
-
- QString category() const;
- void setCategory(const QString &);
-
-public Q_SLOTS:
- void play();
- void stop();
-
-Q_SIGNALS:
- void loopsRemainingChanged();
- void volumeChanged();
- void mutedChanged();
- void loadedChanged();
- void playingChanged();
- void statusChanged();
- void categoryChanged();
-
-private:
- void setStatus(QSoundEffect::Status status);
- void setPlaying(bool playing);
- void setLoopsRemaining(int loopsRemaining);
-
- PrivateSoundSource *d = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QSOUNDEFFECT_QAUDIO_H
diff --git a/src/multimedia/audio/qaudio.cpp b/src/multimedia/audio/qtaudio.cpp
index 82613270a..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>
@@ -46,28 +10,17 @@ QT_BEGIN_NAMESPACE
#define LOG100 4.60517018599
-static void qRegisterAudioMetaTypes()
-{
- qRegisterMetaType<QAudio::Error>();
- qRegisterMetaType<QAudio::State>();
- qRegisterMetaType<QAudio::Mode>();
- qRegisterMetaType<QAudio::Role>();
- qRegisterMetaType<QAudio::VolumeScale>();
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterAudioMetaTypes)
-
/*!
- \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
@@ -77,7 +30,7 @@ Q_CONSTRUCTOR_FUNCTION(qRegisterAudioMetaTypes)
*/
/*!
- \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.
@@ -88,41 +41,10 @@ Q_CONSTRUCTOR_FUNCTION(qRegisterAudioMetaTypes)
\value StoppedState The audio device is closed, and is not processing any audio data
\value IdleState The QIODevice passed in has no data and audio system's buffer is empty, this state
is set after start() is called and while no audio data is available to be processed.
- \value InterruptedState This stream is in a suspended state because another higher priority stream currently
- has control of the audio device. Playback cannot resume until the higher priority
- stream relinquishes control of the audio device.
-*/
-
-/*!
- \enum QAudio::Mode
-
- \value AudioOutput audio output device
- \value AudioInput audio input device
-*/
-
-/*!
- \enum QAudio::Role
-
- This enum describes the role of an audio stream.
-
- \value UnknownRole The role is unknown or undefined
- \value MusicRole Music
- \value VideoRole Soundtrack from a movie or a video
- \value VoiceCommunicationRole Voice communications, such as telephony
- \value AlarmRole Alarm
- \value NotificationRole Notification, such as an incoming e-mail or a chat request
- \value RingtoneRole Ringtone
- \value AccessibilityRole For accessibility, such as with a screen reader
- \value SonificationRole Sonification, such as with user interface sounds
- \value GameRole Game audio
- \value CustomRole The role is specified by QMediaPlayer::customAudioRole()
-
- \since 5.6
- \sa QMediaPlayer::setAudioRole()
*/
/*!
- \enum QAudio::VolumeScale
+ \enum QtAudio::VolumeScale
This enum defines the different audio volume scales.
@@ -137,16 +59,17 @@ Q_CONSTRUCTOR_FUNCTION(qRegisterAudioMetaTypes)
\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
{
/*!
- \fn qreal QAudio::convertVolume(qreal volume, VolumeScale from, VolumeScale to)
-
Converts an audio \a volume \a from a volume scale \a to another, and returns the result.
Depending on the context, different scales are used to represent audio volume. All Qt Multimedia
@@ -164,31 +87,30 @@ namespace QAudio
\snippet multimedia-snippets/audio.cpp Volume conversion
- \since 5.8
- \sa VolumeScale, QMediaPlayer::setVolume(), QAudioOutput::setVolume(),
- QAudioInput::setVolume(), QSoundEffect::setVolume(), QMediaRecorder::setVolume()
+ \sa VolumeScale, QAudioSink::setVolume(), QAudioSource::setVolume(),
+ QSoundEffect::setVolume()
*/
-qreal convertVolume(qreal volume, VolumeScale from, VolumeScale to)
+float convertVolume(float volume, VolumeScale from, VolumeScale to)
{
switch (from) {
case LinearVolumeScale:
- volume = qMax(qreal(0), volume);
+ volume = qMax(float(0), volume);
switch (to) {
case LinearVolumeScale:
return volume;
case CubicVolumeScale:
- return qPow(volume, qreal(1 / 3.0));
+ return qPow(volume, float(1 / 3.0));
case LogarithmicVolumeScale:
return 1 - std::exp(-volume * LOG100);
case DecibelVolumeScale:
if (volume < 0.001)
- return qreal(-200);
+ return float(-200);
else
- return qreal(20.0) * std::log10(volume);
+ return float(20.0) * std::log10(volume);
}
break;
case CubicVolumeScale:
- volume = qMax(qreal(0), volume);
+ volume = qMax(float(0), volume);
switch (to) {
case LinearVolumeScale:
return volume * volume * volume;
@@ -198,13 +120,13 @@ qreal convertVolume(qreal volume, VolumeScale from, VolumeScale to)
return 1 - std::exp(-volume * volume * volume * LOG100);
case DecibelVolumeScale:
if (volume < 0.001)
- return qreal(-200);
+ return float(-200);
else
- return qreal(3.0 * 20.0) * std::log10(volume);
+ return float(3.0 * 20.0) * std::log10(volume);
}
break;
case LogarithmicVolumeScale:
- volume = qMax(qreal(0), volume);
+ volume = qMax(float(0), volume);
switch (to) {
case LinearVolumeScale:
if (volume > 0.99)
@@ -215,29 +137,29 @@ qreal convertVolume(qreal volume, VolumeScale from, VolumeScale to)
if (volume > 0.99)
return 1;
else
- return qPow(-std::log(1 - volume) / LOG100, qreal(1 / 3.0));
+ return qPow(-std::log(1 - volume) / LOG100, float(1 / 3.0));
case LogarithmicVolumeScale:
return volume;
case DecibelVolumeScale:
if (volume < 0.001)
- return qreal(-200);
+ return float(-200);
else if (volume > 0.99)
return 0;
else
- return qreal(20.0) * std::log10(-std::log(1 - volume) / LOG100);
+ return float(20.0) * std::log10(-std::log(1 - volume) / LOG100);
}
break;
case DecibelVolumeScale:
switch (to) {
case LinearVolumeScale:
- return qPow(qreal(10.0), volume / qreal(20.0));
+ return qPow(float(10.0), volume / float(20.0));
case CubicVolumeScale:
- return qPow(qreal(10.0), volume / qreal(3.0 * 20.0));
+ return qPow(float(10.0), volume / float(3.0 * 20.0));
case LogarithmicVolumeScale:
if (qFuzzyIsNull(volume))
return 1;
else
- return 1 - std::exp(-qPow(qreal(10.0), volume / qreal(20.0)) * LOG100);
+ return 1 - std::exp(-qPow(float(10.0), volume / float(20.0)) * LOG100);
case DecibelVolumeScale:
return volume;
}
@@ -291,66 +213,6 @@ QDebug operator<<(QDebug dbg, QAudio::State state)
case QAudio::IdleState:
dbg << "IdleState";
break;
- case QAudio::InterruptedState:
- dbg << "InterruptedState";
- break;
- }
- return dbg;
-}
-
-QDebug operator<<(QDebug dbg, QAudio::Mode mode)
-{
- QDebugStateSaver saver(dbg);
- dbg.nospace();
- switch (mode) {
- case QAudio::AudioInput:
- dbg << "AudioInput";
- break;
- case QAudio::AudioOutput:
- dbg << "AudioOutput";
- break;
- }
- return dbg;
-}
-
-QDebug operator<<(QDebug dbg, QAudio::Role role)
-{
- QDebugStateSaver saver(dbg);
- dbg.nospace();
- switch (role) {
- case QAudio::UnknownRole:
- dbg << "UnknownRole";
- break;
- case QAudio::AccessibilityRole:
- dbg << "AccessibilityRole";
- break;
- case QAudio::AlarmRole:
- dbg << "AlarmRole";
- break;
- case QAudio::GameRole:
- dbg << "GameRole";
- break;
- case QAudio::MusicRole:
- dbg << "MusicRole";
- break;
- case QAudio::NotificationRole:
- dbg << "NotificationRole";
- break;
- case QAudio::RingtoneRole:
- dbg << "RingtoneRole";
- break;
- case QAudio::SonificationRole:
- dbg << "SonificationRole";
- break;
- case QAudio::VideoRole:
- dbg << "VideoRole";
- break;
- case QAudio::VoiceCommunicationRole:
- dbg << "VoiceCommunicationRole";
- break;
- case QAudio::CustomRole:
- dbg << "CustomRole";
- break;
}
return dbg;
}
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
new file mode 100644
index 000000000..452363ddc
--- /dev/null
+++ b/src/multimedia/audio/qwavedecoder.cpp
@@ -0,0 +1,507 @@
+// 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"
+
+#include <QtCore/qtimer.h>
+#include <QtCore/qendian.h>
+#include <limits.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+
+void bswap2(char *data, qsizetype count) noexcept
+{
+ for (qsizetype i = 0; i < count; ++i) {
+ qSwap(data[0], data[1]);
+ ++count;
+ data += 2;
+ }
+}
+
+void bswap4(char *data, qsizetype count) noexcept
+{
+ for (qsizetype i = 0; i < count; ++i) {
+ qSwap(data[0], data[3]);
+ qSwap(data[1], data[2]);
+ ++count;
+ data += 4;
+ }
+}
+
+}
+
+QWaveDecoder::QWaveDecoder(QIODevice *device, QObject *parent)
+ : QIODevice(parent),
+ device(device)
+{
+}
+
+QWaveDecoder::QWaveDecoder(QIODevice *device, const QAudioFormat &format, QObject *parent)
+ : QIODevice(parent),
+ device(device),
+ format(format)
+{
+}
+
+QWaveDecoder::~QWaveDecoder() = default;
+
+bool QWaveDecoder::open(QIODevice::OpenMode mode)
+{
+ bool canOpen = false;
+ if (mode & QIODevice::ReadOnly && mode & ~QIODevice::WriteOnly) {
+ canOpen = QIODevice::open(mode | QIODevice::Unbuffered);
+ if (canOpen && enoughDataAvailable())
+ handleData();
+ else
+ connect(device, &QIODevice::readyRead, this, &QWaveDecoder::handleData);
+ return canOpen;
+ }
+
+ if (mode & QIODevice::WriteOnly) {
+ if (format.sampleFormat() != QAudioFormat::Int16)
+ return false; // data format is not supported
+ canOpen = QIODevice::open(mode);
+ if (canOpen && writeHeader())
+ haveHeader = true;
+ return canOpen;
+ }
+ return QIODevice::open(mode);
+}
+
+void QWaveDecoder::close()
+{
+ if (isOpen() && (openMode() & QIODevice::WriteOnly)) {
+ Q_ASSERT(dataSize < INT_MAX);
+ if (!device->isOpen() || !writeDataLength())
+ qWarning() << "Failed to finalize wav file";
+ }
+ QIODevice::close();
+}
+
+bool QWaveDecoder::seek(qint64 pos)
+{
+ return device->seek(pos);
+}
+
+qint64 QWaveDecoder::pos() const
+{
+ return device->pos();
+}
+
+void QWaveDecoder::setIODevice(QIODevice * /* device */)
+{
+}
+
+QAudioFormat QWaveDecoder::audioFormat() const
+{
+ return format;
+}
+
+QIODevice* QWaveDecoder::getDevice()
+{
+ return device;
+}
+
+int QWaveDecoder::duration() const
+{
+ if (openMode() & QIODevice::WriteOnly)
+ return 0;
+ int bytesPerSec = format.bytesPerFrame() * format.sampleRate();
+ return bytesPerSec ? size() * 1000 / bytesPerSec : 0;
+}
+
+qint64 QWaveDecoder::size() const
+{
+ 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
+{
+ return device->isSequential();
+}
+
+qint64 QWaveDecoder::bytesAvailable() const
+{
+ return haveFormat ? device->bytesAvailable() : 0;
+}
+
+qint64 QWaveDecoder::headerLength()
+{
+ return HeaderLength;
+}
+
+qint64 QWaveDecoder::readData(char *data, qint64 maxlen)
+{
+ const int bytesPerSample = format.bytesPerSample();
+ if (!haveFormat || bytesPerSample == 0)
+ return 0;
+
+ 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 read;
+
+ nSamples = read / bytesPerSample;
+ switch (bytesPerSample) {
+ case 2:
+ bswap2(data, nSamples);
+ break;
+ case 4:
+ bswap4(data, nSamples);
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ return read;
+
+}
+
+qint64 QWaveDecoder::writeData(const char *data, qint64 len)
+{
+ if (!haveHeader)
+ return 0;
+ qint64 written = device->write(data, len);
+ dataSize += written;
+ return written;
+}
+
+bool QWaveDecoder::writeHeader()
+{
+ if (device->size() != 0)
+ return false;
+
+#ifndef Q_LITTLE_ENDIAN
+ // only implemented for LITTLE ENDIAN
+ return false;
+#endif
+
+ CombinedHeader header;
+
+ memset(&header, 0, HeaderLength);
+
+ // RIFF header
+ memcpy(header.riff.descriptor.id,"RIFF",4);
+ qToLittleEndian<quint32>(quint32(dataSize + HeaderLength - 8),
+ reinterpret_cast<unsigned char*>(&header.riff.descriptor.size));
+ memcpy(header.riff.type, "WAVE",4);
+
+ // WAVE header
+ memcpy(header.wave.descriptor.id,"fmt ",4);
+ qToLittleEndian<quint32>(quint32(16),
+ reinterpret_cast<unsigned char*>(&header.wave.descriptor.size));
+ qToLittleEndian<quint16>(quint16(1),
+ reinterpret_cast<unsigned char*>(&header.wave.audioFormat));
+ qToLittleEndian<quint16>(quint16(format.channelCount()),
+ reinterpret_cast<unsigned char*>(&header.wave.numChannels));
+ qToLittleEndian<quint32>(quint32(format.sampleRate()),
+ reinterpret_cast<unsigned char*>(&header.wave.sampleRate));
+ qToLittleEndian<quint32>(quint32(format.sampleRate() * format.bytesPerFrame()),
+ reinterpret_cast<unsigned char*>(&header.wave.byteRate));
+ qToLittleEndian<quint16>(quint16(format.channelCount() * format.bytesPerSample()),
+ reinterpret_cast<unsigned char*>(&header.wave.blockAlign));
+ qToLittleEndian<quint16>(quint16(format.bytesPerSample() * 8),
+ reinterpret_cast<unsigned char*>(&header.wave.bitsPerSample));
+
+ // DATA header
+ memcpy(header.data.descriptor.id,"data",4);
+ qToLittleEndian<quint32>(quint32(dataSize),
+ reinterpret_cast<unsigned char*>(&header.data.descriptor.size));
+
+ return device->write(reinterpret_cast<const char *>(&header), HeaderLength);
+}
+
+bool QWaveDecoder::writeDataLength()
+{
+#ifndef Q_LITTLE_ENDIAN
+ // only implemented for LITTLE ENDIAN
+ return false;
+#endif
+
+ if (isSequential())
+ return false;
+
+ // seek to RIFF header size, see header.riff.descriptor.size above
+ if (!device->seek(4)) {
+ qDebug() << "can't seek";
+ return false;
+ }
+
+ quint32 length = dataSize + HeaderLength - 8;
+ if (device->write(reinterpret_cast<const char *>(&length), 4) != 4)
+ return false;
+
+ // seek to DATA header size, see header.data.descriptor.size above
+ if (!device->seek(40))
+ return false;
+
+ return device->write(reinterpret_cast<const char *>(&dataSize), 4);
+}
+
+void QWaveDecoder::parsingFailed()
+{
+ Q_ASSERT(device);
+ disconnect(device, &QIODevice::readyRead, this, &QWaveDecoder::handleData);
+ emit parsingError();
+}
+
+void QWaveDecoder::handleData()
+{
+ if (openMode() == QIODevice::WriteOnly)
+ return;
+
+ // As a special "state", if we have junk to skip, we do
+ if (junkToSkip > 0) {
+ discardBytes(junkToSkip); // this also updates junkToSkip
+
+ // If we couldn't skip all the junk, return
+ if (junkToSkip > 0) {
+ // We might have run out
+ if (device->atEnd())
+ parsingFailed();
+ return;
+ }
+ }
+
+ if (state == QWaveDecoder::InitialState) {
+ if (device->bytesAvailable() < qint64(sizeof(RIFFHeader)))
+ return;
+
+ RIFFHeader riff;
+ device->read(reinterpret_cast<char *>(&riff), sizeof(RIFFHeader));
+
+ // RIFF = little endian RIFF, RIFX = big endian RIFF
+ if (((qstrncmp(riff.descriptor.id, "RIFF", 4) != 0) && (qstrncmp(riff.descriptor.id, "RIFX", 4) != 0))
+ || qstrncmp(riff.type, "WAVE", 4) != 0) {
+ parsingFailed();
+ return;
+ }
+
+ state = QWaveDecoder::WaitingForFormatState;
+ bigEndian = (qstrncmp(riff.descriptor.id, "RIFX", 4) == 0);
+ byteSwap = (bigEndian != (QSysInfo::ByteOrder == QSysInfo::BigEndian));
+ }
+
+ if (state == QWaveDecoder::WaitingForFormatState) {
+ if (findChunk("fmt ")) {
+ chunk descriptor;
+ peekChunk(&descriptor);
+
+ quint32 rawChunkSize = descriptor.size + sizeof(chunk);
+ if (device->bytesAvailable() < qint64(rawChunkSize))
+ return;
+
+ WAVEHeader wave;
+ device->read(reinterpret_cast<char *>(&wave), sizeof(WAVEHeader));
+
+ if (rawChunkSize > sizeof(WAVEHeader))
+ discardBytes(rawChunkSize - sizeof(WAVEHeader));
+
+ // Swizzle this
+ if (bigEndian) {
+ wave.audioFormat = qFromBigEndian<quint16>(wave.audioFormat);
+ } else {
+ wave.audioFormat = qFromLittleEndian<quint16>(wave.audioFormat);
+ }
+
+ if (wave.audioFormat != 0 && wave.audioFormat != 1) {
+ // 32bit wave files have format == 0xFFFE (WAVE_FORMAT_EXTENSIBLE).
+ // but don't support them at the moment.
+ parsingFailed();
+ return;
+ }
+
+ int rate;
+ int channels;
+ if (bigEndian) {
+ bps = qFromBigEndian<quint16>(wave.bitsPerSample);
+ rate = qFromBigEndian<quint32>(wave.sampleRate);
+ channels = qFromBigEndian<quint16>(wave.numChannels);
+ } else {
+ bps = qFromLittleEndian<quint16>(wave.bitsPerSample);
+ rate = qFromLittleEndian<quint32>(wave.sampleRate);
+ channels = qFromLittleEndian<quint16>(wave.numChannels);
+ }
+
+ QAudioFormat::SampleFormat fmt = QAudioFormat::Unknown;
+ switch(bps) {
+ case 8:
+ fmt = QAudioFormat::UInt8;
+ break;
+ case 16:
+ fmt = QAudioFormat::Int16;
+ break;
+ case 24:
+ fmt = QAudioFormat::Int16;
+ break;
+ case 32:
+ fmt = QAudioFormat::Int32;
+ break;
+ }
+ if (fmt == QAudioFormat::Unknown || rate == 0 || channels == 0) {
+ parsingFailed();
+ return;
+ }
+
+ format.setSampleFormat(fmt);
+ format.setSampleRate(rate);
+ format.setChannelCount(channels);
+
+ state = QWaveDecoder::WaitingForDataState;
+ }
+ }
+
+ if (state == QWaveDecoder::WaitingForDataState) {
+ if (findChunk("data")) {
+ disconnect(device, &QIODevice::readyRead, this, &QWaveDecoder::handleData);
+
+ chunk descriptor;
+ device->read(reinterpret_cast<char *>(&descriptor), sizeof(chunk));
+ if (bigEndian)
+ descriptor.size = qFromBigEndian<quint32>(descriptor.size);
+ else
+ descriptor.size = qFromLittleEndian<quint32>(descriptor.size);
+
+ dataSize = descriptor.size; //means the data size from the data header, not the actual file size
+ if (!dataSize)
+ dataSize = device->size() - headerLength();
+
+ haveFormat = true;
+ connect(device, &QIODevice::readyRead, this, &QIODevice::readyRead);
+ emit formatKnown();
+
+ return;
+ }
+ }
+
+ // If we hit the end without finding data, it's a parsing error
+ if (device->atEnd()) {
+ parsingFailed();
+ }
+}
+
+bool QWaveDecoder::enoughDataAvailable()
+{
+ chunk descriptor;
+ if (!peekChunk(&descriptor, false))
+ return false;
+
+ // This is only called for the RIFF/RIFX header, before bigEndian is set,
+ // so we have to manually swizzle
+ if (qstrncmp(descriptor.id, "RIFX", 4) == 0)
+ descriptor.size = qFromBigEndian<quint32>(descriptor.size);
+ if (qstrncmp(descriptor.id, "RIFF", 4) == 0)
+ descriptor.size = qFromLittleEndian<quint32>(descriptor.size);
+
+ if (device->bytesAvailable() < qint64(sizeof(chunk) + descriptor.size))
+ return false;
+
+ return true;
+}
+
+bool QWaveDecoder::findChunk(const char *chunkId)
+{
+ chunk descriptor;
+
+ do {
+ if (!peekChunk(&descriptor))
+ return false;
+
+ 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) + sizeWithPad);
+
+ // Skip the current amount
+ if (junkToSkip > 0)
+ discardBytes(junkToSkip);
+
+ // If we still have stuff left, just exit and try again later
+ // since we can't call peekChunk
+ if (junkToSkip > 0)
+ return false;
+
+ } while (device->bytesAvailable() > 0);
+
+ return false;
+}
+
+bool QWaveDecoder::peekChunk(chunk *pChunk, bool handleEndianness)
+{
+ if (device->bytesAvailable() < qint64(sizeof(chunk)))
+ return false;
+
+ if (!device->peek(reinterpret_cast<char *>(pChunk), sizeof(chunk)))
+ return false;
+
+ if (handleEndianness) {
+ if (bigEndian)
+ pChunk->size = qFromBigEndian<quint32>(pChunk->size);
+ else
+ pChunk->size = qFromLittleEndian<quint32>(pChunk->size);
+ }
+ return true;
+}
+
+void QWaveDecoder::discardBytes(qint64 numBytes)
+{
+ // Discards a number of bytes
+ // If the iodevice doesn't have this many bytes in it,
+ // remember how much more junk we have to skip.
+ if (device->isSequential()) {
+ QByteArray r = device->read(qMin(numBytes, qint64(16384))); // uggh, wasted memory, limit to a max of 16k
+ if (r.size() < numBytes)
+ junkToSkip = numBytes - r.size();
+ else
+ junkToSkip = 0;
+ } else {
+ quint64 origPos = device->pos();
+ device->seek(device->pos() + numBytes);
+ junkToSkip = origPos + numBytes - device->pos();
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qwavedecoder.cpp"
diff --git a/src/multimedia/audio/qwavedecoder.h b/src/multimedia/audio/qwavedecoder.h
new file mode 100644
index 000000000..a96e731db
--- /dev/null
+++ b/src/multimedia/audio/qwavedecoder.h
@@ -0,0 +1,115 @@
+// 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
+
+#include <QtCore/qiodevice.h>
+#include <QtMultimedia/qaudioformat.h>
+
+
+QT_BEGIN_NAMESPACE
+
+
+
+class Q_MULTIMEDIA_EXPORT QWaveDecoder : public QIODevice
+{
+ Q_OBJECT
+
+public:
+ explicit QWaveDecoder(QIODevice *device, QObject *parent = nullptr);
+ explicit QWaveDecoder(QIODevice *device, const QAudioFormat &format,
+ QObject *parent = nullptr);
+ ~QWaveDecoder();
+
+ QAudioFormat audioFormat() const;
+ QIODevice* getDevice();
+ int duration() const;
+ static qint64 headerLength();
+
+ bool open(QIODevice::OpenMode mode) override;
+ void close() override;
+ bool seek(qint64 pos) override;
+ qint64 pos() const override;
+ void setIODevice(QIODevice *device);
+ qint64 size() const override;
+ bool isSequential() const override;
+ qint64 bytesAvailable() const override;
+
+Q_SIGNALS:
+ void formatKnown();
+ void parsingError();
+
+private Q_SLOTS:
+ void handleData();
+
+private:
+ qint64 readData(char *data, qint64 maxlen) override;
+ qint64 writeData(const char *data, qint64 len) override;
+
+ bool writeHeader();
+ bool writeDataLength();
+ bool enoughDataAvailable();
+ bool findChunk(const char *chunkId);
+ void discardBytes(qint64 numBytes);
+ void parsingFailed();
+
+ enum State {
+ InitialState,
+ WaitingForFormatState,
+ WaitingForDataState
+ };
+
+ struct chunk
+ {
+ 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
+ {
+ chunk descriptor;
+ char type[4];
+ };
+ struct WAVEHeader
+ {
+ chunk descriptor;
+ quint16 audioFormat;
+ quint16 numChannels;
+ quint32 sampleRate;
+ quint32 byteRate;
+ quint16 blockAlign;
+ quint16 bitsPerSample;
+ };
+
+ struct DATAHeader
+ {
+ chunk descriptor;
+ };
+
+ struct CombinedHeader
+ {
+ RIFFHeader riff;
+ WAVEHeader wave;
+ DATAHeader data;
+ };
+ static const int HeaderLength = sizeof(CombinedHeader);
+
+ bool haveFormat = false;
+ bool haveHeader = false;
+ qint64 dataSize = 0;
+ QIODevice *device = nullptr;
+ QAudioFormat format;
+ State state = InitialState;
+ quint32 junkToSkip = 0;
+ bool bigEndian = false;
+ bool byteSwap = false;
+ int bps = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // WAVEDECODER_H
diff --git a/src/multimedia/audio/qwavedecoder_p.cpp b/src/multimedia/audio/qwavedecoder_p.cpp
deleted file mode 100644
index 7e10a0f10..000000000
--- a/src/multimedia/audio/qwavedecoder_p.cpp
+++ /dev/null
@@ -1,312 +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 "qwavedecoder_p.h"
-
-#include <QtCore/qtimer.h>
-#include <QtCore/qendian.h>
-
-QT_BEGIN_NAMESPACE
-
-QWaveDecoder::QWaveDecoder(QIODevice *s, QObject *parent):
- QIODevice(parent),
- haveFormat(false),
- dataSize(0),
- source(s),
- state(QWaveDecoder::InitialState),
- junkToSkip(0),
- bigEndian(false)
-{
- open(QIODevice::ReadOnly | QIODevice::Unbuffered);
-
- if (enoughDataAvailable())
- QTimer::singleShot(0, this, SLOT(handleData()));
- else
- connect(source, SIGNAL(readyRead()), SLOT(handleData()));
-}
-
-QWaveDecoder::~QWaveDecoder()
-{
-}
-
-QAudioFormat QWaveDecoder::audioFormat() const
-{
- return format;
-}
-
-int QWaveDecoder::duration() const
-{
- return size() * 1000 / (format.sampleSize() / 8) / format.channelCount() / format.sampleRate();
-}
-
-qint64 QWaveDecoder::size() const
-{
- return haveFormat ? dataSize : 0;
-}
-
-bool QWaveDecoder::isSequential() const
-{
- return source->isSequential();
-}
-
-qint64 QWaveDecoder::bytesAvailable() const
-{
- return haveFormat ? source->bytesAvailable() : 0;
-}
-
-qint64 QWaveDecoder::readData(char *data, qint64 maxlen)
-{
- return haveFormat ? source->read(data, maxlen) : 0;
-}
-
-qint64 QWaveDecoder::writeData(const char *data, qint64 len)
-{
- Q_UNUSED(data);
- Q_UNUSED(len);
-
- return -1;
-}
-
-void QWaveDecoder::parsingFailed()
-{
- Q_ASSERT(source);
- source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData()));
- emit parsingError();
-}
-
-void QWaveDecoder::handleData()
-{
- // As a special "state", if we have junk to skip, we do
- if (junkToSkip > 0) {
- discardBytes(junkToSkip); // this also updates junkToSkip
-
- // If we couldn't skip all the junk, return
- if (junkToSkip > 0) {
- // We might have run out
- if (source->atEnd())
- parsingFailed();
- return;
- }
- }
-
- if (state == QWaveDecoder::InitialState) {
- if (source->bytesAvailable() < qint64(sizeof(RIFFHeader)))
- return;
-
- RIFFHeader riff;
- source->read(reinterpret_cast<char *>(&riff), sizeof(RIFFHeader));
-
- // RIFF = little endian RIFF, RIFX = big endian RIFF
- if (((qstrncmp(riff.descriptor.id, "RIFF", 4) != 0) && (qstrncmp(riff.descriptor.id, "RIFX", 4) != 0))
- || qstrncmp(riff.type, "WAVE", 4) != 0) {
- parsingFailed();
- return;
- } else {
- state = QWaveDecoder::WaitingForFormatState;
- if (qstrncmp(riff.descriptor.id, "RIFX", 4) == 0)
- bigEndian = true;
- else
- bigEndian = false;
- }
- }
-
- if (state == QWaveDecoder::WaitingForFormatState) {
- if (findChunk("fmt ")) {
- chunk descriptor;
- peekChunk(&descriptor);
-
- quint32 rawChunkSize = descriptor.size + sizeof(chunk);
- if (source->bytesAvailable() < qint64(rawChunkSize))
- return;
-
- WAVEHeader wave;
- source->read(reinterpret_cast<char *>(&wave), sizeof(WAVEHeader));
-
- if (rawChunkSize > sizeof(WAVEHeader))
- discardBytes(rawChunkSize - sizeof(WAVEHeader));
-
- // Swizzle this
- if (bigEndian) {
- wave.audioFormat = qFromBigEndian<quint16>(wave.audioFormat);
- } else {
- wave.audioFormat = qFromLittleEndian<quint16>(wave.audioFormat);
- }
-
- if (wave.audioFormat != 0 && wave.audioFormat != 1) {
- // 32bit wave files have format == 0xFFFE (WAVE_FORMAT_EXTENSIBLE).
- // but don't support them at the moment.
- parsingFailed();
- return;
- } else {
- format.setCodec(QLatin1String("audio/pcm"));
-
- if (bigEndian) {
- int bps = qFromBigEndian<quint16>(wave.bitsPerSample);
-
- format.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt);
- format.setByteOrder(QAudioFormat::BigEndian);
- format.setSampleRate(qFromBigEndian<quint32>(wave.sampleRate));
- format.setSampleSize(bps);
- format.setChannelCount(qFromBigEndian<quint16>(wave.numChannels));
- } else {
- int bps = qFromLittleEndian<quint16>(wave.bitsPerSample);
-
- format.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt);
- format.setByteOrder(QAudioFormat::LittleEndian);
- format.setSampleRate(qFromLittleEndian<quint32>(wave.sampleRate));
- format.setSampleSize(bps);
- format.setChannelCount(qFromLittleEndian<quint16>(wave.numChannels));
- }
-
- state = QWaveDecoder::WaitingForDataState;
- }
- }
- }
-
- if (state == QWaveDecoder::WaitingForDataState) {
- if (findChunk("data")) {
- source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData()));
-
- chunk descriptor;
- source->read(reinterpret_cast<char *>(&descriptor), sizeof(chunk));
- if (bigEndian)
- descriptor.size = qFromBigEndian<quint32>(descriptor.size);
- else
- descriptor.size = qFromLittleEndian<quint32>(descriptor.size);
-
- dataSize = descriptor.size;
-
- haveFormat = true;
- connect(source, SIGNAL(readyRead()), SIGNAL(readyRead()));
- emit formatKnown();
-
- return;
- }
- }
-
- // If we hit the end without finding data, it's a parsing error
- if (source->atEnd()) {
- parsingFailed();
- }
-}
-
-bool QWaveDecoder::enoughDataAvailable()
-{
- chunk descriptor;
- if (!peekChunk(&descriptor, false))
- return false;
-
- // This is only called for the RIFF/RIFX header, before bigEndian is set,
- // so we have to manually swizzle
- if (qstrncmp(descriptor.id, "RIFX", 4) == 0)
- descriptor.size = qFromBigEndian<quint32>(descriptor.size);
- if (qstrncmp(descriptor.id, "RIFF", 4) == 0)
- descriptor.size = qFromLittleEndian<quint32>(descriptor.size);
-
- if (source->bytesAvailable() < qint64(sizeof(chunk) + descriptor.size))
- return false;
-
- return true;
-}
-
-bool QWaveDecoder::findChunk(const char *chunkId)
-{
- chunk descriptor;
-
- do {
- if (!peekChunk(&descriptor))
- return false;
-
- if (qstrncmp(descriptor.id, chunkId, 4) == 0)
- return true;
-
- // It's possible that bytes->available() is less than the chunk size
- // if it's corrupt.
- junkToSkip = qint64(sizeof(chunk) + descriptor.size);
-
- // Skip the current amount
- if (junkToSkip > 0)
- discardBytes(junkToSkip);
-
- // If we still have stuff left, just exit and try again later
- // since we can't call peekChunk
- if (junkToSkip > 0)
- return false;
-
- } while (source->bytesAvailable() > 0);
-
- return false;
-}
-
-bool QWaveDecoder::peekChunk(chunk *pChunk, bool handleEndianness)
-{
- if (source->bytesAvailable() < qint64(sizeof(chunk)))
- return false;
-
- source->peek(reinterpret_cast<char *>(pChunk), sizeof(chunk));
- if (handleEndianness) {
- if (bigEndian)
- pChunk->size = qFromBigEndian<quint32>(pChunk->size);
- else
- pChunk->size = qFromLittleEndian<quint32>(pChunk->size);
- }
- return true;
-}
-
-void QWaveDecoder::discardBytes(qint64 numBytes)
-{
- // Discards a number of bytes
- // If the iodevice doesn't have this many bytes in it,
- // remember how much more junk we have to skip.
- if (source->isSequential()) {
- QByteArray r = source->read(qMin(numBytes, qint64(16384))); // uggh, wasted memory, limit to a max of 16k
- if (r.size() < numBytes)
- junkToSkip = numBytes - r.size();
- else
- junkToSkip = 0;
- } else {
- quint64 origPos = source->pos();
- source->seek(source->pos() + numBytes);
- junkToSkip = origPos + numBytes - source->pos();
- }
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qwavedecoder_p.cpp"
diff --git a/src/multimedia/audio/qwavedecoder_p.h b/src/multimedia/audio/qwavedecoder_p.h
deleted file mode 100644
index 3be0dbaa6..000000000
--- a/src/multimedia/audio/qwavedecoder_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 WAVEDECODER_H
-#define WAVEDECODER_H
-
-//
-// 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.
-//
-
-#include <QtCore/qiodevice.h>
-#include <qaudioformat.h>
-
-
-QT_BEGIN_NAMESPACE
-
-
-
-class QWaveDecoder : public QIODevice
-{
- Q_OBJECT
-
-public:
- explicit QWaveDecoder(QIODevice *source, QObject *parent = nullptr);
- ~QWaveDecoder();
-
- QAudioFormat audioFormat() const;
- int duration() const;
-
- qint64 size() const override;
- bool isSequential() const override;
- qint64 bytesAvailable() const override;
-
-Q_SIGNALS:
- void formatKnown();
- void parsingError();
-
-private Q_SLOTS:
- void handleData();
-
-private:
- qint64 readData(char *data, qint64 maxlen) override;
- qint64 writeData(const char *data, qint64 len) override;
-
- bool enoughDataAvailable();
- bool findChunk(const char *chunkId);
- void discardBytes(qint64 numBytes);
- void parsingFailed();
-
- enum State {
- InitialState,
- WaitingForFormatState,
- WaitingForDataState
- };
-
- struct chunk
- {
- char id[4];
- quint32 size;
- };
- bool peekChunk(chunk* pChunk, bool handleEndianness = true);
-
- struct RIFFHeader
- {
- chunk descriptor;
- char type[4];
- };
- struct WAVEHeader
- {
- chunk descriptor;
- quint16 audioFormat;
- quint16 numChannels;
- quint32 sampleRate;
- quint32 byteRate;
- quint16 blockAlign;
- quint16 bitsPerSample;
- };
-
- bool haveFormat;
- qint64 dataSize;
- QAudioFormat format;
- QIODevice *source;
- State state;
- quint32 junkToSkip;
- bool bigEndian;
-};
-
-QT_END_NAMESPACE
-
-#endif // WAVEDECODER_H
diff --git a/src/multimedia/camera/camera.pri b/src/multimedia/camera/camera.pri
deleted file mode 100644
index 29ed96668..000000000
--- a/src/multimedia/camera/camera.pri
+++ /dev/null
@@ -1,22 +0,0 @@
-INCLUDEPATH += camera
-
-PRIVATE_HEADERS += \
- camera/qcamera_p.h
-
-PUBLIC_HEADERS += \
- camera/qcamera.h \
- camera/qcameraimagecapture.h \
- camera/qcameraexposure.h \
- camera/qcamerafocus.h \
- camera/qcameraimageprocessing.h \
- camera/qcamerainfo.h \
- camera/qcameraviewfindersettings.h
-
-SOURCES += \
- camera/qcamera.cpp \
- camera/qcameraexposure.cpp \
- camera/qcamerafocus.cpp \
- camera/qcameraimageprocessing.cpp \
- camera/qcameraimagecapture.cpp \
- camera/qcamerainfo.cpp \
- camera/qcameraviewfindersettings.cpp
diff --git a/src/multimedia/camera/qcamera.cpp b/src/multimedia/camera/qcamera.cpp
index b4515cfad..9cfbcc01d 100644
--- a/src/multimedia/camera/qcamera.cpp
+++ b/src/multimedia/camera/qcamera.cpp
@@ -1,87 +1,21 @@
-/****************************************************************************
-**
-** 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"
-#include "qmediaserviceprovider_p.h"
-
-#include <qcamerainfo.h>
-#include <qcameracontrol.h>
-#include <qcameralockscontrol.h>
-#include <qcameraexposurecontrol.h>
-#include <qcamerafocuscontrol.h>
-#include <qmediarecordercontrol.h>
-#include <qcameraimageprocessingcontrol.h>
-#include <qcameraimagecapturecontrol.h>
-#include <qvideodeviceselectorcontrol.h>
-#include <qcamerainfocontrol.h>
-#include <qcameraviewfindersettingscontrol.h>
+
+#include <qcameradevice.h>
+#include <private/qplatformcamera_p.h>
+#include <private/qplatformimagecapture_p.h>
+#include <private/qplatformmediaintegration_p.h>
+#include <private/qplatformmediacapture_p.h>
+#include <qmediadevices.h>
+#include <qmediacapturesession.h>
#include <QDebug>
QT_BEGIN_NAMESPACE
-static void qRegisterCameraMetaTypes()
-{
- qRegisterMetaType<QCamera::Error>("QCamera::Error");
- qRegisterMetaType<QCamera::State>("QCamera::State");
- qRegisterMetaType<QCamera::Status>("QCamera::Status");
- qRegisterMetaType<QCamera::CaptureModes>("QCamera::CaptureModes");
- qRegisterMetaType<QCamera::LockType>("QCamera::LockType");
- qRegisterMetaType<QCamera::LockStatus>("QCamera::LockStatus");
- qRegisterMetaType<QCamera::LockChangeReason>("QCamera::LockChangeReason");
- qRegisterMetaType<QCamera::Position>("QCamera::Position");
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterCameraMetaTypes)
-
-Q_DECL_CONSTEXPR static bool qt_sizeLessThan(const QSize &s1, const QSize &s2) Q_DECL_NOTHROW
-{
- return (s1.width() * s1.height()) < (s2.width() * s2.height());
-}
-
-Q_DECL_CONSTEXPR static bool qt_frameRateRangeLessThan(const QCamera::FrameRateRange &s1, const QCamera::FrameRateRange &s2) Q_DECL_NOTHROW
-{
- return qFuzzyCompare(s1.maximumFrameRate, s2.maximumFrameRate) ? (s1.minimumFrameRate < s2.minimumFrameRate)
- : (s1.maximumFrameRate < s2.maximumFrameRate);
-}
-
/*!
\class QCamera
@@ -92,301 +26,173 @@ Q_DECL_CONSTEXPR static bool qt_frameRateRangeLessThan(const QCamera::FrameRateR
\ingroup multimedia
\ingroup multimedia_camera
- QCamera can be used with QCameraViewfinder for viewfinder display,
- QMediaRecorder for video recording and QCameraImageCapture for image taking.
+ QCamera can be used within a QMediaCaptureSession for video recording and image taking.
- You can use QCameraInfo to list available cameras and choose which one to use.
+ You can use QCameraDevice to list available cameras and choose which one to use.
\snippet multimedia-snippets/camera.cpp Camera selection
- See the \l{Camera Overview}{camera overview} for more information.
-*/
-
-void QCameraPrivate::_q_error(int error, const QString &errorString)
-{
- Q_Q(QCamera);
+ 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.
- this->error = QCamera::Error(error);
- this->errorString = errorString;
+ \snippet multimedia-snippets/camera.cpp Camera custom focus
- emit q->errorOccurred(this->error);
-}
+ The \l minimumZoomFactor() and \l maximumZoomFactor() methods provide the
+ range of supported zoom factors. The \l zoomTo() method allows changing
+ the zoom factor.
-void QCameraPrivate::setState(QCamera::State newState)
-{
- unsetError();
-
- if (!control) {
- _q_error(QCamera::ServiceMissingError, QCamera::tr("The camera service is missing"));
- return;
- }
+ \snippet multimedia-snippets/camera.cpp Camera zoom
- restartPending = false;
- control->setState(newState);
-}
-void QCameraPrivate::_q_updateState(QCamera::State newState)
-{
- Q_Q(QCamera);
+ 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.
- //omit changins state to Loaded when the camera is temporarily
- //stopped to apply shanges
- if (restartPending)
- return;
+ 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:
- if (newState != state) {
- state = newState;
- emit q->stateChanged(state);
- }
-}
+ \snippet multimedia-snippets/camera.cpp Camera image whitebalance
-void QCameraPrivate::_q_preparePropertyChange(int changeType)
-{
- if (!control)
- return;
+ For more information on image processing of camera frames, see
+ \l {camera_image_processing}{Camera Image Processing}.
- QCamera::Status status = control->status();
+ See the \l{Camera Overview}{camera overview} for more information.
+*/
- //all the changes are allowed until the camera is starting
- if (control->state() != QCamera::ActiveState)
- return;
+/*!
+ \qmltype Camera
+ \instantiates QCamera
+ \inqmlmodule QtMultimedia
+ \brief An interface for camera settings related to focus and zoom.
+ \ingroup multimedia_qml
+ \ingroup camera_qml
- if (control->canChangeProperty(QCameraControl::PropertyChangeType(changeType), status))
- return;
+ The Camera element can be used within a \l CaptureSession for video recording
+ and image taking.
- restartPending = true;
- control->setState(QCamera::LoadedState);
- QMetaObject::invokeMethod(q_ptr, "_q_restartCamera", Qt::QueuedConnection);
-}
+ You can use \l MediaDevices to list available cameras and choose which one to use.
-void QCameraPrivate::_q_restartCamera()
-{
- if (restartPending) {
- restartPending = false;
- control->setState(QCamera::ActiveState);
+ \qml
+ MediaDevices {
+ id: mediaDevices
}
-}
-
-void QCameraPrivate::init()
-{
- Q_Q(QCamera);
- provider = QMediaServiceProvider::defaultServiceProvider();
- initControls();
- cameraExposure = new QCameraExposure(q);
- cameraFocus = new QCameraFocus(q);
- imageProcessing = new QCameraImageProcessing(q);
-}
-
-void QCameraPrivate::initControls()
-{
- Q_Q(QCamera);
-
- if (service) {
- control = qobject_cast<QCameraControl *>(service->requestControl(QCameraControl_iid));
- locksControl = qobject_cast<QCameraLocksControl *>(service->requestControl(QCameraLocksControl_iid));
- deviceControl = qobject_cast<QVideoDeviceSelectorControl*>(service->requestControl(QVideoDeviceSelectorControl_iid));
- infoControl = qobject_cast<QCameraInfoControl*>(service->requestControl(QCameraInfoControl_iid));
- viewfinderSettingsControl2 = qobject_cast<QCameraViewfinderSettingsControl2*>(service->requestControl(QCameraViewfinderSettingsControl2_iid));
- if (!viewfinderSettingsControl2)
- viewfinderSettingsControl = qobject_cast<QCameraViewfinderSettingsControl*>(service->requestControl(QCameraViewfinderSettingsControl_iid));
-
- if (control) {
- q->connect(control, SIGNAL(stateChanged(QCamera::State)), q, SLOT(_q_updateState(QCamera::State)));
- q->connect(control, SIGNAL(statusChanged(QCamera::Status)), q, SIGNAL(statusChanged(QCamera::Status)));
- q->connect(control, SIGNAL(captureModeChanged(QCamera::CaptureModes)),
- q, SIGNAL(captureModeChanged(QCamera::CaptureModes)));
- q->connect(control, SIGNAL(error(int,QString)), q, SLOT(_q_error(int,QString)));
-
+ CaptureSession {
+ camera: Camera {
+ cameraDevice: mediaDevices.defaultVideoInput
}
-
- if (locksControl) {
- q->connect(locksControl, SIGNAL(lockStatusChanged(QCamera::LockType,QCamera::LockStatus,QCamera::LockChangeReason)),
- q, SLOT(_q_updateLockStatus(QCamera::LockType,QCamera::LockStatus,QCamera::LockChangeReason)));
- }
-
- error = QCamera::NoError;
- } else {
- control = nullptr;
- locksControl = nullptr;
- deviceControl = nullptr;
- infoControl = nullptr;
- viewfinderSettingsControl = nullptr;
- viewfinderSettingsControl2 = nullptr;
-
- error = QCamera::ServiceMissingError;
- errorString = QCamera::tr("The camera service is missing");
}
-}
+ \endqml
-void QCameraPrivate::clear()
-{
- delete cameraExposure;
- delete cameraFocus;
- delete imageProcessing;
-
- if (service) {
- if (control)
- service->releaseControl(control);
- if (locksControl)
- service->releaseControl(locksControl);
- if (deviceControl)
- service->releaseControl(deviceControl);
- if (infoControl)
- service->releaseControl(infoControl);
- if (viewfinderSettingsControl)
- service->releaseControl(viewfinderSettingsControl);
- if (viewfinderSettingsControl2)
- service->releaseControl(viewfinderSettingsControl2);
-
- provider->releaseService(service);
- }
+ 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.
- cameraExposure = nullptr;
- cameraFocus = nullptr;
- imageProcessing = nullptr;
- control = nullptr;
- locksControl = nullptr;
- deviceControl = nullptr;
- infoControl = nullptr;
- viewfinderSettingsControl = nullptr;
- viewfinderSettingsControl2 = nullptr;
- service = nullptr;
-}
+ \qml
-void QCameraPrivate::updateLockStatus()
-{
- Q_Q(QCamera);
+ Item {
+ width: 640
+ height: 360
- QCamera::LockStatus oldStatus = lockStatus;
+ CaptureSession {
+ camera: Camera {
+ id: camera
- QMap<QCamera::LockStatus, int> lockStatusPriority;
- lockStatusPriority.insert(QCamera::Locked, 1);
- lockStatusPriority.insert(QCamera::Unlocked, 2);
- lockStatusPriority.insert(QCamera::Searching, 3);
+ focusMode: Camera.FocusModeAutoNear
+ customFocusPoint: Qt.point(0.2, 0.2) // Focus relative to top-left corner
+ }
+ videoOutput: videoOutput
+ }
- lockStatus = requestedLocks ? QCamera::Locked : QCamera::Unlocked;
- int priority = 0;
+ VideoOutput {
+ id: videoOutput
+ anchors.fill: parent
+ }
+ }
- QList<QCamera::LockStatus> lockStatuses;
+ \endqml
- if (requestedLocks & QCamera::LockFocus)
- lockStatuses << q->lockStatus(QCamera::LockFocus);
+ The \l minimumZoomFactor and \l maximumZoomFactor properties provide the
+ range of supported zoom factors. The \l zoomFactor property allows changing
+ the zoom factor.
- if (requestedLocks & QCamera::LockExposure)
- lockStatuses << q->lockStatus(QCamera::LockExposure);
+ \qml
+ Camera {
+ zoomFactor: maximumZoomFactor // zoom in as much as possible
+ }
+ \endqml
- if (requestedLocks & QCamera::LockWhiteBalance)
- lockStatuses << q->lockStatus(QCamera::LockWhiteBalance);
+ 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:
- for (QCamera::LockStatus currentStatus : qAsConst(lockStatuses)) {
- int currentPriority = lockStatusPriority.value(currentStatus, -1);
- if (currentPriority > priority) {
- priority = currentPriority;
- lockStatus = currentStatus;
- }
+ \qml
+ Camera {
+ whiteBalanceMode: Camera.WhiteBalanceManual
+ colorTemperature: 5600
}
+ \endqml
- if (!supressLockChangedSignal && oldStatus != lockStatus) {
- emit q->lockStatusChanged(lockStatus, lockChangeReason);
+ For more information on image processing of camera frames, see
+ \l {camera_image_processing}{Camera Image Processing}.
- if (lockStatus == QCamera::Locked)
- emit q->locked();
- else if (lockStatus == QCamera::Unlocked && lockChangeReason == QCamera::LockFailed)
- emit q->lockFailed();
- }
-/*
- qDebug() << "Requested locks:" << (requestedLocks & QCamera::LockExposure ? 'e' : ' ')
- << (requestedLocks & QCamera::LockFocus ? 'f' : ' ')
- << (requestedLocks & QCamera::LockWhiteBalance ? 'w' : ' ');
- qDebug() << "Lock status: f:" << q->lockStatus(QCamera::LockFocus)
- << " e:" << q->lockStatus(QCamera::LockExposure)
- << " w:" << q->lockStatus(QCamera::LockWhiteBalance)
- << " composite:" << lockStatus;
+ See the \l{Camera Overview}{camera overview} for more information.
*/
-}
-void QCameraPrivate::_q_updateLockStatus(QCamera::LockType type, QCamera::LockStatus status, QCamera::LockChangeReason reason)
+void QCameraPrivate::init(const QCameraDevice &device)
{
Q_Q(QCamera);
- lockChangeReason = reason;
- updateLockStatus();
- emit q->lockStatusChanged(type, status, reason);
-}
-
-
-/*!
- Construct a QCamera with a \a parent.
-*/
-
-QCamera::QCamera(QObject *parent):
- QMediaObject(*new QCameraPrivate,
- parent,
- QMediaServiceProvider::defaultServiceProvider()->requestService(Q_MEDIASERVICE_CAMERA))
-{
- Q_D(QCamera);
- d->init();
- // Select the default camera
- if (d->service != nullptr && d->deviceControl)
- d->deviceControl->setSelectedDevice(d->deviceControl->defaultDevice());
+ auto maybeControl = QPlatformMediaIntegration::instance()->createCamera(q);
+ if (!maybeControl) {
+ qWarning() << "Failed to initialize QCamera" << maybeControl.error();
+ return;
+ }
+ control = maybeControl.value();
+ cameraDevice = !device.isNull() ? device : QMediaDevices::defaultVideoInput();
+ if (cameraDevice.isNull())
+ control->updateError(QCamera::CameraError, QStringLiteral("No camera detected"));
+ control->setCamera(cameraDevice);
+ q->connect(control, &QPlatformVideoSource::activeChanged, q, &QCamera::activeChanged);
+ q->connect(control, &QPlatformCamera::errorChanged, q, &QCamera::errorChanged);
+ q->connect(control, &QPlatformCamera::errorOccurred, q, &QCamera::errorOccurred);
}
/*!
- Construct a QCamera from \a deviceName and \a parent.
+ Construct a QCamera with a \a parent.
- If no camera with that \a deviceName exists, the camera object will
- be invalid.
+ Selects the default camera on the system if more than one camera is available.
*/
-QCamera::QCamera(const QByteArray& deviceName, QObject *parent):
- QMediaObject(*new QCameraPrivate, parent,
- QMediaServiceProvider::defaultServiceProvider()->requestService(Q_MEDIASERVICE_CAMERA,
- QMediaServiceProviderHint(deviceName)))
+QCamera::QCamera(QObject *parent)
+ : QCamera(QMediaDevices::defaultVideoInput(), parent)
{
- Q_D(QCamera);
- d->init();
-
- bool found = false;
- // Pass device name to service.
- if (d->deviceControl) {
- const QString name = QString::fromLatin1(deviceName);
- for (int i = 0; i < d->deviceControl->deviceCount(); i++) {
- if (d->deviceControl->deviceName(i) == name) {
- d->deviceControl->setSelectedDevice(i);
- found = true;
- break;
- }
- }
- }
-
- // The camera should not be used if device with requested name does not exist.
- if (!found) {
- if (d->service) {
- if (d->control)
- d->service->releaseControl(d->control);
- if (d->deviceControl)
- d->service->releaseControl(d->deviceControl);
- if (d->infoControl)
- d->service->releaseControl(d->infoControl);
- }
- d->control = nullptr;
- d->deviceControl = nullptr;
- d->infoControl = nullptr;
- d->error = QCamera::ServiceMissingError;
- d->errorString = QCamera::tr("The camera service is missing");
- }
}
/*!
\since 5.3
- Construct a QCamera from a camera description \a cameraInfo and \a parent.
+ Construct a QCamera from a camera description \a cameraDevice and \a parent.
*/
-QCamera::QCamera(const QCameraInfo &cameraInfo, QObject *parent)
- : QCamera(cameraInfo.deviceName().toLatin1(), parent)
+QCamera::QCamera(const QCameraDevice &cameraDevice, QObject *parent)
+ : QObject(*new QCameraPrivate, parent)
{
+ Q_D(QCamera);
+ d->init(cameraDevice);
}
/*!
@@ -398,33 +204,23 @@ QCamera::QCamera(const QCameraInfo &cameraInfo, QObject *parent)
back-facing cameras.
If no camera is available at the specified \a position or if \a position is
- QCamera::UnspecifiedPosition, the default camera is used.
+ QCameraDevice::UnspecifiedPosition, the default camera is used.
*/
-QCamera::QCamera(QCamera::Position position, QObject *parent)
- : QMediaObject(*new QCameraPrivate,
- parent,
- QMediaServiceProvider::defaultServiceProvider()->requestService(Q_MEDIASERVICE_CAMERA, QMediaServiceProviderHint(position)))
+QCamera::QCamera(QCameraDevice::Position position, QObject *parent)
+ : QObject(*new QCameraPrivate, parent)
{
Q_D(QCamera);
- d->init();
-
- if (d->service != nullptr && d->deviceControl) {
- bool selectDefault = true;
-
- if (d->infoControl && position != UnspecifiedPosition) {
- for (int i = 0; i < d->deviceControl->deviceCount(); i++) {
- if (d->infoControl->cameraPosition(d->deviceControl->deviceName(i)) == position) {
- d->deviceControl->setSelectedDevice(i);
- selectDefault = false;
- break;
- }
- }
- }
- if (selectDefault)
- d->deviceControl->setSelectedDevice(d->deviceControl->defaultDevice());
+ QCameraDevice device;
+ auto cameras = QMediaDevices::videoInputs();
+ for (const auto &c : cameras) {
+ if (c.position() == position) {
+ device = c;
+ break;
+ }
}
+ d->init(device);
}
/*!
@@ -434,873 +230,1128 @@ QCamera::QCamera(QCamera::Position position, QObject *parent)
QCamera::~QCamera()
{
Q_D(QCamera);
- d->clear();
+ if (d->captureSession)
+ d->captureSession->setCamera(nullptr);
}
/*!
- Returns the availability state of the camera service.
+ Returns true if the camera can be used.
*/
-QMultimedia::AvailabilityStatus QCamera::availability() const
+bool QCamera::isAvailable() const
{
Q_D(const QCamera);
- if (d->control == nullptr)
- return QMultimedia::ServiceMissing;
+ return d->control && !d->cameraDevice.isNull();
+}
- if (d->deviceControl && d->deviceControl->deviceCount() == 0)
- return QMultimedia::ResourceError;
+/*! \qmlproperty bool QtMultimedia::Camera::active
- if (d->error != QCamera::NoError)
- return QMultimedia::ResourceError;
+ Describes whether the camera is currently active.
+*/
- return QMediaObject::availability();
-}
+/*! \property QCamera::active
+ Describes whether the camera is currently active.
+*/
/*!
- Returns the camera exposure control object.
+ Returns true if the camera is currently active.
*/
-QCameraExposure *QCamera::exposure() const
+bool QCamera::isActive() const
{
- return d_func()->cameraExposure;
+ Q_D(const QCamera);
+ return d->control && d->control->isActive();
}
/*!
- Returns the camera focus control object.
+ Turns the camera on if \a active is \c{true}, or off if it's \c{false}.
*/
-QCameraFocus *QCamera::focus() const
+void QCamera::setActive(bool active)
{
- return d_func()->cameraFocus;
+ Q_D(const QCamera);
+ if (d->control)
+ d->control->setActive(active);
}
/*!
- Returns the camera image processing control object.
+ \qmlproperty enumeration QtMultimedia::Camera::error
+
+ Returns the error state of the camera.
+
+ \sa QCamera::Error
*/
-QCameraImageProcessing *QCamera::imageProcessing() const
+
+/*!
+ \property QCamera::error
+
+ Returns the error state of the camera.
+*/
+
+QCamera::Error QCamera::error() const
{
- return d_func()->imageProcessing;
+ Q_D(const QCamera);
+
+ return d->control ? d->control->error() : QCamera::CameraError;
}
/*!
- Sets the QVideoWidget based camera \a viewfinder.
- The previously set viewfinder is detached.
+ \qmlproperty string QtMultimedia::Camera::errorString
- //! QVideoWidget is forward declared.
+ Returns a human readable string describing a camera's error state.
*/
-void QCamera::setViewfinder(QVideoWidget *viewfinder)
-{
- Q_D(QCamera);
- d->_q_preparePropertyChange(QCameraControl::Viewfinder);
- if (d->viewfinder)
- unbind(d->viewfinder);
+/*!
+ \property QCamera::errorString
- // We don't know (in this library) that QVideoWidget inherits QObject
- QObject *viewFinderObject = reinterpret_cast<QObject*>(viewfinder);
+ Returns a human readable string describing a camera's error state.
+*/
+QString QCamera::errorString() const
+{
+ Q_D(const QCamera);
- d->viewfinder = viewFinderObject && bind(viewFinderObject) ? viewFinderObject : nullptr;
+ return d->control ? d->control->errorString()
+ : QStringLiteral("Camera is not supported on the platform");
}
+/*! \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.
+*/
+
/*!
- Sets the QGraphicsVideoItem based camera \a viewfinder.
- The previously set viewfinder is detached.
+ \qmlproperty Features QtMultimedia::Camera::supportedFeatures
+ Returns the features supported by this camera.
- //! QGraphicsVideoItem is forward declared.
+ \sa QCamera::Feature
*/
-void QCamera::setViewfinder(QGraphicsVideoItem *viewfinder)
-{
- Q_D(QCamera);
- d->_q_preparePropertyChange(QCameraControl::Viewfinder);
- if (d->viewfinder)
- unbind(d->viewfinder);
+/*!
+ \property QCamera::supportedFeatures
- // We don't know (in this library) that QGraphicsVideoItem (multiply) inherits QObject
- // but QObject inheritance depends on QObject coming first, so try this out.
- QObject *viewFinderObject = reinterpret_cast<QObject*>(viewfinder);
+ Returns the features supported by this camera.
- d->viewfinder = viewFinderObject && bind(viewFinderObject) ? viewFinderObject : nullptr;
+ \sa QCamera::Feature
+*/
+QCamera::Features QCamera::supportedFeatures() const
+{
+ Q_D(const QCamera);
+ return d->control ? d->control->supportedFeatures() : QCamera::Features{};
}
-/*!
- Sets a video \a surface as the viewfinder of a camera.
+/*! \qmlmethod void Camera::start()
+
+ Starts the camera.
- If a viewfinder has already been set on the camera the new surface
- will replace it.
+ Same as setting the active property to true.
+
+ If the camera can't be started for some reason, the errorOccurred() signal is emitted.
*/
-void QCamera::setViewfinder(QAbstractVideoSurface *surface)
-{
- Q_D(QCamera);
+/*! \fn void QCamera::start()
- d->surfaceViewfinder.setVideoSurface(surface);
+ Starts the camera.
- if (d->viewfinder != &d->surfaceViewfinder) {
- if (d->viewfinder)
- unbind(d->viewfinder);
+ Same as setActive(true).
- d->viewfinder = nullptr;
+ If the camera can't be started for some reason, the errorOccurred() signal is emitted.
+*/
- if (surface && bind(&d->surfaceViewfinder))
- d->viewfinder = &d->surfaceViewfinder;
- } else if (!surface) {
- //unbind the surfaceViewfinder if null surface is set
- unbind(&d->surfaceViewfinder);
- d->viewfinder = nullptr;
- }
-}
+/*! \qmlmethod void Camera::stop()
-/*!
- Returns the viewfinder settings being used by the camera.
+ Stops the camera.
+ Same as setting the active property to false.
+*/
- Settings may change when the camera is started, for example if the viewfinder settings
- are undefined or if unsupported values are set.
+/*! \fn void QCamera::stop()
- If viewfinder settings are not supported by the camera, it always returns a null
- QCameraViewfinderSettings object.
+ Stops the camera.
+ Same as setActive(false).
+*/
- \sa setViewfinderSettings()
+/*!
+ Returns the capture session this camera is connected to, or
+ a nullptr if the camera is not connected to a capture session.
- \since 5.5
+ use QMediaCaptureSession::setCamera() to connect the camera to
+ a session.
*/
-QCameraViewfinderSettings QCamera::viewfinderSettings() const
+QMediaCaptureSession *QCamera::captureSession() const
{
Q_D(const QCamera);
+ return d->captureSession;
+}
- if (d->viewfinderSettingsControl2)
- return d->viewfinderSettingsControl2->viewfinderSettings();
+/*!
+ \internal
+*/
+void QCamera::setCaptureSession(QMediaCaptureSession *session)
+{
+ Q_D(QCamera);
+ d->captureSession = session;
+}
- QCameraViewfinderSettings settings;
- if (d->viewfinderSettingsControl) {
- if (d->viewfinderSettingsControl->isViewfinderParameterSupported(QCameraViewfinderSettingsControl::Resolution))
- settings.setResolution(d->viewfinderSettingsControl->viewfinderParameter(QCameraViewfinderSettingsControl::Resolution).toSize());
+/*!
+ \internal
+*/
+QPlatformCamera *QCamera::platformCamera()
+{
+ Q_D(const QCamera);
+ return d->control;
+}
- if (d->viewfinderSettingsControl->isViewfinderParameterSupported(QCameraViewfinderSettingsControl::MinimumFrameRate))
- settings.setMinimumFrameRate(d->viewfinderSettingsControl->viewfinderParameter(QCameraViewfinderSettingsControl::MinimumFrameRate).toReal());
+/*! \qmlproperty cameraDevice QtMultimedia::Camera::cameraDevice
- if (d->viewfinderSettingsControl->isViewfinderParameterSupported(QCameraViewfinderSettingsControl::MaximumFrameRate))
- settings.setMaximumFrameRate(d->viewfinderSettingsControl->viewfinderParameter(QCameraViewfinderSettingsControl::MaximumFrameRate).toReal());
+ Gets or sets the currently active camera device.
+*/
- if (d->viewfinderSettingsControl->isViewfinderParameterSupported(QCameraViewfinderSettingsControl::PixelAspectRatio))
- settings.setPixelAspectRatio(d->viewfinderSettingsControl->viewfinderParameter(QCameraViewfinderSettingsControl::PixelAspectRatio).toSize());
+/*!
+ \property QCamera::cameraDevice
- if (d->viewfinderSettingsControl->isViewfinderParameterSupported(QCameraViewfinderSettingsControl::PixelFormat))
- settings.setPixelFormat(qvariant_cast<QVideoFrame::PixelFormat>(d->viewfinderSettingsControl->viewfinderParameter(QCameraViewfinderSettingsControl::PixelFormat)));
- }
- return settings;
+ Returns the QCameraDevice object associated with this camera.
+ */
+QCameraDevice QCamera::cameraDevice() const
+{
+ Q_D(const QCamera);
+ return d->cameraDevice;
}
/*!
- Sets the viewfinder \a settings.
+ Connects the camera object to the physical camera device described by
+ \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)
+{
+ Q_D(QCamera);
+ auto dev = cameraDevice;
+ if (dev.isNull())
+ dev = QMediaDevices::defaultVideoInput();
+ if (d->cameraDevice == dev)
+ return;
+ d->cameraDevice = dev;
+ if (d->control)
+ d->control->setCamera(d->cameraDevice);
+ emit cameraDeviceChanged();
+ 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.
- If some parameters are not specified, or null settings are passed, the camera will choose
- default values.
+ \sa cameraDevice::videoFormats
+*/
- If the camera is used to capture videos or images, the viewfinder settings might be
- ignored if they conflict with the capture settings. You can check the actual viewfinder settings
- once the camera is in the \c QCamera::ActiveStatus status.
+/*!
+ \property QCamera::cameraFormat
- Changing the viewfinder settings while the camera is in the QCamera::ActiveState state may
- cause the camera to be restarted.
+ Returns the camera format currently used by the camera.
- \sa viewfinderSettings(), supportedViewfinderResolutions(), supportedViewfinderFrameRateRanges(),
- supportedViewfinderPixelFormats()
+ \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.
- \since 5.5
+ \sa QCameraDevice::videoFormats
*/
-void QCamera::setViewfinderSettings(const QCameraViewfinderSettings &settings)
+QCameraFormat QCamera::cameraFormat() const
+{
+ Q_D(const QCamera);
+ return d->cameraFormat;
+}
+
+/*!
+ 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)
{
Q_D(QCamera);
+ if (!d->control || !d->control->setCameraFormat(format))
+ return;
- if (d->viewfinderSettingsControl || d->viewfinderSettingsControl2)
- d->_q_preparePropertyChange(QCameraControl::ViewfinderSettings);
+ d->cameraFormat = format;
+ emit cameraFormatChanged();
+}
- if (d->viewfinderSettingsControl2) {
- d->viewfinderSettingsControl2->setViewfinderSettings(settings);
+/*!
+ \enum QCamera::Error
- } else if (d->viewfinderSettingsControl) {
- if (d->viewfinderSettingsControl->isViewfinderParameterSupported(QCameraViewfinderSettingsControl::Resolution))
- d->viewfinderSettingsControl->setViewfinderParameter(QCameraViewfinderSettingsControl::Resolution, settings.resolution());
+ This enum holds the last error code.
- if (d->viewfinderSettingsControl->isViewfinderParameterSupported(QCameraViewfinderSettingsControl::MinimumFrameRate))
- d->viewfinderSettingsControl->setViewfinderParameter(QCameraViewfinderSettingsControl::MinimumFrameRate, settings.minimumFrameRate());
+ \value NoError No errors have occurred.
+ \value CameraError An error has occurred.
+*/
- if (d->viewfinderSettingsControl->isViewfinderParameterSupported(QCameraViewfinderSettingsControl::MaximumFrameRate))
- d->viewfinderSettingsControl->setViewfinderParameter(QCameraViewfinderSettingsControl::MaximumFrameRate, settings.maximumFrameRate());
+/*!
+ \qmlsignal void Camera::errorOccurred(Camera::Error error, string errorString)
- if (d->viewfinderSettingsControl->isViewfinderParameterSupported(QCameraViewfinderSettingsControl::PixelAspectRatio))
- d->viewfinderSettingsControl->setViewfinderParameter(QCameraViewfinderSettingsControl::PixelAspectRatio, settings.pixelAspectRatio());
+ This signal is emitted when error state changes to \a error. A description
+ of the error is provided as \a errorString.
+*/
- if (d->viewfinderSettingsControl->isViewfinderParameterSupported(QCameraViewfinderSettingsControl::PixelFormat))
- d->viewfinderSettingsControl->setViewfinderParameter(QCameraViewfinderSettingsControl::PixelFormat, settings.pixelFormat());
- }
-}
+/*!
+ \fn void QCamera::errorOccurred(QCamera::Error error, const QString &errorString)
+
+ This signal is emitted when error state changes to \a error. A description
+ of the error is provided as \a errorString.
+*/
/*!
- Returns a list of supported viewfinder settings.
+ \qmlproperty enumeration Camera::focusMode
+
+ This property holds the current camera focus mode.
- The list is ordered by preference; preferred settings come first.
+ \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.
- The optional \a settings argument can be used to conveniently filter the results.
- If \a settings is non null, the returned list is reduced to settings matching the given partial
- \a settings.
+ \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.
+
+ If a certain focus mode is not supported, setting it will have no effect.
+
+ \sa isFocusModeSupported
+*/
- The status of the camera must be LoadedStatus before calling this function, otherwise the returned list
- is empty.
+/*!
+ \property QCamera::focusMode
+ \brief the current camera focus mode.
- \sa setViewfinderSettings(), supportedViewfinderResolutions(), supportedViewfinderFrameRateRanges(),
- supportedViewfinderPixelFormats()
+ Sets up different focus modes for the camera. All auto focus modes will focus continuously.
+ Locking the focus is possible by setting the focus mode to \l FocusModeManual. This will keep
+ the current focus and stop any automatic focusing.
- \since 5.5
+ \sa isFocusModeSupported
*/
-QList<QCameraViewfinderSettings> QCamera::supportedViewfinderSettings(const QCameraViewfinderSettings &settings) const
+QCamera::FocusMode QCamera::focusMode() const
{
Q_D(const QCamera);
+ return d->control ? d->control->focusMode() : QCamera::FocusModeAuto;
+}
- if (!d->viewfinderSettingsControl2)
- return QList<QCameraViewfinderSettings>();
-
- if (settings.isNull())
- return d->viewfinderSettingsControl2->supportedViewfinderSettings();
-
- QList<QCameraViewfinderSettings> results;
- const QList<QCameraViewfinderSettings> supported = d->viewfinderSettingsControl2->supportedViewfinderSettings();
- for (const QCameraViewfinderSettings &s : supported) {
- if ((settings.resolution().isEmpty() || settings.resolution() == s.resolution())
- && (qFuzzyIsNull(settings.minimumFrameRate()) || qFuzzyCompare((float)settings.minimumFrameRate(), (float)s.minimumFrameRate()))
- && (qFuzzyIsNull(settings.maximumFrameRate()) || qFuzzyCompare((float)settings.maximumFrameRate(), (float)s.maximumFrameRate()))
- && (settings.pixelFormat() == QVideoFrame::Format_Invalid || settings.pixelFormat() == s.pixelFormat())
- && (settings.pixelAspectRatio().isEmpty() || settings.pixelAspectRatio() == s.pixelAspectRatio())) {
- results.append(s);
- }
- }
+/*!
+ \fn void QCamera::focusModeChanged()
- return results;
+ Signals when the focusMode changes.
+*/
+void QCamera::setFocusMode(QCamera::FocusMode mode)
+{
+ Q_D(QCamera);
+ if (!d->control || d->control->focusMode() == mode)
+ return;
+ d->control->setFocusMode(mode);
+ emit focusModeChanged();
}
/*!
- Returns a list of supported viewfinder resolutions.
+ \qmlmethod bool Camera::isFocusModeSupported(FocusMode mode)
- This is a convenience function which retrieves unique resolutions from the supported settings.
+ Returns true if the focus \a mode is supported by the camera.
+*/
- If non null viewfinder \a settings are passed, the returned list is reduced to resolutions
- supported with partial \a settings applied.
+/*!
+ Returns true if the focus \a mode is supported by the camera.
+*/
+bool QCamera::isFocusModeSupported(FocusMode mode) const
+{
+ Q_D(const QCamera);
+ return d->control ? d->control->isFocusModeSupported(mode) : false;
+}
- The camera must be loaded before calling this function, otherwise the returned list
- is empty.
+/*!
+ \qmlproperty point QtMultimedia::Camera::focusPoint
+ Returns the point currently used by the auto focus system to focus onto.
+*/
- \sa QCameraViewfinderSettings::resolution(), setViewfinderSettings()
+/*!
+ \property QCamera::focusPoint
- \since 5.5
-*/
-QList<QSize> QCamera::supportedViewfinderResolutions(const QCameraViewfinderSettings &settings) const
+ Returns the point currently used by the auto focus system to focus onto.
+ */
+QPointF QCamera::focusPoint() const
{
- QList<QSize> resolutions;
- const QList<QCameraViewfinderSettings> capabilities = supportedViewfinderSettings(settings);
- for (const QCameraViewfinderSettings &s : capabilities) {
- if (!resolutions.contains(s.resolution()))
- resolutions.append(s.resolution());
- }
- std::sort(resolutions.begin(), resolutions.end(), qt_sizeLessThan);
+ Q_D(const QCamera);
+ return d->control ? d->control->focusPoint() : QPointF(-1., -1.);
- return resolutions;
}
/*!
- Returns a list of supported viewfinder frame rate ranges.
+ \qmlproperty point QtMultimedia::Camera::customFocusPoint
+
+ 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.
- This is a convenience function which retrieves unique frame rate ranges from the supported settings.
+ Custom focus point is used only in \c FocusPointCustom focus mode.
- If non null viewfinder \a settings are passed, the returned list is reduced to frame rate ranges
- supported with partial \a settings applied.
+ You can check whether custom focus points are supported by querying
+ supportedFeatures() with the Feature.CustomFocusPoint flag.
+*/
- The camera must be loaded before calling this function, otherwise the returned list
- is empty.
+/*!
+ \property QCamera::customFocusPoint
- \sa QCameraViewfinderSettings::minimumFrameRate(), QCameraViewfinderSettings::maximumFrameRate(),
- setViewfinderSettings()
+ 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.
- \since 5.5
+ 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.
*/
-QList<QCamera::FrameRateRange> QCamera::supportedViewfinderFrameRateRanges(const QCameraViewfinderSettings &settings) const
+QPointF QCamera::customFocusPoint() const
{
- QList<QCamera::FrameRateRange> frameRateRanges;
- const QList<QCameraViewfinderSettings> capabilities = supportedViewfinderSettings(settings);
- for (const QCameraViewfinderSettings &s : capabilities) {
- QCamera::FrameRateRange range(s.minimumFrameRate(), s.maximumFrameRate());
- if (!frameRateRanges.contains(range))
- frameRateRanges.append(range);
- }
- std::sort(frameRateRanges.begin(), frameRateRanges.end(), qt_frameRateRangeLessThan);
+ Q_D(const QCamera);
+ return d->control ? d->control->customFocusPoint() : QPointF{-1., -1.};
+}
- return frameRateRanges;
+void QCamera::setCustomFocusPoint(const QPointF &point)
+{
+ Q_D(QCamera);
+ if (d->control)
+ d->control->setCustomFocusPoint(point);
}
/*!
- Returns a list of supported viewfinder pixel formats.
+ \qmlproperty float QtMultimedia::Camera::focusDistance
- This is a convenience function which retrieves unique pixel formats from the supported settings.
+ 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.
- If non null viewfinder \a settings are passed, the returned list is reduced to pixel formats
- supported with partial \a settings applied.
+ Setting the focus distance will be ignored unless the focus mode is set to
+ \l {focusMode}{FocusModeManual}.
+*/
- The camera must be loaded before calling this function, otherwise the returned list
- is empty.
+/*!
+ \property QCamera::focusDistance
- \sa QCameraViewfinderSettings::pixelFormat(), setViewfinderSettings()
+ 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.
- \since 5.5
+ Setting the focus distance will be ignored unless the focus mode is set to
+ \l FocusModeManual.
*/
-QList<QVideoFrame::PixelFormat> QCamera::supportedViewfinderPixelFormats(const QCameraViewfinderSettings &settings) const
+void QCamera::setFocusDistance(float d)
{
- QList<QVideoFrame::PixelFormat> pixelFormats;
- const QList<QCameraViewfinderSettings> capabilities = supportedViewfinderSettings(settings);
- for (const QCameraViewfinderSettings &s : capabilities) {
- if (!pixelFormats.contains(s.pixelFormat()))
- pixelFormats.append(s.pixelFormat());
- }
+ if (!d_func()->control || focusMode() != FocusModeManual)
+ return;
+ d_func()->control->setFocusDistance(d);
+}
- return pixelFormats;
+float QCamera::focusDistance() const
+{
+ if (d_func()->control && focusMode() == FocusModeManual)
+ return d_func()->control->focusDistance();
+ return 0.;
}
/*!
- Returns the error state of the object.
+ \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.
*/
-QCamera::Error QCamera::error() const
-{
- return d_func()->error;
-}
/*!
- Returns a string describing a camera's error state.
+ \property QCamera::maximumZoomFactor
+
+ Returns the maximum zoom factor.
+
+ This will be \c 1.0 on cameras that do not support zooming.
*/
-QString QCamera::errorString() const
+
+float QCamera::maximumZoomFactor() const
{
- return d_func()->errorString;
+ Q_D(const QCamera);
+ 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.
+*/
/*!
- Returns true if the capture \a mode is suported.
+ \property QCamera::minimumZoomFactor
+
+ Returns the minimum zoom factor.
+
+ This will be \c 1.0 on cameras that do not support zooming.
*/
-bool QCamera::isCaptureModeSupported(QCamera::CaptureModes mode) const
+
+float QCamera::minimumZoomFactor() const
{
- return d_func()->control ? d_func()->control->isCaptureModeSupported(mode) : false;
+ Q_D(const QCamera);
+ return d->control ? d->control->minZoomFactor() : 1.f;
}
/*!
- \property QCamera::captureMode
+ \qmlproperty real QtMultimedia::Camera::zoomFactor
- The type of media (video or still images),
- the camera is configured to capture.
-
- It's allowed to change capture mode in any camera state,
- but if the camera is currently active,
- chaging capture mode is likely to lead to camera status
- chaged to QCamera::LoadedStatus, QCamera::LoadingStatus,
- and when the camera is ready to QCamera::ActiveStatus.
+ Gets or sets the current zoom factor. Values will be clamped between
+ \l minimumZoomFactor and \l maximumZoomFactor.
*/
-QCamera::CaptureModes QCamera::captureMode() const
+/*!
+ \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
{
- return d_func()->control ? d_func()->control->captureMode() : QCamera::CaptureStillImage;
+ Q_D(const QCamera);
+ return d->control ? d->control->zoomFactor() : 1.f;
}
-
-void QCamera::setCaptureMode(QCamera::CaptureModes mode)
+/*!
+ Zooms to a zoom factor \a factor at a rate of 1 factor per second.
+ */
+void QCamera::setZoomFactor(float factor)
{
- Q_D(QCamera);
-
- if (mode != captureMode()) {
- if (d->control) {
- d->_q_preparePropertyChange(QCameraControl::CaptureMode);
- d->control->setCaptureMode(mode);
- }
- }
+ zoomTo(factor, 0.f);
}
-
/*!
- Starts the camera.
+ \qmlmethod void QtMultimedia::Camera::zoomTo(factor, rate)
- State is changed to QCamera::ActiveState if camera is started
- successfully, otherwise errorOccurred() signal is emitted.
+ Zooms to a zoom factor \a factor using \a rate.
- While the camera state is changed to QCamera::ActiveState,
- starting the camera service can be asynchronous with the actual
- status reported with QCamera::status property.
+ 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::start()
-{
- Q_D(QCamera);
- d->setState(QCamera::ActiveState);
-}
/*!
- Stops the camera.
- The camera state is changed from QCamera::ActiveState to QCamera::LoadedState.
+ Zooms to a zoom factor \a factor using \a rate.
- In this state, the camera still consumes power.
+ 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.
- \sa unload(), QCamera::UnloadedState
+ \note Using a specific rate is not supported on all cameras. If not supported,
+ zooming will happen as fast as possible.
*/
-void QCamera::stop()
+void QCamera::zoomTo(float factor, float rate)
{
+ Q_ASSERT(rate >= 0.f);
+ if (rate < 0.f)
+ rate = 0.f;
+
Q_D(QCamera);
- d->setState(QCamera::LoadedState);
+ if (!d->control)
+ return;
+ factor = qBound(d->control->minZoomFactor(), factor, d->control->maxZoomFactor());
+ d->control->zoomTo(factor, rate);
}
/*!
- Opens the camera device.
- The camera state is changed to QCamera::LoadedState.
+ \enum QCamera::FocusMode
+
+ \value FocusModeAuto Continuous auto focus mode.
+ \value FocusModeAutoNear Continuous auto focus mode on near objects.
+ \value FocusModeAutoFar Continuous auto focus mode on objects far away.
+ \value 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 FocusModeInfinity Focus strictly to infinity.
+ \value FocusModeManual Manual or fixed focus mode.
+*/
+
+/*!
+ \qmlproperty enumeration QtMultimedia::Camera::flashMode
- It's not necessary to explicitly load the camera, unless the application
- needs to read the supported camera settings and change the default values
- according to the camera capabilities.
+ Gets or sets a certain flash mode if the camera has a flash.
- In all the other cases, it's possible to start the camera directly
- from the unloaded state.
+ \value Camera.FlashOff Flash is Off.
+ \value Camera.FlashOn Flash is On.
+ \value Camera.FlashAuto Automatic flash.
- /sa QCamera::UnloadedState
+ \sa isFlashModeSupported, isFlashReady
*/
-void QCamera::load()
-{
- Q_D(QCamera);
- d->setState(QCamera::LoadedState);
-}
/*!
- Closes the camera device and deallocates the related resources.
- The camera state is changed to QCamera::UnloadedState.
+ \property QCamera::flashMode
+ \brief The flash mode being used.
+
+ Enables a certain flash mode if the camera has a flash.
+
+ \sa QCamera::FlashMode, QCamera::isFlashModeSupported, QCamera::isFlashReady
*/
-void QCamera::unload()
+QCamera::FlashMode QCamera::flashMode() const
{
- Q_D(QCamera);
- d->setState(QCamera::UnloadedState);
+ Q_D(const QCamera);
+ return d->control ? d->control->flashMode() : QCamera::FlashOff;
}
-QCamera::State QCamera::state() const
+void QCamera::setFlashMode(QCamera::FlashMode mode)
{
- return d_func()->state;
+ Q_D(QCamera);
+ if (d->control)
+ d->control->setFlashMode(mode);
}
-QCamera::Status QCamera::status() const
-{
- if(d_func()->control)
- return (QCamera::Status)d_func()->control->status();
-
- return QCamera::UnavailableStatus;
-}
+/*!
+ \qmlmethod bool QtMultimedia::Camera::isFlashModeSupported(FlashMode mode)
+ Returns true if the flash \a mode is supported.
+*/
/*!
- Returns the lock types that the camera supports.
+ Returns true if the flash \a mode is supported.
*/
-QCamera::LockTypes QCamera::supportedLocks() const
+bool QCamera::isFlashModeSupported(QCamera::FlashMode mode) const
{
Q_D(const QCamera);
-
- return d->locksControl
- ? d->locksControl->supportedLocks()
- : QCamera::LockTypes();
+ return d->control ? d->control->isFlashModeSupported(mode) : (mode == FlashOff);
}
/*!
- Returns the requested lock types.
+ \qmlmethod bool QtMultimedia::Camera::isFlashReady()
+
+ Returns true if flash is charged.
*/
-QCamera::LockTypes QCamera::requestedLocks() const
-{
- return d_func()->requestedLocks;
-}
/*!
- Returns the status of requested camera settings locks.
+ Returns true if flash is charged.
*/
-QCamera::LockStatus QCamera::lockStatus() const
+bool QCamera::isFlashReady() const
{
- return d_func()->lockStatus;
+ Q_D(const QCamera);
+ return d->control ? d->control->isFlashReady() : false;
}
/*!
- Returns the lock status for a given \a lockType.
+ \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
*/
-QCamera::LockStatus QCamera::lockStatus(QCamera::LockType lockType) const
-{
- const QCameraPrivate *d = d_func();
- if (!(lockType & d->requestedLocks))
- return QCamera::Unlocked;
+/*!
+ \property QCamera::torchMode
+ \brief 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.
- if (d->locksControl)
- return d->locksControl->lockStatus(lockType);
+ \sa QCamera::TorchMode, QCamera::isTorchModeSupported, QCamera::flashMode
+*/
+QCamera::TorchMode QCamera::torchMode() const
+{
+ Q_D(const QCamera);
+ return d->control ? d->control->torchMode() : TorchOff;
+}
- return QCamera::Locked;
+void QCamera::setTorchMode(QCamera::TorchMode mode)
+{
+ Q_D(QCamera);
+ if (d->control)
+ d->control->setTorchMode(mode);
}
/*!
- \fn void QCamera::searchAndLock(QCamera::LockTypes locks)
+ \qmlmethod bool QtMultimedia::Camera::isTorchModeSupported(TorchMode mode)
- Locks the camera settings with the requested \a locks, including focusing in the single autofocus mode,
- exposure and white balance if the exposure and white balance modes are not manual.
+ Returns true if the torch \a mode is supported.
+*/
- The camera settings are usually locked before taking one or multiple still images,
- in responce to the shutter button being half pressed.
+/*!
+ Returns true if the torch \a mode is supported.
+*/
+bool QCamera::isTorchModeSupported(QCamera::TorchMode mode) const
+{
+ Q_D(const QCamera);
+ return d->control ? d->control->isTorchModeSupported(mode) : (mode == TorchOff);
+}
- The QCamera::locked() signal is emitted when camera settings are successfully locked,
- otherwise QCamera::lockFailed() is emitted.
+/*!
+ \qmlproperty ExposureMode QtMultimedia::Camera::exposureMode
+ \brief The exposure mode being used.
- QCamera also emits lockStatusChanged(QCamera::LockType, QCamera::LockStatus)
- on individual lock status changes and lockStatusChanged(QCamera::LockStatus) signal on composite status changes.
+ \sa QCamera::ExposureMode, Camera::isExposureModeSupported()
+*/
- Locking serves two roles: it initializes calculation of automatic parameter
- (focusing, calculating the correct exposure and white balance) and allows
- to keep some or all of those parameters during number of shots.
+/*!
+ \property QCamera::exposureMode
+ \brief The exposure mode being used.
- If the camera doesn't support keeping one of parameters between shots, the related
- lock state changes to QCamera::Unlocked.
+ \sa QCamera::isExposureModeSupported
+*/
+QCamera::ExposureMode QCamera::exposureMode() const
+{
+ Q_D(const QCamera);
+ return d->control ? d->control->exposureMode() : QCamera::ExposureAuto;
+}
- It's also acceptable to relock already locked settings,
- depending on the lock parameter this initiates new focusing, exposure or white balance calculation.
- */
-void QCamera::searchAndLock(QCamera::LockTypes locks)
+void QCamera::setExposureMode(QCamera::ExposureMode mode)
{
Q_D(QCamera);
+ if (d->control)
+ d->control->setExposureMode(mode);
+}
- QCamera::LockStatus oldStatus = d->lockStatus;
- d->supressLockChangedSignal = true;
-
- if (d->locksControl) {
- locks &= d->locksControl->supportedLocks();
- d->requestedLocks |= locks;
- d->locksControl->searchAndLock(locks);
- }
+/*!
+ \qmlmethod bool QtMultimedia::Camera::isExposureModeSupported(ExposureMode mode)
- d->supressLockChangedSignal = false;
+ Returns true if the exposure \a mode is supported.
+*/
- d->lockStatus = oldStatus;
- d->updateLockStatus();
+/*!
+ Returns true if the exposure \a mode is supported.
+*/
+bool QCamera::isExposureModeSupported(QCamera::ExposureMode mode) const
+{
+ Q_D(const QCamera);
+ return d->control && d->control->isExposureModeSupported(mode);
}
/*!
- Lock all the supported camera settings.
- */
-void QCamera::searchAndLock()
+ \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.
+*/
+float QCamera::exposureCompensation() const
{
- searchAndLock(LockExposure | LockWhiteBalance | LockFocus);
+ Q_D(const QCamera);
+ return d->control ? d->control->exposureCompensation() : 0.f;
}
-/*!
- Unlocks the camera settings specified with \a locks or cancel the current locking if one is active.
- */
-void QCamera::unlock(QCamera::LockTypes locks)
+void QCamera::setExposureCompensation(float ev)
{
Q_D(QCamera);
+ if (d->control)
+ d->control->setExposureCompensation(ev);
+}
- QCamera::LockStatus oldStatus = d->lockStatus;
- d->supressLockChangedSignal = true;
+/*!
+ \qmlproperty int QtMultimedia::Camera::isoSensitivity
- d->requestedLocks &= ~locks;
+ Describes the ISO sensitivity currently used by the camera.
- if (d->locksControl) {
- locks &= d->locksControl->supportedLocks();
- d->locksControl->unlock(locks);
- }
+*/
- d->supressLockChangedSignal = false;
+/*!
+ \property QCamera::isoSensitivity
+ \brief The sensor ISO sensitivity.
- d->lockStatus = oldStatus;
- d->updateLockStatus();
-}
+ Describes the ISO sensitivity currently used by the camera.
-/*!
- Unlock all the requested camera locks.
- */
-void QCamera::unlock()
+ \sa setAutoIsoSensitivity(), setManualIsoSensitivity()
+*/
+int QCamera::isoSensitivity() const
{
- unlock(d_func()->requestedLocks);
+ Q_D(const QCamera);
+ return d->control ? d->control->isoSensitivity() : -1;
}
-
/*!
- \class QCamera::FrameRateRange
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_camera
- \since 5.5
-
- \brief A FrameRateRange represents a range of frame rates as minimum and maximum rate.
+ \qmlproperty int QtMultimedia::Camera::manualIsoSensitivity
- If the minimum frame rate is equal to the maximum frame rate, the frame rate is fixed.
- If not, the actual frame rate fluctuates between the minimum and the maximum.
+ Describes a manually set ISO sensitivity
- \sa QCamera::supportedViewfinderFrameRateRanges(), QCameraViewfinderSettings
+ Setting this property to -1 (the default), implies that the camera
+ automatically adjusts the ISO sensitivity.
*/
/*!
- \fn QCamera::FrameRateRange::FrameRateRange()
+ \property QCamera::manualIsoSensitivity
+ \brief Describes a manually set ISO sensitivity
- Constructs a null frame rate range, with both minimumFrameRate and maximumFrameRate
- equal to \c 0.0.
+ Setting this property to -1 (the default), implies that the camera
+ automatically adjusts the ISO sensitivity.
*/
+void QCamera::setManualIsoSensitivity(int iso)
+{
+ Q_D(QCamera);
+ if (iso <= 0)
+ iso = -1;
+ if (d->control)
+ d->control->setManualIsoSensitivity(iso);
+}
+
+int QCamera::manualIsoSensitivity() const
+{
+ Q_D(const QCamera);
+ return d->control ? d->control->manualIsoSensitivity() : 100;
+}
/*!
- \fn QCamera::FrameRateRange::FrameRateRange(qreal minimum, qreal maximum)
+ \fn QCamera::setAutoIsoSensitivity()
+ Turn on auto sensitivity
+*/
- Constructs a frame rate range with the given \a minimum and \a maximum frame rates.
+void QCamera::setAutoIsoSensitivity()
+{
+ Q_D(QCamera);
+ if (d->control)
+ 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;
+}
/*!
- \variable QCamera::FrameRateRange::minimumFrameRate
- The minimum frame rate supported by the range, in frames per second.
+ Returns the maximum ISO sensitivity supported by the camera.
*/
+int QCamera::maximumIsoSensitivity() const
+{
+ Q_D(const QCamera);
+ return d->control ? d->control->maxIso() : -1;
+}
/*!
- \variable QCamera::FrameRateRange::maximumFrameRate
- The maximum frame rate supported by the range, in frames per second.
+ The minimal exposure time in seconds.
*/
+float QCamera::minimumExposureTime() const
+{
+ Q_D(const QCamera);
+ return d->control ? d->control->minExposureTime() : -1.f;
+}
/*!
- \enum QCamera::State
+ The maximal exposure time in seconds.
+*/
+float QCamera::maximumExposureTime() const
+{
+ Q_D(const QCamera);
+ return d->control ? d->control->maxExposureTime() : -1.f;
+}
- This enum holds the current state of the camera.
+/*!
+ \qmlproperty float QtMultimedia::Camera::exposureTime
+ Returns the Camera's exposure time in seconds.
- \value UnloadedState
- The initial camera state, with camera not loaded.
- The camera capabilities, except supported capture modes,
- are unknown.
- While the supported settings are unknown in this state,
- it's allowed to set the camera capture settings like codec,
- resolution, or frame rate.
- \value LoadedState
- The camera is loaded and ready to be configured.
- In this state it's allowed to query camera capabilities,
- set capture resolution, codecs, etc.
- The viewfinder is not active in the loaded state.
- The camera consumes power in the loaded state.
- \value ActiveState
- In the active state as soon as camera is started
- the viewfinder displays video frames and the
- camera is ready for capture.
+ \sa manualExposureTime
*/
-
/*!
- \property QCamera::state
- \brief The current state of the camera object.
+ \property QCamera::exposureTime
+ \brief Camera's exposure time in seconds.
+
+ \sa minimumExposureTime(), maximumExposureTime(), setManualExposureTime()
*/
/*!
- \enum QCamera::Status
+ \fn QCamera::exposureTimeChanged(float speed)
- This enum holds the current status of the camera.
-
- \value ActiveStatus
- The camera has been started and can produce data.
- The viewfinder displays video frames in active state.
- Depending on backend, changing some camera settings like
- capture mode, codecs or resolution in ActiveState may lead
- to changing the camera status to LoadedStatus and StartingStatus while
- the settings are applied and back to ActiveStatus when the camera is ready.
- \value StartingStatus
- The camera is starting in result of state transition to QCamera::ActiveState.
- The camera service is not ready to capture yet.
- \value StoppingStatus
- The camera is stopping in result of state transition from QCamera::ActiveState
- to QCamera::LoadedState or QCamera::UnloadedState.
- \value StandbyStatus
- The camera is in the power saving standby mode.
- The camera may come to the standby mode after some time of inactivity
- in the QCamera::LoadedState state.
- \value LoadedStatus
- The camera is loaded and ready to be configured.
- This status indicates the camera device is opened and
- it's possible to query for supported image and video capture settings,
- like resolution, framerate and codecs.
- \value LoadingStatus
- The camera device loading in result of state transition from
- QCamera::UnloadedState to QCamera::LoadedState or QCamera::ActiveState.
- \value UnloadingStatus
- The camera device is unloading in result of state transition from
- QCamera::LoadedState or QCamera::ActiveState to QCamera::UnloadedState.
- \value UnloadedStatus
- The initial camera status, with camera not loaded.
- The camera capabilities including supported capture settings may be unknown.
- \value UnavailableStatus
- The camera or camera backend is not available.
+ Signals that a camera's exposure \a speed has changed.
*/
-
/*!
- \property QCamera::status
- \brief The current status of the camera object.
+ Returns the current exposure time in seconds.
*/
+float QCamera::exposureTime() const
+{
+ Q_D(const QCamera);
+ return d->control ? d->control->exposureTime() : -1;
+}
/*!
- \enum QCamera::CaptureMode
+ \qmlproperty real QtMultimedia::Camera::manualExposureTime
- This enum holds the capture mode of the camera.
+ Gets or sets a manual exposure time.
- \value CaptureViewfinder Camera is only configured to display viewfinder.
- \value CaptureStillImage Camera is configured for still frames capture.
- \value CaptureVideo Camera is configured for video capture.
+ Setting this property to -1 (the default) means that the camera
+ automatically determines the exposure time.
*/
/*!
- \enum QCamera::LockType
-
- This enum holds the camera lock type.
+ \property QCamera::manualExposureTime
- \value NoLock
- \value LockExposure
- Lock camera exposure.
- \value LockWhiteBalance
- Lock the white balance.
- \value LockFocus
- Lock camera focus.
+ Set the manual exposure time to \a seconds
*/
+void QCamera::setManualExposureTime(float seconds)
+{
+ Q_D(QCamera);
+ if (d->control)
+ d->control->setManualExposureTime(seconds);
+}
/*!
- \property QCamera::lockStatus
- \brief The overall status for all the requested camera locks.
+ Returns the manual exposure time in seconds, or -1
+ if the camera is using automatic exposure times.
*/
+float QCamera::manualExposureTime() const
+{
+ Q_D(const QCamera);
+ return d->control ? d->control->manualExposureTime() : -1;
+}
/*!
- \fn void QCamera::locked()
-
- Signals all the requested camera settings are locked.
+ Use automatically calculated exposure time
*/
+void QCamera::setAutoExposureTime()
+{
+ Q_D(QCamera);
+ if (d->control)
+ d->control->setManualExposureTime(-1);
+}
+
/*!
- \fn void QCamera::lockFailed()
+ \enum QCamera::FlashMode
- Signals locking of at least one requested camera settings failed.
+ \value FlashOff Flash is Off.
+ \value FlashOn Flash is On.
+ \value FlashAuto Automatic flash.
*/
/*!
- \fn QCamera::lockStatusChanged(QCamera::LockStatus status, QCamera::LockChangeReason reason)
+ \enum QCamera::TorchMode
- Signals the overall \a status for all the requested camera locks was changed with specified \a reason.
+ \value TorchOff Torch is Off.
+ \value TorchOn Torch is On.
+ \value TorchAuto Automatic torch.
*/
/*!
- \fn QCamera::lockStatusChanged(QCamera::LockType lock, QCamera::LockStatus status, QCamera::LockChangeReason reason)
- Signals the \a lock \a status was changed with specified \a reason.
+ \enum QCamera::ExposureMode
+
+ \value ExposureAuto Automatic mode.
+ \value ExposureManual Manual mode.
+ \value ExposurePortrait Portrait exposure mode.
+ \value ExposureNight Night mode.
+ \value ExposureSports Spots exposure mode.
+ \value ExposureSnow Snow exposure mode.
+ \value ExposureBeach Beach exposure mode.
+ \value ExposureAction Action mode. Since 5.5
+ \value ExposureLandscape Landscape mode. Since 5.5
+ \value ExposureNightPortrait Night portrait mode. Since 5.5
+ \value ExposureTheatre Theatre mode. Since 5.5
+ \value ExposureSunset Sunset mode. Since 5.5
+ \value ExposureSteadyPhoto Steady photo mode. Since 5.5
+ \value ExposureFireworks Fireworks mode. Since 5.5
+ \value ExposureParty Party mode. Since 5.5
+ \value ExposureCandlelight Candlelight mode. Since 5.5
+ \value ExposureBarcode Barcode mode. Since 5.5
*/
/*!
- \enum QCamera::LockStatus
+ \qmlproperty bool QtMultimedia::Camera::flashReady
- This enum holds the overall status for all the requested camera locks.
-
- \value Unlocked
- The application is not interested in camera settings value.
- The camera may keep this parameter without changes, this is common with camera focus,
- or adjust exposure and white balance constantly to keep the viewfinder image nice.
- \value Searching
- The application has requested the camera focus, exposure or white balance lock with
- QCamera::searchAndLock(). This state indicates the camera is focusing or
- calculating exposure and white balance.
- \value Locked
- The camera focus, exposure or white balance is locked.
- The camera is ready to capture, application may check the exposure
- stays the same, parameters. The \c Locked status usually means the
- requested parameter except in the cases when the parameter is requested
- to be constantly updated. For example, in continuous focusing mode,
- the focus is considered locked as long as the object is in focus, even
- while the actual focusing distance may be constantly changing.
+ Indicates if the flash is charged and ready to use.
*/
/*!
- \enum QCamera::LockChangeReason
+ \property QCamera::flashReady
+ \brief Indicates if the flash is charged and ready to use.
+*/
- This enum holds the reason why the camera lock status changed.
+/*!
+ \fn void QCamera::flashReady(bool ready)
- \value UserRequest
- The lock status changed in result of user request, usually to unlock camera settings.
- \value LockAcquired
- The lock status successfuly changed to QCamera::Locked.
- \value LockFailed
- The camera failed to acquire the requested lock in result of
- autofocus failure, exposure out of supported range, etc.
- \value LockLost
- The camera is not able to maintain the requested lock any more.
- Lock status is changed to QCamera::Unlocked.
- \value LockTemporaryLost
- The lock is lost, but the camera is working hard to reacquire it.
- This value may be used in continuous focusing mode,
- when the camera loses the focus, the focus lock state is changed to Qcamera::Searching
- with LockTemporaryLost reason.
+ Signal the flash \a ready status has changed.
*/
/*!
- \enum QCamera::Error
-
- This enum holds the last error code.
+ \fn void QCamera::isoSensitivityChanged(int value)
- \value NoError No errors have occurred.
- \value CameraError An error has occurred.
- \value InvalidRequestError System resource doesn't support requested functionality.
- \value ServiceMissingError No camera service available.
- \value NotSupportedFeatureError The feature is not supported.
+ Signal emitted when sensitivity changes to \a value.
*/
/*!
- \fn void QCamera::error(QCamera::Error value)
- \obsolete
+ \fn void QCamera::exposureCompensationChanged(float value)
- Use errorOccurred() instead.
+ Signal emitted when the exposure compensation changes to \a value.
*/
+
/*!
- \fn void QCamera::errorOccurred(QCamera::Error value)
- \since 5.15
+ \qmlproperty WhiteBalanceMode QtMultimedia::Camera::whiteBalanceMode
+
+ Gets or sets the white balance mode being used.
- Signal emitted when error state changes to \a value.
+ \sa QCamera::WhiteBalanceMode
*/
/*!
- \enum QCamera::Position
- \since 5.3
+ \property QCamera::whiteBalanceMode
- This enum specifies the physical position of the camera on the system hardware.
+ Returns the white balance mode being used.
+*/
+QCamera::WhiteBalanceMode QCamera::whiteBalanceMode() const
+{
+ Q_D(const QCamera);
+ return d->control ? d->control->whiteBalanceMode() : QCamera::WhiteBalanceAuto;
+}
- \value UnspecifiedPosition The camera position is unspecified or unknown.
+/*!
+ Sets the white balance to \a mode.
+*/
+void QCamera::setWhiteBalanceMode(QCamera::WhiteBalanceMode mode)
+{
+ Q_D(QCamera);
+ if (!d->control)
+ return;
+ if (!d->control->isWhiteBalanceModeSupported(mode))
+ return;
+ d->control->setWhiteBalanceMode(mode);
+ if (mode == QCamera::WhiteBalanceManual)
+ d->control->setColorTemperature(5600);
+}
- \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.
+/*!
+ \qmlmethod bool QtMultimedia::Camera::isWhiteBalanceModeSupported(WhiteBalanceMode 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.
+ Returns true if the white balance \a mode is supported.
+*/
- \sa QCameraInfo::position()
+/*!
+ Returns true if the white balance \a mode is supported.
*/
+bool QCamera::isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const
+{
+ Q_D(const QCamera);
+ return d->control && d->control->isWhiteBalanceModeSupported(mode);
+}
/*!
- \fn void QCamera::captureModeChanged(QCamera::CaptureModes mode)
+ \qmlmethod QtMultimedia::Camera::colorTemperature
- Signals the capture \a mode has changed.
+ 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.
*/
/*!
- \fn QCamera::stateChanged(QCamera::State state)
-
- Signals the camera \a state has changed.
+ \property QCamera::colorTemperature
- Usually the state changes is caused by calling
- load(), unload(), start() and stop(),
- but the state can also be changed change as a result of camera error.
+ Returns the current color temperature if the
+ current white balance mode is \c WhiteBalanceManual. For other modes the
+ return value is undefined.
*/
+int QCamera::colorTemperature() const
+{
+ Q_D(const QCamera);
+ return d->control ? d->control->colorTemperature() : 0;
+}
/*!
- \fn QCamera::statusChanged(QCamera::Status status)
+ Sets manual white balance to \a colorTemperature. This is used
+ when whiteBalanceMode() is set to \c WhiteBalanceManual. The units are Kelvin.
- Signals the camera \a status has changed.
+ 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.
+*/
+void QCamera::setColorTemperature(int colorTemperature)
+{
+ Q_D(QCamera);
+ if (!d->control)
+ return;
+ if (colorTemperature < 0)
+ colorTemperature = 0;
+ if (colorTemperature == 0) {
+ d->control->setWhiteBalanceMode(WhiteBalanceAuto);
+ } else if (!isWhiteBalanceModeSupported(WhiteBalanceManual)) {
+ return;
+ } else {
+ d->control->setWhiteBalanceMode(WhiteBalanceManual);
+ }
+ d->control->setColorTemperature(colorTemperature);
+}
+
+/*!
+ \enum QCamera::WhiteBalanceMode
+
+ \value WhiteBalanceAuto Auto white balance mode.
+ \value WhiteBalanceManual Manual white balance. In this mode the white
+ balance should be set with setColorTemperature()
+ \value WhiteBalanceSunlight Sunlight white balance mode.
+ \value WhiteBalanceCloudy Cloudy white balance mode.
+ \value WhiteBalanceShade Shade white balance mode.
+ \value WhiteBalanceTungsten Tungsten (incandescent) white balance mode.
+ \value WhiteBalanceFluorescent Fluorescent white balance mode.
+ \value WhiteBalanceFlash Flash white balance mode.
+ \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 d088e9beb..ce7e83427 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
@@ -46,248 +10,265 @@
#include <QtCore/qpoint.h>
#include <QtCore/qrect.h>
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmediaobject.h>
-#include <QtMultimedia/qmediaservice.h>
+#include <QtCore/qobject.h>
-#include <QtMultimedia/qcameraexposure.h>
-#include <QtMultimedia/qcamerafocus.h>
-#include <QtMultimedia/qcameraimageprocessing.h>
-#include <QtMultimedia/qcameraviewfindersettings.h>
+#include <QtMultimedia/qcameradevice.h>
#include <QtMultimedia/qmediaenumdebug.h>
QT_BEGIN_NAMESPACE
-class QAbstractVideoSurface;
-class QVideoWidget;
-class QGraphicsVideoItem;
-class QCameraInfo;
+class QCameraDevice;
+class QPlatformMediaCaptureSession;
+class QMediaCaptureSession;
class QCameraPrivate;
-class Q_MULTIMEDIA_EXPORT QCamera : public QMediaObject
+class Q_MULTIMEDIA_EXPORT QCamera : public QObject
{
Q_OBJECT
- Q_PROPERTY(QCamera::State state READ state NOTIFY stateChanged)
- Q_PROPERTY(QCamera::Status status READ status NOTIFY statusChanged)
- Q_PROPERTY(QCamera::CaptureModes captureMode READ captureMode WRITE setCaptureMode NOTIFY captureModeChanged)
- Q_PROPERTY(QCamera::LockStatus lockStatus READ lockStatus NOTIFY lockStatusChanged)
-
- Q_ENUMS(Status)
- Q_ENUMS(State)
- Q_ENUMS(CaptureMode)
- Q_ENUMS(Error)
- Q_ENUMS(LockStatus)
- Q_ENUMS(LockChangeReason)
- Q_ENUMS(LockType)
- Q_ENUMS(Position)
-public:
- struct FrameRateRange
- {
- Q_DECL_CONSTEXPR FrameRateRange() Q_DECL_NOTHROW
- : minimumFrameRate(0)
- , maximumFrameRate(0)
- { }
-
- Q_DECL_CONSTEXPR FrameRateRange(qreal minimum, qreal maximum) Q_DECL_NOTHROW
- : minimumFrameRate(minimum)
- , maximumFrameRate(maximum)
- { }
-
- qreal minimumFrameRate;
- qreal maximumFrameRate;
- };
-
- enum Status {
- UnavailableStatus,
- UnloadedStatus,
- LoadingStatus,
- UnloadingStatus,
- LoadedStatus,
- StandbyStatus,
- StartingStatus,
- StoppingStatus,
- ActiveStatus
- };
-
- enum State {
- UnloadedState,
- LoadedState,
- ActiveState
- };
-
- enum CaptureMode
- {
- CaptureViewfinder = 0,
- CaptureStillImage = 0x01,
- CaptureVideo = 0x02
- };
- Q_DECLARE_FLAGS(CaptureModes, CaptureMode)
+ 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 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(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(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)
+ Q_PROPERTY(QCamera::TorchMode torchMode READ torchMode WRITE setTorchMode NOTIFY torchModeChanged)
+
+ Q_PROPERTY(WhiteBalanceMode whiteBalanceMode READ whiteBalanceMode WRITE setWhiteBalanceMode NOTIFY whiteBalanceModeChanged)
+ Q_PROPERTY(int colorTemperature READ colorTemperature WRITE setColorTemperature NOTIFY colorTemperatureChanged)
+ Q_PROPERTY(Features supportedFeatures READ supportedFeatures NOTIFY supportedFeaturesChanged)
+public:
enum Error
{
NoError,
- CameraError,
- InvalidRequestError,
- ServiceMissingError,
- NotSupportedFeatureError
+ CameraError
};
-
- enum LockStatus
- {
- Unlocked,
- Searching,
- Locked
+ Q_ENUM(Error)
+
+ enum FocusMode {
+ FocusModeAuto,
+ FocusModeAutoNear,
+ FocusModeAutoFar,
+ FocusModeHyperfocal,
+ FocusModeInfinity,
+ FocusModeManual
};
+ Q_ENUM(FocusMode)
- enum LockChangeReason {
- UserRequest,
- LockAcquired,
- LockFailed,
- LockLost,
- LockTemporaryLost
+ enum FlashMode {
+ FlashOff,
+ FlashOn,
+ FlashAuto
};
+ Q_ENUM(FlashMode)
- enum LockType
- {
- NoLock = 0,
- LockExposure = 0x01,
- LockWhiteBalance = 0x02,
- LockFocus = 0x04
+ enum TorchMode {
+ TorchOff,
+ TorchOn,
+ TorchAuto
};
- Q_DECLARE_FLAGS(LockTypes, LockType)
-
- enum Position
- {
- UnspecifiedPosition,
- BackFace,
- FrontFace
+ Q_ENUM(TorchMode)
+
+ enum ExposureMode {
+ ExposureAuto,
+ ExposureManual,
+ ExposurePortrait,
+ ExposureNight,
+ ExposureSports,
+ ExposureSnow,
+ ExposureBeach,
+ ExposureAction,
+ ExposureLandscape,
+ ExposureNightPortrait,
+ ExposureTheatre,
+ ExposureSunset,
+ ExposureSteadyPhoto,
+ ExposureFireworks,
+ ExposureParty,
+ ExposureCandlelight,
+ ExposureBarcode
+ };
+ Q_ENUM(ExposureMode)
+
+ enum WhiteBalanceMode {
+ WhiteBalanceAuto = 0,
+ WhiteBalanceManual = 1,
+ WhiteBalanceSunlight = 2,
+ WhiteBalanceCloudy = 3,
+ WhiteBalanceShade = 4,
+ WhiteBalanceTungsten = 5,
+ WhiteBalanceFluorescent = 6,
+ WhiteBalanceFlash = 7,
+ WhiteBalanceSunset = 8
};
+ Q_ENUM(WhiteBalanceMode)
+
+ enum class Feature {
+ ColorTemperature = 0x1,
+ ExposureCompensation = 0x2,
+ IsoSensitivity = 0x4,
+ ManualExposureTime = 0x8,
+ CustomFocusPoint = 0x10,
+ FocusDistance = 0x20
+ };
+ Q_DECLARE_FLAGS(Features, Feature)
+ Q_FLAG(Features)
explicit QCamera(QObject *parent = nullptr);
- explicit QCamera(const QByteArray& deviceName, QObject *parent = nullptr);
- explicit QCamera(const QCameraInfo& cameraInfo, QObject *parent = nullptr);
- explicit QCamera(QCamera::Position position, QObject *parent = nullptr);
+ explicit QCamera(const QCameraDevice& cameraDevice, QObject *parent = nullptr);
+ explicit QCamera(QCameraDevice::Position position, QObject *parent = nullptr);
~QCamera();
- QMultimedia::AvailabilityStatus availability() const override;
+ bool isAvailable() const;
+ bool isActive() const;
- State state() const;
- Status status() const;
+ QMediaCaptureSession *captureSession() const;
- CaptureModes captureMode() const;
- bool isCaptureModeSupported(CaptureModes mode) const;
+ QCameraDevice cameraDevice() const;
+ void setCameraDevice(const QCameraDevice &cameraDevice);
- QCameraExposure *exposure() const;
- QCameraFocus *focus() const;
- QCameraImageProcessing *imageProcessing() const;
+ QCameraFormat cameraFormat() const;
+ void setCameraFormat(const QCameraFormat &format);
- void setViewfinder(QVideoWidget *viewfinder);
- void setViewfinder(QGraphicsVideoItem *viewfinder);
- void setViewfinder(QAbstractVideoSurface *surface);
+ Error error() const;
+ QString errorString() const;
- QCameraViewfinderSettings viewfinderSettings() const;
- void setViewfinderSettings(const QCameraViewfinderSettings &settings);
+ Features supportedFeatures() const;
- QList<QCameraViewfinderSettings> supportedViewfinderSettings(
- const QCameraViewfinderSettings &settings = QCameraViewfinderSettings()) const;
+ FocusMode focusMode() const;
+ void setFocusMode(FocusMode mode);
+ Q_INVOKABLE bool isFocusModeSupported(FocusMode mode) const;
- QList<QSize> supportedViewfinderResolutions(
- const QCameraViewfinderSettings &settings = QCameraViewfinderSettings()) const;
+ QPointF focusPoint() const;
- QList<FrameRateRange> supportedViewfinderFrameRateRanges(
- const QCameraViewfinderSettings &settings = QCameraViewfinderSettings()) const;
+ QPointF customFocusPoint() const;
+ void setCustomFocusPoint(const QPointF &point);
- QList<QVideoFrame::PixelFormat> supportedViewfinderPixelFormats(
- const QCameraViewfinderSettings &settings = QCameraViewfinderSettings()) const;
+ void setFocusDistance(float d);
+ float focusDistance() const;
- Error error() const;
- QString errorString() const;
+ float minimumZoomFactor() const;
+ float maximumZoomFactor() const;
+ float zoomFactor() const;
+ void setZoomFactor(float factor);
- QCamera::LockTypes supportedLocks() const;
- QCamera::LockTypes requestedLocks() const;
+ FlashMode flashMode() const;
+ Q_INVOKABLE bool isFlashModeSupported(FlashMode mode) const;
+ Q_INVOKABLE bool isFlashReady() const;
- QCamera::LockStatus lockStatus() const;
- QCamera::LockStatus lockStatus(QCamera::LockType lock) const;
+ TorchMode torchMode() const;
+ Q_INVOKABLE bool isTorchModeSupported(TorchMode mode) const;
-public Q_SLOTS:
- void setCaptureMode(QCamera::CaptureModes mode);
+ ExposureMode exposureMode() const;
+ Q_INVOKABLE bool isExposureModeSupported(ExposureMode mode) const;
- void load();
- void unload();
+ float exposureCompensation() const;
- void start();
- void stop();
+ int isoSensitivity() const;
+ int manualIsoSensitivity() const;
- void searchAndLock();
- void unlock();
+ float exposureTime() const;
+ float manualExposureTime() const;
- void searchAndLock(QCamera::LockTypes locks);
- void unlock(QCamera::LockTypes locks);
+ int minimumIsoSensitivity() const;
+ int maximumIsoSensitivity() const;
-Q_SIGNALS:
- void stateChanged(QCamera::State state);
- void captureModeChanged(QCamera::CaptureModes);
- void statusChanged(QCamera::Status status);
+ float minimumExposureTime() const;
+ float maximumExposureTime() const;
- void locked();
- void lockFailed();
+ WhiteBalanceMode whiteBalanceMode() const;
+ Q_INVOKABLE bool isWhiteBalanceModeSupported(WhiteBalanceMode mode) const;
- void lockStatusChanged(QCamera::LockStatus status, QCamera::LockChangeReason reason);
- void lockStatusChanged(QCamera::LockType lock, QCamera::LockStatus status, QCamera::LockChangeReason reason);
+ int colorTemperature() const;
- void errorOccurred(QCamera::Error);
+public Q_SLOTS:
+ void setActive(bool active);
+ void start() { setActive(true); }
+ void stop() { setActive(false); }
-private:
- Q_DISABLE_COPY(QCamera)
- Q_DECLARE_PRIVATE(QCamera)
- Q_PRIVATE_SLOT(d_func(), void _q_preparePropertyChange(int))
- Q_PRIVATE_SLOT(d_func(), void _q_restartCamera())
- Q_PRIVATE_SLOT(d_func(), void _q_error(int, const QString &))
- Q_PRIVATE_SLOT(d_func(), void _q_updateLockStatus(QCamera::LockType, QCamera::LockStatus, QCamera::LockChangeReason))
- Q_PRIVATE_SLOT(d_func(), void _q_updateState(QCamera::State))
- friend class QCameraInfo;
-};
+ void zoomTo(float zoom, float rate);
-Q_DECLARE_OPERATORS_FOR_FLAGS(QCamera::LockTypes)
+ void setFlashMode(FlashMode mode);
+ void setTorchMode(TorchMode mode);
+ void setExposureMode(ExposureMode mode);
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_CLANG("-Wfloat-equal")
-QT_WARNING_DISABLE_GCC("-Wfloat-equal")
+ void setExposureCompensation(float ev);
-Q_DECL_CONSTEXPR Q_INLINE_TEMPLATE bool operator==(const QCamera::FrameRateRange &r1, const QCamera::FrameRateRange &r2) Q_DECL_NOTHROW
-{
- return qFuzzyCompare(r1.minimumFrameRate, r2.minimumFrameRate)
- && qFuzzyCompare(r1.maximumFrameRate, r2.maximumFrameRate);
-}
+ void setManualIsoSensitivity(int iso);
+ void setAutoIsoSensitivity();
+
+ void setManualExposureTime(float seconds);
+ void setAutoExposureTime();
-QT_WARNING_POP
+ void setWhiteBalanceMode(WhiteBalanceMode mode);
+ void setColorTemperature(int colorTemperature);
+
+Q_SIGNALS:
+ void activeChanged(bool);
+ void errorChanged();
+ void errorOccurred(QCamera::Error error, const QString &errorString);
+ void cameraDeviceChanged();
+ void cameraFormatChanged();
+ void supportedFeaturesChanged();
+
+ void focusModeChanged();
+ void zoomFactorChanged(float);
+ void minimumZoomFactorChanged(float);
+ void maximumZoomFactorChanged(float);
+ void focusDistanceChanged(float);
+ void focusPointChanged();
+ void customFocusPointChanged();
+
+ void flashReady(bool);
+ void flashModeChanged();
+ void torchModeChanged();
+
+ void exposureTimeChanged(float speed);
+ void manualExposureTimeChanged(float speed);
+ void isoSensitivityChanged(int);
+ void manualIsoSensitivityChanged(int);
+ void exposureCompensationChanged(float);
+ void exposureModeChanged();
+
+ void whiteBalanceModeChanged() QT6_ONLY(const);
+ void colorTemperatureChanged() QT6_ONLY(const);
+ void brightnessChanged();
+ void contrastChanged();
+ void saturationChanged();
+ void hueChanged();
-Q_DECL_CONSTEXPR Q_INLINE_TEMPLATE bool operator!=(const QCamera::FrameRateRange &r1, const QCamera::FrameRateRange &r2) Q_DECL_NOTHROW
-{ return !(r1 == r2); }
+private:
+ class QPlatformCamera *platformCamera();
+ void setCaptureSession(QMediaCaptureSession *session);
+ friend class QMediaCaptureSession;
+ Q_DISABLE_COPY(QCamera)
+ Q_DECLARE_PRIVATE(QCamera)
+ friend class QCameraDevice;
+};
-Q_DECLARE_TYPEINFO(QCamera::FrameRateRange, Q_PRIMITIVE_TYPE);
+Q_DECLARE_OPERATORS_FOR_FLAGS(QCamera::Features)
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QCamera::State)
-Q_DECLARE_METATYPE(QCamera::Status)
-Q_DECLARE_METATYPE(QCamera::Error)
-Q_DECLARE_METATYPE(QCamera::CaptureMode)
-Q_DECLARE_METATYPE(QCamera::CaptureModes)
-Q_DECLARE_METATYPE(QCamera::LockType)
-Q_DECLARE_METATYPE(QCamera::LockStatus)
-Q_DECLARE_METATYPE(QCamera::LockChangeReason)
-Q_DECLARE_METATYPE(QCamera::Position)
-
-Q_MEDIA_ENUM_DEBUG(QCamera, State)
-Q_MEDIA_ENUM_DEBUG(QCamera, Status)
Q_MEDIA_ENUM_DEBUG(QCamera, Error)
-Q_MEDIA_ENUM_DEBUG(QCamera, CaptureMode)
-Q_MEDIA_ENUM_DEBUG(QCamera, LockType)
-Q_MEDIA_ENUM_DEBUG(QCamera, LockStatus)
-Q_MEDIA_ENUM_DEBUG(QCamera, LockChangeReason)
-Q_MEDIA_ENUM_DEBUG(QCamera, Position)
#endif // QCAMERA_H
diff --git a/src/multimedia/camera/qcamera_p.h b/src/multimedia/camera/qcamera_p.h
index 99759dbd3..ae1299435 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
@@ -51,94 +15,26 @@
// We mean it.
//
-#include "qmediaobject_p.h"
-#include "qvideosurfaceoutput_p.h"
+#include "private/qobject_p.h"
#include "qcamera.h"
+#include "qcameradevice.h"
QT_BEGIN_NAMESPACE
-class QMediaServiceProvider;
-class QCameraControl;
-class QVideoDeviceSelectorControl;
-class QCameraLocksControl;
-class QCameraInfoControl;
-class QCameraViewfinderSettingsControl;
-class QCameraViewfinderSettingsControl2;
+class QPlatformCamera;
+class QPlatformMediaCaptureSession;
-class QCameraPrivate : public QMediaObjectPrivate
+class QCameraPrivate : public QObjectPrivate
{
- Q_DECLARE_NON_CONST_PUBLIC(QCamera)
+ Q_DECLARE_PUBLIC(QCamera)
public:
- QCameraPrivate():
- QMediaObjectPrivate(),
- provider(nullptr),
- control(nullptr),
- deviceControl(nullptr),
- locksControl(nullptr),
- infoControl(nullptr),
- viewfinderSettingsControl(nullptr),
- viewfinderSettingsControl2(nullptr),
- cameraExposure(nullptr),
- cameraFocus(nullptr),
- imageProcessing(nullptr),
- viewfinder(nullptr),
- capture(nullptr),
- state(QCamera::UnloadedState),
- error(QCamera::NoError),
- requestedLocks(QCamera::NoLock),
- lockStatus(QCamera::Unlocked),
- lockChangeReason(QCamera::UserRequest),
- supressLockChangedSignal(false),
- restartPending(false)
- {
- }
+ void init(const QCameraDevice &device);
- void init();
- void initControls();
+ QMediaCaptureSession *captureSession = nullptr;
+ QPlatformCamera *control = nullptr;
- void clear();
-
- QMediaServiceProvider *provider;
-
- QCameraControl *control;
- QVideoDeviceSelectorControl *deviceControl;
- QCameraLocksControl *locksControl;
- QCameraInfoControl *infoControl;
- QCameraViewfinderSettingsControl *viewfinderSettingsControl;
- QCameraViewfinderSettingsControl2 *viewfinderSettingsControl2;
-
- QCameraExposure *cameraExposure;
- QCameraFocus *cameraFocus;
- QCameraImageProcessing *imageProcessing;
-
- QObject *viewfinder;
- QObject *capture;
-
- QCamera::State state;
-
- QCamera::Error error;
- QString errorString;
-
- QCamera::LockTypes requestedLocks;
-
- QCamera::LockStatus lockStatus;
- QCamera::LockChangeReason lockChangeReason;
- bool supressLockChangedSignal;
-
- bool restartPending;
-
- QVideoSurfaceOutput surfaceViewfinder;
-
- void _q_error(int error, const QString &errorString);
- void unsetError() { error = QCamera::NoError; errorString.clear(); }
-
- void setState(QCamera::State);
-
- void _q_updateLockStatus(QCamera::LockType, QCamera::LockStatus, QCamera::LockChangeReason);
- void _q_updateState(QCamera::State newState);
- void _q_preparePropertyChange(int changeType);
- void _q_restartCamera();
- void updateLockStatus();
+ QCameraDevice cameraDevice;
+ QCameraFormat cameraFormat;
};
QT_END_NAMESPACE
diff --git a/src/multimedia/camera/qcameradevice.cpp b/src/multimedia/camera/qcameradevice.cpp
new file mode 100644
index 000000000..63e7fb4c0
--- /dev/null
+++ b/src/multimedia/camera/qcameradevice.cpp
@@ -0,0 +1,470 @@
+// 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"
+
+#include "qcamera_p.h"
+
+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)
+ return true;
+ if (!d || !other.d)
+ return false;
+ return d->pixelFormat == other.d->pixelFormat &&
+ d->minFrameRate == other.d->minFrameRate &&
+ d->maxFrameRate == other.d->maxFrameRate &&
+ d->resolution == other.d->resolution;
+}
+
+/*!
+ \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.
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \ingroup multimedia_camera
+
+ QCameraDevice represents a physical camera device and its properties.
+
+ You can discover what cameras are available on a system using the
+ availableCameras() and defaultCamera() functions. These are contained within
+ QtMultimedia::MediaDevices.
+
+ This example prints the name of all available cameras:
+
+ \snippet multimedia-snippets/camera.cpp Camera listing
+
+ A QCameraDevice can be used to construct a QCamera. The following example
+ instantiates a QCamera whose camera device is named \c {mycamera}:
+
+ \snippet multimedia-snippets/camera.cpp Camera selection
+
+ You can also use QCameraDevice to get general information about a camera
+ device such as description and physical position on the system.
+
+ \snippet multimedia-snippets/camera.cpp Camera info
+
+ \sa QCamera
+*/
+
+/*!
+ \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;
+
+/*!
+ Constructs a copy of \a other.
+*/
+QCameraDevice::QCameraDevice(const QCameraDevice &other) = default;
+
+/*!
+ Destroys the QCameraDevice.
+*/
+QCameraDevice::~QCameraDevice() = default;
+
+/*!
+ Returns true if this QCameraDevice is equal to \a other.
+*/
+bool QCameraDevice::operator==(const QCameraDevice &other) const
+{
+ if (d == other.d)
+ return true;
+
+ if (!d || ! other.d)
+ return false;
+
+ return (d->id == other.d->id
+ && d->description == other.d->description
+ && d->position == other.d->position);
+}
+
+/*!
+ Returns true if this QCameraDevice is null or invalid.
+*/
+bool QCameraDevice::isNull() const
+{
+ return !d;
+}
+
+/*!
+ \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.
+*/
+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
+{
+ return d ? d->description : QString();
+}
+
+/*!
+ \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
+{
+ 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
+{
+ return d ? d->videoFormats : QList<QCameraFormat>{};
+}
+
+QCameraDevice::QCameraDevice(QCameraDevicePrivate *p)
+ : d(p)
+{}
+
+/*!
+ Sets the QCameraDevice object to be equal to \a other.
+*/
+QCameraDevice& QCameraDevice::operator=(const QCameraDevice& other) = default;
+
+/*!
+ \fn QCameraDevice::operator!=(const QCameraDevice &other) const
+
+ Returns true if this QCameraDevice is different from \a other.
+*/
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const QCameraDevice &camera)
+{
+ d.maybeSpace() << QStringLiteral("QCameraDevice(name=%1, id=%2, position=%3)")
+ .arg(camera.description())
+ .arg(QLatin1StringView(camera.id()))
+ .arg(QLatin1StringView(
+ QMetaEnum::fromType<QCameraDevice::Position>().valueToKey(
+ camera.position())));
+ return d.space();
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qcameradevice.cpp"
diff --git a/src/multimedia/camera/qcameradevice.h b/src/multimedia/camera/qcameradevice.h
new file mode 100644
index 000000000..2a9fac659
--- /dev/null
+++ b/src/multimedia/camera/qcameradevice.h
@@ -0,0 +1,104 @@
+// 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>
+
+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;
+ QCameraFormat &operator=(const QCameraFormat &other) noexcept;
+ ~QCameraFormat();
+
+ QVideoFrameFormat::PixelFormat pixelFormat() const noexcept;
+ QSize resolution() const noexcept;
+ float minFrameRate() const noexcept;
+ float maxFrameRate() const noexcept;
+
+ bool isNull() const noexcept { return !d; }
+
+ bool operator==(const QCameraFormat &other) const;
+ inline bool operator!=(const QCameraFormat &other) const
+ { return !operator==(other); }
+
+private:
+ friend class QCameraFormatPrivate;
+ QCameraFormat(QCameraFormatPrivate *p);
+ QExplicitlySharedDataPointer<QCameraFormatPrivate> d;
+};
+
+class QCameraDevicePrivate;
+class Q_MULTIMEDIA_EXPORT QCameraDevice
+{
+ Q_GADGET
+ Q_PROPERTY(QByteArray id READ id CONSTANT)
+ 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);
+ QCameraDevice& operator=(const QCameraDevice& other);
+ ~QCameraDevice();
+
+ bool operator==(const QCameraDevice &other) const;
+ inline bool operator!=(const QCameraDevice &other) const;
+
+ bool isNull() const;
+
+ QByteArray id() const;
+ QString description() const;
+
+ // ### Add here and to QAudioDevice
+// QByteArray groupId() const;
+// QString groupDescription() const;
+
+ bool isDefault() const;
+
+ enum Position
+ {
+ UnspecifiedPosition,
+ BackFace,
+ FrontFace
+ };
+ Q_ENUM(Position)
+
+ Position position() const;
+
+ QList<QSize> photoResolutions() const;
+ QList<QCameraFormat> videoFormats() const;
+
+ QtVideo::Rotation correctionAngle() const;
+ // ### Add zoom and other camera information
+
+private:
+ friend class QCameraDevicePrivate;
+ QCameraDevice(QCameraDevicePrivate *p);
+ QExplicitlySharedDataPointer<QCameraDevicePrivate> d;
+};
+
+bool QCameraDevice::operator!=(const QCameraDevice &other) const { return !operator==(other); }
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, const QCameraDevice&);
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QCAMERAINFO_H
diff --git a/src/multimedia/camera/qcameradevice_p.h b/src/multimedia/camera/qcameradevice_p.h
new file mode 100644
index 000000000..638cc0cae
--- /dev/null
+++ b/src/multimedia/camera/qcameradevice_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 QCAMERAINFO_P_H
+#define QCAMERAINFO_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/qcameradevice.h>
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/private/qglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QCameraFormatPrivate : public QSharedData
+{
+public:
+ 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); }
+};
+
+class QCameraDevicePrivate : public QSharedData
+{
+public:
+ QByteArray id;
+ QString description;
+ bool isDefault = false;
+ QCameraDevice::Position position = QCameraDevice::UnspecifiedPosition;
+ int orientation = 0;
+ 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); }
+};
+
+QT_END_NAMESPACE
+
+#endif // QCAMERAINFO_P_H
diff --git a/src/multimedia/camera/qcameraexposure.cpp b/src/multimedia/camera/qcameraexposure.cpp
deleted file mode 100644
index 022dea28c..000000000
--- a/src/multimedia/camera/qcameraexposure.cpp
+++ /dev/null
@@ -1,707 +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 "qcameraexposure.h"
-#include "qmediaobject_p.h"
-
-#include <qcamera.h>
-#include <qcameraexposurecontrol.h>
-#include <qcameraflashcontrol.h>
-
-#include <QtCore/QMetaObject>
-#include <QtCore/QDebug>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QCameraExposure
-
-
- \brief The QCameraExposure class provides interface for exposure related camera settings.
-
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_camera
-
-*/
-
-//#define DEBUG_EXPOSURE_CHANGES 1
-
-static void qRegisterCameraExposureMetaTypes()
-{
- qRegisterMetaType<QCameraExposure::ExposureMode>("QCameraExposure::ExposureMode");
- qRegisterMetaType<QCameraExposure::FlashModes>("QCameraExposure::FlashModes");
- qRegisterMetaType<QCameraExposure::MeteringMode>("QCameraExposure::MeteringMode");
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterCameraExposureMetaTypes)
-
-
-class QCameraExposurePrivate
-{
- Q_DECLARE_NON_CONST_PUBLIC(QCameraExposure)
-public:
- void initControls();
- QCameraExposure *q_ptr;
-
- template<typename T> T actualExposureParameter(QCameraExposureControl::ExposureParameter parameter, const T &defaultValue) const;
- template<typename T> T requestedExposureParameter(QCameraExposureControl::ExposureParameter parameter, const T &defaultValue) const;
- template<typename T> void setExposureParameter(QCameraExposureControl::ExposureParameter parameter, const T &value);
- void resetExposureParameter(QCameraExposureControl::ExposureParameter parameter);
-
- QCamera *camera;
- QCameraExposureControl *exposureControl;
- QCameraFlashControl *flashControl;
-
- void _q_exposureParameterChanged(int parameter);
- void _q_exposureParameterRangeChanged(int parameter);
-};
-
-void QCameraExposurePrivate::initControls()
-{
- Q_Q(QCameraExposure);
-
- QMediaService *service = camera->service();
- exposureControl = nullptr;
- flashControl = nullptr;
- if (service) {
- exposureControl = qobject_cast<QCameraExposureControl *>(service->requestControl(QCameraExposureControl_iid));
- flashControl = qobject_cast<QCameraFlashControl *>(service->requestControl(QCameraFlashControl_iid));
- }
- if (exposureControl) {
- q->connect(exposureControl, SIGNAL(actualValueChanged(int)),
- q, SLOT(_q_exposureParameterChanged(int)));
- q->connect(exposureControl, SIGNAL(parameterRangeChanged(int)),
- q, SLOT(_q_exposureParameterRangeChanged(int)));
- }
-
- if (flashControl)
- q->connect(flashControl, SIGNAL(flashReady(bool)), q, SIGNAL(flashReady(bool)));
-}
-
-template<typename T>
-T QCameraExposurePrivate::actualExposureParameter(QCameraExposureControl::ExposureParameter parameter, const T &defaultValue) const
-{
- QVariant value = exposureControl ? exposureControl->actualValue(parameter) : QVariant();
-
- return value.isValid() ? value.value<T>() : defaultValue;
-}
-
-template<typename T>
-T QCameraExposurePrivate::requestedExposureParameter(QCameraExposureControl::ExposureParameter parameter, const T &defaultValue) const
-{
- QVariant value = exposureControl ? exposureControl->requestedValue(parameter) : QVariant();
-
- return value.isValid() ? value.value<T>() : defaultValue;
-}
-
-template<typename T>
-void QCameraExposurePrivate::setExposureParameter(QCameraExposureControl::ExposureParameter parameter, const T &value)
-{
- if (exposureControl)
- exposureControl->setValue(parameter, QVariant::fromValue<T>(value));
-}
-
-void QCameraExposurePrivate::resetExposureParameter(QCameraExposureControl::ExposureParameter parameter)
-{
- if (exposureControl)
- exposureControl->setValue(parameter, QVariant());
-}
-
-
-void QCameraExposurePrivate::_q_exposureParameterChanged(int parameter)
-{
- Q_Q(QCameraExposure);
-
-#if DEBUG_EXPOSURE_CHANGES
- qDebug() << "Exposure parameter changed:"
- << QCameraExposureControl::ExposureParameter(parameter)
- << exposureControl->actualValue(QCameraExposureControl::ExposureParameter(parameter));
-#endif
-
- switch (parameter) {
- case QCameraExposureControl::ISO:
- emit q->isoSensitivityChanged(q->isoSensitivity());
- break;
- case QCameraExposureControl::Aperture:
- emit q->apertureChanged(q->aperture());
- break;
- case QCameraExposureControl::ShutterSpeed:
- emit q->shutterSpeedChanged(q->shutterSpeed());
- break;
- case QCameraExposureControl::ExposureCompensation:
- emit q->exposureCompensationChanged(q->exposureCompensation());
- break;
- }
-}
-
-void QCameraExposurePrivate::_q_exposureParameterRangeChanged(int parameter)
-{
- Q_Q(QCameraExposure);
-
- switch (parameter) {
- case QCameraExposureControl::Aperture:
- emit q->apertureRangeChanged();
- break;
- case QCameraExposureControl::ShutterSpeed:
- emit q->shutterSpeedRangeChanged();
- break;
- }
-}
-
-/*!
- Construct a QCameraExposure from service \a provider and \a parent.
-*/
-
-QCameraExposure::QCameraExposure(QCamera *parent):
- QObject(parent), d_ptr(new QCameraExposurePrivate)
-{
- Q_D(QCameraExposure);
- d->camera = parent;
- d->q_ptr = this;
- d->initControls();
-}
-
-
-/*!
- Destroys the camera exposure object.
-*/
-
-QCameraExposure::~QCameraExposure()
-{
- Q_D(QCameraExposure);
- if (d->exposureControl)
- d->camera->service()->releaseControl(d->exposureControl);
-
- delete d;
-}
-
-/*!
- Returns true if exposure settings are supported by this camera.
-*/
-bool QCameraExposure::isAvailable() const
-{
- return d_func()->exposureControl != nullptr;
-}
-
-
-/*!
- \property QCameraExposure::flashMode
- \brief The flash mode being used.
-
- Usually the single QCameraExposure::FlashMode flag is used,
- but some non conflicting flags combination are also allowed,
- like QCameraExposure::FlashManual | QCameraExposure::FlashSlowSyncRearCurtain.
-
- \sa QCameraExposure::isFlashModeSupported(), QCameraExposure::isFlashReady()
-*/
-
-QCameraExposure::FlashModes QCameraExposure::flashMode() const
-{
- return d_func()->flashControl ? d_func()->flashControl->flashMode() : QCameraExposure::FlashOff;
-}
-
-void QCameraExposure::setFlashMode(QCameraExposure::FlashModes mode)
-{
- if (d_func()->flashControl)
- d_func()->flashControl->setFlashMode(mode);
-}
-
-/*!
- Returns true if the flash \a mode is supported.
-*/
-
-bool QCameraExposure::isFlashModeSupported(QCameraExposure::FlashModes mode) const
-{
- return d_func()->flashControl ? d_func()->flashControl->isFlashModeSupported(mode) : false;
-}
-
-/*!
- Returns true if flash is charged.
-*/
-
-bool QCameraExposure::isFlashReady() const
-{
- return d_func()->flashControl ? d_func()->flashControl->isFlashReady() : false;
-}
-
-/*!
- \property QCameraExposure::exposureMode
- \brief The exposure mode being used.
-
- \sa QCameraExposure::isExposureModeSupported()
-*/
-
-QCameraExposure::ExposureMode QCameraExposure::exposureMode() const
-{
- return d_func()->actualExposureParameter<QCameraExposure::ExposureMode>(QCameraExposureControl::ExposureMode, QCameraExposure::ExposureAuto);
-}
-
-void QCameraExposure::setExposureMode(QCameraExposure::ExposureMode mode)
-{
- d_func()->setExposureParameter<QCameraExposure::ExposureMode>(QCameraExposureControl::ExposureMode, mode);
-}
-
-/*!
- Returns true if the exposure \a mode is supported.
-*/
-
-bool QCameraExposure::isExposureModeSupported(QCameraExposure::ExposureMode mode) const
-{
- if (!d_func()->exposureControl)
- return false;
-
- bool continuous = false;
- return d_func()->exposureControl->supportedParameterRange(QCameraExposureControl::ExposureMode, &continuous)
- .contains(QVariant::fromValue<QCameraExposure::ExposureMode>(mode));
-}
-
-/*!
- \property QCameraExposure::exposureCompensation
- \brief Exposure compensation in EV units.
-
- Exposure compensation property allows to adjust the automatically calculated exposure.
-*/
-
-qreal QCameraExposure::exposureCompensation() const
-{
- return d_func()->actualExposureParameter<qreal>(QCameraExposureControl::ExposureCompensation, 0.0);
-}
-
-void QCameraExposure::setExposureCompensation(qreal ev)
-{
- d_func()->setExposureParameter<qreal>(QCameraExposureControl::ExposureCompensation, ev);
-}
-
-/*!
- \property QCameraExposure::meteringMode
- \brief The metering mode being used.
-
- \sa QCameraExposure::isMeteringModeSupported()
-*/
-
-QCameraExposure::MeteringMode QCameraExposure::meteringMode() const
-{
- return d_func()->actualExposureParameter<QCameraExposure::MeteringMode>(QCameraExposureControl::MeteringMode, QCameraExposure::MeteringMatrix);
-}
-
-void QCameraExposure::setMeteringMode(QCameraExposure::MeteringMode mode)
-{
- d_func()->setExposureParameter<QCameraExposure::MeteringMode>(QCameraExposureControl::MeteringMode, mode);
-}
-
-/*!
- \fn QCameraExposure::spotMeteringPoint() const
-
- When supported, the spot metering point is the (normalized) position of the point of the image
- where exposure metering will be performed. This is typically used to indicate an
- "interesting" area of the image that should be exposed properly.
-
- The coordinates are relative frame coordinates:
- QPointF(0,0) points to the left top frame point, QPointF(0.5,0.5) points to the frame center,
- which is typically the default spot metering point.
-
- The spot metering point is only used with spot metering mode.
-
- \sa setSpotMeteringPoint()
-*/
-
-QPointF QCameraExposure::spotMeteringPoint() const
-{
- return d_func()->exposureControl ? d_func()->exposureControl->actualValue(QCameraExposureControl::SpotMeteringPoint).toPointF() : QPointF();
-}
-
-/*!
- \fn QCameraExposure::setSpotMeteringPoint(const QPointF &point)
-
- Allows setting the spot metering point to \a point.
-
- \sa spotMeteringPoint()
-*/
-
-void QCameraExposure::setSpotMeteringPoint(const QPointF &point)
-{
- if (d_func()->exposureControl)
- d_func()->exposureControl->setValue(QCameraExposureControl::SpotMeteringPoint, point);
-}
-
-
-/*!
- Returns true if the metering \a mode is supported.
-*/
-bool QCameraExposure::isMeteringModeSupported(QCameraExposure::MeteringMode mode) const
-{
- if (!d_func()->exposureControl)
- return false;
-
- bool continuous = false;
- return d_func()->exposureControl->supportedParameterRange(QCameraExposureControl::MeteringMode, &continuous)
- .contains(QVariant::fromValue<QCameraExposure::MeteringMode>(mode));
-}
-
-int QCameraExposure::isoSensitivity() const
-{
- return d_func()->actualExposureParameter<int>(QCameraExposureControl::ISO, -1);
-}
-
-/*!
- Returns the requested ISO sensitivity
- or -1 if automatic ISO is turned on.
-*/
-int QCameraExposure::requestedIsoSensitivity() const
-{
- return d_func()->requestedExposureParameter<int>(QCameraExposureControl::ISO, -1);
-}
-
-/*!
- Returns the list of ISO senitivities camera supports.
-
- If the camera supports arbitrary ISO sensitivities within the supported range,
- *\a continuous is set to true, otherwise *\a continuous is set to false.
-*/
-QList<int> QCameraExposure::supportedIsoSensitivities(bool *continuous) const
-{
- QList<int> res;
- QCameraExposureControl *control = d_func()->exposureControl;
-
- bool tmp = false;
- if (!continuous)
- continuous = &tmp;
-
- if (!control)
- return res;
-
- const auto range = control->supportedParameterRange(QCameraExposureControl::ISO, continuous);
- for (const QVariant &value : range) {
- bool ok = false;
- int intValue = value.toInt(&ok);
- if (ok)
- res.append(intValue);
- else
- qWarning() << "Incompatible ISO value type, int is expected";
- }
-
- return res;
-}
-
-/*!
- \fn QCameraExposure::setManualIsoSensitivity(int iso)
- Sets the manual sensitivity to \a iso
-*/
-
-void QCameraExposure::setManualIsoSensitivity(int iso)
-{
- d_func()->setExposureParameter<int>(QCameraExposureControl::ISO, iso);
-}
-
-/*!
- \fn QCameraExposure::setAutoIsoSensitivity()
- Turn on auto sensitivity
-*/
-
-void QCameraExposure::setAutoIsoSensitivity()
-{
- d_func()->resetExposureParameter(QCameraExposureControl::ISO);
-}
-
-/*!
- \property QCameraExposure::shutterSpeed
- \brief Camera's shutter speed in seconds.
-
- \sa supportedShutterSpeeds(), setAutoShutterSpeed(), setManualShutterSpeed()
-*/
-
-/*!
- \fn QCameraExposure::shutterSpeedChanged(qreal speed)
-
- Signals that a camera's shutter \a speed has changed.
-*/
-
-/*!
- \property QCameraExposure::isoSensitivity
- \brief The sensor ISO sensitivity.
-
- \sa supportedIsoSensitivities(), setAutoIsoSensitivity(), setManualIsoSensitivity()
-*/
-
-/*!
- \property QCameraExposure::aperture
- \brief Lens aperture is specified as an F number, the ratio of the focal length to effective aperture diameter.
-
- \sa supportedApertures(), setAutoAperture(), setManualAperture(), requestedAperture()
-*/
-
-
-qreal QCameraExposure::aperture() const
-{
- return d_func()->actualExposureParameter<qreal>(QCameraExposureControl::Aperture, -1.0);
-}
-
-/*!
- Returns the requested manual aperture
- or -1.0 if automatic aperture is turned on.
-*/
-qreal QCameraExposure::requestedAperture() const
-{
- return d_func()->requestedExposureParameter<qreal>(QCameraExposureControl::Aperture, -1.0);
-}
-
-
-/*!
- Returns the list of aperture values camera supports.
- The apertures list can change depending on the focal length,
- in such a case the apertureRangeChanged() signal is emitted.
-
- If the camera supports arbitrary aperture values within the supported range,
- *\a continuous is set to true, otherwise *\a continuous is set to false.
-*/
-QList<qreal> QCameraExposure::supportedApertures(bool * continuous) const
-{
- QList<qreal> res;
- QCameraExposureControl *control = d_func()->exposureControl;
-
- bool tmp = false;
- if (!continuous)
- continuous = &tmp;
-
- if (!control)
- return res;
-
- const auto range = control->supportedParameterRange(QCameraExposureControl::Aperture, continuous);
- for (const QVariant &value : range) {
- bool ok = false;
- qreal realValue = value.toReal(&ok);
- if (ok)
- res.append(realValue);
- else
- qWarning() << "Incompatible aperture value type, qreal is expected";
- }
-
- return res;
-}
-
-/*!
- \fn QCameraExposure::setManualAperture(qreal aperture)
- Sets the manual camera \a aperture value.
-*/
-
-void QCameraExposure::setManualAperture(qreal aperture)
-{
- d_func()->setExposureParameter<qreal>(QCameraExposureControl::Aperture, aperture);
-}
-
-/*!
- \fn QCameraExposure::setAutoAperture()
- Turn on auto aperture
-*/
-
-void QCameraExposure::setAutoAperture()
-{
- d_func()->resetExposureParameter(QCameraExposureControl::Aperture);
-}
-
-/*!
- Returns the current shutter speed in seconds.
-*/
-
-qreal QCameraExposure::shutterSpeed() const
-{
- return d_func()->actualExposureParameter<qreal>(QCameraExposureControl::ShutterSpeed, -1.0);
-}
-
-/*!
- Returns the requested manual shutter speed in seconds
- or -1.0 if automatic shutter speed is turned on.
-*/
-qreal QCameraExposure::requestedShutterSpeed() const
-{
- return d_func()->requestedExposureParameter<qreal>(QCameraExposureControl::ShutterSpeed, -1.0);
-}
-
-/*!
- Returns the list of shutter speed values in seconds camera supports.
-
- If the camera supports arbitrary shutter speed values within the supported range,
- *\a continuous is set to true, otherwise *\a continuous is set to false.
-*/
-QList<qreal> QCameraExposure::supportedShutterSpeeds(bool *continuous) const
-{
- QList<qreal> res;
- QCameraExposureControl *control = d_func()->exposureControl;
-
- bool tmp = false;
- if (!continuous)
- continuous = &tmp;
-
- if (!control)
- return res;
-
- const auto range = control->supportedParameterRange(QCameraExposureControl::ShutterSpeed, continuous);
- for (const QVariant &value : range) {
- bool ok = false;
- qreal realValue = value.toReal(&ok);
- if (ok)
- res.append(realValue);
- else
- qWarning() << "Incompatible shutter speed value type, qreal is expected";
- }
-
- return res;
-}
-
-/*!
- Set the manual shutter speed to \a seconds
-*/
-
-void QCameraExposure::setManualShutterSpeed(qreal seconds)
-{
- d_func()->setExposureParameter<qreal>(QCameraExposureControl::ShutterSpeed, seconds);
-}
-
-/*!
- Turn on auto shutter speed
-*/
-
-void QCameraExposure::setAutoShutterSpeed()
-{
- d_func()->resetExposureParameter(QCameraExposureControl::ShutterSpeed);
-}
-
-
-/*!
- \enum QCameraExposure::FlashMode
-
- \value FlashAuto Automatic flash.
- \value FlashOff Flash is Off.
- \value FlashOn Flash is On.
- \value FlashRedEyeReduction Red eye reduction flash.
- \value FlashFill Use flash to fillin shadows.
- \value FlashTorch Constant light source. If supported,
- torch can be enabled without loading the camera.
- \value FlashVideoLight Constant light source, useful for video capture.
- The light is turned on only while camera is active.
- \value FlashSlowSyncFrontCurtain
- Use the flash in conjunction with a slow shutter speed.
- This mode allows better exposure of distant objects and/or motion blur effect.
- \value FlashSlowSyncRearCurtain
- The similar mode to FlashSlowSyncFrontCurtain but flash is fired at the end of exposure.
- \value FlashManual Flash power is manualy set.
-*/
-
-/*!
- \enum QCameraExposure::ExposureMode
-
- \value ExposureAuto Automatic mode.
- \value ExposureManual Manual mode.
- \value ExposurePortrait Portrait exposure mode.
- \value ExposureNight Night mode.
- \value ExposureBacklight Backlight exposure mode.
- \value ExposureSpotlight Spotlight exposure mode.
- \value ExposureSports Spots exposure mode.
- \value ExposureSnow Snow exposure mode.
- \value ExposureBeach Beach exposure mode.
- \value ExposureLargeAperture Use larger aperture with small depth of field.
- \value ExposureSmallAperture Use smaller aperture.
- \value ExposureAction Action mode. Since 5.5
- \value ExposureLandscape Landscape mode. Since 5.5
- \value ExposureNightPortrait Night portrait mode. Since 5.5
- \value ExposureTheatre Theatre mode. Since 5.5
- \value ExposureSunset Sunset mode. Since 5.5
- \value ExposureSteadyPhoto Steady photo mode. Since 5.5
- \value ExposureFireworks Fireworks mode. Since 5.5
- \value ExposureParty Party mode. Since 5.5
- \value ExposureCandlelight Candlelight mode. Since 5.5
- \value ExposureBarcode Barcode mode. Since 5.5
- \value ExposureModeVendor The base value for device specific exposure modes.
-*/
-
-/*!
- \enum QCameraExposure::MeteringMode
-
- \value MeteringMatrix Matrix metering mode.
- \value MeteringAverage Center weighted average metering mode.
- \value MeteringSpot Spot metering mode.
-*/
-
-/*!
- \property QCameraExposure::flashReady
- \brief Indicates if the flash is charged and ready to use.
-*/
-
-/*!
- \fn void QCameraExposure::flashReady(bool ready)
-
- Signal the flash \a ready status has changed.
-*/
-
-/*!
- \fn void QCameraExposure::apertureChanged(qreal value)
-
- Signal emitted when aperature changes to \a value.
-*/
-
-/*!
- \fn void QCameraExposure::apertureRangeChanged()
-
- Signal emitted when aperature range has changed.
-*/
-
-
-/*!
- \fn void QCameraExposure::shutterSpeedRangeChanged()
-
- Signal emitted when the shutter speed range has changed.
-*/
-
-
-/*!
- \fn void QCameraExposure::isoSensitivityChanged(int value)
-
- Signal emitted when sensitivity changes to \a value.
-*/
-
-/*!
- \fn void QCameraExposure::exposureCompensationChanged(qreal value)
-
- Signal emitted when the exposure compensation changes to \a value.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qcameraexposure.cpp"
diff --git a/src/multimedia/camera/qcameraexposure.h b/src/multimedia/camera/qcameraexposure.h
deleted file mode 100644
index a1dc96701..000000000
--- a/src/multimedia/camera/qcameraexposure.h
+++ /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$
-**
-****************************************************************************/
-
-#ifndef QCAMERAEXPOSURE_H
-#define QCAMERAEXPOSURE_H
-
-#include <QtMultimedia/qmediaobject.h>
-#include <QtMultimedia/qmediaenumdebug.h>
-
-QT_BEGIN_NAMESPACE
-
-
-class QCamera;
-class QCameraExposurePrivate;
-
-class Q_MULTIMEDIA_EXPORT QCameraExposure : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(qreal aperture READ aperture NOTIFY apertureChanged)
- Q_PROPERTY(qreal shutterSpeed READ shutterSpeed NOTIFY shutterSpeedChanged)
- Q_PROPERTY(int isoSensitivity READ isoSensitivity NOTIFY isoSensitivityChanged)
- Q_PROPERTY(qreal exposureCompensation READ exposureCompensation WRITE setExposureCompensation NOTIFY exposureCompensationChanged)
- Q_PROPERTY(bool flashReady READ isFlashReady NOTIFY flashReady)
- Q_PROPERTY(QCameraExposure::FlashModes flashMode READ flashMode WRITE setFlashMode)
- Q_PROPERTY(QCameraExposure::ExposureMode exposureMode READ exposureMode WRITE setExposureMode)
- Q_PROPERTY(QCameraExposure::MeteringMode meteringMode READ meteringMode WRITE setMeteringMode)
-
- Q_ENUMS(FlashMode)
- Q_ENUMS(ExposureMode)
- Q_ENUMS(MeteringMode)
-public:
- enum FlashMode {
- FlashAuto = 0x1,
- FlashOff = 0x2,
- FlashOn = 0x4,
- FlashRedEyeReduction = 0x8,
- FlashFill = 0x10,
- FlashTorch = 0x20,
- FlashVideoLight = 0x40,
- FlashSlowSyncFrontCurtain = 0x80,
- FlashSlowSyncRearCurtain = 0x100,
- FlashManual = 0x200
- };
- Q_DECLARE_FLAGS(FlashModes, FlashMode)
-
- enum ExposureMode {
- ExposureAuto = 0,
- ExposureManual = 1,
- ExposurePortrait = 2,
- ExposureNight = 3,
- ExposureBacklight = 4,
- ExposureSpotlight = 5,
- ExposureSports = 6,
- ExposureSnow = 7,
- ExposureBeach = 8,
- ExposureLargeAperture = 9,
- ExposureSmallAperture = 10,
- ExposureAction = 11,
- ExposureLandscape = 12,
- ExposureNightPortrait = 13,
- ExposureTheatre = 14,
- ExposureSunset = 15,
- ExposureSteadyPhoto = 16,
- ExposureFireworks = 17,
- ExposureParty = 18,
- ExposureCandlelight = 19,
- ExposureBarcode = 20,
- ExposureModeVendor = 1000
- };
-
- enum MeteringMode {
- MeteringMatrix = 1,
- MeteringAverage = 2,
- MeteringSpot = 3
- };
-
- bool isAvailable() const;
-
- FlashModes flashMode() const;
- bool isFlashModeSupported(FlashModes mode) const;
- bool isFlashReady() const;
-
- ExposureMode exposureMode() const;
- bool isExposureModeSupported(ExposureMode mode) const;
-
- qreal exposureCompensation() const;
-
- MeteringMode meteringMode() const;
- bool isMeteringModeSupported(MeteringMode mode) const;
-
- QPointF spotMeteringPoint() const;
- void setSpotMeteringPoint(const QPointF &point);
-
- int isoSensitivity() const;
- qreal aperture() const;
- qreal shutterSpeed() const;
-
- int requestedIsoSensitivity() const;
- qreal requestedAperture() const;
- qreal requestedShutterSpeed() const;
-
- QList<int> supportedIsoSensitivities(bool *continuous = nullptr) const;
- QList<qreal> supportedApertures(bool *continuous = nullptr) const;
- QList<qreal> supportedShutterSpeeds(bool *continuous = nullptr) const;
-
-public Q_SLOTS:
- void setFlashMode(FlashModes mode);
- void setExposureMode(ExposureMode mode);
- void setMeteringMode(MeteringMode mode);
-
- void setExposureCompensation(qreal ev);
-
- void setManualIsoSensitivity(int iso);
- void setAutoIsoSensitivity();
-
- void setManualAperture(qreal aperture);
- void setAutoAperture();
-
- void setManualShutterSpeed(qreal seconds);
- void setAutoShutterSpeed();
-
-Q_SIGNALS:
- void flashReady(bool);
-
- void apertureChanged(qreal);
- void apertureRangeChanged();
- void shutterSpeedChanged(qreal speed);
- void shutterSpeedRangeChanged();
- void isoSensitivityChanged(int);
- void exposureCompensationChanged(qreal);
-
-protected:
- virtual ~QCameraExposure();
-
-private:
- friend class QCamera;
- friend class QCameraPrivate;
- explicit QCameraExposure(QCamera *parent = nullptr);
-
- Q_DISABLE_COPY(QCameraExposure)
- Q_DECLARE_PRIVATE(QCameraExposure)
- Q_PRIVATE_SLOT(d_func(), void _q_exposureParameterChanged(int))
- Q_PRIVATE_SLOT(d_func(), void _q_exposureParameterRangeChanged(int))
- QCameraExposurePrivate *d_ptr;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QCameraExposure::FlashModes)
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QCameraExposure::ExposureMode)
-Q_DECLARE_METATYPE(QCameraExposure::FlashModes)
-Q_DECLARE_METATYPE(QCameraExposure::MeteringMode)
-
-Q_MEDIA_ENUM_DEBUG(QCameraExposure, ExposureMode)
-Q_MEDIA_ENUM_DEBUG(QCameraExposure, FlashMode)
-Q_MEDIA_ENUM_DEBUG(QCameraExposure, MeteringMode)
-
-#endif // QCAMERAEXPOSURE_H
diff --git a/src/multimedia/camera/qcamerafocus.cpp b/src/multimedia/camera/qcamerafocus.cpp
deleted file mode 100644
index 980b9dc93..000000000
--- a/src/multimedia/camera/qcamerafocus.cpp
+++ /dev/null
@@ -1,614 +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 "qcamerafocus.h"
-#include "qmediaobject_p.h"
-
-#include <qcamera.h>
-#include <qcameracontrol.h>
-#include <qcameraexposurecontrol.h>
-#include <qcamerafocuscontrol.h>
-#include <qcamerazoomcontrol.h>
-#include <qmediarecordercontrol.h>
-#include <qcameraimagecapturecontrol.h>
-#include <qvideodeviceselectorcontrol.h>
-
-#include <QtCore/QDebug>
-
-QT_BEGIN_NAMESPACE
-
-static void qRegisterCameraFocusMetaTypes()
-{
- qRegisterMetaType<QCameraFocus::FocusModes>("QCameraFocus::FocusModes");
- qRegisterMetaType<QCameraFocus::FocusPointMode>("QCameraFocus::FocusPointMode");
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterCameraFocusMetaTypes)
-
-
-class QCameraFocusFakeZoomControl : public QCameraZoomControl
-{
-public:
- QCameraFocusFakeZoomControl(QObject *parent) :
- QCameraZoomControl(parent) {}
-
- qreal maximumOpticalZoom() const override { return 1.0; }
- qreal maximumDigitalZoom() const override { return 1.0; }
-
- qreal requestedOpticalZoom() const override { return 1.0; }
- qreal requestedDigitalZoom() const override { return 1.0; }
- qreal currentOpticalZoom() const override { return 1.0; }
- qreal currentDigitalZoom() const override { return 1.0; }
-
- void zoomTo(qreal, qreal) override { qWarning("The camera doesn't support zooming."); }
-};
-
-class QCameraFocusFakeFocusControl : public QCameraFocusControl
-{
-public:
- QCameraFocusFakeFocusControl(QObject *parent) :
- QCameraFocusControl(parent) {}
-
- QCameraFocus::FocusModes focusMode() const override { return QCameraFocus::AutoFocus; }
- void setFocusMode(QCameraFocus::FocusModes) override { qWarning("Focus mode selection is not supported"); }
- bool isFocusModeSupported(QCameraFocus::FocusModes) const override { return false; }
-
- QCameraFocus::FocusPointMode focusPointMode() const override { return QCameraFocus::FocusPointAuto; }
- void setFocusPointMode(QCameraFocus::FocusPointMode) override { qWarning("Focus points mode selection is not supported"); }
- bool isFocusPointModeSupported(QCameraFocus::FocusPointMode) const override { return false; }
- QPointF customFocusPoint() const override { return QPointF(0.5,0.5); }
- void setCustomFocusPoint(const QPointF &) override { qWarning("Focus points selection is not supported"); }
-
- QCameraFocusZoneList focusZones() const override { return QCameraFocusZoneList(); }
-};
-
-
-
-class QCameraFocusZoneData : public QSharedData
-{
-public:
- QCameraFocusZoneData():
- status(QCameraFocusZone::Invalid)
- {
-
- }
-
- QCameraFocusZoneData(const QRectF &_area, QCameraFocusZone::FocusZoneStatus _status):
- area(_area),
- status(_status)
- {
-
- }
-
-
- QCameraFocusZoneData(const QCameraFocusZoneData &other):
- QSharedData(other),
- area(other.area),
- status(other.status)
- {
- }
-
- QCameraFocusZoneData& operator=(const QCameraFocusZoneData &other)
- {
- area = other.area;
- status = other.status;
- return *this;
- }
-
- QRectF area;
- QCameraFocusZone::FocusZoneStatus status;
-};
-
-
-/*!
- \class QCameraFocusZone
-
- \brief The QCameraFocusZone class provides information on zones used for autofocusing a camera.
-
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_camera
-
- For cameras that support autofocusing, in order for a camera to autofocus on
- part of a sensor frame, it considers different zones within the frame. Which
- zones to use, and where the zones are located vary between different cameras.
-
- This class exposes what zones are used by a particular camera, and a list of the
- zones can be retrieved by a \l QCameraFocus instance.
-
- You can use this information to present visual feedback - for example, drawing
- rectangles around areas of the camera frame that are in focus, or changing the
- color of a zone as it comes into focus.
-
- \snippet multimedia-snippets/camera.cpp Camera focus zones
-
- \sa QCameraFocus
-*/
-
-/*!
- \enum QCameraFocusZone::FocusZoneStatus
-
- \value Invalid This zone is not valid
- \value Unused This zone may be used for autofocusing, but is not currently.
- \value Selected This zone is currently being used for autofocusing, but is not in focus.
- \value Focused This zone is being used for autofocusing and is currently in focus.
-*/
-
-/*!
- * \internal
- * Creates a new, empty QCameraFocusZone.
- */
-QCameraFocusZone::QCameraFocusZone()
- :d(new QCameraFocusZoneData)
-{
-
-}
-
-/*!
- * \internal
- * Creates a new QCameraFocusZone with the supplied \a area and \a status.
- */
-QCameraFocusZone::QCameraFocusZone(const QRectF &area, QCameraFocusZone::FocusZoneStatus status)
- :d(new QCameraFocusZoneData(area, status))
-{
-}
-
-/*!
- * Creates a new QCameraFocusZone as a copy of \a other.
- */
-QCameraFocusZone::QCameraFocusZone(const QCameraFocusZone &other)
- :d(other.d)
-{
-
-}
-
-/*!
- * Destroys this QCameraFocusZone.
- */
-QCameraFocusZone::~QCameraFocusZone()
-{
-
-}
-
-/*!
- * Assigns \a other to this QCameraFocusZone.
- */
-QCameraFocusZone& QCameraFocusZone::operator=(const QCameraFocusZone &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- * Returns true if this focus zone is the same as \a other.
- */
-bool QCameraFocusZone::operator==(const QCameraFocusZone &other) const
-{
- return d == other.d ||
- (d->area == other.d->area && d->status == other.d->status);
-}
-
-/*!
- * Returns true if this focus zone is not the same as \a other.
- */
-bool QCameraFocusZone::operator!=(const QCameraFocusZone &other) const
-{
- return !(*this == other);
-}
-
-/*!
- * Returns true if this focus zone has a valid area and status.
- */
-bool QCameraFocusZone::isValid() const
-{
- return d->status != Invalid && !d->area.isValid();
-}
-
-/*!
- * Returns the area of the camera frame that this focus zone encompasses.
- *
- * Coordinates are in frame relative coordinates - \c QPointF(0,0) is the top
- * left of the frame, and \c QPointF(1,1) is the bottom right.
- */
-QRectF QCameraFocusZone::area() const
-{
- return d->area;
-}
-
-/*!
- * Returns the current status of this focus zone.
- */
-QCameraFocusZone::FocusZoneStatus QCameraFocusZone::status() const
-{
- return d->status;
-}
-
-/*!
- * \internal
- * Sets the current status of this focus zone to \a status.
- */
-void QCameraFocusZone::setStatus(QCameraFocusZone::FocusZoneStatus status)
-{
- d->status = status;
-}
-
-
-/*!
- \class QCameraFocus
-
- \brief The QCameraFocus class provides an interface for focus and zoom related camera settings.
-
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_camera
-
- On hardware that supports it, this class lets you adjust the focus
- or zoom (both optical and digital). This also includes things
- like "Macro" mode for close up work (e.g. reading barcodes, or
- recognising letters), or "touch to focus" - indicating an
- interesting area of the viewfinder for the hardware to attempt
- to focus on.
-
- \snippet multimedia-snippets/camera.cpp Camera custom zoom
-
- Zooming can be accomplished in a number of ways - usually the more
- expensive but higher quality approach is an optical zoom, which allows
- using the full extent of the camera sensor to gather image pixels. In
- addition it is possible to digitally zoom, which will generally just
- enlarge part of the sensor frame and throw away other parts. If the
- camera hardware supports optical zoom this should generally always
- be used first. The \l maximumOpticalZoom() method allows this to be
- checked. The \l zoomTo() method allows changing both optical and
- digital zoom at once.
-
- \snippet multimedia-snippets/camera.cpp Camera combined zoom
-
- \section2 Some notes on autofocus
- Some hardware supports a movable focus lens assembly, and typically
- this hardware also supports automatically focusing via some heuristic.
- You can influence this via the \l FocusPointMode setting - typically
- the center of the frame is brought into focus, but some hardware
- also supports focusing on any faces detected in the frame, or on
- a specific point (usually provided by a user in a "touch to focus"
- scenario).
-
- This class (in combination with \l QCameraFocusZone)
- can expose information on what parts of the camera sensor image
- are in focus or are being used for autofocusing via the \l focusZones()
- property:
-
- \snippet multimedia-snippets/camera.cpp Camera focus zones
-
- \sa QCameraFocusZone
-*/
-
-
-class QCameraFocusPrivate : public QMediaObjectPrivate
-{
- Q_DECLARE_NON_CONST_PUBLIC(QCameraFocus)
-public:
- void initControls();
-
- QCamera *camera;
-
- QCameraFocusControl *focusControl;
- QCameraZoomControl *zoomControl;
- bool available;
-};
-
-
-void QCameraFocusPrivate::initControls()
-{
- Q_Q(QCameraFocus);
-
- focusControl = nullptr;
- zoomControl = nullptr;
-
- QMediaService *service = camera->service();
- if (service) {
- focusControl = qobject_cast<QCameraFocusControl *>(service->requestControl(QCameraFocusControl_iid));
- zoomControl = qobject_cast<QCameraZoomControl *>(service->requestControl(QCameraZoomControl_iid));
- }
-
- available = focusControl != nullptr;
-
- if (!focusControl)
- focusControl = new QCameraFocusFakeFocusControl(q);
-
- if (!zoomControl)
- zoomControl = new QCameraFocusFakeZoomControl(q);
-
- q->connect(focusControl, SIGNAL(focusZonesChanged()), q, SIGNAL(focusZonesChanged()));
-
- q->connect(zoomControl, SIGNAL(currentOpticalZoomChanged(qreal)),
- q, SIGNAL(opticalZoomChanged(qreal)));
- q->connect(zoomControl, SIGNAL(currentDigitalZoomChanged(qreal)),
- q, SIGNAL(digitalZoomChanged(qreal)));
- q->connect(zoomControl, SIGNAL(maximumOpticalZoomChanged(qreal)),
- q, SIGNAL(maximumOpticalZoomChanged(qreal)));
- q->connect(zoomControl, SIGNAL(maximumDigitalZoomChanged(qreal)),
- q, SIGNAL(maximumDigitalZoomChanged(qreal)));
-}
-
-/*!
- \internal
- Construct a QCameraFocus for \a camera.
-*/
-
-QCameraFocus::QCameraFocus(QCamera *camera)
- : QObject(*new QCameraFocusPrivate, camera)
-{
- Q_D(QCameraFocus);
- d->camera = camera;
- d->initControls();
-}
-
-
-/*!
- Destroys the camera focus object.
-*/
-
-QCameraFocus::~QCameraFocus()
-{
-}
-
-/*!
- Returns true if focus related settings are supported by this camera.
-
- You may need to also check if any specific features are supported.
-*/
-bool QCameraFocus::isAvailable() const
-{
- return d_func()->available;
-}
-
-/*!
- \property QCameraFocus::focusMode
- \brief the current camera focus mode.
-
-
- This controls the way the camera lens assembly is configured.
-
- \sa QCameraFocus::isFocusModeSupported()
-*/
-
-QCameraFocus::FocusModes QCameraFocus::focusMode() const
-{
- return d_func()->focusControl->focusMode();
-}
-
-void QCameraFocus::setFocusMode(QCameraFocus::FocusModes mode)
-{
- d_func()->focusControl->setFocusMode(mode);
-}
-
-/*!
- Returns true if the focus \a mode is supported by camera.
-*/
-
-bool QCameraFocus::isFocusModeSupported(FocusModes mode) const
-{
- return d_func()->focusControl->isFocusModeSupported(mode);
-}
-
-/*!
- \property QCameraFocus::focusPointMode
- \brief the current camera focus point selection mode.
-
- If the camera focus mode is set to use an autofocusing mode,
- this property controls the way the camera will select areas
- of the frame to use for autofocusing.
-
- \sa QCameraFocus::isFocusPointModeSupported()
-*/
-
-QCameraFocus::FocusPointMode QCameraFocus::focusPointMode() const
-{
- return d_func()->focusControl->focusPointMode();
-}
-
-void QCameraFocus::setFocusPointMode(QCameraFocus::FocusPointMode mode)
-{
- d_func()->focusControl->setFocusPointMode(mode);
-}
-
-/*!
- Returns true if focus point \a mode is supported.
- */
-bool QCameraFocus::isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const
-{
- return d_func()->focusControl->isFocusPointModeSupported(mode);
-}
-
-/*!
- \property QCameraFocus::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.
- */
-
-QPointF QCameraFocus::customFocusPoint() const
-{
- return d_func()->focusControl->customFocusPoint();
-}
-
-void QCameraFocus::setCustomFocusPoint(const QPointF &point)
-{
- d_func()->focusControl->setCustomFocusPoint(point);
-}
-
-/*!
- \property QCameraFocus::focusZones
-
- Returns the list of active focus zones.
-
- If QCamera::FocusPointAuto or QCamera::FocusPointFaceDetection focus mode is selected
- this method returns the list of zones the camera is actually focused on.
-
- The coordinates system is the same as for custom focus points:
- QPointF(0,0) points to the left top frame point, QPointF(0.5,0.5) points to the frame center.
- */
-QCameraFocusZoneList QCameraFocus::focusZones() const
-{
- return d_func()->focusControl->focusZones();
-}
-
-/*!
- Returns the maximum optical zoom.
-
- This will be \c 1.0 on cameras that do not support optical zoom.
-*/
-
-qreal QCameraFocus::maximumOpticalZoom() const
-{
- return d_func()->zoomControl->maximumOpticalZoom();
-}
-
-/*!
- Returns the maximum digital zoom
-
- This will be \c 1.0 on cameras that do not support digital zoom.
-*/
-
-qreal QCameraFocus::maximumDigitalZoom() const
-{
- return d_func()->zoomControl->maximumDigitalZoom();
-}
-
-/*!
- \property QCameraFocus::opticalZoom
- \brief the current optical zoom value.
-
- \sa QCameraFocus::digitalZoom
-*/
-
-qreal QCameraFocus::opticalZoom() const
-{
- return d_func()->zoomControl->currentOpticalZoom();
-}
-
-/*!
- \property QCameraFocus::digitalZoom
- \brief the current digital zoom value.
-
- \sa QCameraFocus::opticalZoom
-*/
-qreal QCameraFocus::digitalZoom() const
-{
- return d_func()->zoomControl->currentDigitalZoom();
-}
-
-
-/*!
- Set the camera \a optical and \a digital zoom values.
-
- Since there may be a physical component to move, the change in
- zoom value may not be instantaneous.
-
-*/
-void QCameraFocus::zoomTo(qreal optical, qreal digital)
-{
- d_func()->zoomControl->zoomTo(optical, digital);
-}
-
-/*!
- \enum QCameraFocus::FocusMode
-
- \value ManualFocus Manual or fixed focus mode.
- \value HyperfocalFocus 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 InfinityFocus Focus strictly to infinity.
- \value AutoFocus One-shot auto focus mode.
- \value ContinuousFocus Continuous auto focus mode.
- \value MacroFocus One shot auto focus to objects close to camera.
-*/
-
-/*!
- \enum QCameraFocus::FocusPointMode
-
- \value FocusPointAuto Automatically select one or multiple focus points.
- \value FocusPointCenter Focus to the frame center.
- \value FocusPointFaceDetection Focus on faces in the frame.
- \value FocusPointCustom Focus to the custom point, defined by QCameraFocus::customFocusPoint property.
-*/
-
-/*!
- \fn void QCameraFocus::opticalZoomChanged(qreal value)
-
- Signal emitted when optical zoom value changes to new \a value.
-*/
-
-/*!
- \fn void QCameraFocus::digitalZoomChanged(qreal value)
-
- Signal emitted when digital zoom value changes to new \a value.
-*/
-
-/*!
- \fn void QCameraFocus::maximumOpticalZoomChanged(qreal zoom)
-
- Signal emitted when the maximum supported optical \a zoom value changed.
-*/
-
-/*!
- \fn void QCameraFocus::maximumDigitalZoomChanged(qreal zoom)
-
- Signal emitted when the maximum supported digital \a zoom value changed.
-
- The maximum supported zoom value can depend on other camera settings,
- like capture mode or resolution.
-*/
-
-
-
-/*!
- \fn QCameraFocus::focusZonesChanged()
-
- This signal is emitted when the set of zones used in autofocusing is changed.
-
- This can change when a zone is focused or loses focus, or new focus zones
- have been detected.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qcamerafocus.cpp"
diff --git a/src/multimedia/camera/qcamerafocus.h b/src/multimedia/camera/qcamerafocus.h
deleted file mode 100644
index 11639c3da..000000000
--- a/src/multimedia/camera/qcamerafocus.h
+++ /dev/null
@@ -1,177 +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 QCAMERAFOCUS_H
-#define QCAMERAFOCUS_H
-
-#include <QtCore/qstringlist.h>
-#include <QtCore/qpair.h>
-#include <QtCore/qsize.h>
-#include <QtCore/qpoint.h>
-#include <QtCore/qrect.h>
-#include <QtCore/qshareddata.h>
-
-#include <QtMultimedia/qmediaobject.h>
-#include <QtMultimedia/qmediaenumdebug.h>
-
-QT_BEGIN_NAMESPACE
-
-
-class QCamera;
-
-class QCameraFocusZoneData;
-
-class Q_MULTIMEDIA_EXPORT QCameraFocusZone {
-public:
- enum FocusZoneStatus {
- Invalid,
- Unused,
- Selected,
- Focused
- };
-
- QCameraFocusZone();
- QCameraFocusZone(const QRectF &area, FocusZoneStatus status = Selected);
- QCameraFocusZone(const QCameraFocusZone &other);
-
- QCameraFocusZone& operator=(const QCameraFocusZone &other);
- bool operator==(const QCameraFocusZone &other) const;
- bool operator!=(const QCameraFocusZone &other) const;
-
- ~QCameraFocusZone();
-
- bool isValid() const;
-
- QRectF area() const;
-
- FocusZoneStatus status() const;
- void setStatus(FocusZoneStatus status);
-
-private:
- QSharedDataPointer<QCameraFocusZoneData> d;
-};
-
-typedef QList<QCameraFocusZone> QCameraFocusZoneList;
-
-
-class QCameraFocusPrivate;
-class Q_MULTIMEDIA_EXPORT QCameraFocus : public QObject
-{
- Q_OBJECT
-
- Q_PROPERTY(FocusModes focusMode READ focusMode WRITE setFocusMode)
- Q_PROPERTY(FocusPointMode focusPointMode READ focusPointMode WRITE setFocusPointMode)
- Q_PROPERTY(QPointF customFocusPoint READ customFocusPoint WRITE setCustomFocusPoint)
- Q_PROPERTY(QCameraFocusZoneList focusZones READ focusZones NOTIFY focusZonesChanged)
- Q_PROPERTY(qreal opticalZoom READ opticalZoom NOTIFY opticalZoomChanged)
- Q_PROPERTY(qreal digitalZoom READ digitalZoom NOTIFY digitalZoomChanged)
-
- Q_ENUMS(FocusMode)
- Q_ENUMS(FocusPointMode)
-public:
- enum FocusMode {
- ManualFocus = 0x1,
- HyperfocalFocus = 0x02,
- InfinityFocus = 0x04,
- AutoFocus = 0x8,
- ContinuousFocus = 0x10,
- MacroFocus = 0x20
- };
- Q_DECLARE_FLAGS(FocusModes, FocusMode)
-
- enum FocusPointMode {
- FocusPointAuto,
- FocusPointCenter,
- FocusPointFaceDetection,
- FocusPointCustom
- };
-
- bool isAvailable() const;
-
- FocusModes focusMode() const;
- void setFocusMode(FocusModes mode);
- bool isFocusModeSupported(FocusModes mode) const;
-
- FocusPointMode focusPointMode() const;
- void setFocusPointMode(FocusPointMode mode);
- bool isFocusPointModeSupported(FocusPointMode) const;
- QPointF customFocusPoint() const;
- void setCustomFocusPoint(const QPointF &point);
-
- QCameraFocusZoneList focusZones() const;
-
- qreal maximumOpticalZoom() const;
- qreal maximumDigitalZoom() const;
- qreal opticalZoom() const;
- qreal digitalZoom() const;
-
- void zoomTo(qreal opticalZoom, qreal digitalZoom);
-
-Q_SIGNALS:
- void opticalZoomChanged(qreal);
- void digitalZoomChanged(qreal);
-
- void focusZonesChanged();
-
- void maximumOpticalZoomChanged(qreal);
- void maximumDigitalZoomChanged(qreal);
-
-protected:
- ~QCameraFocus();
-
-private:
- friend class QCamera;
- friend class QCameraPrivate;
- QCameraFocus(QCamera *camera);
-
- Q_DISABLE_COPY(QCameraFocus)
- Q_DECLARE_PRIVATE(QCameraFocus)
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QCameraFocus::FocusModes)
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QCameraFocus::FocusModes)
-Q_DECLARE_METATYPE(QCameraFocus::FocusPointMode)
-
-Q_MEDIA_ENUM_DEBUG(QCameraFocus, FocusMode)
-Q_MEDIA_ENUM_DEBUG(QCameraFocus, FocusPointMode)
-
-#endif // QCAMERAFOCUS_H
diff --git a/src/multimedia/camera/qcameraimagecapture.cpp b/src/multimedia/camera/qcameraimagecapture.cpp
deleted file mode 100644
index 7eb67daed..000000000
--- a/src/multimedia/camera/qcameraimagecapture.cpp
+++ /dev/null
@@ -1,651 +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 <qcameraimagecapture.h>
-#include <qcameraimagecapturecontrol.h>
-#include <qmediaencodersettings.h>
-#include <qcameracapturedestinationcontrol.h>
-#include <qcameracapturebufferformatcontrol.h>
-
-#include <qimageencodercontrol.h>
-#include "qmediaobject_p.h"
-#include <qmediaservice.h>
-#include <qcamera.h>
-#include <qcameracontrol.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qurl.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qmetaobject.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QCameraImageCapture
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_camera
-
-
- \brief The QCameraImageCapture class is used for the recording of media content.
-
- The QCameraImageCapture class is a high level images recording class.
- It's not intended to be used alone but for accessing the media
- recording functions of other media objects, like QCamera.
-
- \snippet multimedia-snippets/camera.cpp Camera
-
- \snippet multimedia-snippets/camera.cpp Camera keys
-
- \sa QCamera
-*/
-
-/*!
- \enum QCameraImageCapture::CaptureDestination
-
- \value CaptureToFile Capture the image to a file.
- \value CaptureToBuffer Capture the image to a buffer for further processing.
-*/
-
-static void qRegisterCameraImageCaptureMetaTypes()
-{
- qRegisterMetaType<QCameraImageCapture::Error>("QCameraImageCapture::Error");
- qRegisterMetaType<QCameraImageCapture::CaptureDestination>("QCameraImageCapture::CaptureDestination");
- qRegisterMetaType<QCameraImageCapture::CaptureDestinations>("QCameraImageCapture::CaptureDestinations");
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterCameraImageCaptureMetaTypes)
-
-
-class QCameraImageCapturePrivate
-{
- Q_DECLARE_NON_CONST_PUBLIC(QCameraImageCapture)
-public:
- QCameraImageCapturePrivate();
-
- QMediaObject *mediaObject;
-
- QCameraImageCaptureControl *control;
- QImageEncoderControl *encoderControl;
- QCameraCaptureDestinationControl *captureDestinationControl;
- QCameraCaptureBufferFormatControl *bufferFormatControl;
-
- QCameraImageCapture::Error error;
- QString errorString;
-
- void _q_error(int id, int error, const QString &errorString);
- void _q_readyChanged(bool);
- void _q_serviceDestroyed();
-
- void unsetError() { error = QCameraImageCapture::NoError; errorString.clear(); }
-
- QCameraImageCapture *q_ptr;
-};
-
-QCameraImageCapturePrivate::QCameraImageCapturePrivate():
- mediaObject(nullptr),
- control(nullptr),
- encoderControl(nullptr),
- captureDestinationControl(nullptr),
- bufferFormatControl(nullptr),
- error(QCameraImageCapture::NoError)
-{
-}
-
-void QCameraImageCapturePrivate::_q_error(int id, int error, const QString &errorString)
-{
- Q_Q(QCameraImageCapture);
-
- this->error = QCameraImageCapture::Error(error);
- this->errorString = errorString;
-
- emit q->error(id, this->error, errorString);
-}
-
-void QCameraImageCapturePrivate::_q_readyChanged(bool ready)
-{
- Q_Q(QCameraImageCapture);
- emit q->readyForCaptureChanged(ready);
-}
-
-void QCameraImageCapturePrivate::_q_serviceDestroyed()
-{
- mediaObject = nullptr;
- control = nullptr;
- encoderControl = nullptr;
- captureDestinationControl = nullptr;
- bufferFormatControl = nullptr;
-}
-
-/*!
- Constructs a media recorder which records the media produced by \a mediaObject.
-
- The \a parent is passed to QMediaObject.
-*/
-
-QCameraImageCapture::QCameraImageCapture(QMediaObject *mediaObject, QObject *parent):
- QObject(parent), d_ptr(new QCameraImageCapturePrivate)
-{
- Q_D(QCameraImageCapture);
-
- d->q_ptr = this;
-
- if (mediaObject)
- mediaObject->bind(this);
-}
-
-/*!
- Destroys images capture object.
-*/
-
-QCameraImageCapture::~QCameraImageCapture()
-{
- Q_D(QCameraImageCapture);
-
- if (d->mediaObject)
- d->mediaObject->unbind(this);
-
- delete d_ptr;
-}
-
-/*!
- \reimp
-*/
-QMediaObject *QCameraImageCapture::mediaObject() const
-{
- return d_func()->mediaObject;
-}
-
-/*!
- \reimp
-*/
-bool QCameraImageCapture::setMediaObject(QMediaObject *mediaObject)
-{
- Q_D(QCameraImageCapture);
-
- if (d->mediaObject) {
- if (d->control) {
- disconnect(d->control, SIGNAL(imageExposed(int)),
- this, SIGNAL(imageExposed(int)));
- disconnect(d->control, SIGNAL(imageCaptured(int,QImage)),
- this, SIGNAL(imageCaptured(int,QImage)));
- disconnect(d->control, SIGNAL(imageAvailable(int,QVideoFrame)),
- this, SIGNAL(imageAvailable(int,QVideoFrame)));
- disconnect(d->control, SIGNAL(imageMetadataAvailable(int,QString,QVariant)),
- this, SIGNAL(imageMetadataAvailable(int,QString,QVariant)));
- disconnect(d->control, SIGNAL(imageSaved(int,QString)),
- this, SIGNAL(imageSaved(int,QString)));
- disconnect(d->control, SIGNAL(readyForCaptureChanged(bool)),
- this, SLOT(_q_readyChanged(bool)));
- disconnect(d->control, SIGNAL(error(int,int,QString)),
- this, SLOT(_q_error(int,int,QString)));
-
- if (d->captureDestinationControl) {
- disconnect(d->captureDestinationControl, SIGNAL(captureDestinationChanged(QCameraImageCapture::CaptureDestinations)),
- this, SIGNAL(captureDestinationChanged(QCameraImageCapture::CaptureDestinations)));
- }
-
- if (d->bufferFormatControl) {
- disconnect(d->bufferFormatControl, SIGNAL(bufferFormatChanged(QVideoFrame::PixelFormat)),
- this, SIGNAL(bufferFormatChanged(QVideoFrame::PixelFormat)));
- }
-
- QMediaService *service = d->mediaObject->service();
- service->releaseControl(d->control);
- if (d->encoderControl)
- service->releaseControl(d->encoderControl);
- if (d->captureDestinationControl)
- service->releaseControl(d->captureDestinationControl);
- if (d->bufferFormatControl)
- service->releaseControl(d->bufferFormatControl);
-
- disconnect(service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed()));
- }
- }
-
- d->mediaObject = mediaObject;
-
- if (d->mediaObject) {
- QMediaService *service = mediaObject->service();
- if (service) {
- d->control = qobject_cast<QCameraImageCaptureControl*>(service->requestControl(QCameraImageCaptureControl_iid));
-
- if (d->control) {
- d->encoderControl = qobject_cast<QImageEncoderControl *>(service->requestControl(QImageEncoderControl_iid));
- d->captureDestinationControl = qobject_cast<QCameraCaptureDestinationControl *>(
- service->requestControl(QCameraCaptureDestinationControl_iid));
- d->bufferFormatControl = qobject_cast<QCameraCaptureBufferFormatControl *>(
- service->requestControl(QCameraCaptureBufferFormatControl_iid));
-
- 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,QString,QVariant)),
- this, SIGNAL(imageMetadataAvailable(int,QString,QVariant)));
- connect(d->control, SIGNAL(imageAvailable(int,QVideoFrame)),
- this, SIGNAL(imageAvailable(int,QVideoFrame)));
- connect(d->control, SIGNAL(imageSaved(int,QString)),
- this, SIGNAL(imageSaved(int,QString)));
- connect(d->control, SIGNAL(readyForCaptureChanged(bool)),
- this, SLOT(_q_readyChanged(bool)));
- connect(d->control, SIGNAL(error(int,int,QString)),
- this, SLOT(_q_error(int,int,QString)));
-
- if (d->captureDestinationControl) {
- connect(d->captureDestinationControl, SIGNAL(captureDestinationChanged(QCameraImageCapture::CaptureDestinations)),
- this, SIGNAL(captureDestinationChanged(QCameraImageCapture::CaptureDestinations)));
- }
-
- if (d->bufferFormatControl) {
- connect(d->bufferFormatControl, SIGNAL(bufferFormatChanged(QVideoFrame::PixelFormat)),
- this, SIGNAL(bufferFormatChanged(QVideoFrame::PixelFormat)));
- }
-
- connect(service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed()));
-
- return true;
- }
- }
- }
-
- // without QCameraImageCaptureControl discard the media object
- d->mediaObject = nullptr;
- d->control = nullptr;
- d->encoderControl = nullptr;
- d->captureDestinationControl = nullptr;
- d->bufferFormatControl = nullptr;
-
- return false;
-}
-
-/*!
- Returns true if the images capture service ready to use.
-*/
-bool QCameraImageCapture::isAvailable() const
-{
- if (d_func()->control != nullptr)
- return true;
- else
- return false;
-}
-
-/*!
- Returns the availability of this functionality.
-*/
-QMultimedia::AvailabilityStatus QCameraImageCapture::availability() const
-{
- if (d_func()->control != nullptr)
- return QMultimedia::Available;
- else
- return QMultimedia::ServiceMissing;
-}
-
-/*!
- Returns the current error state.
-
- \sa errorString()
-*/
-
-QCameraImageCapture::Error QCameraImageCapture::error() const
-{
- return d_func()->error;
-}
-
-/*!
- Returns a string describing the current error state.
-
- \sa error()
-*/
-
-QString QCameraImageCapture::errorString() const
-{
- return d_func()->errorString;
-}
-
-
-/*!
- Returns a list of supported image codecs.
-*/
-QStringList QCameraImageCapture::supportedImageCodecs() const
-{
- return d_func()->encoderControl ?
- d_func()->encoderControl->supportedImageCodecs() : QStringList();
-}
-
-/*!
- Returns a description of an image \a codec.
-*/
-QString QCameraImageCapture::imageCodecDescription(const QString &codec) const
-{
- return d_func()->encoderControl ?
- d_func()->encoderControl->imageCodecDescription(codec) : QString();
-}
-
-/*!
- Returns a list of resolutions images can be encoded at.
-
- If non null image \a settings parameter is passed,
- the returned list is reduced to resolution supported with partial settings like image codec or quality applied.
-
- If the encoder supports arbitrary resolutions within the supported range,
- *\a continuous is set to true, otherwise *\a continuous is set to false.
-
- \sa QImageEncoderSettings::resolution()
-*/
-QList<QSize> QCameraImageCapture::supportedResolutions(const QImageEncoderSettings &settings, bool *continuous) const
-{
- if (continuous)
- *continuous = false;
-
- return d_func()->encoderControl ?
- d_func()->encoderControl->supportedResolutions(settings, continuous) : QList<QSize>();
-}
-
-/*!
- Returns the image encoder settings being used.
-
- \sa setEncodingSettings()
-*/
-
-QImageEncoderSettings QCameraImageCapture::encodingSettings() const
-{
- return d_func()->encoderControl ?
- d_func()->encoderControl->imageSettings() : QImageEncoderSettings();
-}
-
-/*!
- Sets the image encoding \a settings.
-
- If some parameters are not specified, or null settings are passed,
- the encoder choose the default encoding parameters.
-
- \sa encodingSettings()
-*/
-
-void QCameraImageCapture::setEncodingSettings(const QImageEncoderSettings &settings)
-{
- Q_D(QCameraImageCapture);
-
- if (d->encoderControl) {
- QCamera *camera = qobject_cast<QCamera*>(d->mediaObject);
- if (camera && camera->captureMode() == QCamera::CaptureStillImage) {
- QMetaObject::invokeMethod(camera,
- "_q_preparePropertyChange",
- Qt::DirectConnection,
- Q_ARG(int, QCameraControl::ImageEncodingSettings));
- }
-
- d->encoderControl->setImageSettings(settings);
- }
-}
-
-/*!
- Returns the list of supported buffer image capture formats.
-
- \sa bufferFormat(), setBufferFormat()
-*/
-QList<QVideoFrame::PixelFormat> QCameraImageCapture::supportedBufferFormats() const
-{
- if (d_func()->bufferFormatControl)
- return d_func()->bufferFormatControl->supportedBufferFormats();
- else
- return QList<QVideoFrame::PixelFormat>();
-}
-
-/*!
- Returns the buffer image capture format being used.
-
- \sa supportedBufferFormats(), setBufferFormat()
-*/
-QVideoFrame::PixelFormat QCameraImageCapture::bufferFormat() const
-{
- if (d_func()->bufferFormatControl)
- return d_func()->bufferFormatControl->bufferFormat();
- else
- return QVideoFrame::Format_Invalid;
-}
-
-/*!
- Sets the buffer image capture \a format to be used.
-
- \sa bufferFormat(), supportedBufferFormats(), captureDestination()
-*/
-void QCameraImageCapture::setBufferFormat(const QVideoFrame::PixelFormat format)
-{
- if (d_func()->bufferFormatControl)
- d_func()->bufferFormatControl->setBufferFormat(format);
-}
-
-/*!
- Returns true if the image capture \a destination is supported; otherwise returns false.
-
- \sa captureDestination(), setCaptureDestination()
-*/
-bool QCameraImageCapture::isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const
-{
- if (d_func()->captureDestinationControl)
- return d_func()->captureDestinationControl->isCaptureDestinationSupported(destination);
- else
- return destination == CaptureToFile;
-}
-
-/*!
- Returns the image capture destination being used.
-
- \sa isCaptureDestinationSupported(), setCaptureDestination()
-*/
-QCameraImageCapture::CaptureDestinations QCameraImageCapture::captureDestination() const
-{
- if (d_func()->captureDestinationControl)
- return d_func()->captureDestinationControl->captureDestination();
- else
- return CaptureToFile;
-}
-
-/*!
- Sets the capture \a destination to be used.
-
- \sa isCaptureDestinationSupported(), captureDestination()
-*/
-void QCameraImageCapture::setCaptureDestination(QCameraImageCapture::CaptureDestinations destination)
-{
- Q_D(QCameraImageCapture);
-
- if (d->captureDestinationControl)
- d->captureDestinationControl->setCaptureDestination(destination);
-}
-
-/*!
- \property QCameraImageCapture::readyForCapture
- \brief whether the service is ready to capture a an image immediately.
-
- Calling capture() while \e readyForCapture is \c false is not permitted and
- results in an error.
-*/
-
-bool QCameraImageCapture::isReadyForCapture() const
-{
- if (d_func()->control)
- return d_func()->control->isReadyForCapture();
- else
- return false;
-}
-
-/*!
- \fn QCameraImageCapture::readyForCaptureChanged(bool ready)
-
- Signals that a camera's \a ready for capture state has changed.
-*/
-
-
-/*!
- Capture the image and save it to \a file.
- This operation is asynchronous in majority of cases,
- followed by signals QCameraImageCapture::imageExposed(),
- QCameraImageCapture::imageCaptured(), QCameraImageCapture::imageSaved()
- or QCameraImageCapture::error().
-
- If an empty \a file is passed, the camera backend choses
- the default location and naming scheme for photos on the system,
- if only file name without full path is specified, the image will be saved to
- the default directory, with a full path reported with imageCaptured() and imageSaved() signals.
-
- QCamera saves 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.
-
- QCameraImageCapture::capture returns the capture Id parameter, used with
- imageExposed(), imageCaptured() and imageSaved() signals.
-
- \sa isReadyForCapture()
-*/
-int QCameraImageCapture::capture(const QString &file)
-{
- Q_D(QCameraImageCapture);
-
- d->unsetError();
-
- if (d->control) {
- return d->control->capture(file);
- } else {
- d->error = NotSupportedFeatureError;
- d->errorString = tr("Device does not support images capture.");
-
- emit error(-1, d->error, d->errorString);
- }
-
- return -1;
-}
-
-/*!
- Cancel incomplete capture requests.
- Already captured and queused for proicessing images may be discarded.
-*/
-void QCameraImageCapture::cancelCapture()
-{
- Q_D(QCameraImageCapture);
-
- d->unsetError();
-
- if (d->control) {
- d->control->cancelCapture();
- } else {
- d->error = NotSupportedFeatureError;
- d->errorString = tr("Device does not support images capture.");
-
- emit error(-1, d->error, d->errorString);
- }
-}
-
-
-/*!
- \enum QCameraImageCapture::Error
-
- \value NoError No Errors.
- \value NotReadyError The service is not ready for capture yet.
- \value ResourceError Device is not ready or not available.
- \value OutOfSpaceError No space left on device.
- \value NotSupportedFeatureError Device does not support stillimages capture.
- \value FormatError Current format is not supported.
-*/
-
-/*!
- \enum QCameraImageCapture::DriveMode
-
- \value SingleImageCapture Drive mode is capturing a single picture.
-*/
-
-/*!
- \fn QCameraImageCapture::error(int id, QCameraImageCapture::Error error, const QString &errorString)
-
- Signals that the capture request \a id has failed with an \a error
- and \a errorString description.
-*/
-
-/*!
- \fn QCameraImageCapture::bufferFormatChanged(QVideoFrame::PixelFormat format)
-
- Signal emitted when the buffer \a format for the buffer image capture has changed.
-*/
-
-/*!
- \fn QCameraImageCapture::captureDestinationChanged(CaptureDestinations destination)
-
- Signal emitted when the capture \a destination has changed.
-*/
-
-/*!
- \fn QCameraImageCapture::imageExposed(int id)
-
- Signal emitted when the frame with request \a id was exposed.
-*/
-
-/*!
- \fn QCameraImageCapture::imageCaptured(int id, const QImage &preview);
-
- Signal emitted when QAbstractVideoSurface is used as a viewfinder and
- the frame with request \a id was captured, but not processed and saved yet.
- Frame \a preview can be displayed to user.
-*/
-
-/*!
- \fn QCameraImageCapture::imageMetadataAvailable(int id, const QString &key, const QVariant &value)
-
- Signals that a metadata for an image with request \a id is available. Also
- includes the \a key and \a value of the metadata.
-
- This signal is emitted between imageExposed and imageSaved signals.
-*/
-
-/*!
- \fn QCameraImageCapture::imageAvailable(int id, const QVideoFrame &frame)
-
- Signal emitted when QCameraImageCapture::CaptureToBuffer is set and
- the \a frame with request \a id is available.
-*/
-
-/*!
- \fn QCameraImageCapture::imageSaved(int id, const QString &fileName)
-
- Signal emitted when QCameraImageCapture::CaptureToFile is set and
- the frame with request \a id was saved to \a fileName.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qcameraimagecapture.cpp"
diff --git a/src/multimedia/camera/qcameraimagecapture.h b/src/multimedia/camera/qcameraimagecapture.h
deleted file mode 100644
index 931fe3902..000000000
--- a/src/multimedia/camera/qcameraimagecapture.h
+++ /dev/null
@@ -1,161 +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 QCAMERAIMAGECAPTURE_H
-#define QCAMERAIMAGECAPTURE_H
-
-#include <QtMultimedia/qmediaobject.h>
-#include <QtMultimedia/qmediaencodersettings.h>
-#include <QtMultimedia/qmediabindableinterface.h>
-#include <QtMultimedia/qvideoframe.h>
-
-#include <QtMultimedia/qmediaenumdebug.h>
-
-QT_BEGIN_NAMESPACE
-
-class QSize;
-QT_END_NAMESPACE
-
-QT_BEGIN_NAMESPACE
-
-class QImageEncoderSettings;
-
-class QCameraImageCapturePrivate;
-class Q_MULTIMEDIA_EXPORT QCameraImageCapture : public QObject, public QMediaBindableInterface
-{
- Q_OBJECT
- Q_INTERFACES(QMediaBindableInterface)
- Q_ENUMS(Error)
- Q_ENUMS(CaptureDestination)
- Q_PROPERTY(bool readyForCapture READ isReadyForCapture NOTIFY readyForCaptureChanged)
-public:
- enum Error
- {
- NoError,
- NotReadyError,
- ResourceError,
- OutOfSpaceError,
- NotSupportedFeatureError,
- FormatError
- };
-
- enum DriveMode
- {
- SingleImageCapture
- };
-
- enum CaptureDestination
- {
- CaptureToFile = 0x01,
- CaptureToBuffer = 0x02
- };
- Q_DECLARE_FLAGS(CaptureDestinations, CaptureDestination)
-
- explicit QCameraImageCapture(QMediaObject *mediaObject, QObject *parent = nullptr);
- ~QCameraImageCapture();
-
- bool isAvailable() const;
- QMultimedia::AvailabilityStatus availability() const;
-
- QMediaObject *mediaObject() const override;
-
- Error error() const;
- QString errorString() const;
-
- bool isReadyForCapture() const;
-
- QStringList supportedImageCodecs() const;
- QString imageCodecDescription(const QString &codecName) const;
-
- QList<QSize> supportedResolutions(const QImageEncoderSettings &settings = QImageEncoderSettings(),
- bool *continuous = nullptr) const;
-
- QImageEncoderSettings encodingSettings() const;
- void setEncodingSettings(const QImageEncoderSettings& settings);
-
- QList<QVideoFrame::PixelFormat> supportedBufferFormats() const;
- QVideoFrame::PixelFormat bufferFormat() const;
- void setBufferFormat(const QVideoFrame::PixelFormat format);
-
- bool isCaptureDestinationSupported(CaptureDestinations destination) const;
- CaptureDestinations captureDestination() const;
- void setCaptureDestination(CaptureDestinations destination);
-
-public Q_SLOTS:
- int capture(const QString &location = QString());
- void cancelCapture();
-
-Q_SIGNALS:
- void error(int id, QCameraImageCapture::Error error, const QString &errorString);
-
- void readyForCaptureChanged(bool ready);
- void bufferFormatChanged(QVideoFrame::PixelFormat format);
- void captureDestinationChanged(QCameraImageCapture::CaptureDestinations destination);
-
- 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 &frame);
- void imageSaved(int id, const QString &fileName);
-
-protected:
- bool setMediaObject(QMediaObject *) override;
-
- QCameraImageCapturePrivate *d_ptr;
-private:
- Q_DISABLE_COPY(QCameraImageCapture)
- Q_DECLARE_PRIVATE(QCameraImageCapture)
- Q_PRIVATE_SLOT(d_func(), void _q_error(int, int, const QString &))
- Q_PRIVATE_SLOT(d_func(), void _q_readyChanged(bool))
- Q_PRIVATE_SLOT(d_func(), void _q_serviceDestroyed())
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QCameraImageCapture::CaptureDestinations)
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QCameraImageCapture::Error)
-Q_DECLARE_METATYPE(QCameraImageCapture::CaptureDestination)
-Q_DECLARE_METATYPE(QCameraImageCapture::CaptureDestinations)
-
-Q_MEDIA_ENUM_DEBUG(QCameraImageCapture, Error)
-Q_MEDIA_ENUM_DEBUG(QCameraImageCapture, CaptureDestination)
-
-#endif
-
diff --git a/src/multimedia/camera/qcameraimageprocessing.cpp b/src/multimedia/camera/qcameraimageprocessing.cpp
deleted file mode 100644
index af6c22391..000000000
--- a/src/multimedia/camera/qcameraimageprocessing.cpp
+++ /dev/null
@@ -1,401 +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 "qcameraimageprocessing.h"
-#include "qmediaobject_p.h"
-
-#include <qcameracontrol.h>
-#include <qcameraexposurecontrol.h>
-#include <qcamerafocuscontrol.h>
-#include <qmediarecordercontrol.h>
-#include <qcameraimageprocessingcontrol.h>
-#include <qcameraimagecapturecontrol.h>
-#include <qvideodeviceselectorcontrol.h>
-
-#include <QtCore/QDebug>
-
-QT_BEGIN_NAMESPACE
-
-static void qRegisterCameraImageProcessingMetaTypes()
- {
- qRegisterMetaType<QCameraImageProcessing::WhiteBalanceMode>();
- qRegisterMetaType<QCameraImageProcessing::ColorFilter>();
- }
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterCameraImageProcessingMetaTypes)
-
-
-/*!
- \class QCameraImageProcessing
-
- \brief The QCameraImageProcessing class provides an interface for
- image processing related camera settings.
-
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_camera
-
- After capturing the data for a camera frame, the camera hardware and
- software performs various image processing tasks to produce a final
- image. This includes compensating for ambient light color, reducing
- noise, as well as making some other adjustments to the image.
-
- You can retrieve this class from an instance of a \l QCamera object.
-
- For example, you can set the white balance (or color temperature) used
- for processing images:
-
- \snippet multimedia-snippets/camera.cpp Camera image whitebalance
-
- Or adjust the amount of denoising performed:
-
- \snippet multimedia-snippets/camera.cpp Camera image denoising
-
- In some cases changing these settings may result in a longer delay
- before an image is ready.
-
- For more information on image processing of camera frames, see \l {camera_image_processing}{Camera Image Processing}.
-
- \sa QCameraImageProcessingControl
-*/
-
-class QCameraImageProcessingFakeControl : public QCameraImageProcessingControl {
-public:
- QCameraImageProcessingFakeControl(QObject *parent) :
- QCameraImageProcessingControl(parent)
- {}
-
- bool isParameterSupported(ProcessingParameter) const override { return false; }
- bool isParameterValueSupported(ProcessingParameter, const QVariant &) const override { return false; }
- QVariant parameter(ProcessingParameter) const override { return QVariant(); }
- void setParameter(ProcessingParameter, const QVariant &) override {}
-};
-
-
-class QCameraImageProcessingPrivate : public QMediaObjectPrivate
-{
- Q_DECLARE_NON_CONST_PUBLIC(QCameraImageProcessing)
-public:
- void initControls();
-
- QCamera *camera;
- QCameraImageProcessingControl *imageControl;
- bool available;
-};
-
-
-void QCameraImageProcessingPrivate::initControls()
-{
- imageControl = 0;
-
- QMediaService *service = camera->service();
- if (service)
- imageControl = qobject_cast<QCameraImageProcessingControl *>(service->requestControl(QCameraImageProcessingControl_iid));
-
- available = (imageControl != nullptr);
-
- if (!imageControl)
- imageControl = new QCameraImageProcessingFakeControl(q_ptr);
-}
-
-/*!
- Construct a QCameraImageProcessing for \a camera.
-*/
-
-QCameraImageProcessing::QCameraImageProcessing(QCamera *camera)
- : QObject(*new QCameraImageProcessingPrivate, camera)
-{
- Q_D(QCameraImageProcessing);
- d->camera = camera;
- d->initControls();
-}
-
-
-/*!
- Destroys the camera focus object.
-*/
-
-QCameraImageProcessing::~QCameraImageProcessing()
-{
-}
-
-
-/*!
- Returns true if image processing related settings are supported by this camera.
-*/
-bool QCameraImageProcessing::isAvailable() const
-{
- return d_func()->available;
-}
-
-
-/*!
- Returns the white balance mode being used.
-*/
-
-QCameraImageProcessing::WhiteBalanceMode QCameraImageProcessing::whiteBalanceMode() const
-{
- return d_func()->imageControl->parameter(QCameraImageProcessingControl::WhiteBalancePreset)
- .value<QCameraImageProcessing::WhiteBalanceMode>();
-}
-
-/*!
- Sets the white balance to \a mode.
-*/
-
-void QCameraImageProcessing::setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode)
-{
- d_func()->imageControl->setParameter(
- QCameraImageProcessingControl::WhiteBalancePreset,
- QVariant::fromValue<QCameraImageProcessing::WhiteBalanceMode>(mode));
-}
-
-/*!
- Returns true if the white balance \a mode is supported.
-*/
-
-bool QCameraImageProcessing::isWhiteBalanceModeSupported(QCameraImageProcessing::WhiteBalanceMode mode) const
-{
- return d_func()->imageControl->isParameterValueSupported(
- QCameraImageProcessingControl::WhiteBalancePreset,
- QVariant::fromValue<QCameraImageProcessing::WhiteBalanceMode>(mode));
-
-}
-
-/*!
- Returns the current color temperature if the
- current white balance mode is \c WhiteBalanceManual. For other modes the
- return value is undefined.
-*/
-
-qreal QCameraImageProcessing::manualWhiteBalance() const
-{
- return d_func()->imageControl->parameter(QCameraImageProcessingControl::ColorTemperature).toReal();
-}
-
-/*!
- Sets manual white balance to \a colorTemperature. This is used
- when whiteBalanceMode() is set to \c WhiteBalanceManual. The units are Kelvin.
-*/
-
-void QCameraImageProcessing::setManualWhiteBalance(qreal colorTemperature)
-{
- d_func()->imageControl->setParameter(
- QCameraImageProcessingControl::ColorTemperature,
- QVariant(colorTemperature));
-}
-
-/*!
- Returns the brightness adjustment setting.
- */
-qreal QCameraImageProcessing::brightness() const
-{
- return d_func()->imageControl->parameter(QCameraImageProcessingControl::BrightnessAdjustment).toReal();
-}
-
-/*!
- Set the brightness adjustment to \a value.
-
- Valid brightness adjustment values range between -1.0 and 1.0, with a default of 0.
- */
-void QCameraImageProcessing::setBrightness(qreal value)
-{
- d_func()->imageControl->setParameter(QCameraImageProcessingControl::BrightnessAdjustment,
- QVariant(value));
-}
-
-/*!
- Returns the contrast adjustment setting.
-*/
-qreal QCameraImageProcessing::contrast() const
-{
- return d_func()->imageControl->parameter(QCameraImageProcessingControl::ContrastAdjustment).toReal();
-}
-
-/*!
- Set the contrast adjustment to \a value.
-
- Valid contrast adjustment values range between -1.0 and 1.0, with a default of 0.
-*/
-void QCameraImageProcessing::setContrast(qreal value)
-{
- d_func()->imageControl->setParameter(QCameraImageProcessingControl::ContrastAdjustment,
- QVariant(value));
-}
-
-/*!
- Returns the saturation adjustment value.
-*/
-qreal QCameraImageProcessing::saturation() const
-{
- return d_func()->imageControl->parameter(QCameraImageProcessingControl::SaturationAdjustment).toReal();
-}
-
-/*!
- Sets the saturation adjustment value to \a value.
-
- Valid saturation values range between -1.0 and 1.0, with a default of 0.
-*/
-
-void QCameraImageProcessing::setSaturation(qreal value)
-{
- d_func()->imageControl->setParameter(QCameraImageProcessingControl::SaturationAdjustment,
- QVariant(value));
-}
-
-/*!
- Returns the sharpening adjustment level.
-*/
-qreal QCameraImageProcessing::sharpeningLevel() const
-{
- return d_func()->imageControl->parameter(QCameraImageProcessingControl::SharpeningAdjustment).toReal();
-}
-
-/*!
- Sets the sharpening adjustment \a level.
-
- Valid sharpening values range between -1.0 and 1.0, with a default of 0.
-*/
-
-void QCameraImageProcessing::setSharpeningLevel(qreal level)
-{
- d_func()->imageControl->setParameter(QCameraImageProcessingControl::SharpeningAdjustment,
- QVariant(level));
-}
-
-/*!
- Returns the denoising adjustment level.
-*/
-qreal QCameraImageProcessing::denoisingLevel() const
-{
- return d_func()->imageControl->parameter(QCameraImageProcessingControl::DenoisingAdjustment).toReal();
-}
-
-/*!
- Sets the denoising adjustment \a level.
-
- Valid denoising values range between -1.0 and 1.0, with a default of 0.
-
- If the parameter value is set to 0, the amount of denoising applied
- is selected by camera and depends on camera capabilities and settings.
- Changing value in -1.0..1.0 range adjusts the amount of denoising applied
- within the supported range.
-*/
-void QCameraImageProcessing::setDenoisingLevel(qreal level)
-{
- d_func()->imageControl->setParameter(QCameraImageProcessingControl::DenoisingAdjustment,
- QVariant(level));
-}
-
-/*!
- \enum QCameraImageProcessing::WhiteBalanceMode
-
- \value WhiteBalanceAuto Auto white balance mode.
- \value WhiteBalanceManual Manual white balance. In this mode the white balance should be set with
- setManualWhiteBalance()
- \value WhiteBalanceSunlight Sunlight white balance mode.
- \value WhiteBalanceCloudy Cloudy white balance mode.
- \value WhiteBalanceShade Shade white balance mode.
- \value WhiteBalanceTungsten Tungsten (incandescent) white balance mode.
- \value WhiteBalanceFluorescent Fluorescent white balance mode.
- \value WhiteBalanceFlash Flash white balance mode.
- \value WhiteBalanceSunset Sunset white balance mode.
- \value WhiteBalanceVendor Base value for vendor defined white balance modes.
-*/
-
-/*!
- \enum QCameraImageProcessing::ColorFilter
-
- \value ColorFilterNone No filter is applied to images.
- \value ColorFilterGrayscale A grayscale filter.
- \value ColorFilterNegative A negative filter.
- \value ColorFilterSolarize A solarize filter.
- \value ColorFilterSepia A sepia filter.
- \value ColorFilterPosterize A posterize filter.
- \value ColorFilterWhiteboard A whiteboard filter.
- \value ColorFilterBlackboard A blackboard filter.
- \value ColorFilterAqua An aqua filter.
- \value ColorFilterVendor The base value for vendor defined filters.
-
- \since 5.5
-*/
-
-/*!
- Returns the color filter which will be applied to image data captured by the camera.
-
- \since 5.5
-*/
-
-QCameraImageProcessing::ColorFilter QCameraImageProcessing::colorFilter() const
-{
- return d_func()->imageControl->parameter(QCameraImageProcessingControl::ColorFilter)
- .value<QCameraImageProcessing::ColorFilter>();
-}
-
-
-/*!
- Sets the color \a filter which will be applied to image data captured by the camera.
-
- \since 5.5
-*/
-
-void QCameraImageProcessing::setColorFilter(QCameraImageProcessing::ColorFilter filter)
-{
- d_func()->imageControl->setParameter(
- QCameraImageProcessingControl::ColorFilter,
- QVariant::fromValue<QCameraImageProcessing::ColorFilter>(filter));
-}
-
-/*!
- Returns true if a color \a filter is supported.
-
- \since 5.5
-*/
-
-bool QCameraImageProcessing::isColorFilterSupported(QCameraImageProcessing::ColorFilter filter) const
-{
- return d_func()->imageControl->isParameterValueSupported(
- QCameraImageProcessingControl::ColorFilter,
- QVariant::fromValue<QCameraImageProcessing::ColorFilter>(filter));
-
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qcameraimageprocessing.cpp"
diff --git a/src/multimedia/camera/qcameraimageprocessing.h b/src/multimedia/camera/qcameraimageprocessing.h
deleted file mode 100644
index ddb94f70a..000000000
--- a/src/multimedia/camera/qcameraimageprocessing.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 QCAMERAIMAGEPROCESSING_H
-#define QCAMERAIMAGEPROCESSING_H
-
-#include <QtCore/qstringlist.h>
-#include <QtCore/qpair.h>
-#include <QtCore/qsize.h>
-#include <QtCore/qpoint.h>
-#include <QtCore/qrect.h>
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmediaobject.h>
-#include <QtMultimedia/qmediaservice.h>
-#include <QtMultimedia/qmediaenumdebug.h>
-
-QT_BEGIN_NAMESPACE
-
-
-class QCamera;
-
-class QCameraImageProcessingPrivate;
-class Q_MULTIMEDIA_EXPORT QCameraImageProcessing : public QObject
-{
- Q_OBJECT
- Q_ENUMS(WhiteBalanceMode ColorFilter)
-public:
- enum WhiteBalanceMode {
- WhiteBalanceAuto = 0,
- WhiteBalanceManual = 1,
- WhiteBalanceSunlight = 2,
- WhiteBalanceCloudy = 3,
- WhiteBalanceShade = 4,
- WhiteBalanceTungsten = 5,
- WhiteBalanceFluorescent = 6,
- WhiteBalanceFlash = 7,
- WhiteBalanceSunset = 8,
- WhiteBalanceVendor = 1000
- };
-
- enum ColorFilter {
- ColorFilterNone,
- ColorFilterGrayscale,
- ColorFilterNegative,
- ColorFilterSolarize,
- ColorFilterSepia,
- ColorFilterPosterize,
- ColorFilterWhiteboard,
- ColorFilterBlackboard,
- ColorFilterAqua,
- ColorFilterVendor = 1000
- };
-
- bool isAvailable() const;
-
- WhiteBalanceMode whiteBalanceMode() const;
- void setWhiteBalanceMode(WhiteBalanceMode mode);
- bool isWhiteBalanceModeSupported(WhiteBalanceMode mode) const;
-
- qreal manualWhiteBalance() const;
- void setManualWhiteBalance(qreal colorTemperature);
-
- qreal brightness() const;
- void setBrightness(qreal value);
-
- qreal contrast() const;
- void setContrast(qreal value);
-
- qreal saturation() const;
- void setSaturation(qreal value);
-
- qreal sharpeningLevel() const;
- void setSharpeningLevel(qreal value);
-
- qreal denoisingLevel() const;
- void setDenoisingLevel(qreal value);
-
- ColorFilter colorFilter() const;
- void setColorFilter(ColorFilter filter);
- bool isColorFilterSupported(ColorFilter filter) const;
-
-protected:
- ~QCameraImageProcessing();
-
-private:
- friend class QCamera;
- friend class QCameraPrivate;
- QCameraImageProcessing(QCamera *camera);
-
- Q_DISABLE_COPY(QCameraImageProcessing)
- Q_DECLARE_PRIVATE(QCameraImageProcessing)
-};
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QCameraImageProcessing::WhiteBalanceMode)
-Q_DECLARE_METATYPE(QCameraImageProcessing::ColorFilter)
-
-Q_MEDIA_ENUM_DEBUG(QCameraImageProcessing, WhiteBalanceMode)
-Q_MEDIA_ENUM_DEBUG(QCameraImageProcessing, ColorFilter)
-
-#endif // QCAMERAIMAGEPROCESSING_H
diff --git a/src/multimedia/camera/qcamerainfo.cpp b/src/multimedia/camera/qcamerainfo.cpp
deleted file mode 100644
index 1e7511851..000000000
--- a/src/multimedia/camera/qcamerainfo.cpp
+++ /dev/null
@@ -1,287 +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 "qcamerainfo.h"
-
-#include "qcamera_p.h"
-#include "qmediaserviceprovider_p.h"
-
-#include <qvideodeviceselectorcontrol.h>
-#include <qcamerainfocontrol.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QCameraInfo
- \brief The QCameraInfo class provides general information about camera devices.
- \since 5.3
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_camera
-
- QCameraInfo lets you query for camera devices that are currently available on the system.
-
- The static functions defaultCamera() and availableCameras() provide you a list of all
- available cameras.
-
- This example prints the name of all available cameras:
-
- \snippet multimedia-snippets/camera.cpp Camera listing
-
- A QCameraInfo can be used to construct a QCamera. The following example instantiates a QCamera
- whose camera device is named 'mycamera':
-
- \snippet multimedia-snippets/camera.cpp Camera selection
-
- You can also use QCameraInfo to get general information about a camera device such as
- description, physical position on the system, or camera sensor orientation.
-
- \snippet multimedia-snippets/camera.cpp Camera info
-
- \sa QCamera
-*/
-
-class QCameraInfoPrivate
-{
-public:
- QCameraInfoPrivate() : isNull(true), position(QCamera::UnspecifiedPosition), orientation(0)
- { }
-
- bool isNull;
- QString deviceName;
- QString description;
- QCamera::Position position;
- int orientation;
-};
-
-/*!
- Constructs a camera info object for \a camera.
-
- You can use it to query information about the \a camera object passed as argument.
-
- If the \a camera is invalid, for example when no camera device is available on the system,
- the QCameraInfo object will be invalid and isNull() will return true.
-*/
-QCameraInfo::QCameraInfo(const QCamera &camera)
- : d(new QCameraInfoPrivate)
-{
- const QVideoDeviceSelectorControl *deviceControl = camera.d_func()->deviceControl;
- if (deviceControl && deviceControl->deviceCount() > 0) {
- const int selectedDevice = deviceControl->selectedDevice();
- d->deviceName = deviceControl->deviceName(selectedDevice);
- d->description = deviceControl->deviceDescription(selectedDevice);
- d->isNull = false;
- }
-
- const QCameraInfoControl *infoControl = camera.d_func()->infoControl;
- if (infoControl) {
- d->position = infoControl->cameraPosition(d->deviceName);
- d->orientation = infoControl->cameraOrientation(d->deviceName);
- d->isNull = false;
- }
-}
-
-/*!
- Constructs a camera info object from a camera device \a name.
-
- If no such device exists, the QCameraInfo object will be invalid and isNull() will return true.
-*/
-QCameraInfo::QCameraInfo(const QByteArray &name)
- : d(new QCameraInfoPrivate)
-{
- if (!name.isNull()) {
- QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider();
- const QByteArray service(Q_MEDIASERVICE_CAMERA);
- if (provider->devices(service).contains(name)) {
- d->deviceName = QString::fromLatin1(name);
- d->description = provider->deviceDescription(service, name);
- d->position = provider->cameraPosition(name);
- d->orientation = provider->cameraOrientation(name);
- d->isNull = false;
- }
- }
-}
-
-/*!
- Constructs a copy of \a other.
-*/
-QCameraInfo::QCameraInfo(const QCameraInfo &other)
- : d(other.d)
-{
-}
-
-/*!
- Destroys the QCameraInfo.
-*/
-QCameraInfo::~QCameraInfo()
-{
-}
-
-/*!
- Returns true if this QCameraInfo is equal to \a other.
-*/
-bool QCameraInfo::operator==(const QCameraInfo &other) const
-{
- if (d == other.d)
- return true;
-
- return (d->deviceName == other.d->deviceName
- && d->description == other.d->description
- && d->position == other.d->position
- && d->orientation == other.d->orientation);
-}
-
-/*!
- Returns true if this QCameraInfo is null or invalid.
-*/
-bool QCameraInfo::isNull() const
-{
- return d->isNull;
-}
-
-/*!
- Returns the device name of the camera
-
- This is a unique ID to identify the camera and may not be human-readable.
-*/
-QString QCameraInfo::deviceName() const
-{
- return d->deviceName;
-}
-
-/*!
- Returns the human-readable description of the camera.
-*/
-QString QCameraInfo::description() const
-{
- return d->description;
-}
-
-/*!
- Returns the physical position of the camera on the hardware system.
-*/
-QCamera::Position QCameraInfo::position() const
-{
- return d->position;
-}
-
-/*!
- Returns the physical orientation of the camera sensor.
-
- The value is the orientation angle (clockwise, in steps of 90 degrees) of the camera sensor
- in relation to the display in its natural orientation.
-
- You can show the camera image in the correct orientation by rotating it by this value in the
- anti-clockwise direction.
-
- For example, suppose a mobile device which is naturally in portrait orientation. The back-facing
- camera is mounted in landscape. If the top side of the camera sensor is aligned with the
- right edge of the screen in natural orientation, the value should be 270. If the top side of a
- front-facing camera sensor is aligned with the right of the screen, the value should be 90.
-*/
-int QCameraInfo::orientation() const
-{
- return d->orientation;
-}
-
-/*!
- Returns the default camera on the system.
-
- The returned object should be checked using isNull() before being used, in case there is no
- default camera or no cameras at all.
-
- \sa availableCameras()
-*/
-QCameraInfo QCameraInfo::defaultCamera()
-{
- return QCameraInfo(QMediaServiceProvider::defaultServiceProvider()->defaultDevice(Q_MEDIASERVICE_CAMERA));
-}
-
-/*!
- Returns a list of available cameras on the system which are located at \a position.
-
- If \a position is not specified or if the value is QCamera::UnspecifiedPosition, a list of
- all available cameras will be returned.
-*/
-QList<QCameraInfo> QCameraInfo::availableCameras(QCamera::Position position)
-{
- QList<QCameraInfo> cameras;
-
- const QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider();
- const QByteArray service(Q_MEDIASERVICE_CAMERA);
- const QList<QByteArray> devices = provider->devices(service);
- for (int i = 0; i < devices.count(); ++i) {
- const QByteArray &name = devices.at(i);
- if (position == QCamera::UnspecifiedPosition
- || position == provider->cameraPosition(name)) {
- cameras.append(QCameraInfo(name));
- }
- }
-
- return cameras;
-}
-
-/*!
- Sets the QCameraInfo object to be equal to \a other.
-*/
-QCameraInfo& QCameraInfo::operator=(const QCameraInfo& other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- \fn QCameraInfo::operator!=(const QCameraInfo &other) const
-
- Returns true if this QCameraInfo is different from \a other.
-*/
-
-#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug d, const QCameraInfo &camera)
-{
- d.maybeSpace() << QStringLiteral("QCameraInfo(deviceName=%1, position=%2, orientation=%3)")
- .arg(camera.deviceName())
- .arg(QString::fromLatin1(QCamera::staticMetaObject.enumerator(QCamera::staticMetaObject.indexOfEnumerator("Position"))
- .valueToKey(camera.position())))
- .arg(camera.orientation());
- return d.space();
-}
-#endif
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/camera/qcamerainfo.h b/src/multimedia/camera/qcamerainfo.h
deleted file mode 100644
index 821ebb4a5..000000000
--- a/src/multimedia/camera/qcamerainfo.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 QCAMERAINFO_H
-#define QCAMERAINFO_H
-
-#include <QtMultimedia/qcamera.h>
-#include <QtCore/qsharedpointer.h>
-
-QT_BEGIN_NAMESPACE
-
-class QCameraInfoPrivate;
-
-class Q_MULTIMEDIA_EXPORT QCameraInfo
-{
-public:
- explicit QCameraInfo(const QByteArray &name = QByteArray());
- explicit QCameraInfo(const QCamera &camera);
- QCameraInfo(const QCameraInfo& other);
- ~QCameraInfo();
-
- QCameraInfo& operator=(const QCameraInfo& other);
- bool operator==(const QCameraInfo &other) const;
- inline bool operator!=(const QCameraInfo &other) const;
-
- bool isNull() const;
-
- QString deviceName() const;
- QString description() const;
- QCamera::Position position() const;
- int orientation() const;
-
- static QCameraInfo defaultCamera();
- static QList<QCameraInfo> availableCameras(QCamera::Position position = QCamera::UnspecifiedPosition);
-
-private:
- QSharedPointer<QCameraInfoPrivate> d;
-};
-
-bool QCameraInfo::operator!=(const QCameraInfo &other) const { return !operator==(other); }
-
-#ifndef QT_NO_DEBUG_STREAM
-Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, const QCameraInfo&);
-#endif
-
-QT_END_NAMESPACE
-
-#endif // QCAMERAINFO_H
diff --git a/src/multimedia/camera/qcameraviewfindersettings.cpp b/src/multimedia/camera/qcameraviewfindersettings.cpp
deleted file mode 100644
index 90b61bcf7..000000000
--- a/src/multimedia/camera/qcameraviewfindersettings.cpp
+++ /dev/null
@@ -1,331 +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 "qcameraviewfindersettings.h"
-
-QT_BEGIN_NAMESPACE
-
-static void qRegisterViewfinderSettingsMetaType()
-{
- qRegisterMetaType<QCameraViewfinderSettings>();
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterViewfinderSettingsMetaType)
-
-
-class QCameraViewfinderSettingsPrivate : public QSharedData
-{
-public:
- QCameraViewfinderSettingsPrivate() :
- isNull(true),
- minimumFrameRate(0.0),
- maximumFrameRate(0.0),
- pixelFormat(QVideoFrame::Format_Invalid)
- {
- }
-
- QCameraViewfinderSettingsPrivate(const QCameraViewfinderSettingsPrivate &other):
- QSharedData(other),
- isNull(other.isNull),
- resolution(other.resolution),
- minimumFrameRate(other.minimumFrameRate),
- maximumFrameRate(other.maximumFrameRate),
- pixelFormat(other.pixelFormat),
- pixelAspectRatio(other.pixelAspectRatio)
- {
- }
-
- bool isNull;
- QSize resolution;
- qreal minimumFrameRate;
- qreal maximumFrameRate;
- QVideoFrame::PixelFormat pixelFormat;
- QSize pixelAspectRatio;
-
-private:
- QCameraViewfinderSettingsPrivate& operator=(const QCameraViewfinderSettingsPrivate &other);
-};
-
-
-/*!
- \class QCameraViewfinderSettings
- \since 5.5
- \brief The QCameraViewfinderSettings class provides a set of viewfinder settings.
-
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_camera
-
- A viewfinder settings object is used to specify the viewfinder settings used by QCamera.
- Viewfinder settings are selected by constructing a QCameraViewfinderSettings object,
- setting the desired properties and then passing it to a QCamera instance using the
- QCamera::setViewfinderSettings() function.
-
- \snippet multimedia-snippets/camera.cpp Camera viewfinder settings
-
- Different cameras may have different capabilities. The application should query the camera
- capabilities before setting parameters. For example, the application should call
- QCamera::supportedViewfinderResolutions() before calling setResolution().
-
- \sa QCamera
-*/
-
-/*!
- Constructs a null viewfinder settings object.
-*/
-QCameraViewfinderSettings::QCameraViewfinderSettings()
- : d(new QCameraViewfinderSettingsPrivate)
-{
-}
-
-/*!
- Constructs a copy of the viewfinder settings object \a other.
-*/
-QCameraViewfinderSettings::QCameraViewfinderSettings(const QCameraViewfinderSettings &other)
- : d(other.d)
-{
-
-}
-
-/*!
- Destroys a viewfinder settings object.
-*/
-QCameraViewfinderSettings::~QCameraViewfinderSettings()
-{
-
-}
-
-/*!
- Assigns the value of \a other to a viewfinder settings object.
-*/
-QCameraViewfinderSettings &QCameraViewfinderSettings::operator=(const QCameraViewfinderSettings &other)
-{
- d = other.d;
- return *this;
-}
-
-/*! \fn QCameraViewfinderSettings &QCameraViewfinderSettings::operator=(QCameraViewfinderSettings &&other)
-
- Moves \a other to this viewfinder settings object and returns a reference to this object.
-*/
-
-/*!
- \fn void QCameraViewfinderSettings::swap(QCameraViewfinderSettings &other)
-
- Swaps this viewfinder settings object with \a other. This
- function is very fast and never fails.
-*/
-
-/*!
- \relates QCameraViewfinderSettings
- \since 5.5
-
- Determines if \a lhs is of equal value to \a rhs.
-
- Returns true if the settings objects are of equal value, and false if they
- are not of equal value.
-*/
-bool operator==(const QCameraViewfinderSettings &lhs, const QCameraViewfinderSettings &rhs) Q_DECL_NOTHROW
-{
- return (lhs.d == rhs.d) ||
- (lhs.d->isNull == rhs.d->isNull &&
- lhs.d->resolution == rhs.d->resolution &&
- lhs.d->minimumFrameRate == rhs.d->minimumFrameRate &&
- lhs.d->maximumFrameRate == rhs.d->maximumFrameRate &&
- lhs.d->pixelFormat == rhs.d->pixelFormat &&
- lhs.d->pixelAspectRatio == rhs.d->pixelAspectRatio);
-}
-
-/*!
- \fn bool operator!=(const QCameraViewfinderSettings &lhs, const QCameraViewfinderSettings &rhs)
- \relates QCameraViewfinderSettings
- \since 5.5
-
- Determines if \a lhs is of equal value to \a rhs.
-
- Returns true if the settings objects are not of equal value, and false if
- they are of equal value.
-*/
-
-/*!
- Identifies if a viewfinder settings object is uninitalized.
-
- Returns true if the settings are null, and false if they are not.
-*/
-bool QCameraViewfinderSettings::isNull() const
-{
- return d->isNull;
-}
-
-/*!
- Returns the viewfinder resolution.
-*/
-QSize QCameraViewfinderSettings::resolution() const
-{
- return d->resolution;
-}
-
-/*!
- Sets the viewfinder \a resolution.
-
- If the given \a resolution is empty, the backend makes an optimal choice based on the
- supported resolutions and the other viewfinder settings.
-
- If the camera is used to capture videos or images, the viewfinder resolution might be
- ignored if it conflicts with the capture resolution.
-
- \sa QVideoEncoderSettings::setResolution(), QImageEncoderSettings::setResolution(),
- QCamera::supportedViewfinderResolutions()
-*/
-void QCameraViewfinderSettings::setResolution(const QSize &resolution)
-{
- d->isNull = false;
- d->resolution = resolution;
-}
-
-/*!
- \fn QCameraViewfinderSettings::setResolution(int width, int height)
-
- This is an overloaded function.
-
- Sets the \a width and \a height of the viewfinder resolution.
-*/
-
-/*!
- Returns the viewfinder minimum frame rate in frames per second.
-
- \sa maximumFrameRate()
-*/
-qreal QCameraViewfinderSettings::minimumFrameRate() const
-{
- return d->minimumFrameRate;
-}
-
-/*!
- Sets the viewfinder minimum frame \a rate in frames per second.
-
- If the minimum frame \a rate is equal to the maximum frame rate, the frame rate is fixed.
- If not, the actual frame rate fluctuates between the minimum and the maximum.
-
- If the given \a rate equals to \c 0, the backend makes an optimal choice based on the
- supported frame rates and the other viewfinder settings.
-
- \sa setMaximumFrameRate(), QCamera::supportedViewfinderFrameRateRanges()
-*/
-void QCameraViewfinderSettings::setMinimumFrameRate(qreal rate)
-{
- d->isNull = false;
- d->minimumFrameRate = rate;
-}
-
-/*!
- Returns the viewfinder maximum frame rate in frames per second.
-
- \sa minimumFrameRate()
-*/
-qreal QCameraViewfinderSettings::maximumFrameRate() const
-{
- return d->maximumFrameRate;
-}
-
-/*!
- Sets the viewfinder maximum frame \a rate in frames per second.
-
- If the maximum frame \a rate is equal to the minimum frame rate, the frame rate is fixed.
- If not, the actual frame rate fluctuates between the minimum and the maximum.
-
- If the given \a rate equals to \c 0, the backend makes an optimal choice based on the
- supported frame rates and the other viewfinder settings.
-
- \sa setMinimumFrameRate(), QCamera::supportedViewfinderFrameRateRanges()
-*/
-void QCameraViewfinderSettings::setMaximumFrameRate(qreal rate)
-{
- d->isNull = false;
- d->maximumFrameRate = rate;
-}
-
-/*!
- Returns the viewfinder pixel format.
-*/
-QVideoFrame::PixelFormat QCameraViewfinderSettings::pixelFormat() const
-{
- return d->pixelFormat;
-}
-
-/*!
- Sets the viewfinder pixel \a format.
-
- If the given \a format is equal to QVideoFrame::Format_Invalid, the backend uses the
- default format.
-
- \sa QCamera::supportedViewfinderPixelFormats()
-*/
-void QCameraViewfinderSettings::setPixelFormat(QVideoFrame::PixelFormat format)
-{
- d->isNull = false;
- d->pixelFormat = format;
-}
-
-/*!
- Returns the viewfinder pixel aspect ratio.
-*/
-QSize QCameraViewfinderSettings::pixelAspectRatio() const
-{
- return d->pixelAspectRatio;
-}
-
-/*!
- Sets the viewfinder pixel aspect \a ratio.
-*/
-void QCameraViewfinderSettings::setPixelAspectRatio(const QSize &ratio)
-{
- d->isNull = false;
- d->pixelAspectRatio = ratio;
-}
-
-/*!
- \fn QCameraViewfinderSettings::setPixelAspectRatio(int horizontal, int vertical)
-
- This is an overloaded function.
-
- Sets the \a horizontal and \a vertical elements of the viewfinder's pixel aspect ratio.
-*/
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/camera/qcameraviewfindersettings.h b/src/multimedia/camera/qcameraviewfindersettings.h
deleted file mode 100644
index 432bdcf1f..000000000
--- a/src/multimedia/camera/qcameraviewfindersettings.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 Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** 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 QCAMERAVIEWFINDERSETTINGS_H
-#define QCAMERAVIEWFINDERSETTINGS_H
-
-#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qvideoframe.h>
-
-#include <QtCore/qshareddata.h>
-#include <QtCore/qsize.h>
-
-QT_BEGIN_NAMESPACE
-
-class QCameraViewfinderSettingsPrivate;
-
-class Q_MULTIMEDIA_EXPORT QCameraViewfinderSettings
-{
-public:
- QCameraViewfinderSettings();
- QCameraViewfinderSettings(const QCameraViewfinderSettings& other);
-
- ~QCameraViewfinderSettings();
-
- QCameraViewfinderSettings& operator=(const QCameraViewfinderSettings &other);
-#ifdef Q_COMPILER_RVALUE_REFS
- QCameraViewfinderSettings &operator=(QCameraViewfinderSettings &&other) Q_DECL_NOTHROW
- { swap(other); return *this; }
-#endif
-
- void swap(QCameraViewfinderSettings &other) Q_DECL_NOTHROW { d.swap(other.d); }
-
- friend Q_MULTIMEDIA_EXPORT bool operator==(const QCameraViewfinderSettings &lhs, const QCameraViewfinderSettings &rhs) Q_DECL_NOTHROW;
- bool isNull() const;
-
- QSize resolution() const;
- void setResolution(const QSize &);
- inline void setResolution(int width, int height)
- { setResolution(QSize(width, height)); }
-
- qreal minimumFrameRate() const;
- void setMinimumFrameRate(qreal rate);
-
- qreal maximumFrameRate() const;
- void setMaximumFrameRate(qreal rate);
-
- QVideoFrame::PixelFormat pixelFormat() const;
- void setPixelFormat(QVideoFrame::PixelFormat format);
-
- QSize pixelAspectRatio() const;
- void setPixelAspectRatio(const QSize &ratio);
- inline void setPixelAspectRatio(int horizontal, int vertical)
- { setPixelAspectRatio(QSize(horizontal, vertical)); }
-
-private:
- QSharedDataPointer<QCameraViewfinderSettingsPrivate> d;
-};
-Q_DECLARE_SHARED(QCameraViewfinderSettings)
-
-inline bool operator!=(const QCameraViewfinderSettings &lhs, const QCameraViewfinderSettings &rhs) Q_DECL_NOTHROW
-{ return !operator==(lhs, rhs); }
-
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QCameraViewfinderSettings)
-
-#endif // QCAMERAVIEWFINDERSETTINGS_H
diff --git a/src/multimedia/camera/qimagecapture.cpp b/src/multimedia/camera/qimagecapture.cpp
new file mode 100644
index 000000000..ecf39935c
--- /dev/null
+++ b/src/multimedia/camera/qimagecapture.cpp
@@ -0,0 +1,548 @@
+// 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>
+#include <private/qplatformmediacapture_p.h>
+#include <private/qplatformmediaintegration_p.h>
+#include <private/qplatformmediaformatinfo_p.h>
+#include <qmediacapturesession.h>
+
+#include "private/qobject_p.h"
+#include <qcamera.h>
+#include <private/qplatformcamera_p.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QImageCapture
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \ingroup multimedia_camera
+
+
+ \brief The QImageCapture class is used for the recording of media content.
+
+ The QImageCapture class is a high level images recording class.
+ It's not intended to be used alone but for accessing the media
+ recording functions of other media objects, like QCamera.
+
+ \snippet multimedia-snippets/camera.cpp Camera
+
+ \snippet multimedia-snippets/camera.cpp Camera keys
+
+ \sa QCamera
+*/
+
+class QImageCapturePrivate
+{
+ Q_DECLARE_PUBLIC(QImageCapture)
+public:
+ QCamera *camera = nullptr;
+
+ QMediaCaptureSession *captureSession = nullptr;
+ QPlatformImageCapture *control = nullptr;
+
+ QImageCapture::Error error = QImageCapture::NoError;
+ QString errorString;
+ QMediaMetaData metaData;
+
+ void _q_error(int id, int error, const QString &errorString);
+
+ void unsetError() { error = QImageCapture::NoError; errorString.clear(); }
+
+ QImageCapture *q_ptr;
+};
+
+void QImageCapturePrivate::_q_error(int id, int error, const QString &errorString)
+{
+ Q_Q(QImageCapture);
+
+ this->error = QImageCapture::Error(error);
+ this->errorString = errorString;
+
+ emit q->errorChanged();
+ emit q->errorOccurred(id, this->error, errorString);
+}
+
+/*!
+ Constructs a image capture object, from a \a parent, that can capture
+ individual still images produced by a camera.
+
+ You must connect both an image capture object and a QCamera to a capture
+ session to capture images.
+*/
+
+QImageCapture::QImageCapture(QObject *parent)
+ : QObject(parent), d_ptr(new QImageCapturePrivate)
+{
+ Q_D(QImageCapture);
+ d->q_ptr = this;
+
+ 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, &QPlatformImageCapture::imageExposed, this, &QImageCapture::imageExposed);
+ connect(d->control, &QPlatformImageCapture::imageCaptured, this, &QImageCapture::imageCaptured);
+ connect(d->control, &QPlatformImageCapture::imageMetadataAvailable, this,
+ &QImageCapture::imageMetadataAvailable);
+ connect(d->control, &QPlatformImageCapture::imageAvailable, this,
+ &QImageCapture::imageAvailable);
+ connect(d->control, &QPlatformImageCapture::imageSaved, this, &QImageCapture::imageSaved);
+ connect(d->control, &QPlatformImageCapture::readyForCaptureChanged, this,
+ &QImageCapture::readyForCaptureChanged);
+ connect(d->control, SIGNAL(error(int,int,QString)),
+ this, SLOT(_q_error(int,int,QString)));
+}
+
+/*!
+ \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->setImageCapture(nullptr);
+ delete d_ptr;
+}
+
+/*!
+ Returns true if the images capture service ready to use.
+*/
+bool QImageCapture::isAvailable() const
+{
+ return d_func()->control && d_func()->captureSession && d_func()->captureSession->camera();
+}
+
+/*!
+ Returns the capture session this camera is connected to, or
+ a nullptr if the camera is not connected to a capture session.
+
+ Use QMediaCaptureSession::setImageCapture() to connect the image capture to
+ a session.
+*/
+QMediaCaptureSession *QImageCapture::captureSession() const
+{
+ return d_ptr->captureSession;
+}
+
+/*!
+ \property QImageCapture::error
+
+ Returns the current error state.
+
+ \sa errorString()
+*/
+
+QImageCapture::Error QImageCapture::error() const
+{
+ return d_func()->error;
+}
+
+/*!
+ \property QImageCapture::errorString
+
+ Returns a string describing the current error state.
+
+ \sa error()
+*/
+
+QString QImageCapture::errorString() const
+{
+ return d_func()->errorString;
+}
+
+/*!
+ \property QImageCapture::metaData
+ \brief The meta data that will get embedded into the image.
+
+ \note Additional fields such as a time stamp or location may get added by
+ the camera back end.
+*/
+QMediaMetaData QImageCapture::metaData() const
+{
+ Q_D(const QImageCapture);
+ return d->metaData;
+}
+
+/*!
+ Replaces any existing meta data, to be embedded into the captured image,
+ with a set of \a metaData.
+*/
+void QImageCapture::setMetaData(const QMediaMetaData &metaData)
+{
+ Q_D(QImageCapture);
+ d->metaData = metaData;
+ if (d->control)
+ d->control->setMetaData(d->metaData);
+ emit metaDataChanged();
+}
+
+/*!
+ Adds additional \a metaData to any existing meta data, that is embedded
+ into the captured image.
+*/
+void QImageCapture::addMetaData(const QMediaMetaData &metaData)
+{
+ Q_D(QImageCapture);
+ auto data = d->metaData;
+ for (auto &&[key, value] : metaData.asKeyValueRange())
+ data.insert(key, value);
+ setMetaData(data);
+}
+
+/*!
+ \property QImageCapture::readyForCapture
+
+ Holds \c true if the camera is ready to capture an image immediately.
+ Calling capture() while \c readyForCapture is \c false is not
+ permitted and results in an error.
+*/
+bool QImageCapture::isReadyForCapture() const
+{
+ Q_D(const QImageCapture);
+ if (!d->control || !d->captureSession || !d->control->isReadyForCapture())
+ return false;
+ auto *camera = d->captureSession->camera();
+ if (!camera || !camera->isActive())
+ return false;
+ return true;
+}
+
+/*!
+ \fn QImageCapture::readyForCaptureChanged(bool ready)
+
+ Signals that a camera's \a ready for capture state has changed.
+*/
+
+
+/*!
+ Capture the image and save it to \a file.
+ This operation is asynchronous in majority of cases,
+ followed by signals QImageCapture::imageExposed(),
+ QImageCapture::imageCaptured(), QImageCapture::imageSaved()
+ or QImageCapture::error().
+
+ If an empty \a file is passed, the camera back end chooses
+ the default location and naming scheme for photos on the system,
+ if only file name without full path is specified, the image will be saved to
+ the default directory, with a full path reported with imageCaptured() and imageSaved() signals.
+
+ QCamera saves 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.
+
+ QImageCapture::capture returns the capture Id parameter, used with
+ imageExposed(), imageCaptured() and imageSaved() signals.
+
+ \sa isReadyForCapture()
+*/
+int QImageCapture::captureToFile(const QString &file)
+{
+ Q_D(QImageCapture);
+ if (!d->control) {
+ 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;
+ }
+
+ return d->control->capture(file);
+}
+
+/*!
+ Capture the image and make it available as a QImage.
+ This operation is asynchronous in majority of cases,
+ followed by signals QImageCapture::imageExposed(),
+ QImageCapture::imageCaptured()
+ or QImageCapture::error().
+
+ QImageCapture::capture returns the capture Id parameter, used with
+ imageExposed(), imageCaptured() and imageSaved() signals.
+
+ \sa isReadyForCapture()
+*/
+int QImageCapture::capture()
+{
+ Q_D(QImageCapture);
+ if (!d->control) {
+ d->_q_error(-1, d->error, d->errorString);
+ return -1;
+ } else {
+ d->unsetError();
+ return d->control->captureToBuffer();
+ }
+}
+
+/*!
+ \enum QImageCapture::Error
+
+ \value NoError No Errors.
+ \value NotReadyError The service is not ready for capture yet.
+ \value ResourceError Device is not ready or not available.
+ \value OutOfSpaceError No space left on device.
+ \value NotSupportedFeatureError Device does not support stillimages capture.
+ \value FormatError Current format is not supported.
+*/
+
+/*!
+ \fn QImageCapture::errorOccurred(int id, QImageCapture::Error error, const QString &errorString);
+
+ Signals that the capture request \a id has failed with an \a error
+ and \a errorString description.
+*/
+
+/*!
+ \fn QImageCapture::imageExposed(int id)
+
+ Signal emitted when the frame with request \a id was exposed.
+*/
+
+/*!
+ \fn QImageCapture::imageCaptured(int id, const QImage &preview);
+
+ Signal emitted when the frame with request \a id was captured, but not
+ processed and saved yet. Frame \a preview can be displayed to user.
+*/
+
+/*!
+ \fn QImageCapture::imageAvailable(int id, const QVideoFrame &frame)
+
+ Signal emitted when the \a frame with request \a id is available.
+*/
+
+/*!
+ \fn QImageCapture::imageSaved(int id, const QString &fileName)
+
+ Signal emitted when QImageCapture::CaptureToFile is set and
+ the frame with request \a id was saved to \a fileName.
+*/
+
+/*!
+ \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.
+*/
+
+QImageCapture::FileFormat QImageCapture::fileFormat() const
+{
+ Q_D(const QImageCapture);
+ return d->control ? d->control->imageSettings().format() : UnspecifiedFormat;
+}
+
+/*!
+ Sets the image \a format.
+*/
+void QImageCapture::setFileFormat(QImageCapture::FileFormat format)
+{
+ Q_D(QImageCapture);
+ if (!d->control)
+ return;
+ auto fmt = d->control->imageSettings();
+ if (fmt.format() == format)
+ return;
+ fmt.setFormat(format);
+ d->control->setImageSettings(fmt);
+ 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;
+ switch (f) {
+ case UnspecifiedFormat:
+ name = "Unspecified image format";
+ break;
+ case JPEG:
+ name = "JPEG";
+ break;
+ case PNG:
+ name = "PNG";
+ break;
+ case WebP:
+ name = "WebP";
+ break;
+ case Tiff:
+ name = "Tiff";
+ break;
+ }
+ return QString::fromUtf8(name);
+}
+
+/*!
+ Returns the description of the given file format, \a f.
+*/
+QString QImageCapture::fileFormatDescription(QImageCapture::FileFormat f)
+{
+ const char *name = nullptr;
+ switch (f) {
+ case UnspecifiedFormat:
+ name = "Unspecified image format";
+ break;
+ case JPEG:
+ name = "JPEG";
+ break;
+ case PNG:
+ name = "PNG";
+ break;
+ case WebP:
+ name = "WebP";
+ break;
+ case Tiff:
+ name = "Tiff";
+ break;
+ }
+ return QString::fromUtf8(name);
+}
+
+/*!
+ Returns the resolution of the encoded image.
+*/
+
+QSize QImageCapture::resolution() const
+{
+ Q_D(const QImageCapture);
+ 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
+ what is available from the image source and the limitations of the codec.
+*/
+void QImageCapture::setResolution(const QSize &resolution)
+{
+ Q_D(QImageCapture);
+ if (!d->control)
+ return;
+ auto fmt = d->control->imageSettings();
+ if (fmt.resolution() == resolution)
+ return;
+ fmt.setResolution(resolution);
+ d->control->setImageSettings(fmt);
+ emit resolutionChanged();
+}
+
+/*!
+ Sets the \a width and \a height of the resolution of the encoded image.
+
+ \overload
+*/
+void QImageCapture::setResolution(int width, int height)
+{
+ setResolution(QSize(width, height));
+}
+
+/*!
+ \enum QImageCapture::Quality
+
+ Enumerates quality encoding levels.
+
+ \value VeryLowQuality
+ \value LowQuality
+ \value NormalQuality
+ \value HighQuality
+ \value VeryHighQuality
+*/
+
+/*!
+ \property QImageCapture::quality
+ \brief The image encoding quality.
+*/
+QImageCapture::Quality QImageCapture::quality() const
+{
+ Q_D(const QImageCapture);
+ return d->control ? d->control->imageSettings().quality() : NormalQuality;
+}
+
+/*!
+ Sets the image encoding \a quality.
+*/
+void QImageCapture::setQuality(Quality quality)
+{
+ Q_D(QImageCapture);
+ if (!d->control)
+ return;
+ auto fmt = d->control->imageSettings();
+ if (fmt.quality() == quality)
+ return;
+ fmt.setQuality(quality);
+ d->control->setImageSettings(fmt);
+ 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
new file mode 100644
index 000000000..48608792a
--- /dev/null
+++ b/src/multimedia/camera/qimagecapture.h
@@ -0,0 +1,135 @@
+// 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
+
+#include <QtCore/qobject.h>
+#include <QtMultimedia/qvideoframe.h>
+
+#include <QtMultimedia/qmediaenumdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSize;
+class QMediaMetaData;
+QT_END_NAMESPACE
+
+QT_BEGIN_NAMESPACE
+
+class QImageEncoderSettings;
+class QCamera;
+class QMediaCaptureSession;
+
+class QImageCapturePrivate;
+class Q_MULTIMEDIA_EXPORT QImageCapture : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool readyForCapture READ isReadyForCapture NOTIFY readyForCaptureChanged)
+ Q_PROPERTY(QMediaMetaData metaData READ metaData WRITE setMetaData NOTIFY metaDataChanged)
+ Q_PROPERTY(Error error READ error NOTIFY errorChanged)
+ Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged)
+ Q_PROPERTY(FileFormat fileFormat READ fileFormat NOTIFY setFileFormat NOTIFY fileFormatChanged)
+ Q_PROPERTY(Quality quality READ quality NOTIFY setQuality NOTIFY qualityChanged)
+public:
+ enum Error
+ {
+ NoError,
+ NotReadyError,
+ ResourceError,
+ OutOfSpaceError,
+ NotSupportedFeatureError,
+ FormatError
+ };
+ Q_ENUM(Error)
+
+ enum Quality
+ {
+ VeryLowQuality,
+ LowQuality,
+ NormalQuality,
+ HighQuality,
+ VeryHighQuality
+ };
+ Q_ENUM(Quality)
+
+ enum FileFormat {
+ UnspecifiedFormat,
+ JPEG,
+ PNG,
+ WebP,
+ Tiff,
+ LastFileFormat = Tiff
+ };
+ Q_ENUM(FileFormat)
+
+ explicit QImageCapture(QObject *parent = nullptr);
+ ~QImageCapture();
+
+ bool isAvailable() const;
+
+ QMediaCaptureSession *captureSession() const;
+
+ Error error() const;
+ QString errorString() const;
+
+ bool isReadyForCapture() const;
+
+ FileFormat fileFormat() const;
+ void setFileFormat(FileFormat format);
+
+ static QList<FileFormat> supportedFormats();
+ static QString fileFormatName(FileFormat c);
+ static QString fileFormatDescription(FileFormat c);
+
+ QSize resolution() const;
+ void setResolution(const QSize &);
+ void setResolution(int width, int height);
+
+ Quality quality() const;
+ void setQuality(Quality quality);
+
+ QMediaMetaData metaData() const;
+ void setMetaData(const QMediaMetaData &metaData);
+ void addMetaData(const QMediaMetaData &metaData);
+
+public Q_SLOTS:
+ int captureToFile(const QString &location = QString());
+ int capture();
+
+Q_SIGNALS:
+ void errorChanged();
+ void errorOccurred(int id, QImageCapture::Error error, const QString &errorString);
+
+ void readyForCaptureChanged(bool ready);
+ void metaDataChanged();
+
+ void fileFormatChanged();
+ void qualityChanged();
+ void resolutionChanged();
+
+ void imageExposed(int id);
+ void imageCaptured(int id, const QImage &preview);
+ void imageMetadataAvailable(int id, const QMediaMetaData &metaData);
+ void imageAvailable(int id, const QVideoFrame &frame);
+ void imageSaved(int id, const QString &fileName);
+
+private:
+ // This is here to flag an incompatibilities with Qt 5
+ QImageCapture(QCamera *) = delete;
+
+ friend class QMediaCaptureSession;
+ class QPlatformImageCapture *platformImageCapture();
+ void setCaptureSession(QMediaCaptureSession *session);
+ QImageCapturePrivate *d_ptr;
+ Q_DISABLE_COPY(QImageCapture)
+ Q_DECLARE_PRIVATE(QImageCapture)
+ Q_PRIVATE_SLOT(d_func(), void _q_error(int, int, const QString &))
+};
+
+QT_END_NAMESPACE
+
+Q_MEDIA_ENUM_DEBUG(QImageCapture, Error)
+
+#endif
+
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
new file mode 100644
index 000000000..4bc66e038
--- /dev/null
+++ b/src/multimedia/configure.cmake
@@ -0,0 +1,203 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+
+
+#### Inputs
+
+
+
+#### Libraries
+
+qt_find_package(ALSA PROVIDED_TARGETS ALSA::ALSA MODULE_NAME multimedia QMAKE_LIB alsa)
+qt_find_package(AVFoundation PROVIDED_TARGETS AVFoundation::AVFoundation MODULE_NAME multimedia QMAKE_LIB avfoundation)
+qt_find_package(GStreamer PROVIDED_TARGETS GStreamer::GStreamer MODULE_NAME multimedia QMAKE_LIB gstreamer_1_0)
+qt_find_package(GStreamer COMPONENTS App PROVIDED_TARGETS GStreamer::App MODULE_NAME multimedia QMAKE_LIB gstreamer_app_1_0)
+qt_add_qmake_lib_dependency(gstreamer_app_1_0 gstreamer_1_0)
+qt_find_package(GStreamer OPTIONAL_COMPONENTS Photography PROVIDED_TARGETS GStreamer::Photography MODULE_NAME multimedia QMAKE_LIB gstreamer_photography_1_0) # special case
+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)
+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)
+if(TARGET EGL::EGL)
+ qt_internal_disable_find_package_global_promotion(EGL::EGL)
+endif()
+qt_find_package(EGL PROVIDED_TARGETS EGL::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
+
+
+qt_config_compile_test("evr"
+ LABEL "evr.h"
+ PROJECT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../config.tests/evr"
+)
+
+qt_config_compile_test("gpu_vivante"
+ LABEL "Vivante GPU"
+ PROJECT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../config.tests/gpu_vivante"
+)
+
+qt_config_compile_test("linux_v4l"
+ LABEL "Video for Linux"
+ PROJECT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../config.tests/linux_v4l"
+)
+
+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 (experimental)"
+ AUTODETECT false
+ CONDITION UNIX AND NOT QNX AND ALSA_FOUND AND NOT QT_FEATURE_pulseaudio
+)
+qt_feature("avfoundation" PUBLIC PRIVATE
+ LABEL "AVFoundation"
+ CONDITION AVFoundation_FOUND
+)
+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("gstreamer" PRIVATE
+ LABEL "QtMM GStreamer plugin"
+ CONDITION GStreamer_FOUND AND GStreamer_App_FOUND
+ ENABLE INPUT_gstreamer STREQUAL 'yes'
+ DISABLE INPUT_gstreamer STREQUAL 'no'
+)
+qt_feature("gstreamer_photography" PRIVATE
+ LABEL "GStreamer Photography"
+ CONDITION QT_FEATURE_gstreamer AND GStreamer_Photography_FOUND
+)
+qt_feature("gstreamer_gl" PRIVATE
+ LABEL "GStreamer OpenGL"
+ CONDITION QT_FEATURE_opengl AND QT_FEATURE_gstreamer AND GStreamer_Gl_FOUND AND EGL_FOUND
+)
+qt_feature("gpu_vivante" PRIVATE
+ LABEL "Vivante GPU"
+ CONDITION QT_FEATURE_gui AND QT_FEATURE_opengles2 AND TEST_gpu_vivante
+)
+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 MMRendererCore_FOUND
+ EMIT_IF QNX
+)
+qt_feature("pulseaudio" PUBLIC PRIVATE
+ LABEL "PulseAudio"
+ DISABLE INPUT_pulseaudio STREQUAL 'no'
+ CONDITION WrapPulseAudio_FOUND
+)
+qt_feature("wmsdk" PRIVATE
+ 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 "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/configure.json b/src/multimedia/configure.json
deleted file mode 100644
index d50f8c015..000000000
--- a/src/multimedia/configure.json
+++ /dev/null
@@ -1,300 +0,0 @@
-{
- "module": "multimedia",
- "depends": [
- "gui"
- ],
- "condition": "module.gui",
- "testDir": "../../config.tests",
-
- "commandline": {
- "options": {
- "alsa": "boolean",
- "evr": { "type": "boolean" },
- "directshow": { "type": "boolean" },
- "wmf": { "type": "boolean" },
- "gstreamer": { "type": "optionalString", "values": [ "no", "yes", "0.10", "1.0" ] },
- "pulseaudio": "boolean"
- }
- },
-
- "libraries": {
- "alsa": {
- "label": "ALSA",
- "test": "alsa",
- "sources": [
- "-lasound"
- ]
- },
- "avfoundation": {
- "label": "AVFoundation",
- "test": "avfoundation",
- "sources": [
- { "libs": "-framework AVFoundation -framework Foundation" }
- ]
- },
- "directshow": {
- "label": "DirectShow",
- "test": "directshow",
- "sources": [
- { "libs": "-lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32" }
- ]
- },
- "gstreamer_0_10": {
- "label": "GStreamer 0.10",
- "export": "gstreamer",
- "test": "gstreamer",
- "sources": [
- { "type": "pkgConfig",
- "args": "gstreamer-0.10 gstreamer-base-0.10 gstreamer-audio-0.10 gstreamer-video-0.10 gstreamer-pbutils-0.10 gstreamer-interfaces-0.10" }
- ]
- },
- "gstreamer_1_0": {
- "label": "GStreamer 1.0",
- "export": "gstreamer",
- "test": "gstreamer",
- "sources": [
- { "type": "pkgConfig",
- "args": "gstreamer-1.0 gstreamer-base-1.0 gstreamer-audio-1.0 gstreamer-video-1.0 gstreamer-pbutils-1.0 gstreamer-allocators-1.0" },
- { "libs": "-lgstreamer-1.0 -lgstbase-1.0 -lgstaudio-1.0 -lgstvideo-1.0 -lgstpbutils-1.0 -lglib-2.0 -lgobject-2.0",
- "condition": "config.win32 || config.macos" },
- { "libs": "", "condition": "config.android && input.gstreamer != ''" }
- ]
- },
- "gstreamer_app_0_10": {
- "label": "GStreamer App 0.10",
- "export": "gstreamer_app",
- "test": "gstreamer_appsrc",
- "use": "gstreamer_0_10",
- "sources": [
- { "type": "pkgConfig", "args": "gstreamer-app-0.10" }
- ]
- },
- "gstreamer_app_1_0": {
- "label": "GStreamer App 1.0",
- "export": "gstreamer_app",
- "test": "gstreamer_appsrc",
- "use": "gstreamer_1_0",
- "sources": [
- { "type": "pkgConfig", "args": "gstreamer-app-1.0" },
- { "libs": "-lgstapp-1.0", "condition": "config.win32 || config.macos" },
- { "libs": "", "condition": "config.android && input.gstreamer != ''" }
- ]
- },
- "gstreamer_photography_0_10": {
- "label": "GStreamer Photography 0.10",
- "export": "gstreamer_photography",
- "test": "gstreamer_photography",
- "use": "gstreamer_0_10",
- "sources": [
- { "libs": "-lgstphotography-0.10" }
- ]
- },
- "gstreamer_photography_1_0": {
- "label": "GStreamer Photography 1.0",
- "export": "gstreamer_photography",
- "test": "gstreamer_photography",
- "use": "gstreamer_1_0",
- "sources": [
- { "libs": "-lgstphotography-1.0" }
- ]
- },
- "gstreamer_gl_1_0": {
- "label": "GStreamer OpenGL 1.0",
- "export": "gstreamer_gl",
- "test": {
- "include": "gst/gl/gl.h"
- },
- "use": "gstreamer_1_0",
- "sources": [
- { "type": "pkgConfig", "args": "gstreamer-gl-1.0" }
- ]
- },
- "libresourceqt5": {
- "label": "libresourceqt5",
- "test": "resourcepolicy",
- "sources": [
- { "type": "pkgConfig", "args": "libresourceqt5" }
- ]
- },
- "mmrenderer": {
- "label": "MMRenderer",
- "test": "mmrenderer",
- "sources": [
- { "libs": "-lmmrndclient -lstrm" }
- ]
- },
- "pulseaudio": {
- "label": "PulseAudio >= 0.9.10",
- "test": "pulseaudio",
- "sources": [
- { "type": "pkgConfig", "args": "libpulse >= 0.9.10 libpulse-mainloop-glib" }
- ]
- },
- "wmf": {
- "label": "WMF",
- "test": "wmf",
- "sources": [
- { "libs": "-lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32 -lMf -lMfuuid -lMfplat -lPropsys" }
- ]
- }
- },
-
- "tests": {
- "evr": {
- "label": "evr.h",
- "type": "compile",
- "test": "evr"
- },
- "gstreamer_encodingprofiles": {
- "label": "GStreamer encoding-profile.h",
- "type": "compile",
- "use": "gstreamer",
- "test": "gstreamer_encodingprofiles"
- },
- "gpu_vivante": {
- "label": "Vivante GPU",
- "type": "compile",
- "test": "gpu_vivante"
- },
- "linux_v4l": {
- "label": "Video for Linux",
- "type": "compile",
- "test": "linux_v4l"
- },
- "wmsdk": {
- "label": "wmsdk.h",
- "type": "compile",
- "test": "wmsdk"
- },
- "wshellitem": {
- "label": "WShellItem",
- "type": "compile",
- "test": "wshellitem"
- }
- },
-
- "features": {
- "alsa": {
- "label": "ALSA",
- "condition": "config.unix && !config.qnx && libs.alsa",
- "output": [ "feature", "privateFeature" ]
- },
- "avfoundation": {
- "label": "AVFoundation",
- "emitIf": "config.darwin",
- "condition": "libs.avfoundation",
- "output": [ "feature", "privateFeature" ]
- },
- "directshow": {
- "label": "DirectShow",
- "condition": "config.win32 && libs.directshow",
- "output": [ "feature", "privateFeature" ]
- },
- "evr": {
- "label": "evr.h",
- "condition": "config.win32 && tests.evr",
- "output": [ "feature", "privateFeature" ]
- },
- "gstreamer_0_10": {
- "label": "GStreamer 0.10",
- "disable": "input.gstreamer == '1.0' || input.gstreamer == 'no'",
- "enable": "input.gstreamer == '0.10'",
- "condition": "!features.gstreamer_1_0 && libs.gstreamer_0_10",
- "output": [ "privateFeature" ]
- },
- "gstreamer_1_0": {
- "label": "GStreamer 1.0",
- "disable": "input.gstreamer == '0.10' || input.gstreamer == 'no'",
- "enable": "input.gstreamer == '1.0'",
- "condition": "libs.gstreamer_1_0",
- "output": [ "privateFeature" ]
- },
- "gstreamer": {
- "condition": "features.gstreamer_1_0 || features.gstreamer_0_10",
- "output": [ "privateFeature" ]
- },
- "gstreamer_app": {
- "label": "GStreamer App",
- "condition": "(features.gstreamer_1_0 && libs.gstreamer_app_1_0) || (features.gstreamer_0_10 && libs.gstreamer_app_0_10)",
- "output": [ "privateFeature" ]
- },
- "gstreamer_encodingprofiles": {
- "label": "GStreamer encoding-profile.h",
- "condition": "features.gstreamer && tests.gstreamer_encodingprofiles",
- "output": [ "privateFeature" ]
- },
- "gstreamer_photography": {
- "label": "GStreamer Photography",
- "condition": "(features.gstreamer_1_0 && libs.gstreamer_photography_1_0) || (features.gstreamer_0_10 && libs.gstreamer_photography_0_10)",
- "output": [ "privateFeature" ]
- },
- "gstreamer_gl": {
- "label": "GStreamer OpenGL",
- "condition": "features.opengl && features.gstreamer_1_0 && libs.gstreamer_gl_1_0",
- "output": [ "privateFeature" ]
- },
- "gpu_vivante": {
- "label": "Vivante GPU",
- "condition": "features.gui && features.opengles2 && tests.gpu_vivante",
- "output": [ "privateFeature" ]
- },
- "resourcepolicy": {
- "label": "Resource Policy (libresourceqt5)",
- "condition": "libs.libresourceqt5",
- "output": [ "privateFeature" ]
- },
- "linux_v4l": {
- "label": "Video for Linux",
- "condition": "config.unix && tests.linux_v4l",
- "output": [ "privateFeature" ]
- },
- "mmrenderer": {
- "label": "MMRenderer",
- "emitIf": "config.qnx",
- "condition": "libs.mmrenderer",
- "output": [ "feature", "privateFeature" ]
- },
- "pulseaudio": {
- "label": "PulseAudio",
- "autoDetect": "config.unix",
- "condition": "libs.pulseaudio",
- "output": [ "feature", "privateFeature" ]
- },
- "wmsdk": {
- "label": "wmsdk.h",
- "condition": "config.win32 && tests.wmsdk",
- "output": [ "privateFeature" ]
- },
- "wshellitem": {
- "label": "WShellItem",
- "condition": "config.win32 && features.directshow && tests.wshellitem",
- "output": [ "feature", "privateFeature" ]
- },
- "wmf": {
- "label": "Windows Media Foundation",
- "condition": "config.win32 && libs.wmf",
- "output": [ "privateFeature" ]
- }
- },
-
- "report": [
- ],
-
- "summary": [
- {
- "section": "Qt Multimedia",
- "entries": [
- "alsa",
- "gstreamer_1_0",
- "gstreamer_0_10",
- "linux_v4l",
- "pulseaudio",
- "resourcepolicy",
- "mmrenderer",
- "avfoundation",
- "directshow",
- "wmf"
- ]
- }
- ]
-}
diff --git a/src/multimedia/controls/controls.pri b/src/multimedia/controls/controls.pri
deleted file mode 100644
index c0eb28936..000000000
--- a/src/multimedia/controls/controls.pri
+++ /dev/null
@@ -1,80 +0,0 @@
-
-INCLUDEPATH += controls
-
-PUBLIC_HEADERS += \
- controls/qaudiodecodercontrol.h \
- controls/qaudioencodersettingscontrol.h \
- controls/qaudioinputselectorcontrol.h \
- controls/qaudiooutputselectorcontrol.h \
- controls/qcameracapturebufferformatcontrol.h \
- controls/qcameracapturedestinationcontrol.h \
- controls/qcameracontrol.h \
- controls/qcamerainfocontrol.h \
- controls/qcameraexposurecontrol.h \
- controls/qcamerafeedbackcontrol.h \
- controls/qcameraflashcontrol.h \
- controls/qcamerafocuscontrol.h \
- controls/qcamerazoomcontrol.h \
- controls/qcameraimagecapturecontrol.h \
- controls/qcameraimageprocessingcontrol.h \
- controls/qcameralockscontrol.h \
- controls/qcameraviewfindersettingscontrol.h \
- controls/qimageencodercontrol.h \
- controls/qmediacontainercontrol.h \
- controls/qmediagaplessplaybackcontrol.h \
- controls/qmediaplayercontrol.h \
- controls/qmediarecordercontrol.h \
- controls/qmediastreamscontrol.h \
- controls/qmetadatareadercontrol.h \
- controls/qmetadatawritercontrol.h \
- controls/qvideodeviceselectorcontrol.h \
- controls/qvideoencodersettingscontrol.h \
- controls/qvideorenderercontrol.h \
- controls/qvideowindowcontrol.h \
- controls/qmediaaudioprobecontrol.h \
- controls/qmediavideoprobecontrol.h \
- controls/qmediaavailabilitycontrol.h \
- controls/qaudiorolecontrol.h \
- controls/qcustomaudiorolecontrol.h
-
-PRIVATE_HEADERS += \
- controls/qmediaplaylistcontrol_p.h \
- controls/qmediaplaylistsourcecontrol_p.h
-
-SOURCES += \
- controls/qcameracapturebufferformatcontrol.cpp \
- controls/qcameracapturedestinationcontrol.cpp \
- controls/qcameracontrol.cpp \
- controls/qcamerainfocontrol.cpp \
- controls/qcameraexposurecontrol.cpp \
- controls/qcamerafeedbackcontrol.cpp \
- controls/qcameraflashcontrol.cpp \
- controls/qcamerafocuscontrol.cpp \
- controls/qcamerazoomcontrol.cpp \
- controls/qcameraimagecapturecontrol.cpp \
- controls/qcameraimageprocessingcontrol.cpp \
- controls/qcameralockscontrol.cpp \
- controls/qcameraviewfindersettingscontrol.cpp \
- controls/qimageencodercontrol.cpp \
- controls/qmediacontainercontrol.cpp \
- controls/qmediagaplessplaybackcontrol.cpp \
- controls/qmediaplayercontrol.cpp \
- controls/qmediaplaylistcontrol.cpp \
- controls/qmediaplaylistsourcecontrol.cpp \
- controls/qmediarecordercontrol.cpp \
- controls/qmediastreamscontrol.cpp \
- controls/qmetadatareadercontrol.cpp \
- controls/qmetadatawritercontrol.cpp \
- controls/qvideorenderercontrol.cpp \
- controls/qvideowindowcontrol.cpp \
- controls/qmediaaudioprobecontrol.cpp \
- controls/qmediavideoprobecontrol.cpp \
- controls/qmediaavailabilitycontrol.cpp \
- controls/qaudiodecodercontrol.cpp \
- controls/qvideoencodersettingscontrol.cpp \
- controls/qaudioencodersettingscontrol.cpp \
- controls/qaudioinputselectorcontrol.cpp \
- controls/qaudiooutputselectorcontrol.cpp \
- controls/qvideodeviceselectorcontrol.cpp \
- controls/qaudiorolecontrol.cpp \
- controls/qcustomaudiorolecontrol.cpp
diff --git a/src/multimedia/controls/qaudiodecodercontrol.cpp b/src/multimedia/controls/qaudiodecodercontrol.cpp
deleted file mode 100644
index 711303174..000000000
--- a/src/multimedia/controls/qaudiodecodercontrol.cpp
+++ /dev/null
@@ -1,267 +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 "qmediacontrol_p.h"
-#include "qaudiodecodercontrol.h"
-
-QT_BEGIN_NAMESPACE
-
-
-/*!
- \class QAudioDecoderControl
- \obsolete
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
- \brief The QAudioDecoderControl class provides access to the audio decoding
- functionality of a QMediaService.
-
- \preliminary
-
- The functionality provided by this control is exposed to application
- code through the QAudioDecoder class.
-
- The interface name of QAudioDecoderControl is \c org.qt-project.qt.audiodecodercontrol/5.0 as
- defined in QAudioDecoderControl_iid.
-
- \sa QMediaService::requestControl(), QAudioDecoder
-*/
-
-/*!
- \macro QAudioDecoderControl_iid
-
- \c org.qt-project.qt.audiodecodercontrol/5.0
-
- Defines the interface name of the QAudioDecoderControl class.
-
- \relates QAudioDecoderControl
-*/
-
-/*!
- Destroys an audio decoder control.
-*/
-QAudioDecoderControl::~QAudioDecoderControl()
-{
-}
-
-/*!
- Constructs a new audio decoder control with the given \a parent.
-*/
-QAudioDecoderControl::QAudioDecoderControl(QObject *parent):
- QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- \fn QAudioDecoderControl::state() const
-
- Returns the state of a player control.
-*/
-
-/*!
- \fn QAudioDecoderControl::stateChanged(QAudioDecoder::State newState)
-
- Signals that the state of a player control has changed to \a newState.
-
- \sa state()
-*/
-
-/*!
- \fn QAudioDecoderControl::sourceFilename() const
-
- Returns the current media source filename, or a null QString if none (or a device)
-*/
-
-/*!
- \fn QAudioDecoderControl::setSourceFilename(const QString &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 QAudioDecoderControl::sourceDevice() const
-
- Returns the current media source QIODevice, or 0 if none (or a file).
-*/
-
-/*!
- \fn QAudioDecoderControl::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 QAudioDecoderControl::start()
-
- Starts decoding the current media.
-
- If successful the player control will immediately enter the \l {QAudioDecoder::DecodingState}
- {decoding} state.
-
- \sa state(), read()
-*/
-
-/*!
- \fn QAudioDecoderControl::stop()
-
- Stops playback of the current media and discards any buffers.
-
- If successful the player control will immediately enter the \l {QAudioDecoder::StoppedState}
- {stopped} state.
-*/
-
-/*!
- \fn QAudioDecoderControl::error(int error, const QString &errorString)
-
- Signals that an \a error has occurred. The \a errorString provides a more detailed explanation.
-*/
-
-/*!
- \fn QAudioDecoderControl::bufferAvailableChanged(bool available)
-
- Signals that the bufferAvailable property has changed to \a available.
-*/
-
-/*!
- \fn QAudioDecoderControl::bufferReady()
-
- Signals that a new buffer is ready for reading.
-*/
-
-/*!
- \fn QAudioDecoderControl::bufferAvailable() const
-
- Returns true if a buffer is available to be read,
- and false otherwise.
-*/
-
-/*!
- \fn QAudioDecoderControl::sourceChanged()
-
- Signals that the current source of the decoder has changed.
-
- \sa sourceFilename(), sourceDevice()
-*/
-
-/*!
- \fn QAudioDecoderControl::formatChanged(const QAudioFormat &format)
-
- Signals that the current audio format of the decoder has changed to \a format.
-
- \sa audioFormat(), setAudioFormat()
-*/
-
-/*!
- \fn void QAudioDecoderControl::finished()
-
- Signals that the decoding has finished successfully.
- If decoding fails, error signal is emitted instead.
-
- \sa start(), stop(), error()
-*/
-
-/*!
- \fn void QAudioDecoderControl::positionChanged(qint64 position)
-
- Signals that the current \a position of the decoder has changed.
-
- \sa durationChanged()
-*/
-
-/*!
- \fn void QAudioDecoderControl::durationChanged(qint64 duration)
-
- Signals that the estimated \a duration of the decoded data has changed.
-
- \sa positionChanged()
-*/
-
-/*!
- \fn QAudioDecoderControl::audioFormat() const
- Returns the current audio format of the decoded stream.
-
- Any buffers returned should have this format.
-
- \sa setAudioFormat(), formatChanged()
-*/
-
-/*!
- \fn QAudioDecoderControl::setAudioFormat(const QAudioFormat &format)
- Set the desired audio format for decoded samples to \a format.
-
- If the decoder does not support this format, \l error() will
- be set to \c FormatError.
-
- If you do not specify a format, the format of the decoded
- audio itself will be used. Otherwise, some format conversion
- will be applied.
-
- If you wish to reset the decoded format to that of the original
- audio file, you can specify an invalid \a format.
-*/
-
-/*!
- \fn QAudioDecoderControl::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 QAudioDecoderControl::position() const
- Returns position (in milliseconds) of the last buffer read from
- the decoder or -1 if no buffers have been read.
-*/
-
-/*!
- \fn QAudioDecoderControl::duration() const
- Returns total duration (in milliseconds) of the audio stream
- or -1 if not available.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qaudiodecodercontrol.cpp"
diff --git a/src/multimedia/controls/qaudiodecodercontrol.h b/src/multimedia/controls/qaudiodecodercontrol.h
deleted file mode 100644
index 6ab27ba62..000000000
--- a/src/multimedia/controls/qaudiodecodercontrol.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 QAUDIODECODERCONTROL_H
-#define QAUDIODECODERCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qaudiodecoder.h>
-
-#include <QtCore/qpair.h>
-
-#include <QtMultimedia/qaudiobuffer.h>
-
-QT_BEGIN_NAMESPACE
-
-class QIODevice;
-class Q_MULTIMEDIA_EXPORT QAudioDecoderControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- ~QAudioDecoderControl();
-
- virtual QAudioDecoder::State state() const = 0;
-
- virtual QString sourceFilename() const = 0;
- virtual void setSourceFilename(const QString &fileName) = 0;
-
- virtual QIODevice* sourceDevice() const = 0;
- virtual void setSourceDevice(QIODevice *device) = 0;
-
- virtual void start() = 0;
- virtual void stop() = 0;
-
- virtual QAudioFormat audioFormat() const = 0;
- virtual void setAudioFormat(const QAudioFormat &format) = 0;
-
- virtual QAudioBuffer read() = 0;
- virtual bool bufferAvailable() const = 0;
-
- virtual qint64 position() const = 0;
- virtual qint64 duration() const = 0;
-
-Q_SIGNALS:
- void stateChanged(QAudioDecoder::State newState);
- void formatChanged(const QAudioFormat &format);
- void sourceChanged();
-
- void error(int error, const QString &errorString);
-
- void bufferReady();
- void bufferAvailableChanged(bool available);
- void finished();
-
- void positionChanged(qint64 position);
- void durationChanged(qint64 duration);
-
-protected:
- explicit QAudioDecoderControl(QObject *parent = nullptr);
-};
-
-#define QAudioDecoderControl_iid "org.qt-project.qt.audiodecodercontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QAudioDecoderControl, QAudioDecoderControl_iid)
-
-QT_END_NAMESPACE
-
-#endif // QAUDIODECODERCONTROL_H
diff --git a/src/multimedia/controls/qaudioencodersettingscontrol.cpp b/src/multimedia/controls/qaudioencodersettingscontrol.cpp
deleted file mode 100644
index 5ae473178..000000000
--- a/src/multimedia/controls/qaudioencodersettingscontrol.cpp
+++ /dev/null
@@ -1,140 +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 "qaudioencodersettingscontrol.h"
-#include <QtCore/qstringlist.h>
-
-QT_BEGIN_NAMESPACE
-
-
-/*!
- \class QAudioEncoderSettingsControl
- \obsolete
- \inmodule QtMultimedia
-
- \ingroup multimedia_control
-
- \brief The QAudioEncoderSettingsControl class provides access to the settings of a
- media service that performs audio encoding.
-
- If a QMediaService supports encoding audio data it will implement
- QAudioEncoderSettingsControl. This control provides information about the limits
- of restricted audio encoder options and allows the selection of a set of
- audio encoder settings as specified in a QAudioEncoderSettings object.
-
- The functionality provided by this control is exposed to application code through the
- QMediaRecorder class.
-
- The interface name of QAudioEncoderSettingsControl is \c org.qt-project.qt.audioencodersettingscontrol/5.0 as
- defined in QAudioEncoderSettingsControl_iid.
-
- \sa QMediaService::requestControl(), QMediaRecorder
-*/
-
-/*!
- \macro QAudioEncoderSettingsControl_iid
-
- \c org.qt-project.qt.audioencodersettingscontrol/5.0
-
- Defines the interface name of the QAudioEncoderSettingsControl class.
-
- \relates QAudioEncoderSettingsControl
-*/
-
-/*!
- Create a new audio encoder settings control object with the given \a parent.
-*/
-QAudioEncoderSettingsControl::QAudioEncoderSettingsControl(QObject *parent)
- :QMediaControl(parent)
-{
-}
-
-/*!
- Destroys the audio encoder settings control.
-*/
-QAudioEncoderSettingsControl::~QAudioEncoderSettingsControl()
-{
-}
-
-/*!
- \fn QAudioEncoderSettingsControl::supportedAudioCodecs() const
-
- Returns the list of supported audio codec names.
-*/
-
-/*!
- \fn QAudioEncoderSettingsControl::codecDescription(const QString &codecName) const
-
- Returns the description of audio codec \a codecName.
-*/
-
-/*!
- \fn QAudioEncoderSettingsControl::supportedSampleRates(const QAudioEncoderSettings &settings = QAudioEncoderSettings(),
- bool *continuous) const
-
- Returns the list of supported audio sample rates, if known.
-
- If non null audio \a settings parameter is passed,
- the returned list is reduced to sample rates supported with partial settings applied.
-
- It can be used for example to query the list of sample rates, supported by specific audio codec.
-
- If the encoder supports arbitrary sample rates within the supported rates range,
- *\a continuous is set to true, otherwise *\a continuous is set to false.
-*/
-
-/*!
- \fn QAudioEncoderSettingsControl::audioSettings() const
-
- Returns the audio encoder settings.
-
- The returned value may be different tha passed to QAudioEncoderSettingsControl::setAudioSettings()
- if the settings contains the default or undefined parameters.
- In this case if the undefined parameters are already resolved, they should be returned.
-*/
-
-/*!
- \fn QAudioEncoderSettingsControl::setAudioSettings(const QAudioEncoderSettings &settings)
-
- Sets the selected audio \a settings.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qaudioencodersettingscontrol.cpp"
diff --git a/src/multimedia/controls/qaudioencodersettingscontrol.h b/src/multimedia/controls/qaudioencodersettingscontrol.h
deleted file mode 100644
index b4c3abafd..000000000
--- a/src/multimedia/controls/qaudioencodersettingscontrol.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 QAUDIOENCODERSETTINGSCONTROL_H
-#define QAUDIOENCODERSETTINGSCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmediarecorder.h>
-#include <QtCore/qlist.h>
-#include <QtCore/qpair.h>
-
-QT_BEGIN_NAMESPACE
-
-class QAudioFormat;
-QT_END_NAMESPACE
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QAudioEncoderSettingsControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- virtual ~QAudioEncoderSettingsControl();
-
- virtual QStringList supportedAudioCodecs() const = 0;
- virtual QString codecDescription(const QString &codecName) const = 0;
-
- virtual QList<int> supportedSampleRates(const QAudioEncoderSettings &settings,
- bool *continuous = nullptr) const = 0;
-
- virtual QAudioEncoderSettings audioSettings() const = 0;
- virtual void setAudioSettings(const QAudioEncoderSettings &settings) = 0;
-
-protected:
- explicit QAudioEncoderSettingsControl(QObject *parent = nullptr);
-};
-
-#define QAudioEncoderSettingsControl_iid "org.qt-project.qt.audioencodersettingscontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QAudioEncoderSettingsControl, QAudioEncoderSettingsControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif // QAUDIOENCODERSETTINGSCONTROL_H
diff --git a/src/multimedia/controls/qaudioinputselectorcontrol.cpp b/src/multimedia/controls/qaudioinputselectorcontrol.cpp
deleted file mode 100644
index 649891225..000000000
--- a/src/multimedia/controls/qaudioinputselectorcontrol.cpp
+++ /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$
-**
-****************************************************************************/
-
-#include "qaudioinputselectorcontrol.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QAudioInputSelectorControl
- \obsolete
-
- \brief The QAudioInputSelectorControl class provides an audio input selector media control.
- \inmodule QtMultimedia
- \ingroup multimedia_control
-
- The QAudioInputSelectorControl class provides descriptions of the audio
- inputs available on a system and allows one to be selected as the audio
- input of a media service.
-
- The interface name of QAudioInputSelectorControl is \c org.qt-project.qt.audioinputselectorcontrol/5.0 as
- defined in QAudioInputSelectorControl_iid.
-
- \sa QMediaService::requestControl()
-*/
-
-/*!
- \macro QAudioInputSelectorControl_iid
-
- \c org.qt-project.qt.audioinputselectorcontrol/5.0
-
- Defines the interface name of the QAudioInputSelectorControl class.
-
- \relates QAudioInputSelectorControl
-*/
-
-/*!
- Constructs a new audio input selector control with the given \a parent.
-*/
-QAudioInputSelectorControl::QAudioInputSelectorControl(QObject *parent)
- :QMediaControl(parent)
-{
-}
-
-/*!
- Destroys an audio input selector control.
-*/
-QAudioInputSelectorControl::~QAudioInputSelectorControl()
-{
-}
-
-/*!
- \fn QList<QString> QAudioInputSelectorControl::availableInputs() const
-
- Returns a list of the names of the available audio inputs.
-*/
-
-/*!
- \fn QString QAudioInputSelectorControl::inputDescription(const QString& name) const
-
- Returns the description of the input \a name.
-*/
-
-/*!
- \fn QString QAudioInputSelectorControl::defaultInput() const
-
- Returns the name of the default audio input.
-*/
-
-/*!
- \fn QString QAudioInputSelectorControl::activeInput() const
-
- Returns the name of the currently selected audio input.
-*/
-
-/*!
- \fn QAudioInputSelectorControl::setActiveInput(const QString& name)
-
- Set the active audio input to \a name.
-*/
-
-/*!
- \fn QAudioInputSelectorControl::activeInputChanged(const QString& name)
-
- Signals that the audio input has changed to \a name.
-*/
-
-/*!
- \fn QAudioInputSelectorControl::availableInputsChanged()
-
- Signals that list of available inputs has changed.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qaudioinputselectorcontrol.cpp"
diff --git a/src/multimedia/controls/qaudioinputselectorcontrol.h b/src/multimedia/controls/qaudioinputselectorcontrol.h
deleted file mode 100644
index 9665b55de..000000000
--- a/src/multimedia/controls/qaudioinputselectorcontrol.h
+++ /dev/null
@@ -1,80 +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 QAUDIOINPUTSELECTORCONTROL_H
-#define QAUDIOINPUTSELECTORCONTROL_H
-
-#include <QtMultimedia/qaudio.h>
-#include <QtMultimedia/qmediacontrol.h>
-
-QT_BEGIN_NAMESPACE
-
-
-// Class forward declaration required for QDoc bug
-class QString;
-class Q_MULTIMEDIA_EXPORT QAudioInputSelectorControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- virtual ~QAudioInputSelectorControl();
-
- virtual QList<QString> availableInputs() const = 0;
- virtual QString inputDescription(const QString& name) const = 0;
- virtual QString defaultInput() const = 0;
- virtual QString activeInput() const = 0;
-
-public Q_SLOTS:
- virtual void setActiveInput(const QString& name) = 0;
-
-Q_SIGNALS:
- void activeInputChanged(const QString& name);
- void availableInputsChanged();
-
-protected:
- explicit QAudioInputSelectorControl(QObject *parent = nullptr);
-};
-
-#define QAudioInputSelectorControl_iid "org.qt-project.qt.audioinputselectorcontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QAudioInputSelectorControl, QAudioInputSelectorControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif // QAUDIOINPUTSELECTORCONTROL_H
diff --git a/src/multimedia/controls/qaudiooutputselectorcontrol.cpp b/src/multimedia/controls/qaudiooutputselectorcontrol.cpp
deleted file mode 100644
index 64886e4c9..000000000
--- a/src/multimedia/controls/qaudiooutputselectorcontrol.cpp
+++ /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$
-**
-****************************************************************************/
-
-#include "qaudiooutputselectorcontrol.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QAudioOutputSelectorControl
- \obsolete
-
- \brief The QAudioOutputSelectorControl class provides an audio output selector media control.
- \inmodule QtMultimedia
- \ingroup multimedia_control
-
- The QAudioOutputSelectorControl class provides descriptions of the audio
- outputs available on a system and allows one to be selected as the audio
- output of a media service.
-
- The interface name of QAudioOutputSelectorControl is \c org.qt-project.qt.audiooutputselectorcontrol/5.0 as
- defined in QAudioOutputSelectorControl_iid.
-
- \sa QMediaService::requestControl()
-*/
-
-/*!
- \macro QAudioOutputSelectorControl_iid
-
- \c org.qt-project.qt.audiooutputselectorcontrol/5.0
-
- Defines the interface name of the QAudioOutputSelectorControl class.
-
- \relates QAudioOutputSelectorControl
-*/
-
-/*!
- Constructs a new audio output selector control with the given \a parent.
-*/
-QAudioOutputSelectorControl::QAudioOutputSelectorControl(QObject *parent)
- :QMediaControl(parent)
-{
-}
-
-/*!
- Destroys an audio output selector control.
-*/
-QAudioOutputSelectorControl::~QAudioOutputSelectorControl()
-{
-}
-
-/*!
- \fn QList<QString> QAudioOutputSelectorControl::availableOutputs() const
-
- Returns a list of the names of the available audio outputs.
-*/
-
-/*!
- \fn QString QAudioOutputSelectorControl::outputDescription(const QString& name) const
-
- Returns the description of the output \a name.
-*/
-
-/*!
- \fn QString QAudioOutputSelectorControl::defaultOutput() const
-
- Returns the name of the default audio output.
-*/
-
-/*!
- \fn QString QAudioOutputSelectorControl::activeOutput() const
-
- Returns the name of the currently selected audio output.
-*/
-
-/*!
- \fn QAudioOutputSelectorControl::setActiveOutput(const QString& name)
-
- Set the active audio output to \a name.
-*/
-
-/*!
- \fn QAudioOutputSelectorControl::activeOutputChanged(const QString& name)
-
- Signals that the audio output has changed to \a name.
-*/
-
-/*!
- \fn QAudioOutputSelectorControl::availableOutputsChanged()
-
- Signals that list of available outputs has changed.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qaudiooutputselectorcontrol.cpp"
diff --git a/src/multimedia/controls/qaudiooutputselectorcontrol.h b/src/multimedia/controls/qaudiooutputselectorcontrol.h
deleted file mode 100644
index de44d0ebb..000000000
--- a/src/multimedia/controls/qaudiooutputselectorcontrol.h
+++ /dev/null
@@ -1,80 +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 QAUDIOOUTPUTSELECTORCONTROL_H
-#define QAUDIOOUTPUTSELECTORCONTROL_H
-
-#include <QtMultimedia/qaudio.h>
-#include <QtMultimedia/qmediacontrol.h>
-
-QT_BEGIN_NAMESPACE
-
-
-// Class forward declaration required for QDoc bug
-class QString;
-class Q_MULTIMEDIA_EXPORT QAudioOutputSelectorControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- virtual ~QAudioOutputSelectorControl();
-
- virtual QList<QString> availableOutputs() const = 0;
- virtual QString outputDescription(const QString& name) const = 0;
- virtual QString defaultOutput() const = 0;
- virtual QString activeOutput() const = 0;
-
-public Q_SLOTS:
- virtual void setActiveOutput(const QString& name) = 0;
-
-Q_SIGNALS:
- void activeOutputChanged(const QString& name);
- void availableOutputsChanged();
-
-protected:
- explicit QAudioOutputSelectorControl(QObject *parent = nullptr);
-};
-
-#define QAudioOutputSelectorControl_iid "org.qt-project.qt.audiooutputselectorcontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QAudioOutputSelectorControl, QAudioOutputSelectorControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif // QAUDIOOUTPUTSELECTORCONTROL_H
diff --git a/src/multimedia/controls/qaudiorolecontrol.cpp b/src/multimedia/controls/qaudiorolecontrol.cpp
deleted file mode 100644
index 01e60a914..000000000
--- a/src/multimedia/controls/qaudiorolecontrol.cpp
+++ /dev/null
@@ -1,118 +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 "qmediacontrol_p.h"
-#include "qaudiorolecontrol.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QAudioRoleControl
- \obsolete
- \inmodule QtMultimedia
- \ingroup multimedia_control
- \since 5.6
-
- \brief The QAudioRoleControl class provides control over the audio role of a media object.
-
- If a QMediaService supports audio roles it will implement QAudioRoleControl.
-
- The functionality provided by this control is exposed to application code through the
- QMediaPlayer class.
-
- The interface name of QAudioRoleControl is \c org.qt-project.qt.audiorolecontrol/5.6 as
- defined in QAudioRoleControl_iid.
-
- \sa QMediaService::requestControl(), QMediaPlayer
-*/
-
-/*!
- \macro QAudioRoleControl_iid
-
- \c org.qt-project.qt.audiorolecontrol/5.6
-
- Defines the interface name of the QAudioRoleControl class.
-
- \relates QAudioRoleControl
-*/
-
-/*!
- Construct a QAudioRoleControl with the given \a parent.
-*/
-QAudioRoleControl::QAudioRoleControl(QObject *parent)
- : QMediaControl(*new QMediaControlPrivate, parent)
-{
-
-}
-
-/*!
- Destroys the audio role control.
-*/
-QAudioRoleControl::~QAudioRoleControl()
-{
-
-}
-
-/*!
- \fn QAudio::Role QAudioRoleControl::audioRole() const
-
- Returns the audio role of the media played by the media service.
-*/
-
-/*!
- \fn void QAudioRoleControl::setAudioRole(QAudio::Role role)
-
- Sets the audio \a role of the media played by the media service.
-*/
-
-/*!
- \fn QList<QAudio::Role> QAudioRoleControl::supportedAudioRoles() const
-
- Returns a list of audio roles that the media service supports.
-*/
-
-/*!
- \fn void QAudioRoleControl::audioRoleChanged(QAudio::Role role)
-
- Signal emitted when the audio \a role has changed.
- */
-
-QT_END_NAMESPACE
-
-#include "moc_qaudiorolecontrol.cpp"
diff --git a/src/multimedia/controls/qaudiorolecontrol.h b/src/multimedia/controls/qaudiorolecontrol.h
deleted file mode 100644
index c59874fdf..000000000
--- a/src/multimedia/controls/qaudiorolecontrol.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 QAUDIOROLECONTROL_H
-#define QAUDIOROLECONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qaudio.h>
-
-QT_BEGIN_NAMESPACE
-
-// Class forward declaration required for QDoc bug
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QAudioRoleControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- virtual ~QAudioRoleControl();
-
- virtual QAudio::Role audioRole() const = 0;
- virtual void setAudioRole(QAudio::Role role) = 0;
-
- virtual QList<QAudio::Role> supportedAudioRoles() const = 0;
-
-Q_SIGNALS:
- void audioRoleChanged(QAudio::Role role);
-
-protected:
- explicit QAudioRoleControl(QObject *parent = nullptr);
-};
-
-#define QAudioRoleControl_iid "org.qt-project.qt.audiorolecontrol/5.6"
-Q_MEDIA_DECLARE_CONTROL(QAudioRoleControl, QAudioRoleControl_iid)
-
-QT_END_NAMESPACE
-
-#endif // QAUDIOROLECONTROL_H
diff --git a/src/multimedia/controls/qcameracapturebufferformatcontrol.cpp b/src/multimedia/controls/qcameracapturebufferformatcontrol.cpp
deleted file mode 100644
index 8f0c3e6e9..000000000
--- a/src/multimedia/controls/qcameracapturebufferformatcontrol.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 <qcameracapturebufferformatcontrol.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QCameraCaptureBufferFormatControl
- \obsolete
-
- \brief The QCameraCaptureBufferFormatControl class provides a control for setting the capture buffer format.
-
- The format is of type QVideoFrame::PixelFormat.
-
- \inmodule QtMultimedia
-
- \ingroup multimedia_control
-
- The interface name of QCameraCaptureBufferFormatControl is \c org.qt-project.qt.cameracapturebufferformatcontrol/5.0 as
- defined in QCameraCaptureBufferFormatControl_iid.
-
- \sa QMediaService::requestControl()
-*/
-
-/*!
- \macro QCameraCaptureBufferFormatControl_iid
-
- \c org.qt-project.qt.cameracapturebufferformatcontrol/5.0
-
- Defines the interface name of the QCameraCaptureBufferFormatControl class.
-
- \relates QCameraCaptureBufferFormatControl
-*/
-
-/*!
- Constructs a new image buffer capture format control object with the given \a parent
-*/
-QCameraCaptureBufferFormatControl::QCameraCaptureBufferFormatControl(QObject *parent)
- :QMediaControl(parent)
-{
-}
-
-/*!
- Destroys an image buffer capture format control.
-*/
-QCameraCaptureBufferFormatControl::~QCameraCaptureBufferFormatControl()
-{
-}
-
-/*!
- \fn QCameraCaptureBufferFormatControl::supportedBufferFormats() const
-
- Returns the list of the supported buffer capture formats.
-*/
-
-/*!
- \fn QCameraCaptureBufferFormatControl::bufferFormat() const
-
- Returns the current buffer capture format.
-*/
-
-/*!
- \fn QCameraCaptureBufferFormatControl::setBufferFormat(QVideoFrame::PixelFormat format)
-
- Sets the buffer capture \a format.
-*/
-
-/*!
- \fn QCameraCaptureBufferFormatControl::bufferFormatChanged(QVideoFrame::PixelFormat format)
-
- Signals the buffer image capture format changed to \a format.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qcameracapturebufferformatcontrol.cpp"
diff --git a/src/multimedia/controls/qcameracapturebufferformatcontrol.h b/src/multimedia/controls/qcameracapturebufferformatcontrol.h
deleted file mode 100644
index 1c8f44243..000000000
--- a/src/multimedia/controls/qcameracapturebufferformatcontrol.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 QCAMERACAPTUREBUFFERFORMATCONTROL_H
-#define QCAMERACAPTUREBUFFERFORMATCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qcameraimagecapture.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QCameraCaptureBufferFormatControl : public QMediaControl
-{
- Q_OBJECT
-public:
- ~QCameraCaptureBufferFormatControl();
-
- virtual QList<QVideoFrame::PixelFormat> supportedBufferFormats() const = 0;
- virtual QVideoFrame::PixelFormat bufferFormat() const = 0;
- virtual void setBufferFormat(QVideoFrame::PixelFormat format) = 0;
-
-Q_SIGNALS:
- void bufferFormatChanged(QVideoFrame::PixelFormat format);
-
-protected:
- explicit QCameraCaptureBufferFormatControl(QObject *parent = nullptr);
-};
-
-#define QCameraCaptureBufferFormatControl_iid "org.qt-project.qt.cameracapturebufferformatcontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QCameraCaptureBufferFormatControl, QCameraCaptureBufferFormatControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif
-
diff --git a/src/multimedia/controls/qcameracapturedestinationcontrol.cpp b/src/multimedia/controls/qcameracapturedestinationcontrol.cpp
deleted file mode 100644
index a9a54a3b8..000000000
--- a/src/multimedia/controls/qcameracapturedestinationcontrol.cpp
+++ /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$
-**
-****************************************************************************/
-
-#include <qcameracapturedestinationcontrol.h>
-#include <QtCore/qstringlist.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QCameraCaptureDestinationControl
- \obsolete
-
- \brief The QCameraCaptureDestinationControl class provides a control for setting capture destination.
-
- Depending on backend capabilities capture to file, buffer or both can be supported.
-
- \inmodule QtMultimedia
-
- \ingroup multimedia_control
-
- The interface name of QCameraCaptureDestinationControl is \c org.qt-project.qt.cameracapturedestinationcontrol/5.0 as
- defined in QCameraCaptureDestinationControl_iid.
-
-
- \sa QMediaService::requestControl()
-*/
-
-/*!
- \macro QCameraCaptureDestinationControl_iid
-
- \c org.qt-project.qt.cameracapturedestinationcontrol/5.0
-
- Defines the interface name of the QCameraCaptureDestinationControl class.
-
- \relates QCameraCaptureDestinationControl
-*/
-
-/*!
- Constructs a new image capture destination control object with the given \a parent
-*/
-QCameraCaptureDestinationControl::QCameraCaptureDestinationControl(QObject *parent)
- :QMediaControl(parent)
-{
-}
-
-/*!
- Destroys an image capture destination control.
-*/
-QCameraCaptureDestinationControl::~QCameraCaptureDestinationControl()
-{
-}
-
-/*!
- \fn QCameraCaptureDestinationControl::isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const
-
- Returns true if the capture \a destination is supported; and false if it is not.
-*/
-
-/*!
- \fn QCameraCaptureDestinationControl::captureDestination() const
-
- Returns the current capture destination. The default destination is QCameraImageCapture::CaptureToFile.
-*/
-
-/*!
- \fn QCameraCaptureDestinationControl::setCaptureDestination(QCameraImageCapture::CaptureDestinations destination)
-
- Sets the capture \a destination.
-*/
-
-/*!
- \fn QCameraCaptureDestinationControl::captureDestinationChanged(QCameraImageCapture::CaptureDestinations destination)
-
- Signals the image capture \a destination changed.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qcameracapturedestinationcontrol.cpp"
diff --git a/src/multimedia/controls/qcameracapturedestinationcontrol.h b/src/multimedia/controls/qcameracapturedestinationcontrol.h
deleted file mode 100644
index 395f8c511..000000000
--- a/src/multimedia/controls/qcameracapturedestinationcontrol.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 QCAMERACAPTUREDESTINATIONCONTROL_H
-#define QCAMERACAPTUREDESTINATIONCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qcameraimagecapture.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QCameraCaptureDestinationControl : public QMediaControl
-{
- Q_OBJECT
-public:
- ~QCameraCaptureDestinationControl();
-
- virtual bool isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const = 0;
- virtual QCameraImageCapture::CaptureDestinations captureDestination() const = 0;
- virtual void setCaptureDestination(QCameraImageCapture::CaptureDestinations destination) = 0;
-
-Q_SIGNALS:
- void captureDestinationChanged(QCameraImageCapture::CaptureDestinations destination);
-
-protected:
- explicit QCameraCaptureDestinationControl(QObject *parent = nullptr);
-};
-
-#define QCameraCaptureDestinationControl_iid "org.qt-project.qt.cameracapturedestinationcontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QCameraCaptureDestinationControl, QCameraCaptureDestinationControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif
-
diff --git a/src/multimedia/controls/qcameracontrol.cpp b/src/multimedia/controls/qcameracontrol.cpp
deleted file mode 100644
index d33fa94c9..000000000
--- a/src/multimedia/controls/qcameracontrol.cpp
+++ /dev/null
@@ -1,205 +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 <qcameracontrol.h>
-#include "qmediacontrol_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QCameraControl
- \obsolete
-
-
-
- \brief The QCameraControl class is an abstract base class for
- classes that control still cameras or video cameras.
-
- \inmodule QtMultimedia
-
- \ingroup multimedia_control
-
- This service is provided by a QMediaService object via
- QMediaService::control(). It is used by QCamera.
-
- The interface name of QCameraControl is \c org.qt-project.qt.cameracontrol/5.0 as
- defined in QCameraControl_iid.
-
-
-
- \sa QMediaService::requestControl(), QCamera
-*/
-
-/*!
- \macro QCameraControl_iid
-
- \c org.qt-project.qt.cameracontrol/5.0
-
- Defines the interface name of the QCameraControl class.
-
- \relates QCameraControl
-*/
-
-/*!
- Constructs a camera control object with \a parent.
-*/
-
-QCameraControl::QCameraControl(QObject *parent):
- QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- Destruct the camera control object.
-*/
-
-QCameraControl::~QCameraControl()
-{
-}
-
-/*!
- \fn QCameraControl::state() const
-
- Returns the state of the camera service.
-
- \sa QCamera::state
-*/
-
-/*!
- \fn QCameraControl::setState(QCamera::State state)
-
- Sets the camera \a state.
-
- State changes are synchronous and indicate user intention,
- while camera status is used as a feedback mechanism to inform application about backend status.
- Status changes are reported asynchronously with QCameraControl::statusChanged() signal.
-
- \sa QCamera::State
-*/
-
-/*!
- \fn void QCameraControl::stateChanged(QCamera::State state)
-
- Signal emitted when the camera \a state changes.
-
- In most cases the state chage is caused by QCameraControl::setState(),
- but if critical error has occurred the state changes to QCamera::UnloadedState.
-*/
-
-/*!
- \fn QCameraControl::status() const
-
- Returns the status of the camera service.
-
- \sa QCamera::state
-*/
-
-/*!
- \fn void QCameraControl::statusChanged(QCamera::Status status)
-
- Signal emitted when the camera \a status changes.
-*/
-
-
-/*!
- \fn void QCameraControl::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.
-*/
-
-/*!
- \fn Camera::CaptureModes QCameraControl::captureMode() const = 0
-
- Returns the current capture mode.
-*/
-
-/*!
- \fn void QCameraControl::setCaptureMode(QCamera::CaptureModes mode) = 0;
-
- Sets the current capture \a mode.
-
- The capture mode changes are synchronous and allowed in any camera state.
-
- If the capture mode is changed while camera is active,
- it's recommended to change status to QCamera::LoadedStatus
- and start activating the camera in the next event loop
- with the status changed to QCamera::StartingStatus.
- This allows the capture settings to be applied before camera is started.
- Than change the status to QCamera::StartedStatus when the capture mode change is done.
-*/
-
-/*!
- \fn bool QCameraControl::isCaptureModeSupported(QCamera::CaptureModes mode) const = 0;
-
- Returns true if the capture \a mode is suported.
-*/
-
-/*!
- \fn QCameraControl::captureModeChanged(QCamera::CaptureModes mode)
-
- Signal emitted when the camera capture \a mode changes.
- */
-
-/*!
- \fn bool QCameraControl::canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const
-
- Returns true if backend can effectively apply changing camera properties of \a changeType type
- while the camera state is QCamera::Active and camera status matches \a status parameter.
-
- If backend doesn't support applying this change in the active state, it will be stopped
- before the settings are changed and restarted after.
- Otherwise the backend should apply the change in the current state,
- with the camera status indicating the progress, if necessary.
-*/
-
-/*!
- \enum QCameraControl::PropertyChangeType
-
- \value CaptureMode Indicates the capture mode is changed.
- \value ImageEncodingSettings Image encoder settings are changed, including resolution.
- \value VideoEncodingSettings
- Video encoder settings are changed, including audio, video and container settings.
- \value Viewfinder Viewfinder is changed.
- \value ViewfinderSettings Viewfinder settings are changed.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qcameracontrol.cpp"
diff --git a/src/multimedia/controls/qcameracontrol.h b/src/multimedia/controls/qcameracontrol.h
deleted file mode 100644
index 6c5163118..000000000
--- a/src/multimedia/controls/qcameracontrol.h
+++ /dev/null
@@ -1,96 +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 QCAMERACONTROL_H
-#define QCAMERACONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmediaobject.h>
-
-#include <QtMultimedia/qcamera.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QCameraControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- enum PropertyChangeType {
- CaptureMode = 1,
- ImageEncodingSettings = 2,
- VideoEncodingSettings = 3,
- Viewfinder = 4,
- ViewfinderSettings = 5
- };
-
- ~QCameraControl();
-
- virtual QCamera::State state() const = 0;
- virtual void setState(QCamera::State state) = 0;
-
- virtual QCamera::Status status() const = 0;
-
- virtual QCamera::CaptureModes captureMode() const = 0;
- virtual void setCaptureMode(QCamera::CaptureModes) = 0;
- virtual bool isCaptureModeSupported(QCamera::CaptureModes mode) const = 0;
-
- virtual bool canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const = 0;
-
-Q_SIGNALS:
- void stateChanged(QCamera::State);
- void statusChanged(QCamera::Status);
- void error(int error, const QString &errorString);
- void captureModeChanged(QCamera::CaptureModes mode);
-
-protected:
- explicit QCameraControl(QObject *parent = nullptr);
-};
-
-#define QCameraControl_iid "org.qt-project.qt.cameracontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QCameraControl, QCameraControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif // QCAMERACONTROL_H
-
diff --git a/src/multimedia/controls/qcameraexposurecontrol.cpp b/src/multimedia/controls/qcameraexposurecontrol.cpp
deleted file mode 100644
index 2095c9cfa..000000000
--- a/src/multimedia/controls/qcameraexposurecontrol.cpp
+++ /dev/null
@@ -1,207 +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 <qcameraexposurecontrol.h>
-#include "qmediacontrol_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QCameraExposureControl
- \obsolete
-
- \brief The QCameraExposureControl class allows controlling camera exposure parameters.
-
- \inmodule QtMultimedia
-
- \ingroup multimedia_control
-
- The QCameraExposure class is the usual method of adjusting exposure related parameters
- when using camera functionality. This class provides a more complete but less easy
- to use interface, and also forms the interface to implement when writing a new
- implementation of QCamera functionality.
-
- You can adjust a number of parameters that will affect images and video taken with
- the corresponding QCamera object - see the \l {QCameraExposureControl::ExposureParameter}{ExposureParameter} enumeration.
-
- The interface name of QCameraExposureControl is \c org.qt-project.qt.cameraexposurecontrol/5.0 as
- defined in QCameraExposureControl_iid.
-
- \sa QCameraExposure, QCamera
-*/
-
-/*!
- \macro QCameraExposureControl_iid
-
- \c org.qt-project.qt.cameraexposurecontrol/5.0
-
- Defines the interface name of the QCameraExposureControl class.
-
- \relates QCameraExposureControl
-*/
-
-/*!
- Constructs a camera exposure control object with \a parent.
-*/
-QCameraExposureControl::QCameraExposureControl(QObject *parent):
- QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- Destroys the camera exposure control object.
-*/
-QCameraExposureControl::~QCameraExposureControl()
-{
-}
-
-/*!
- \enum QCameraExposureControl::ExposureParameter
- \value ISO
- Camera ISO sensitivity, specified as integer value.
- \value Aperture
- Lens aperture is specified as an qreal F number.
- The supported apertures list can change depending on the focal length,
- in such a case the exposureParameterRangeChanged() signal is emitted.
- \value ShutterSpeed
- Shutter speed in seconds, specified as qreal.
- \value ExposureCompensation
- Exposure compensation, specified as qreal EV value.
- \value FlashPower
- Manual flash power, specified as qreal value.
- Accepted power range is [0..1.0],
- with 0 value means no flash and 1.0 corresponds to full flash power.
-
- This value is only used in the \l{QCameraExposure::FlashManual}{manual flash mode}.
- \value TorchPower
- Manual torch power, specified as qreal value.
- Accepted power range is [0..1.0],
- with 0 value means no light and 1.0 corresponds to full torch power.
-
- This value is only used in the \l{QCameraExposure::FlashTorch}{torch flash mode}.
- \value FlashCompensation
- Flash compensation, specified as qreal EV value.
- \value SpotMeteringPoint
- The relative frame coordinate of the point to use for exposure metering
- in spot metering mode, specified as a QPointF.
- \value ExposureMode
- Camera exposure mode.
- \value MeteringMode
- Camera metering mode.
- \value ExtendedExposureParameter
- The base value for platform specific extended parameters.
- For such parameters the sequential values starting from ExtendedExposureParameter should be used.
-*/
-
-/*!
- \fn QCameraExposureControl::isParameterSupported(ExposureParameter parameter) const
-
- Returns true is exposure \a parameter is supported by backend.
- \since 5.0
-*/
-
-/*!
- \fn QCameraExposureControl::requestedValue(ExposureParameter parameter) const
-
- Returns the requested exposure \a parameter value.
-
- \since 5.0
-*/
-
-/*!
- \fn QCameraExposureControl::actualValue(ExposureParameter parameter) const
-
- Returns the actual exposure \a parameter value, or invalid QVariant() if the value is unknown or not supported.
-
- The actual parameter value may differ for the requested one if automatic mode is selected or
- camera supports only limited set of values within the supported range.
- \since 5.0
-*/
-
-
-/*!
- \fn QCameraExposureControl::supportedParameterRange(ExposureParameter parameter, bool *continuous = 0) const
-
- Returns the list of supported \a parameter values;
-
- If the camera supports arbitrary exposure parameter value within the supported range,
- *\a continuous is set to true, otherwise *\a continuous is set to false.
-
- \since 5.0
-*/
-
-/*!
- \fn bool QCameraExposureControl::setValue(ExposureParameter parameter, const QVariant& value)
-
- Set the exposure \a parameter to \a value.
- If a null or invalid QVariant is passed, backend should choose the value automatically,
- and if possible report the actual value to user with QCameraExposureControl::actualValue().
-
- Returns true if parameter is supported and value is correct.
- \since 5.0
-*/
-
-/*!
- \fn void QCameraExposureControl::requestedValueChanged(int parameter)
-
- Signal emitted when the requested exposure \a parameter value has changed,
- usually in result of setValue() call.
- \since 5.0
-*/
-
-/*!
- \fn void QCameraExposureControl::actualValueChanged(int parameter)
-
- Signal emitted when the actual exposure \a parameter value has changed,
- usually in result of auto exposure algorithms or manual exposure parameter applied.
-
- \since 5.0
-*/
-
-/*!
- \fn void QCameraExposureControl::parameterRangeChanged(int parameter)
-
- Signal emitted when the supported range of exposure \a parameter values has changed.
-
- \since 5.0
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qcameraexposurecontrol.cpp"
diff --git a/src/multimedia/controls/qcameraexposurecontrol.h b/src/multimedia/controls/qcameraexposurecontrol.h
deleted file mode 100644
index 7694380e5..000000000
--- a/src/multimedia/controls/qcameraexposurecontrol.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 Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** 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 QCAMERAEXPOSURECONTROL_H
-#define QCAMERAEXPOSURECONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmediaobject.h>
-
-#include <QtMultimedia/qcameraexposure.h>
-#include <QtMultimedia/qcamera.h>
-#include <QtMultimedia/qmediaenumdebug.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QCameraExposureControl : public QMediaControl
-{
- Q_OBJECT
- Q_ENUMS(ExposureParameter)
-
-public:
- ~QCameraExposureControl();
-
- enum ExposureParameter {
- ISO,
- Aperture,
- ShutterSpeed,
- ExposureCompensation,
- FlashPower,
- FlashCompensation,
- TorchPower,
- SpotMeteringPoint,
- ExposureMode,
- MeteringMode,
- ExtendedExposureParameter = 1000
- };
-
- virtual bool isParameterSupported(ExposureParameter parameter) const = 0;
- virtual QVariantList supportedParameterRange(ExposureParameter parameter, bool *continuous) const = 0;
-
- virtual QVariant requestedValue(ExposureParameter parameter) const = 0;
- virtual QVariant actualValue(ExposureParameter parameter) const = 0;
- virtual bool setValue(ExposureParameter parameter, const QVariant& value) = 0;
-
-Q_SIGNALS:
- void requestedValueChanged(int parameter);
- void actualValueChanged(int parameter);
- void parameterRangeChanged(int parameter);
-
-protected:
- explicit QCameraExposureControl(QObject *parent = nullptr);
-};
-
-#define QCameraExposureControl_iid "org.qt-project.qt.cameraexposurecontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QCameraExposureControl, QCameraExposureControl_iid)
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QCameraExposureControl::ExposureParameter)
-
-Q_MEDIA_ENUM_DEBUG(QCameraExposureControl, ExposureParameter)
-
-
-#endif // QCAMERAEXPOSURECONTROL_H
-
diff --git a/src/multimedia/controls/qcamerafeedbackcontrol.cpp b/src/multimedia/controls/qcamerafeedbackcontrol.cpp
deleted file mode 100644
index 42cd7d661..000000000
--- a/src/multimedia/controls/qcamerafeedbackcontrol.cpp
+++ /dev/null
@@ -1,182 +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 "qcamerafeedbackcontrol.h"
-#include <private/qmediacontrol_p.h>
-
-/*!
- \class QCameraFeedbackControl
- \obsolete
-
- \brief The QCameraFeedbackControl class allows controlling feedback (sounds etc) during camera operation.
-
- \inmodule QtMultimedia
-
- \ingroup multimedia_control
- \since 5.0
-
- When using a camera, there are several times when some form of feedback to
- the user is given - for example, when an image is taken, or when recording is started.
- You can enable or disable some of this feedback, or adjust what sound might be played
- for these actions.
-
- In some cases it may be undesirable to play a sound effect - for example, when initiating
- video recording the sound itself may be recorded.
-
- \note In some countries or regions, feedback sounds or other indications (e.g. a red light) are
- mandatory during camera operation. In these cases, you can check \c isEventFeedbackLocked to check
- if that type of feedback can be modified. Any attempts to change a locked feedback type will be
- ignored.
-
- The interface name of QCameraFeedbackControl is \c org.qt-project.qt.camerafeedbackcontrol/5.0 as
- defined in QCameraFeedbackControl_iid.
-
- \sa QCamera
-*/
-
-/*!
- \enum QCameraFeedbackControl::EventType
-
- This enumeration describes certain events that occur during camera usage. You
- can associate some form of feedback to be given when the event occurs, or check
- whether feedback for this event is enabled or locked so that changes cannot be made.
-
-
-
- \value ViewfinderStarted The viewfinder stream was started (even if not visible)
- \value ViewfinderStopped The viewfinder stream was stopped
- \value ImageCaptured An image was captured but not yet fully processed
- \value ImageSaved An image is fully available and saved somewhere.
- \value ImageError An error occurred while capturing an image
- \value RecordingStarted Video recording has started
- \value RecordingInProgress Video recording is in progress
- \value RecordingStopped Video recording has stopped
- \value AutoFocusInProgress The camera is trying to automatically focus
- \value AutoFocusLocked The camera has automatically focused successfully
- \value AutoFocusFailed The camera was unable to focus automatically
-*/
-
-/*!
- \macro QCameraFeedbackControl_iid
-
- \c org.qt-project.qt.camerafeedbackcontrol/5.0
-
- Defines the interface name of the QCameraFeedbackControl class.
-
- \relates QCameraFeedbackControl
-*/
-
-/*!
- Constructs a camera feedback control object with \a parent.
-*/
-QCameraFeedbackControl::QCameraFeedbackControl(QObject *parent):
- QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- Destroys the camera feedback control object.
-*/
-QCameraFeedbackControl::~QCameraFeedbackControl()
-{
-}
-
-/*!
- \fn bool QCameraFeedbackControl::isEventFeedbackLocked(EventType event) const
-
- Returns true if the feedback setting for \a event is locked. This may be true
- because of legal compliance issues, or because configurability of this event's
- feedback is not supported.
-
- \since 5.0
-*/
-
-/*!
- \fn bool QCameraFeedbackControl::isEventFeedbackEnabled(EventType event) const
-
- Returns true if the feedback for \a event is enabled.
-
- \since 5.0
-*/
-
-/*!
- \fn bool QCameraFeedbackControl::setEventFeedbackEnabled(EventType event, bool enabled)
-
- Turns on feedback for the specific \a event if \a enabled is true, otherwise disables the
- feedback. Returns true if the feedback could be modified, or false otherwise (e.g. this feedback
- type is locked).
-
- \since 5.0
-*/
-
-
-/*!
- \fn void QCameraFeedbackControl::resetEventFeedback(EventType event)
-
- Restores the feedback setting for this \a event to its default setting.
-
- \since 5.0
-*/
-
-/*!
- \fn bool QCameraFeedbackControl::setEventFeedbackSound(EventType event, const QString &filePath)
-
- When the given \a event occurs, the sound effect referenced by \a filePath
- will be played instead of the default sound.
-
- If this feedback type is locked, or if the supplied path is inaccessible,
- this function will return false. In addition, some forms of feedback may
- be non-auditory (e.g. a red light, or a vibration), and false may be
- returned in this case.
-
- The file referenced should be linear PCM (WAV format).
-
- \note In the case that a valid file path to an unsupported file is given, this
- function will return true but the feedback will use the original setting.
-
- \since 5.0
-*/
-
-
-
-
-
-
diff --git a/src/multimedia/controls/qcamerafeedbackcontrol.h b/src/multimedia/controls/qcamerafeedbackcontrol.h
deleted file mode 100644
index 195ad3915..000000000
--- a/src/multimedia/controls/qcamerafeedbackcontrol.h
+++ /dev/null
@@ -1,96 +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 QCAMERAFEEDBACKCONTROL_H
-#define QCAMERAFEEDBACKCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmediaobject.h>
-
-#include <QtMultimedia/qcamera.h>
-#include <QtMultimedia/qmediaenumdebug.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QCameraFeedbackControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- enum EventType {
- ViewfinderStarted = 1,
- ViewfinderStopped,
- ImageCaptured,
- ImageSaved,
- ImageError,
- RecordingStarted,
- RecordingInProgress,
- RecordingStopped,
- AutoFocusInProgress,
- AutoFocusLocked,
- AutoFocusFailed
- };
-
- ~QCameraFeedbackControl();
-
- virtual bool isEventFeedbackLocked(EventType) const = 0;
-
- virtual bool isEventFeedbackEnabled(EventType) const = 0;
-
- virtual bool setEventFeedbackEnabled(EventType, bool) = 0;
- virtual void resetEventFeedback(EventType) = 0;
-
- virtual bool setEventFeedbackSound(EventType, const QString &filePath) = 0;
-
-protected:
- explicit QCameraFeedbackControl(QObject *parent = nullptr);
-};
-
-#define QCameraFeedbackControl_iid "org.qt-project.qt.camerafeedbackcontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QCameraFeedbackControl, QCameraFeedbackControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif // QCAMERAFEEDBACKCONTROL_H
diff --git a/src/multimedia/controls/qcameraflashcontrol.cpp b/src/multimedia/controls/qcameraflashcontrol.cpp
deleted file mode 100644
index 658e2d56c..000000000
--- a/src/multimedia/controls/qcameraflashcontrol.cpp
+++ /dev/null
@@ -1,134 +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 <qcameraflashcontrol.h>
-#include "qmediacontrol_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QCameraFlashControl
- \obsolete
-
- \brief The QCameraFlashControl class allows controlling a camera's flash.
-
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
- You can set the type of flash effect used when an image is captured, and test to see
- if the flash hardware is ready to fire.
-
- You can retrieve this control from the camera object in the usual way:
-
- Some camera devices may not have flash hardware, or may not be configurable. In that
- case, there will be no QCameraFlashControl available.
-
- The interface name of QCameraFlashControl is \c org.qt-project.qt.cameraflashcontrol/5.0 as
- defined in QCameraFlashControl_iid.
-
- \sa QCamera
-*/
-
-/*!
- \macro QCameraFlashControl_iid
-
- \c org.qt-project.qt.cameraflashcontrol/5.0
-
- Defines the interface name of the QCameraFlashControl class.
-
- \relates QCameraFlashControl
-*/
-
-/*!
- Constructs a camera flash control object with \a parent.
-*/
-QCameraFlashControl::QCameraFlashControl(QObject *parent):
- QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- Destroys the camera control object.
-*/
-QCameraFlashControl::~QCameraFlashControl()
-{
-}
-
-/*!
- \fn QCamera::FlashModes QCameraFlashControl::flashMode() const
-
- Returns the current flash mode.
-*/
-
-/*!
- \fn void QCameraFlashControl::setFlashMode(QCameraExposure::FlashModes mode)
-
- Set the current flash \a mode.
-
- Usually a single QCameraExposure::FlashMode flag is used,
- but some non conflicting flags combination are also allowed,
- like QCameraExposure::FlashManual | QCameraExposure::FlashSlowSyncRearCurtain.
-*/
-
-
-/*!
- \fn QCameraFlashControl::isFlashModeSupported(QCameraExposure::FlashModes mode) const
-
- Return true if the reqested flash \a mode is supported.
- Some QCameraExposure::FlashMode values can be combined,
- for example QCameraExposure::FlashManual | QCameraExposure::FlashSlowSyncRearCurtain
-*/
-
-/*!
- \fn bool QCameraFlashControl::isFlashReady() const
-
- Returns true if flash is charged.
-*/
-
-/*!
- \fn void QCameraFlashControl::flashReady(bool ready)
-
- Signal emitted when flash state changes to \a ready.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qcameraflashcontrol.cpp"
diff --git a/src/multimedia/controls/qcameraflashcontrol.h b/src/multimedia/controls/qcameraflashcontrol.h
deleted file mode 100644
index d4b7d1f4c..000000000
--- a/src/multimedia/controls/qcameraflashcontrol.h
+++ /dev/null
@@ -1,81 +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 QCAMERAFLASHCONTROL_H
-#define QCAMERAFLASHCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmediaobject.h>
-
-#include <QtMultimedia/qcameraexposure.h>
-#include <QtMultimedia/qcamera.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QCameraFlashControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- ~QCameraFlashControl();
-
- virtual QCameraExposure::FlashModes flashMode() const = 0;
- virtual void setFlashMode(QCameraExposure::FlashModes mode) = 0;
- virtual bool isFlashModeSupported(QCameraExposure::FlashModes mode) const = 0;
-
- virtual bool isFlashReady() const = 0;
-
-Q_SIGNALS:
- void flashReady(bool);
-
-protected:
- explicit QCameraFlashControl(QObject *parent = nullptr);
-};
-
-#define QCameraFlashControl_iid "org.qt-project.qt.cameraflashcontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QCameraFlashControl, QCameraFlashControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif // QCAMERAFLASHCONTROL_H
-
diff --git a/src/multimedia/controls/qcamerafocuscontrol.cpp b/src/multimedia/controls/qcamerafocuscontrol.cpp
deleted file mode 100644
index b216882b4..000000000
--- a/src/multimedia/controls/qcamerafocuscontrol.cpp
+++ /dev/null
@@ -1,198 +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 <qcamerafocuscontrol.h>
-#include "qmediacontrol_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QCameraFocusControl
- \obsolete
-
-
- \brief The QCameraFocusControl class supplies control for
- focusing related camera parameters.
-
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
- The interface name of QCameraFocusControl is \c org.qt-project.qt.camerafocuscontrol/5.0 as
- defined in QCameraFocusControl_iid.
-
-
- \sa QMediaService::requestControl(), QCamera
-*/
-
-/*!
- \macro QCameraFocusControl_iid
-
- \c org.qt-project.qt.camerafocuscontrol/5.0
-
- Defines the interface name of the QCameraFocusControl class.
-
- \relates QCameraFocusControl
-*/
-
-/*!
- Constructs a camera control object with \a parent.
-*/
-
-QCameraFocusControl::QCameraFocusControl(QObject *parent):
- QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- Destruct the camera control object.
-*/
-
-QCameraFocusControl::~QCameraFocusControl()
-{
-}
-
-
-/*!
- \fn QCameraFocus::FocusModes QCameraFocusControl::focusMode() const
-
- Returns the focus mode being used.
-*/
-
-
-/*!
- \fn void QCameraFocusControl::setFocusMode(QCameraFocus::FocusModes mode)
-
- Set the focus mode to \a mode.
-*/
-
-
-/*!
- \fn bool QCameraFocusControl::isFocusModeSupported(QCameraFocus::FocusModes mode) const
-
- Returns true if focus \a mode is supported.
-*/
-
-/*!
- \fn QCameraFocusControl::focusPointMode() const
-
- Returns the camera focus point selection mode.
-*/
-
-/*!
- \fn QCameraFocusControl::setFocusPointMode(QCameraFocus::FocusPointMode mode)
-
- Sets the camera focus point selection \a mode.
-*/
-
-/*!
- \fn QCameraFocusControl::isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const
-
- Returns true if the camera focus point \a mode is supported.
-*/
-
-/*!
- \fn QCameraFocusControl::customFocusPoint() const
-
- Return the position of 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.
-
- Custom focus point is used only in FocusPointCustom focus mode.
-*/
-
-/*!
- \fn QCameraFocusControl::setCustomFocusPoint(const QPointF &point)
-
- Sets the custom focus \a point.
-
- If camera supports fixed set of focus points,
- it should use the nearest supported focus point,
- and return the actual focus point with QCameraFocusControl::focusZones().
-
- \sa QCameraFocusControl::customFocusPoint(), QCameraFocusControl::focusZones()
-*/
-
-/*!
- \fn QCameraFocusControl::focusZones() const
-
- Returns the list of zones, the camera is using for focusing or focused on.
-*/
-
-/*!
- \fn QCameraFocusControl::focusZonesChanged()
-
- Signal is emitted when the set of zones, camera focused on is changed.
-
- Usually the zones list is changed when the camera is focused.
-
- \sa QCameraFocusControl::focusZones()
-*/
-
-/*!
- \fn void QCameraFocusControl::focusModeChanged(QCameraFocus::FocusModes mode)
-
- Signal is emitted when the focus \a mode is changed,
- usually in result of QCameraFocusControl::setFocusMode call or capture mode changes.
-
- \sa QCameraFocusControl::focusMode(), QCameraFocusControl::setFocusMode()
-*/
-
-/*!
- \fn void QCameraFocusControl::focusPointModeChanged(QCameraFocus::FocusPointMode mode)
-
- Signal is emitted when the focus point \a mode is changed,
- usually in result of QCameraFocusControl::setFocusPointMode call or capture mode changes.
-
- \sa QCameraFocusControl::focusPointMode(), QCameraFocusControl::setFocusPointMode()
-*/
-
-/*!
- \fn void QCameraFocusControl::customFocusPointChanged(const QPointF &point)
-
- Signal is emitted when the custom focus \a point is changed.
-
- \sa QCameraFocusControl::customFocusPoint(), QCameraFocusControl::setCustomFocusPoint()
-*/
-
-
-
-QT_END_NAMESPACE
-
-#include "moc_qcamerafocuscontrol.cpp"
diff --git a/src/multimedia/controls/qcamerafocuscontrol.h b/src/multimedia/controls/qcamerafocuscontrol.h
deleted file mode 100644
index a93d2fd1e..000000000
--- a/src/multimedia/controls/qcamerafocuscontrol.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 QCAMERAFOCUSCONTROL_H
-#define QCAMERAFOCUSCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmediaobject.h>
-
-#include <QtMultimedia/qcamerafocus.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QCameraFocusControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- ~QCameraFocusControl();
-
- virtual QCameraFocus::FocusModes focusMode() const = 0;
- virtual void setFocusMode(QCameraFocus::FocusModes mode) = 0;
- virtual bool isFocusModeSupported(QCameraFocus::FocusModes mode) const = 0;
-
- virtual QCameraFocus::FocusPointMode focusPointMode() const = 0;
- virtual void setFocusPointMode(QCameraFocus::FocusPointMode mode) = 0;
- virtual bool isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const = 0;
- virtual QPointF customFocusPoint() const = 0;
- virtual void setCustomFocusPoint(const QPointF &point) = 0;
-
- virtual QCameraFocusZoneList focusZones() const = 0;
-
-Q_SIGNALS:
- void focusModeChanged(QCameraFocus::FocusModes mode);
- void focusPointModeChanged(QCameraFocus::FocusPointMode mode);
- void customFocusPointChanged(const QPointF &point);
-
- void focusZonesChanged();
-
-protected:
- explicit QCameraFocusControl(QObject *parent = nullptr);
-};
-
-#define QCameraFocusControl_iid "org.qt-project.qt.camerafocuscontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QCameraFocusControl, QCameraFocusControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif // QCAMERAFOCUSCONTROL_H
-
diff --git a/src/multimedia/controls/qcameraimagecapturecontrol.cpp b/src/multimedia/controls/qcameraimagecapturecontrol.cpp
deleted file mode 100644
index 0e089d01b..000000000
--- a/src/multimedia/controls/qcameraimagecapturecontrol.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 <qcameraimagecapturecontrol.h>
-#include <QtCore/qstringlist.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QCameraImageCaptureControl
- \obsolete
-
- \brief The QCameraImageCaptureControl class provides a control interface
- for image capture services.
-
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
- The interface name of QCameraImageCaptureControl is \c org.qt-project.qt.cameraimagecapturecontrol/5.0 as
- defined in QCameraImageCaptureControl_iid.
-
-
- \sa QMediaService::requestControl()
-*/
-
-/*!
- \macro QCameraImageCaptureControl_iid
-
- \c org.qt-project.qt.cameraimagecapturecontrol/5.0
-
- Defines the interface name of the QCameraImageCaptureControl class.
-
- \relates QCameraImageCaptureControl
-*/
-
-/*!
- Constructs a new image capture control object with the given \a parent
-*/
-QCameraImageCaptureControl::QCameraImageCaptureControl(QObject *parent)
- :QMediaControl(parent)
-{
-}
-
-/*!
- Destroys an image capture control.
-*/
-QCameraImageCaptureControl::~QCameraImageCaptureControl()
-{
-}
-
-/*!
- \fn QCameraImageCaptureControl::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 QCameraImageCaptureControl::readyForCaptureChanged(bool ready)
-
- Signals that a capture control's \a ready state has changed.
-*/
-
-/*!
- \fn QCameraImageCaptureControl::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 QCameraImageCaptureControl::cancelCapture()
-
- Cancel pending capture requests.
-*/
-
-/*!
- \fn QCameraImageCaptureControl::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 QCameraImageCaptureControl::imageCaptured(int requestId, const QImage &preview)
-
- Signals that an image with it \a requestId
- has been captured and a \a preview is available.
-*/
-
-/*!
- \fn QCameraImageCaptureControl::imageMetadataAvailable(int id, const QString &key, const QVariant &value)
-
- Signals that a metadata for an image with request \a id is available. Signal
- also contains the \a key and \a value of the metadata.
-
- This signal should be emitted between imageExposed and imageSaved signals.
-*/
-
-/*!
- \fn QCameraImageCaptureControl::imageAvailable(int requestId, const QVideoFrame &buffer)
-
- Signals that a captured \a buffer with a \a requestId is available.
-*/
-
-/*!
- \fn QCameraImageCaptureControl::imageSaved(int requestId, const QString &fileName)
-
- Signals that a captured image with a \a requestId has been saved
- to \a fileName.
-*/
-
-/*!
- \fn QCameraImageCaptureControl::driveMode() const
-
- Returns the current camera drive mode.
-*/
-
-/*!
- \fn QCameraImageCaptureControl::setDriveMode(QCameraImageCapture::DriveMode mode)
-
- Sets the current camera drive \a mode.
-*/
-
-
-/*!
- \fn QCameraImageCaptureControl::error(int id, int error, const QString &errorString)
-
- Signals the capture request \a id failed with \a error code and message \a errorString.
-
- \sa QCameraImageCapture::Error
-*/
-
-
-QT_END_NAMESPACE
-
-#include "moc_qcameraimagecapturecontrol.cpp"
diff --git a/src/multimedia/controls/qcameraimagecapturecontrol.h b/src/multimedia/controls/qcameraimagecapturecontrol.h
deleted file mode 100644
index 72b0abda3..000000000
--- a/src/multimedia/controls/qcameraimagecapturecontrol.h
+++ /dev/null
@@ -1,93 +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 QCAMERAIMAGECAPTURECONTROL_H
-#define QCAMERAIMAGECAPTURECONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qcameraimagecapture.h>
-
-QT_BEGIN_NAMESPACE
-
-class QImage;
-QT_END_NAMESPACE
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QCameraImageCaptureControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- ~QCameraImageCaptureControl();
-
- virtual bool isReadyForCapture() const = 0;
-
- virtual QCameraImageCapture::DriveMode driveMode() const = 0;
- virtual void setDriveMode(QCameraImageCapture::DriveMode mode) = 0;
-
- virtual int capture(const QString &fileName) = 0;
- virtual void cancelCapture() = 0;
-
-Q_SIGNALS:
- void readyForCaptureChanged(bool ready);
-
- void imageExposed(int requestId);
- void imageCaptured(int requestId, const QImage &preview);
- void imageMetadataAvailable(int id, const QString &key, const QVariant &value);
- void imageAvailable(int requestId, const QVideoFrame &buffer);
- void imageSaved(int requestId, const QString &fileName);
-
- void error(int id, int error, const QString &errorString);
-
-protected:
- explicit QCameraImageCaptureControl(QObject *parent = nullptr);
-};
-
-#define QCameraImageCaptureControl_iid "org.qt-project.qt.cameraimagecapturecontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QCameraImageCaptureControl, QCameraImageCaptureControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif // QCAMERAIMAGECAPTURECONTROL_H
-
diff --git a/src/multimedia/controls/qcameraimageprocessingcontrol.cpp b/src/multimedia/controls/qcameraimageprocessingcontrol.cpp
deleted file mode 100644
index fba4bf400..000000000
--- a/src/multimedia/controls/qcameraimageprocessingcontrol.cpp
+++ /dev/null
@@ -1,189 +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 <qcameraimageprocessingcontrol.h>
-#include "qmediacontrol_p.h"
-
-QT_BEGIN_NAMESPACE
-
-static void qRegisterCameraImageProcessingControlMetaTypes()
-{
- qRegisterMetaType<QCameraImageProcessingControl::ProcessingParameter>();
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterCameraImageProcessingControlMetaTypes)
-
-/*!
- \class QCameraImageProcessingControl
- \obsolete
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
-
- \brief The QCameraImageProcessingControl class provides an abstract class
- for controlling image processing parameters, like white balance,
- contrast, saturation, sharpening and denoising.
-
- The interface name of QCameraImageProcessingControl is \c org.qt-project.qt.cameraimageprocessingcontrol/5.0 as
- defined in QCameraImageProcessingControl_iid.
-
- Camera service may choose the parameters of image processing pipeline depending
- on sensor properties camera settings and capture parameters.
-
- This control allows to modify some parameters of image processing pipeline
- to achieve desired results.
-
- Parameters with the "Adjustment" suffix, like ContrastAdjustment, SaturationAdjustment etc
- allows to adjust the parameter values, selected by camera engine,
- while parameters like Contrast and Saturation overwrites them.
-
- For example setting the SharpeningAdjustment parameter to -0.1
- slightly reduces the amount of sharpening applied,
- while settings the Sharpening parameter to 0 disables sharpening at all.
-
- \sa QMediaService::requestControl(), QCamera
-*/
-
-/*!
- \macro QCameraImageProcessingControl_iid
-
- \c org.qt-project.qt.cameraimageprocessingcontrol/5.0
-
- Defines the interface name of the QCameraImageProcessingControl class.
-
- \relates QCameraImageProcessingControl
-*/
-
-/*!
- Constructs an image processing control object with \a parent.
-*/
-
-QCameraImageProcessingControl::QCameraImageProcessingControl(QObject *parent):
- QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- Destruct the image processing control object.
-*/
-
-QCameraImageProcessingControl::~QCameraImageProcessingControl()
-{
-}
-
-/*!
- \fn bool QCameraImageProcessingControl::isParameterSupported(ProcessingParameter parameter) const
-
- Returns true if the camera supports adjusting image processing \a parameter.
-
- Usually the supported setting is static,
- but some parameters may not be available depending on other
- camera settings, like presets.
- In such case the currently supported parameters should be returned.
-*/
-
-/*!
- \fn bool QCameraImageProcessingControl::isParameterValueSupported(ProcessingParameter parameter, const QVariant &value) const
-
- Returns true if the camera supports setting the image processing \a parameter \a value.
-
- It's used only for parameters with a limited set of values, like WhiteBalancePreset.
-*/
-
-
-/*!
- \fn QCameraImageProcessingControl::parameter(ProcessingParameter parameter) const
-
- Returns the image processing \a parameter value.
-*/
-
-/*!
- \fn QCameraImageProcessingControl::setParameter(ProcessingParameter parameter, const QVariant &value)
-
- Sets the image processing \a parameter \a value.
- Passing the null or invalid QVariant value allows
- backend to choose the suitable parameter value.
-
- The valid values range depends on the parameter type.
- For WhiteBalancePreset the value should be one of QCameraImageProcessing::WhiteBalanceMode values;
- for Contrast, Saturation, Brightness, Sharpening and Denoising the value should be
- in [0..1.0] range with invalid QVariant value indicating the default parameter value;
- for ContrastAdjustment, SaturationAdjustment, BrightnessAdjustment,
- SharpeningAdjustment and DenoisingAdjustment the value should be
- in [-1.0..1.0] range with default 0.
-*/
-
-/*!
- \enum QCameraImageProcessingControl::ProcessingParameter
-
- \value WhiteBalancePreset
- The white balance preset.
- \value ColorTemperature
- Color temperature in K. This value is used when the manual white balance mode is selected.
- \value Contrast
- Image contrast.
- \value Saturation
- Image saturation.
- \value Brightness
- Image brightness.
- \value Sharpening
- Amount of sharpening applied.
- \value Denoising
- Amount of denoising applied.
- \value ContrastAdjustment
- Image contrast adjustment.
- \value SaturationAdjustment
- Image saturation adjustment.
- \value BrightnessAdjustment
- Image brightness adjustment.
- \value SharpeningAdjustment
- Adjustment of sharpening applied.
- \value DenoisingAdjustment
- Adjustment of denoising applied.
- \value ColorFilter
- Image filter applied. Since 5.5
- \value ExtendedParameter
- The base value for platform specific extended parameters.
- */
-
-QT_END_NAMESPACE
-
-#include "moc_qcameraimageprocessingcontrol.cpp"
diff --git a/src/multimedia/controls/qcameraimageprocessingcontrol.h b/src/multimedia/controls/qcameraimageprocessingcontrol.h
deleted file mode 100644
index 8be435f8f..000000000
--- a/src/multimedia/controls/qcameraimageprocessingcontrol.h
+++ /dev/null
@@ -1,98 +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 QCAMERAIMAGEPROCESSINGCONTROL_H
-#define QCAMERAIMAGEPROCESSINGCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmediaobject.h>
-
-#include <QtMultimedia/qcamera.h>
-#include <QtMultimedia/qmediaenumdebug.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QCameraImageProcessingControl : public QMediaControl
-{
- Q_OBJECT
- Q_ENUMS(ProcessingParameter)
-
-public:
- ~QCameraImageProcessingControl();
-
- enum ProcessingParameter {
- WhiteBalancePreset,
- ColorTemperature,
- Contrast,
- Saturation,
- Brightness,
- Sharpening,
- Denoising,
- ContrastAdjustment,
- SaturationAdjustment,
- BrightnessAdjustment,
- SharpeningAdjustment,
- DenoisingAdjustment,
- ColorFilter,
- ExtendedParameter = 1000
- };
-
- virtual bool isParameterSupported(ProcessingParameter) const = 0;
- virtual bool isParameterValueSupported(ProcessingParameter parameter, const QVariant &value) const = 0;
- virtual QVariant parameter(ProcessingParameter parameter) const = 0;
- virtual void setParameter(ProcessingParameter parameter, const QVariant &value) = 0;
-
-protected:
- explicit QCameraImageProcessingControl(QObject *parent = nullptr);
-};
-
-#define QCameraImageProcessingControl_iid "org.qt-project.qt.cameraimageprocessingcontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QCameraImageProcessingControl, QCameraImageProcessingControl_iid)
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QCameraImageProcessingControl::ProcessingParameter)
-
-Q_MEDIA_ENUM_DEBUG(QCameraImageProcessingControl, ProcessingParameter)
-
-#endif
-
diff --git a/src/multimedia/controls/qcamerainfocontrol.cpp b/src/multimedia/controls/qcamerainfocontrol.cpp
deleted file mode 100644
index 8a4ef3b44..000000000
--- a/src/multimedia/controls/qcamerainfocontrol.cpp
+++ /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$
-**
-****************************************************************************/
-
-#include "qcamerainfocontrol.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QCameraInfoControl
- \obsolete
- \since 5.3
-
- \brief The QCameraInfoControl class provides a camera info media control.
- \inmodule QtMultimedia
-
- \ingroup multimedia_control
-
- The QCameraInfoControl class provides information about the camera devices
- available on the system.
-
- The interface name of QCameraInfoControl is \c org.qt-project.qt.camerainfocontrol/5.3 as
- defined in QCameraInfoControl_iid.
-*/
-
-/*!
- \macro QCameraInfoControl_iid
-
- \c org.qt-project.qt.camerainfocontrol/5.3
-
- Defines the interface name of the QCameraInfoControl class.
-
- \relates QVideoDeviceSelectorControl
-*/
-
-/*!
- Constructs a camera info control with the given \a parent.
-*/
-QCameraInfoControl::QCameraInfoControl(QObject *parent)
- : QMediaControl(parent)
-{
-}
-
-/*!
- Destroys a camera info control.
-*/
-QCameraInfoControl::~QCameraInfoControl()
-{
-}
-
-/*!
- \fn QCameraInfoControl::cameraPosition(const QString &deviceName) const
-
- Returns the physical position of the camera named \a deviceName on the hardware system.
-*/
-
-/*!
- \fn QCameraInfoControl::cameraOrientation(const QString &deviceName) const
-
- Returns the physical orientation of the sensor for the camera named \a deviceName.
-
- The value is the orientation angle (clockwise, in steps of 90 degrees) of the camera sensor
- in relation to the display in its natural orientation.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qcamerainfocontrol.cpp"
diff --git a/src/multimedia/controls/qcamerainfocontrol.h b/src/multimedia/controls/qcamerainfocontrol.h
deleted file mode 100644
index 9ee0a3abf..000000000
--- a/src/multimedia/controls/qcamerainfocontrol.h
+++ /dev/null
@@ -1,69 +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 QCAMERAINFOCONTROL_H
-#define QCAMERAINFOCONTROL_H
-
-#include <QtMultimedia/qcamera.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QCameraInfoControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- virtual ~QCameraInfoControl();
-
- virtual QCamera::Position cameraPosition(const QString &deviceName) const = 0;
- virtual int cameraOrientation(const QString &deviceName) const = 0;
-
-protected:
- explicit QCameraInfoControl(QObject *parent = nullptr);
-};
-
-#define QCameraInfoControl_iid "org.qt-project.qt.camerainfocontrol/5.3"
-Q_MEDIA_DECLARE_CONTROL(QCameraInfoControl, QCameraInfoControl_iid)
-
-QT_END_NAMESPACE
-
-#endif // QCAMERAINFOCONTROL_H
diff --git a/src/multimedia/controls/qcameralockscontrol.cpp b/src/multimedia/controls/qcameralockscontrol.cpp
deleted file mode 100644
index 27b68cf2c..000000000
--- a/src/multimedia/controls/qcameralockscontrol.cpp
+++ /dev/null
@@ -1,128 +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 <qcameralockscontrol.h>
-#include "qmediacontrol_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QCameraLocksControl
- \obsolete
-
-
-
- \brief The QCameraLocksControl class is an abstract base class for
- classes that control still cameras or video cameras.
-
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
- This service is provided by a QMediaService object via
- QMediaService::control(). It is used by QCamera.
-
- The interface name of QCameraLocksControl is \c org.qt-project.qt.cameralockscontrol/5.0 as
- defined in QCameraLocksControl_iid.
-
-
- \sa QMediaService::requestControl(), QCamera
-*/
-
-/*!
- \macro QCameraLocksControl_iid
-
- \c org.qt-project.qt.cameralockscontrol/5.0
-
- Defines the interface name of the QCameraLocksControl class.
-
- \relates QCameraLocksControl
-*/
-
-/*!
- Constructs a camera locks control object with \a parent.
-*/
-
-QCameraLocksControl::QCameraLocksControl(QObject *parent):
- QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- Destruct the camera locks control object.
-*/
-
-QCameraLocksControl::~QCameraLocksControl()
-{
-}
-
-/*!
- \fn QCameraLocksControl::supportedLocks() const
-
- Returns the lock types, the camera supports.
-*/
-
-/*!
- \fn QCameraLocksControl::lockStatus(QCamera::LockType lock) const
-
- Returns the camera \a lock status.
-*/
-
-/*!
- \fn QCameraLocksControl::searchAndLock(QCamera::LockTypes locks)
-
- Request camera \a locks.
-*/
-
-/*!
- \fn QCameraLocksControl::unlock(QCamera::LockTypes locks)
-
- Unlock camera \a locks.
-*/
-
-/*!
- \fn QCameraLocksControl::lockStatusChanged(QCamera::LockType lock, QCamera::LockStatus status, QCamera::LockChangeReason reason)
-
- Signals the lock \a type \a status was changed with the specified \a reason.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qcameralockscontrol.cpp"
diff --git a/src/multimedia/controls/qcameralockscontrol.h b/src/multimedia/controls/qcameralockscontrol.h
deleted file mode 100644
index d545d971e..000000000
--- a/src/multimedia/controls/qcameralockscontrol.h
+++ /dev/null
@@ -1,80 +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 QCAMERALOCKSCONTROL_H
-#define QCAMERALOCKSCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmediaobject.h>
-
-#include <QtMultimedia/qcamera.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QCameraLocksControl : public QMediaControl
-{
- Q_OBJECT
-public:
- ~QCameraLocksControl();
-
- virtual QCamera::LockTypes supportedLocks() const = 0;
-
- virtual QCamera::LockStatus lockStatus(QCamera::LockType lock) const = 0;
-
- virtual void searchAndLock(QCamera::LockTypes locks) = 0;
- virtual void unlock(QCamera::LockTypes locks) = 0;
-
-Q_SIGNALS:
- void lockStatusChanged(QCamera::LockType type, QCamera::LockStatus status, QCamera::LockChangeReason reason);
-
-protected:
- explicit QCameraLocksControl(QObject *parent = nullptr);
-};
-
-#define QCameraLocksControl_iid "org.qt-project.qt.cameralockscontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QCameraLocksControl, QCameraLocksControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif // QCAMERALOCKSCONTROL_H
-
diff --git a/src/multimedia/controls/qcameraviewfindersettingscontrol.cpp b/src/multimedia/controls/qcameraviewfindersettingscontrol.cpp
deleted file mode 100644
index bd5c7a73b..000000000
--- a/src/multimedia/controls/qcameraviewfindersettingscontrol.cpp
+++ /dev/null
@@ -1,206 +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 "qcameraviewfindersettingscontrol.h"
-#include "qmediacontrol_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QCameraViewfinderSettingsControl
- \obsolete
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
-
- \brief The QCameraViewfinderSettingsControl class provides an abstract class
- for controlling camera viewfinder parameters.
-
- The interface name of QCameraViewfinderSettingsControl is \c org.qt-project.qt.cameraviewfindersettingscontrol/5.0 as
- defined in QCameraViewfinderSettingsControl_iid.
-
- \warning New backends should implement QCameraViewfinderSettingsControl2 instead.
- Application developers should request this control only if QCameraViewfinderSettingsControl2
- is not available.
-
- \sa QMediaService::requestControl(), QCameraViewfinderSettingsControl2, QCamera
-*/
-
-/*!
- \macro QCameraViewfinderSettingsControl_iid
-
- \c org.qt-project.qt.cameraviewfindersettingscontrol/5.0
-
- Defines the interface name of the QCameraViewfinderSettingsControl class.
-
- \relates QCameraViewfinderSettingsControl
-*/
-
-/*!
- Constructs a camera viewfinder control object with \a parent.
-*/
-QCameraViewfinderSettingsControl::QCameraViewfinderSettingsControl(QObject *parent)
- : QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- Destroys the camera viewfinder control object.
-*/
-QCameraViewfinderSettingsControl::~QCameraViewfinderSettingsControl()
-{
-}
-
-/*!
- \enum QCameraViewfinderSettingsControl::ViewfinderParameter
- \value Resolution
- Viewfinder resolution, QSize.
- \value PixelAspectRatio
- Pixel aspect ratio, QSize as in QVideoSurfaceFormat::pixelAspectRatio
- \value MinimumFrameRate
- Minimum viewfinder frame rate, qreal
- \value MaximumFrameRate
- Maximum viewfinder frame rate, qreal
- \value PixelFormat
- Viewfinder pixel format, QVideoFrame::PixelFormat
- \value UserParameter
- The base value for platform specific extended parameters.
- For such parameters the sequential values starting from UserParameter should be used.
-*/
-
-/*!
- \fn bool QCameraViewfinderSettingsControl::isViewfinderParameterSupported(ViewfinderParameter parameter) const
-
- Returns true if configuration of viewfinder \a parameter is supported by camera backend.
-*/
-
-/*!
- \fn QCameraViewfinderSettingsControl::viewfinderParameter(ViewfinderParameter parameter) const
-
- Returns the value of viewfinder \a parameter.
-*/
-
-/*!
- \fn QCameraViewfinderSettingsControl::setViewfinderParameter(ViewfinderParameter parameter, const QVariant &value)
-
- Set the prefferred \a value of viewfinder \a parameter.
-
- Calling this while the camera is active may result in the camera being
- stopped and reloaded. If video recording is in progress, this call may be ignored.
-
- If an unsupported parameter is specified the camera may fail to load,
- or the setting may be ignored.
-
- Viewfinder parameters may also depend on other camera settings,
- especially in video capture mode. If camera configuration conflicts
- with viewfinder settings, the camara configuration is usually preferred.
-*/
-
-
-/*!
- \class QCameraViewfinderSettingsControl2
- \inmodule QtMultimedia
- \ingroup multimedia_control
- \since 5.5
-
- \brief The QCameraViewfinderSettingsControl2 class provides access to the viewfinder settings
- of a camera media service.
-
- The functionality provided by this control is exposed to application code through the QCamera class.
-
- The interface name of QCameraViewfinderSettingsControl2 is \c org.qt-project.qt.cameraviewfindersettingscontrol2/5.5 as
- defined in QCameraViewfinderSettingsControl2_iid.
-
- \sa QMediaService::requestControl(), QCameraViewfinderSettings, QCamera
-*/
-
-/*!
- \macro QCameraViewfinderSettingsControl2_iid
-
- \c org.qt-project.qt.cameraviewfindersettingscontrol2/5.5
-
- Defines the interface name of the QCameraViewfinderSettingsControl2 class.
-
- \relates QCameraViewfinderSettingsControl2
-*/
-
-/*!
- Constructs a camera viewfinder settings control object with \a parent.
-*/
-QCameraViewfinderSettingsControl2::QCameraViewfinderSettingsControl2(QObject *parent)
- : QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- Destroys the camera viewfinder settings control object.
-*/
-QCameraViewfinderSettingsControl2::~QCameraViewfinderSettingsControl2()
-{
-}
-
-/*!
- \fn QCameraViewfinderSettingsControl2::supportedViewfinderSettings() const
-
- Returns a list of supported camera viewfinder settings.
-
- The list is ordered by preference; preferred settings come first.
-*/
-
-/*!
- \fn QCameraViewfinderSettingsControl2::viewfinderSettings() const
-
- Returns the viewfinder settings.
-
- If undefined or unsupported values are passed to QCameraViewfinderSettingsControl2::setViewfinderSettings(),
- this function returns the actual settings used by the camera viewfinder. These may be available
- only once the camera is active.
-*/
-
-/*!
- \fn QCameraViewfinderSettingsControl2::setViewfinderSettings(const QCameraViewfinderSettings &settings)
-
- Sets the camera viewfinder \a settings.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qcameraviewfindersettingscontrol.cpp"
diff --git a/src/multimedia/controls/qcameraviewfindersettingscontrol.h b/src/multimedia/controls/qcameraviewfindersettingscontrol.h
deleted file mode 100644
index 7877bd1db..000000000
--- a/src/multimedia/controls/qcameraviewfindersettingscontrol.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 QCAMERAVIEWFINDERSETTINGSCONTROL_H
-#define QCAMERAVIEWFINDERSETTINGSCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qcamera.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QCameraViewfinderSettingsControl : public QMediaControl
-{
- Q_OBJECT
-public:
- enum ViewfinderParameter {
- Resolution,
- PixelAspectRatio,
- MinimumFrameRate,
- MaximumFrameRate,
- PixelFormat,
- UserParameter = 1000
- };
-
- ~QCameraViewfinderSettingsControl();
-
- virtual bool isViewfinderParameterSupported(ViewfinderParameter parameter) const = 0;
- virtual QVariant viewfinderParameter(ViewfinderParameter parameter) const = 0;
- virtual void setViewfinderParameter(ViewfinderParameter parameter, const QVariant &value) = 0;
-
-protected:
- explicit QCameraViewfinderSettingsControl(QObject *parent = nullptr);
-};
-
-#define QCameraViewfinderSettingsControl_iid "org.qt-project.qt.cameraviewfindersettingscontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QCameraViewfinderSettingsControl, QCameraViewfinderSettingsControl_iid)
-
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QCameraViewfinderSettingsControl2 : public QMediaControl
-{
- Q_OBJECT
-public:
- virtual ~QCameraViewfinderSettingsControl2();
-
- virtual QList<QCameraViewfinderSettings> supportedViewfinderSettings() const = 0;
-
- virtual QCameraViewfinderSettings viewfinderSettings() const = 0;
- virtual void setViewfinderSettings(const QCameraViewfinderSettings &settings) = 0;
-
-protected:
- explicit QCameraViewfinderSettingsControl2(QObject *parent = nullptr);
-};
-
-#define QCameraViewfinderSettingsControl2_iid "org.qt-project.qt.cameraviewfindersettingscontrol2/5.5"
-Q_MEDIA_DECLARE_CONTROL(QCameraViewfinderSettingsControl2, QCameraViewfinderSettingsControl2_iid)
-
-QT_END_NAMESPACE
-
-#endif // QCAMERAVIEWFINDERSETTINGSCONTROL_H
diff --git a/src/multimedia/controls/qcamerazoomcontrol.cpp b/src/multimedia/controls/qcamerazoomcontrol.cpp
deleted file mode 100644
index 1f0835224..000000000
--- a/src/multimedia/controls/qcamerazoomcontrol.cpp
+++ /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$
-**
-****************************************************************************/
-
-#include <qcamerazoomcontrol.h>
-#include "qmediacontrol_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QCameraZoomControl
- \obsolete
-
-
- \brief The QCameraZoomControl class supplies control for
- optical and digital camera zoom.
-
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
- The interface name of QCameraZoomControl is \c org.qt-project.qt.camerazoomcontrol/5.0 as
- defined in QCameraZoomControl_iid.
-
-
- \sa QMediaService::requestControl(), QCamera
-*/
-
-/*!
- \macro QCameraZoomControl_iid
-
- \c org.qt-project.qt.camerazoomcontrol/5.0
-
- Defines the interface name of the QCameraZoomControl class.
-
- \relates QCameraZoomControl
-*/
-
-/*!
- Constructs a camera zoom control object with \a parent.
-*/
-
-QCameraZoomControl::QCameraZoomControl(QObject *parent):
- QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- Destruct the camera zoom control object.
-*/
-
-QCameraZoomControl::~QCameraZoomControl()
-{
-}
-
-/*!
- \fn qreal QCameraZoomControl::maximumOpticalZoom() const
-
- Returns the maximum optical zoom value, or 1.0 if optical zoom is not supported.
-*/
-
-
-/*!
- \fn qreal QCameraZoomControl::maximumDigitalZoom() const
-
- Returns the maximum digital zoom value, or 1.0 if digital zoom is not supported.
-*/
-
-
-/*!
- \fn qreal QCameraZoomControl::requestedOpticalZoom() const
-
- Return the requested optical zoom value.
-*/
-
-/*!
- \fn qreal QCameraZoomControl::requestedDigitalZoom() const
-
- Return the requested digital zoom value.
-*/
-
-/*!
- \fn qreal QCameraZoomControl::currentOpticalZoom() const
-
- Return the current optical zoom value.
-*/
-
-/*!
- \fn qreal QCameraZoomControl::currentDigitalZoom() const
-
- Return the current digital zoom value.
-*/
-
-/*!
- \fn void QCameraZoomControl::zoomTo(qreal optical, qreal digital)
-
- Sets \a optical and \a digital zoom values.
-
- Zooming can be asynchronous with value changes reported with
- currentDigitalZoomChanged() and currentOpticalZoomChanged() signals.
-
- The backend should expect and correctly handle frequent zoomTo() calls
- during zoom animations or slider movements.
-*/
-
-
-/*!
- \fn void QCameraZoomControl::currentOpticalZoomChanged(qreal zoom)
-
- Signal emitted when the current optical \a zoom value changed.
-*/
-
-/*!
- \fn void QCameraZoomControl::currentDigitalZoomChanged(qreal zoom)
-
- Signal emitted when the current digital \a zoom value changed.
-*/
-
-/*!
- \fn void QCameraZoomControl::requestedOpticalZoomChanged(qreal zoom)
-
- Signal emitted when the requested optical \a zoom value changed.
-*/
-
-/*!
- \fn void QCameraZoomControl::requestedDigitalZoomChanged(qreal zoom)
-
- Signal emitted when the requested digital \a zoom value changed.
-*/
-
-
-/*!
- \fn void QCameraZoomControl::maximumOpticalZoomChanged(qreal zoom)
-
- Signal emitted when the maximum supported optical \a zoom value changed.
-
- The maximum supported zoom value can depend on other camera settings,
- like focusing mode.
-*/
-
-/*!
- \fn void QCameraZoomControl::maximumDigitalZoomChanged(qreal zoom)
-
- Signal emitted when the maximum supported digital \a zoom value changed.
-
- The maximum supported zoom value can depend on other camera settings,
- like capture mode or resolution.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qcamerazoomcontrol.cpp"
diff --git a/src/multimedia/controls/qcamerazoomcontrol.h b/src/multimedia/controls/qcamerazoomcontrol.h
deleted file mode 100644
index feca6a362..000000000
--- a/src/multimedia/controls/qcamerazoomcontrol.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 QCAMERAZOOMCONTROL_H
-#define QCAMERAZOOMCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmediaobject.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QCameraZoomControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- ~QCameraZoomControl();
-
- virtual qreal maximumOpticalZoom() const = 0;
- virtual qreal maximumDigitalZoom() const = 0;
-
- virtual qreal requestedOpticalZoom() const = 0;
- virtual qreal requestedDigitalZoom() const = 0;
- virtual qreal currentOpticalZoom() const = 0;
- virtual qreal currentDigitalZoom() const = 0;
-
- virtual void zoomTo(qreal optical, qreal digital) = 0;
-
-Q_SIGNALS:
- void maximumOpticalZoomChanged(qreal);
- void maximumDigitalZoomChanged(qreal);
-
- void requestedOpticalZoomChanged(qreal opticalZoom);
- void requestedDigitalZoomChanged(qreal digitalZoom);
- void currentOpticalZoomChanged(qreal opticalZoom);
- void currentDigitalZoomChanged(qreal digitalZoom);
-
-protected:
- explicit QCameraZoomControl(QObject *parent = nullptr);
-};
-
-#define QCameraZoomControl_iid "org.qt-project.qt.camerazoomcontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QCameraZoomControl, QCameraZoomControl_iid)
-
-QT_END_NAMESPACE
-
-#endif // QCAMERAZOOMCONTROL_H
diff --git a/src/multimedia/controls/qcustomaudiorolecontrol.cpp b/src/multimedia/controls/qcustomaudiorolecontrol.cpp
deleted file mode 100644
index f1b89eda5..000000000
--- a/src/multimedia/controls/qcustomaudiorolecontrol.cpp
+++ /dev/null
@@ -1,119 +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 "qmediacontrol_p.h"
-#include "qcustomaudiorolecontrol.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QCustomAudioRoleControl
- \obsolete
- \inmodule QtMultimedia
- \ingroup multimedia_control
- \since 5.11
-
- \brief The QCustomAudioRoleControl class provides control over the audio role of a media object.
-
- If a QMediaService supports audio roles it may implement QCustomAudioRoleControl in order to
- provide access to roles unknown to Qt.
-
- The functionality provided by this control is exposed to application code through the
- QMediaPlayer class.
-
- The interface name of QCustomAudioRoleControl is \c org.qt-project.qt.customaudiorolecontrol/5.11 as
- defined in QCustomAudioRoleControl_iid.
-
- \sa QMediaService::requestControl(), QMediaPlayer
-*/
-
-/*!
- \macro QCustomAudioRoleControl_iid
-
- \c org.qt-project.qt.customaudiorolecontrol/5.11
-
- Defines the interface name of the QCustomAudioRoleControl class.
-
- \relates QCustomAudioRoleControl
-*/
-
-/*!
- Construct a QCustomAudioRoleControl with the given \a parent.
-*/
-QCustomAudioRoleControl::QCustomAudioRoleControl(QObject *parent)
- : QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- Destroys the audio role control.
-*/
-QCustomAudioRoleControl::~QCustomAudioRoleControl()
-{
-}
-
-/*!
- \fn QAudio::Role QCustomAudioRoleControl::customAudioRole() const
-
- Returns the audio role of the media played by the media service.
-*/
-
-/*!
- \fn void QCustomAudioRoleControl::setCustomAudioRole(const QString &role)
-
- Sets the audio \a role of the media played by the media service.
-*/
-
-/*!
- \fn QStringList QCustomAudioRoleControl::supportedCustomAudioRoles() const
-
- Returns a list of custom audio roles that the media service supports. An
- empty list may indicate that the supported custom audio roles aren't known.
- The list may not be complete.
-*/
-
-/*!
- \fn void QCustomAudioRoleControl::customAudioRoleChanged(const QString &role)
-
- Signal emitted when the audio \a role has changed.
- */
-
-QT_END_NAMESPACE
-
-#include "moc_qcustomaudiorolecontrol.cpp"
diff --git a/src/multimedia/controls/qcustomaudiorolecontrol.h b/src/multimedia/controls/qcustomaudiorolecontrol.h
deleted file mode 100644
index 5a587c034..000000000
--- a/src/multimedia/controls/qcustomaudiorolecontrol.h
+++ /dev/null
@@ -1,75 +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 QCUSTOMAUDIOROLECONTROL_H
-#define QCUSTOMAUDIOROLECONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qaudio.h>
-
-QT_BEGIN_NAMESPACE
-
-// Class forward declaration required for QDoc bug
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QCustomAudioRoleControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- virtual ~QCustomAudioRoleControl();
-
- virtual QString customAudioRole() const = 0;
- virtual void setCustomAudioRole(const QString &role) = 0;
-
- virtual QStringList supportedCustomAudioRoles() const = 0;
-
-Q_SIGNALS:
- void customAudioRoleChanged(const QString &role);
-
-protected:
- explicit QCustomAudioRoleControl(QObject *parent = nullptr);
-};
-
-#define QCustomAudioRoleControl_iid "org.qt-project.qt.customaudiorolecontrol/5.11"
-Q_MEDIA_DECLARE_CONTROL(QCustomAudioRoleControl, QCustomAudioRoleControl_iid)
-
-QT_END_NAMESPACE
-
-#endif // QCUSTOMAUDIOROLECONTROL_H
diff --git a/src/multimedia/controls/qimageencodercontrol.cpp b/src/multimedia/controls/qimageencodercontrol.cpp
deleted file mode 100644
index 6223c33c7..000000000
--- a/src/multimedia/controls/qimageencodercontrol.cpp
+++ /dev/null
@@ -1,137 +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 "qimageencodercontrol.h"
-#include <QtCore/qstringlist.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QImageEncoderControl
- \obsolete
-
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
- \brief The QImageEncoderControl class provides access to the settings of a media service that
- performs image encoding.
-
- If a QMediaService supports encoding image data it will implement QImageEncoderControl.
- This control allows to \l {setImageSettings()}{set image encoding settings} and
- provides functions for quering supported image \l {supportedImageCodecs()}{codecs} and
- \l {supportedResolutions()}{resolutions}.
-
- The interface name of QImageEncoderControl is \c org.qt-project.qt.imageencodercontrol/5.0 as
- defined in QImageEncoderControl_iid.
-
- \sa QImageEncoderSettings, QMediaService::requestControl()
-*/
-
-/*!
- \macro QImageEncoderControl_iid
-
- \c org.qt-project.qt.imageencodercontrol/5.0
-
- Defines the interface name of the QImageEncoderControl class.
-
- \relates QImageEncoderControl
-*/
-
-/*!
- Constructs a new image encoder control object with the given \a parent
-*/
-QImageEncoderControl::QImageEncoderControl(QObject *parent)
- :QMediaControl(parent)
-{
-}
-
-/*!
- Destroys the image encoder control.
-*/
-QImageEncoderControl::~QImageEncoderControl()
-{
-}
-
-/*!
- \fn QImageEncoderControl::supportedResolutions(const QImageEncoderSettings &settings = QImageEncoderSettings(),
- bool *continuous = 0) const
-
- Returns a list of supported resolutions.
-
- If non null image \a settings parameter is passed,
- the returned list is reduced to resolutions supported with partial settings applied.
- It can be used to query the list of resolutions, supported by specific image codec.
-
- If the encoder supports arbitrary resolutions within the supported resolutions range,
- *\a continuous is set to true, otherwise *\a continuous is set to false.
-*/
-
-/*!
- \fn QImageEncoderControl::supportedImageCodecs() const
-
- Returns a list of supported image codecs.
-*/
-
-/*!
- \fn QImageEncoderControl::imageCodecDescription(const QString &codec) const
-
- Returns a description of an image \a codec.
-*/
-
-/*!
- \fn QImageEncoderControl::imageSettings() const
-
- Returns the currently used image encoder settings.
-
- The returned value may be different tha passed to QImageEncoderControl::setImageSettings()
- if the settings contains the default or undefined parameters.
- In this case if the undefined parameters are already resolved, they should be returned.
-*/
-
-/*!
- \fn QImageEncoderControl::setImageSettings(const QImageEncoderSettings &settings)
-
- Sets the selected image encoder \a settings.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qimageencodercontrol.cpp"
diff --git a/src/multimedia/controls/qimageencodercontrol.h b/src/multimedia/controls/qimageencodercontrol.h
deleted file mode 100644
index c33266d9a..000000000
--- a/src/multimedia/controls/qimageencodercontrol.h
+++ /dev/null
@@ -1,82 +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 QIMAGEENCODERCONTROL_H
-#define QIMAGEENCODERCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmediarecorder.h>
-#include <QtMultimedia/qmediaencodersettings.h>
-
-#include <QtCore/qsize.h>
-
-QT_BEGIN_NAMESPACE
-
-class QByteArray;
-QT_END_NAMESPACE
-
-QT_BEGIN_NAMESPACE
-
-class Q_MULTIMEDIA_EXPORT QImageEncoderControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- virtual ~QImageEncoderControl();
-
- virtual QStringList supportedImageCodecs() const = 0;
- virtual QString imageCodecDescription(const QString &codec) const = 0;
-
- virtual QList<QSize> supportedResolutions(const QImageEncoderSettings &settings,
- bool *continuous = nullptr) const = 0;
-
- virtual QImageEncoderSettings imageSettings() const = 0;
- virtual void setImageSettings(const QImageEncoderSettings &settings) = 0;
-
-protected:
- explicit QImageEncoderControl(QObject *parent = nullptr);
-};
-
-#define QImageEncoderControl_iid "org.qt-project.qt.imageencodercontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QImageEncoderControl, QImageEncoderControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif
diff --git a/src/multimedia/controls/qmediaaudioprobecontrol.cpp b/src/multimedia/controls/qmediaaudioprobecontrol.cpp
deleted file mode 100644
index e22135903..000000000
--- a/src/multimedia/controls/qmediaaudioprobecontrol.cpp
+++ /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$
-**
-****************************************************************************/
-
-#include "qmediaaudioprobecontrol.h"
-#include "qmediacontrol_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QMediaAudioProbeControl
- \obsolete
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
- \brief The QMediaAudioProbeControl class allows control over probing audio data in media objects.
-
- \l QAudioProbe is the client facing class for probing audio - this class is implemented by
- media backends to provide this functionality.
-
- The interface name of QMediaAudioProbeControl is \c org.qt-project.qt.mediaaudioprobecontrol/5.0 as
- defined in QMediaAudioProbeControl_iid.
-
- \sa QAudioProbe, QMediaService::requestControl(), QMediaPlayer, QCamera
-*/
-
-/*!
- \macro QMediaAudioProbeControl_iid
-
- \c org.qt-project.qt.mediaaudioprobecontrol/5.0
-
- Defines the interface name of the QMediaAudioProbeControl class.
-
- \relates QMediaAudioProbeControl
-*/
-
-/*!
- Create a new media audio probe control object with the given \a parent.
-*/
-QMediaAudioProbeControl::QMediaAudioProbeControl(QObject *parent)
- : QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*! Destroys this audio probe control */
-QMediaAudioProbeControl::~QMediaAudioProbeControl()
-{
-}
-
-/*!
- \fn QMediaAudioProbeControl::audioBufferProbed(const QAudioBuffer &buffer)
-
- This signal should be emitted when an audio \a buffer is processed in the
- media service.
-*/
-
-
-/*!
- \fn QMediaAudioProbeControl::flush()
-
- This signal should be emitted when it is required to release all frames.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qmediaaudioprobecontrol.cpp"
diff --git a/src/multimedia/controls/qmediaaudioprobecontrol.h b/src/multimedia/controls/qmediaaudioprobecontrol.h
deleted file mode 100644
index 74cb1bc5a..000000000
--- a/src/multimedia/controls/qmediaaudioprobecontrol.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 QMEDIAAUDIOPROBECONTROL_H
-#define QMEDIAAUDIOPROBECONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-
-QT_BEGIN_NAMESPACE
-
-class QAudioBuffer;
-class Q_MULTIMEDIA_EXPORT QMediaAudioProbeControl : public QMediaControl
-{
- Q_OBJECT
-public:
- virtual ~QMediaAudioProbeControl();
-
-Q_SIGNALS:
- void audioBufferProbed(const QAudioBuffer &buffer);
- void flush();
-
-protected:
- explicit QMediaAudioProbeControl(QObject *parent = nullptr);
-};
-
-#define QMediaAudioProbeControl_iid "org.qt-project.qt.mediaaudioprobecontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QMediaAudioProbeControl, QMediaAudioProbeControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif // QMEDIAAUDIOPROBECONTROL_H
diff --git a/src/multimedia/controls/qmediaavailabilitycontrol.cpp b/src/multimedia/controls/qmediaavailabilitycontrol.cpp
deleted file mode 100644
index 68b404369..000000000
--- a/src/multimedia/controls/qmediaavailabilitycontrol.cpp
+++ /dev/null
@@ -1,109 +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 "qmediaavailabilitycontrol.h"
-#include "qmediacontrol_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QMediaAvailabilityControl
- \obsolete
-
- \brief The QMediaAvailabilityControl class supplies a control for reporting availability of a service.
-
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
- An instance of QMediaObject (or its derived classes) can report any changes
- in availability via this control.
-
- The interface name of QMediaAvailabilityControl is \c org.qt-project.qt.mediaavailabilitycontrol/5.0 as
- defined in QMediaAvailabilityControl_iid.
-
- \sa QMediaService::requestControl(), QMediaObject
-*/
-
-/*!
- \macro QMediaAvailabilityControl_iid
-
- \c org.qt-project.qt.mediaavailabilitycontrol/5.0
-
- Defines the interface name of the QMediaAvailabilityControl class.
-
- \relates QMediaAvailabilityControl
-*/
-
-/*!
- Constructs an availability control object with \a parent.
-*/
-QMediaAvailabilityControl::QMediaAvailabilityControl(QObject *parent)
- : QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- Destruct the availability control object.
-*/
-QMediaAvailabilityControl::~QMediaAvailabilityControl()
-{
-}
-
-
-/*!
- \fn QMultimedia::AvailabilityStatus QMediaAvailabilityControl::availability() const
-
- Returns the current availability of this instance of the media service.
- If the availability changes at run time (for example, some other media
- client takes all media resources) the availabilityChanges() signal
- should be emitted.
-*/
-
-
-/*!
- \fn void QMediaAvailabilityControl::availabilityChanged(QMultimedia::AvailabilityStatus availability)
-
- Signal emitted when the current \a availability value changed.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qmediaavailabilitycontrol.cpp"
diff --git a/src/multimedia/controls/qmediaavailabilitycontrol.h b/src/multimedia/controls/qmediaavailabilitycontrol.h
deleted file mode 100644
index a61617b1f..000000000
--- a/src/multimedia/controls/qmediaavailabilitycontrol.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 QMEDIAAVAILABILITYCONTROL_H
-#define QMEDIAAVAILABILITYCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmediaobject.h>
-#include <QtMultimedia/qmultimedia.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QMediaAvailabilityControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- ~QMediaAvailabilityControl();
-
- virtual QMultimedia::AvailabilityStatus availability() const = 0;
-
-Q_SIGNALS:
- void availabilityChanged(QMultimedia::AvailabilityStatus availability);
-
-protected:
- explicit QMediaAvailabilityControl(QObject *parent = nullptr);
-};
-
-#define QMediaAvailabilityControl_iid "org.qt-project.qt.mediaavailabilitycontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QMediaAvailabilityControl, QMediaAvailabilityControl_iid)
-
-QT_END_NAMESPACE
-
-#endif // QMEDIAAVAILABILITYCONTROL_H
diff --git a/src/multimedia/controls/qmediacontainercontrol.cpp b/src/multimedia/controls/qmediacontainercontrol.cpp
deleted file mode 100644
index 2b2c8b78b..000000000
--- a/src/multimedia/controls/qmediacontainercontrol.cpp
+++ /dev/null
@@ -1,122 +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 "qmediacontainercontrol.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QMediaContainerControl
- \obsolete
-
- \brief The QMediaContainerControl class provides access to the output container format of a QMediaService.
-
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
- If a QMediaService supports writing encoded data it will implement
- QMediaContainerControl. This control provides information about the output
- containers supported by a media service and allows one to be selected as
- the current output containers.
-
- The functionality provided by this control is exposed to application code
- through the QMediaRecorder class.
-
- The interface name of QMediaContainerControl is \c org.qt-project.qt.mediacontainercontrol/5.0 as
- defined in QMediaContainerControl_iid.
-
- \sa QMediaService::requestControl(), QMediaRecorder
-*/
-
-/*!
- \macro QMediaContainerControl_iid
-
- \c org.qt-project.qt.mediacontainercontrol/5.0
-
- Defines the interface name of the QMediaContainerControl class.
-
- \relates QMediaContainerControl
-*/
-
-/*!
- Constructs a new media container control with the given \a parent.
-*/
-QMediaContainerControl::QMediaContainerControl(QObject *parent)
- :QMediaControl(parent)
-{
-}
-
-/*!
- Destroys a media container control.
-*/
-QMediaContainerControl::~QMediaContainerControl()
-{
-}
-
-
-/*!
- \fn QMediaContainerControl::supportedContainers() const
-
- Returns a list of MIME types of supported container formats.
-*/
-
-/*!
- \fn QMediaContainerControl::containerFormat() const
-
- Returns the selected container format.
-*/
-
-/*!
- \fn QMediaContainerControl::setContainerFormat(const QString &format)
-
- Sets the current container \a format.
-*/
-
-/*!
- \fn QMediaContainerControl::containerDescription(const QString &formatMimeType) const
-
- Returns a description of the container \a formatMimeType.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qmediacontainercontrol.cpp"
diff --git a/src/multimedia/controls/qmediacontainercontrol.h b/src/multimedia/controls/qmediacontainercontrol.h
deleted file mode 100644
index 23c2918b9..000000000
--- a/src/multimedia/controls/qmediacontainercontrol.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 QMEDIACONTAINERCONTROL_H
-#define QMEDIACONTAINERCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QMediaContainerControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- virtual ~QMediaContainerControl();
-
- virtual QStringList supportedContainers() const = 0;
- virtual QString containerFormat() const = 0;
- virtual void setContainerFormat(const QString &format) = 0;
-
- virtual QString containerDescription(const QString &formatMimeType) const = 0;
-
-protected:
- explicit QMediaContainerControl(QObject *parent = nullptr);
-};
-
-#define QMediaContainerControl_iid "org.qt-project.qt.mediacontainercontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QMediaContainerControl, QMediaContainerControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif // QMEDIACONTAINERCONTROL_H
diff --git a/src/multimedia/controls/qmediagaplessplaybackcontrol.cpp b/src/multimedia/controls/qmediagaplessplaybackcontrol.cpp
deleted file mode 100644
index c9f531454..000000000
--- a/src/multimedia/controls/qmediagaplessplaybackcontrol.cpp
+++ /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$
-**
-****************************************************************************/
-
-#include "qmediagaplessplaybackcontrol.h"
-#include "qmediacontrol_p.h"
-
-/*!
- \class QMediaGaplessPlaybackControl
- \obsolete
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
- \brief The QMediaGaplessPlaybackControl class provides access to the gapless playback
- related control of a QMediaService.
-
- If a QMediaService supports gapless playback it will implement QMediaGaplessPlaybackControl.
- This control provides a means to set the \l {setNextMedia()}{next media} or
- \l {setCrossfadeTime()}{crossfade time} for smooth transitions between tracks.
-
- The functionality provided by this control is exposed to application
- code through the QMediaPlayer class.
-
- The interface name of QMediaGaplessPlaybackControl is
- \c org.qt-project.qt.mediagaplessplaybackcontrol/5.0 as defined in QMediaGaplessPlaybackControl_iid.
-
- \sa QMediaService::requestControl(), QMediaPlayer
-*/
-
-/*!
- \macro QMediaGaplessPlaybackControl_iid
-
- \c org.qt-project.qt.mediagaplessplaybackcontrol/5.0
-
- Defines the interface name of the QMediaGaplessPlaybackControl class.
-
- \relates QMediaGaplessPlaybackControl
-*/
-
-/*!
- Destroys a gapless playback control.
-*/
-QMediaGaplessPlaybackControl::~QMediaGaplessPlaybackControl()
-{
-}
-
-/*!
- Constructs a new gapless playback control with the given \a parent.
-*/
-QMediaGaplessPlaybackControl::QMediaGaplessPlaybackControl(QObject *parent):
- QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- \fn QMediaGaplessPlaybackControl::nextMedia() const
-
- Returns the content of the next media
-*/
-
-/*!
- \fn QMediaGaplessPlaybackControl::setNextMedia(const QMediaContent& media)
-
- Sets the next \a media for smooth transition.
-*/
-
-/*!
- \fn QMediaGaplessPlaybackControl::nextMediaChanged(const QMediaContent& media)
-
- Signals that the next \a media has changed (either explicitly via \l setNextMedia() or when the
- player clears the next media while advancing to it).
-
- \sa nextMedia()
-*/
-
-/*!
- \fn QMediaGaplessPlaybackControl::advancedToNextMedia()
-
- Signals when the player advances to the next media (the content of next media will be cleared).
-
- \sa nextMedia()
-*/
-
-/*!
- \fn QMediaGaplessPlaybackControl::isCrossfadeSupported() const
-
- Indicates whether crossfading is supported or not.
- If crossfading is not supported, \l setCrossfadeTime() will be ignored and \l crossfadeTime() will
- always return 0.
-
-*/
-
-/*!
- \fn QMediaGaplessPlaybackControl::setCrossfadeTime(qreal crossfadeTime)
-
- Sets the \a crossfadeTime in seconds for smooth transition.
-
- Positive value means how much time it will take for the next media to transit from silent to
- full volume and vice versa for current one. So both current and the next one will be playing
- during this period of time.
-
- A crossfade time of zero or negative will result in gapless playback (suitable for some
- continuous media).
-
-*/
-
-/*!
- \fn QMediaGaplessPlaybackControl::crossfadeTime() const
-
- Returns current crossfade time in seconds.
-*/
-
-/*!
- \fn QMediaGaplessPlaybackControl::crossfadeTimeChanged(qreal crossfadeTime)
-
- Signals that the \a crossfadeTime has changed.
-
- \sa crossfadeTime()
-*/
-
diff --git a/src/multimedia/controls/qmediagaplessplaybackcontrol.h b/src/multimedia/controls/qmediagaplessplaybackcontrol.h
deleted file mode 100644
index 23e2b4fc2..000000000
--- a/src/multimedia/controls/qmediagaplessplaybackcontrol.h
+++ /dev/null
@@ -1,77 +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 QMEDIAGAPLESSPLAYBACKCONTROL_H
-#define QMEDIAGAPLESSPLAYBACKCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmediacontent.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QMediaGaplessPlaybackControl : public QMediaControl
-{
- Q_OBJECT
-public:
- virtual ~QMediaGaplessPlaybackControl();
-
- virtual QMediaContent nextMedia() const = 0;
- virtual void setNextMedia(const QMediaContent &media) = 0;
-
- virtual bool isCrossfadeSupported() const = 0;
- virtual qreal crossfadeTime() const = 0;
- virtual void setCrossfadeTime(qreal crossfadeTime) = 0;
-
-Q_SIGNALS:
- void crossfadeTimeChanged(qreal crossfadeTime);
- void nextMediaChanged(const QMediaContent& media);
- void advancedToNextMedia();
-
-protected:
- explicit QMediaGaplessPlaybackControl(QObject *parent = nullptr);
-};
-
-#define QMediaGaplessPlaybackControl_iid "org.qt-project.qt.mediagaplessplaybackcontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QMediaGaplessPlaybackControl, QMediaGaplessPlaybackControl_iid)
-
-QT_END_NAMESPACE
-
-#endif // QMEDIAGAPLESSPLAYBACKCONTROL_H
diff --git a/src/multimedia/controls/qmediaplayercontrol.cpp b/src/multimedia/controls/qmediaplayercontrol.cpp
deleted file mode 100644
index a180413b9..000000000
--- a/src/multimedia/controls/qmediaplayercontrol.cpp
+++ /dev/null
@@ -1,386 +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 "qmediaplayercontrol.h"
-#include "qmediacontrol_p.h"
-#include "qmediaplayer.h"
-
-QT_BEGIN_NAMESPACE
-
-
-/*!
- \class QMediaPlayerControl
- \obsolete
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
-
- \brief The QMediaPlayerControl class provides access to the media playing
- functionality of a QMediaService.
-
- If a QMediaService can play media is will implement QMediaPlayerControl.
- 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 {bufferStatus()}{buffering}
- progress.
-
- The functionality provided by this control is exposed to application
- code through the QMediaPlayer class.
-
- The interface name of QMediaPlayerControl is \c org.qt-project.qt.mediaplayercontrol/5.0 as
- defined in QMediaPlayerControl_iid.
-
- \sa QMediaService::requestControl(), QMediaPlayer
-*/
-
-/*!
- \macro QMediaPlayerControl_iid
-
- \c org.qt-project.qt.mediaplayercontrol/5.0
-
- Defines the interface name of the QMediaPlayerControl class.
-
- \relates QMediaPlayerControl
-*/
-
-/*!
- Destroys a media player control.
-*/
-QMediaPlayerControl::~QMediaPlayerControl()
-{
-}
-
-/*!
- Constructs a new media player control with the given \a parent.
-*/
-QMediaPlayerControl::QMediaPlayerControl(QObject *parent):
- QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- \fn QMediaPlayerControl::state() const
-
- Returns the state of a player control.
-*/
-
-/*!
- \fn QMediaPlayerControl::stateChanged(QMediaPlayer::State newState)
-
- Signals that the state of a player control has changed to \a newState.
-
- \sa state()
-*/
-
-/*!
- \fn QMediaPlayerControl::mediaStatus() const
-
- Returns the status of the current media.
-*/
-
-
-/*!
- \fn QMediaPlayerControl::mediaStatusChanged(QMediaPlayer::MediaStatus status)
-
- Signals that the \a status of the current media has changed.
-
- \sa mediaStatus()
-*/
-
-
-/*!
- \fn QMediaPlayerControl::duration() const
-
- Returns the duration of the current media in milliseconds.
-*/
-
-/*!
- \fn QMediaPlayerControl::durationChanged(qint64 duration)
-
- Signals that the \a duration of the current media has changed.
-
- \sa duration()
-*/
-
-/*!
- \fn QMediaPlayerControl::position() const
-
- Returns the current playback position in milliseconds.
-*/
-
-/*!
- \fn QMediaPlayerControl::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 QMediaPlayerControl::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 QMediaPlayerControl::volume() const
-
- Returns the audio volume of a player control.
-*/
-
-/*!
- \fn QMediaPlayerControl::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 QMediaPlayerControl::volumeChanged(int volume)
-
- Signals the audio \a volume of a player control has changed.
-
- \sa volume()
-*/
-
-/*!
- \fn QMediaPlayerControl::isMuted() const
-
- Returns the mute state of a player control.
-*/
-
-/*!
- \fn QMediaPlayerControl::setMuted(bool mute)
-
- Sets the \a mute state of a player control.
-*/
-
-/*!
- \fn QMediaPlayerControl::mutedChanged(bool mute)
-
- Signals a change in the \a mute status of a player control.
-
- \sa isMuted()
-*/
-
-/*!
- \fn QMediaPlayerControl::bufferStatus() const
-
- Returns the buffering progress of the current media. Progress is measured in the percentage
- of the buffer filled.
-*/
-
-/*!
- \fn QMediaPlayerControl::bufferStatusChanged(int percentFilled)
-
- Signal the amount of the local buffer filled as a percentage by \a percentFilled.
-
- \sa bufferStatus()
-*/
-
-/*!
- \fn QMediaPlayerControl::isAudioAvailable() const
-
- Identifies if there is audio output available for the current media.
-
- Returns true if audio output is available and false otherwise.
-*/
-
-/*!
- \fn QMediaPlayerControl::audioAvailableChanged(bool audioAvailable)
-
- Signals that there has been a change in the availability of audio output \a audioAvailable.
-
- \sa isAudioAvailable()
-*/
-
-/*!
- \fn QMediaPlayerControl::isVideoAvailable() const
-
- Identifies if there is video output available for the current media.
-
- Returns true if video output is available and false otherwise.
-*/
-
-/*!
- \fn QMediaPlayerControl::videoAvailableChanged(bool videoAvailable)
-
- Signal that the availability of visual content has changed to \a videoAvailable.
-
- \sa isVideoAvailable()
-*/
-
-/*!
- \fn QMediaPlayerControl::isSeekable() const
-
- Identifies if the current media is seekable.
-
- Returns true if it possible to seek within the current media, and false otherwise.
-*/
-
-/*!
- \fn QMediaPlayerControl::seekableChanged(bool seekable)
-
- Signals that the \a seekable state of a player control has changed.
-
- \sa isSeekable()
-*/
-
-/*!
- \fn QMediaPlayerControl::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 QMediaPlayerControl::availablePlaybackRangesChanged(const QMediaTimeRange &ranges)
-
- Signals that the available media playback \a ranges have changed.
-
- \sa QMediaPlayerControl::availablePlaybackRanges()
-*/
-
-/*!
- \fn qreal QMediaPlayerControl::playbackRate() const
-
- Returns the rate of playback.
-*/
-
-/*!
- \fn QMediaPlayerControl::setPlaybackRate(qreal rate)
-
- Sets the \a rate of playback.
-*/
-
-/*!
- \fn QMediaPlayerControl::media() const
-
- Returns the current media source.
-*/
-
-/*!
- \fn QMediaPlayerControl::mediaStream() const
-
- Returns the current media stream. This is only a valid if a stream was passed to setMedia().
-
- \sa setMedia()
-*/
-
-/*!
- \fn QMediaPlayerControl::setMedia(const QMediaContent &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 QMediaContent 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 service supports
- QMediaServiceProviderHint::StreamPlayback, 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.
-*/
-
-/*!
- \fn QMediaPlayerControl::mediaChanged(const QMediaContent& content)
-
- Signals that the current media \a content has changed.
-*/
-
-/*!
- \fn QMediaPlayerControl::play()
-
- Starts playback of the current media.
-
- If successful the player control will immediately enter the \l {QMediaPlayer::PlayingState}
- {playing} state.
-
- \sa state()
-*/
-
-/*!
- \fn QMediaPlayerControl::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 QMediaPlayerControl::stop()
-
- Stops playback of the current media.
-
- If successful the player control will immediately enter the \l {QMediaPlayer::StoppedState}
- {stopped} state.
-*/
-
-/*!
- \fn QMediaPlayerControl::error(int error, const QString &errorString)
-
- Signals that an \a error has occurred. The \a errorString provides a more detailed explanation.
-*/
-
-/*!
- \fn QMediaPlayerControl::playbackRateChanged(qreal rate)
-
- Signal emitted when playback rate changes to \a rate.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qmediaplayercontrol.cpp"
diff --git a/src/multimedia/controls/qmediaplayercontrol.h b/src/multimedia/controls/qmediaplayercontrol.h
deleted file mode 100644
index 8b5072572..000000000
--- a/src/multimedia/controls/qmediaplayercontrol.h
+++ /dev/null
@@ -1,123 +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 QMEDIAPLAYERCONTROL_H
-#define QMEDIAPLAYERCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmediaplayer.h>
-#include <QtMultimedia/qmediatimerange.h>
-
-#include <QtCore/qpair.h>
-
-QT_BEGIN_NAMESPACE
-
-
-class QMediaPlaylist;
-
-class Q_MULTIMEDIA_EXPORT QMediaPlayerControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- ~QMediaPlayerControl();
-
- virtual QMediaPlayer::State state() const = 0;
-
- virtual QMediaPlayer::MediaStatus mediaStatus() const = 0;
-
- virtual qint64 duration() const = 0;
-
- virtual qint64 position() const = 0;
- virtual void setPosition(qint64 position) = 0;
-
- virtual int volume() const = 0;
- virtual void setVolume(int volume) = 0;
-
- virtual bool isMuted() const = 0;
- virtual void setMuted(bool mute) = 0;
-
- virtual int bufferStatus() const = 0;
-
- virtual bool isAudioAvailable() const = 0;
- virtual bool isVideoAvailable() const = 0;
-
- virtual bool isSeekable() const = 0;
-
- virtual QMediaTimeRange availablePlaybackRanges() const = 0;
-
- virtual qreal playbackRate() const = 0;
- virtual void setPlaybackRate(qreal rate) = 0;
-
- virtual QMediaContent media() const = 0;
- virtual const QIODevice *mediaStream() const = 0;
- virtual void setMedia(const QMediaContent &media, QIODevice *stream) = 0;
-
- virtual void play() = 0;
- virtual void pause() = 0;
- virtual void stop() = 0;
-
-Q_SIGNALS:
- void mediaChanged(const QMediaContent& content);
- void durationChanged(qint64 duration);
- void positionChanged(qint64 position);
- void stateChanged(QMediaPlayer::State newState);
- void mediaStatusChanged(QMediaPlayer::MediaStatus status);
- void volumeChanged(int volume);
- void mutedChanged(bool mute);
- void audioAvailableChanged(bool audioAvailable);
- void videoAvailableChanged(bool videoAvailable);
- void bufferStatusChanged(int percentFilled);
- void seekableChanged(bool seekable);
- void availablePlaybackRangesChanged(const QMediaTimeRange &ranges);
- void playbackRateChanged(qreal rate);
- void error(int error, const QString &errorString);
-
-protected:
- explicit QMediaPlayerControl(QObject *parent = nullptr);
-};
-
-#define QMediaPlayerControl_iid "org.qt-project.qt.mediaplayercontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QMediaPlayerControl, QMediaPlayerControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif // QMEDIAPLAYERCONTROL_H
-
diff --git a/src/multimedia/controls/qmediaplaylistcontrol.cpp b/src/multimedia/controls/qmediaplaylistcontrol.cpp
deleted file mode 100644
index 61e20e170..000000000
--- a/src/multimedia/controls/qmediaplaylistcontrol.cpp
+++ /dev/null
@@ -1,206 +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 "qmediaplaylistcontrol_p.h"
-#include "qmediacontrol_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QMediaPlaylistControl
- \internal
-
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
-
- \brief The QMediaPlaylistControl class provides access to the playlist
- functionality of a QMediaService.
-
- If a QMediaService contains an internal playlist it will implement
- QMediaPlaylistControl. This control provides access to the contents of the
- \l {playlistProvider()}{playlist}, as well as the \l
- {currentIndex()}{position} of the current media, and a means of navigating
- to the \l {next()}{next} and \l {previous()}{previous} media.
-
- The functionality provided by the control is exposed to application code
- through the QMediaPlaylist class.
-
- The interface name of QMediaPlaylistControl is \c org.qt-project.qt.mediaplaylistcontrol/5.0 as
- defined in QMediaPlaylistControl_iid.
-
- \sa QMediaService::requestControl(), QMediaPlayer
-*/
-
-/*!
- \macro QMediaPlaylistControl_iid
-
- \c org.qt-project.qt.mediaplaylistcontrol/5.0
-
- Defines the interface name of the QMediaPlaylistControl class.
-
- \relates QMediaPlaylistControl
-*/
-
-/*!
- Create a new playlist control object with the given \a parent.
-*/
-QMediaPlaylistControl::QMediaPlaylistControl(QObject *parent):
- QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- Destroys the playlist control.
-*/
-QMediaPlaylistControl::~QMediaPlaylistControl()
-{
-}
-
-
-/*!
- \fn QMediaPlaylistControl::playlistProvider() const
-
- Returns the playlist used by this media player.
-*/
-
-/*!
- \fn QMediaPlaylistControl::setPlaylistProvider(QMediaPlaylistProvider *playlist)
-
- Set the playlist of this media player to \a playlist.
-
- In many cases it is possible just to use the playlist
- constructed by player, but sometimes replacing the whole
- playlist allows to avoid copyting of all the items bettween playlists.
-
- Returns true if player can use this passed playlist; otherwise returns false.
-
-*/
-
-/*!
- \fn QMediaPlaylistControl::currentIndex() const
-
- Returns position of the current media source in the playlist.
-*/
-
-/*!
- \fn QMediaPlaylistControl::setCurrentIndex(int position)
-
- Jump to the item at the given \a position.
-*/
-
-/*!
- \fn QMediaPlaylistControl::nextIndex(int step) const
-
- Returns the index of item, which were current after calling next()
- \a step times.
-
- Returned value depends on the size of playlist, current position
- and playback mode.
-
- \sa QMediaPlaylist::playbackMode
-*/
-
-/*!
- \fn QMediaPlaylistControl::previousIndex(int step) const
-
- Returns the index of item, which were current after calling previous()
- \a step times.
-
- \sa QMediaPlaylist::playbackMode
-*/
-
-/*!
- \fn QMediaPlaylistControl::next()
-
- Moves to the next item in playlist.
-*/
-
-/*!
- \fn QMediaPlaylistControl::previous()
-
- Returns to the previous item in playlist.
-*/
-
-/*!
- \fn QMediaPlaylistControl::playbackMode() const
-
- Returns the playlist navigation mode.
-
- \sa QMediaPlaylist::PlaybackMode
-*/
-
-/*!
- \fn QMediaPlaylistControl::setPlaybackMode(QMediaPlaylist::PlaybackMode mode)
-
- Sets the playback \a mode.
-
- \sa QMediaPlaylist::PlaybackMode
-*/
-
-/*!
- \fn QMediaPlaylistControl::playlistProviderChanged()
-
- Signal emitted when the playlist provider has changed.
-*/
-
-/*!
- \fn QMediaPlaylistControl::currentIndexChanged(int position)
-
- Signal emitted when the playlist \a position is changed.
-*/
-
-/*!
- \fn QMediaPlaylistControl::playbackModeChanged(QMediaPlaylist::PlaybackMode mode)
-
- Signal emitted when the playback \a mode is changed.
-*/
-
-/*!
- \fn QMediaPlaylistControl::currentMediaChanged(const QMediaContent& content)
-
- Signal emitted when current media changes to \a content.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qmediaplaylistcontrol_p.cpp"
diff --git a/src/multimedia/controls/qmediaplaylistcontrol_p.h b/src/multimedia/controls/qmediaplaylistcontrol_p.h
deleted file mode 100644
index 93c5a3e25..000000000
--- a/src/multimedia/controls/qmediaplaylistcontrol_p.h
+++ /dev/null
@@ -1,102 +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 QMEDIAPLAYLISTCONTROL_P_H
-#define QMEDIAPLAYLISTCONTROL_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 "qmediacontrol.h"
-#include <private/qmediaplaylistnavigator_p.h>
-
-
-QT_BEGIN_NAMESPACE
-
-
-class QMediaPlaylistProvider;
-
-class Q_MULTIMEDIA_EXPORT QMediaPlaylistControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- virtual ~QMediaPlaylistControl();
-
- virtual QMediaPlaylistProvider* playlistProvider() const = 0;
- virtual bool setPlaylistProvider(QMediaPlaylistProvider *playlist) = 0;
-
- virtual int currentIndex() const = 0;
- virtual void setCurrentIndex(int position) = 0;
- virtual int nextIndex(int steps) const = 0;
- virtual int previousIndex(int steps) const = 0;
-
- virtual void next() = 0;
- virtual void previous() = 0;
-
- virtual QMediaPlaylist::PlaybackMode playbackMode() const = 0;
- virtual void setPlaybackMode(QMediaPlaylist::PlaybackMode mode) = 0;
-
-Q_SIGNALS:
- void playlistProviderChanged();
- void currentIndexChanged(int position);
- void currentMediaChanged(const QMediaContent&);
- void playbackModeChanged(QMediaPlaylist::PlaybackMode mode);
-
-protected:
- QMediaPlaylistControl(QObject *parent = nullptr);
-};
-
-#define QMediaPlaylistControl_iid "org.qt-project.qt.mediaplaylistcontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QMediaPlaylistControl, QMediaPlaylistControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif // QMEDIAPLAYLISTCONTROL_P_H
diff --git a/src/multimedia/controls/qmediaplaylistsourcecontrol.cpp b/src/multimedia/controls/qmediaplaylistsourcecontrol.cpp
deleted file mode 100644
index f95c4b508..000000000
--- a/src/multimedia/controls/qmediaplaylistsourcecontrol.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 "qmediaplaylistsourcecontrol_p.h"
-#include "qmediacontrol_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QMediaPlaylistSourceControl
- \internal
-
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
-
- \brief The QMediaPlaylistSourceControl class provides access to the playlist playback
- functionality of a QMediaService.
-
- This control allows QMediaPlaylist to be passed directly to the service
- instead of playing media sources one by one. This control should be
- implemented if backend benefits from knowing the next media source to be
- played, for example for preloading, cross fading or gap-less playback.
-
- If QMediaPlaylistSourceControl is provided, the backend must listen for
- current playlist item changes to load corresponding media source and
- advance the playlist with QMediaPlaylist::next() when playback of the
- current media is finished.
-
- The interface name of QMediaPlaylistSourceControl is \c org.qt-project.qt.mediaplaylistsourcecontrol/5.0 as
- defined in QMediaPlaylistSourceControl_iid.
-
- \sa QMediaService::requestControl(), QMediaPlayer
-*/
-
-/*!
- \macro QMediaPlaylistSourceControl_iid
-
- \c org.qt-project.qt.mediaplaylistsourcecontrol/5.0
-
- Defines the interface name of the QMediaPlaylistSourceControl class.
-
- \relates QMediaPlaylistSourceControl
-*/
-
-/*!
- Create a new playlist source control object with the given \a parent.
-*/
-QMediaPlaylistSourceControl::QMediaPlaylistSourceControl(QObject *parent):
- QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- Destroys the playlist control.
-*/
-QMediaPlaylistSourceControl::~QMediaPlaylistSourceControl()
-{
-}
-
-
-/*!
- \fn QMediaPlaylistSourceControl::playlist() const
-
- Returns the current playlist.
- Should return a null pointer if no playlist is assigned.
-*/
-
-/*!
- \fn QMediaPlaylistSourceControl::setPlaylist(QMediaPlaylist *playlist)
-
- Set the playlist of this media player to \a playlist.
- If a null pointer is passed, the playlist source should be disabled.
-
- The current media should be replaced with the current item of the media playlist.
-*/
-
-
-/*!
- \fn QMediaPlaylistSourceControl::playlistChanged(QMediaPlaylist* playlist)
-
- Signal emitted when the playlist has changed to \a playlist.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qmediaplaylistsourcecontrol_p.cpp"
diff --git a/src/multimedia/controls/qmediaplaylistsourcecontrol_p.h b/src/multimedia/controls/qmediaplaylistsourcecontrol_p.h
deleted file mode 100644
index a98ee8738..000000000
--- a/src/multimedia/controls/qmediaplaylistsourcecontrol_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 QMEDIAPLAYLISTSOURCECONTROL_P_H
-#define QMEDIAPLAYLISTSOURCECONTROL_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 <qmediacontrol.h>
-
-QT_BEGIN_NAMESPACE
-
-
-class QMediaPlaylist;
-
-class Q_MULTIMEDIA_EXPORT QMediaPlaylistSourceControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- virtual ~QMediaPlaylistSourceControl();
-
- virtual QMediaPlaylist *playlist() const = 0;
- virtual void setPlaylist(QMediaPlaylist *) = 0;
-
-Q_SIGNALS:
- void playlistChanged(QMediaPlaylist* playlist);
-
-protected:
- QMediaPlaylistSourceControl(QObject *parent = nullptr);
-};
-
-#define QMediaPlaylistSourceControl_iid "org.qt-project.qt.mediaplaylistsourcecontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QMediaPlaylistSourceControl, QMediaPlaylistSourceControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif // QMEDIAPLAYLISTCONTROL_P_H
diff --git a/src/multimedia/controls/qmediarecordercontrol.cpp b/src/multimedia/controls/qmediarecordercontrol.cpp
deleted file mode 100644
index 87ace7017..000000000
--- a/src/multimedia/controls/qmediarecordercontrol.cpp
+++ /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$
-**
-****************************************************************************/
-
-#include "qmediarecordercontrol.h"
-
-QT_BEGIN_NAMESPACE
-
-
-/*!
- \class QMediaRecorderControl
- \obsolete
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
- \brief The QMediaRecorderControl class provides access to the recording
- functionality of a QMediaService.
-
- Generally you will use the QMediaRecorder class in application code - this
- class is mostly used when implementing a new QMediaService or if there is
- access to specific low level functionality not otherwise present in QMediaRecorder.
-
- If a QMediaService can record media it will implement QMediaRecorderControl.
- This control provides a means to set the \l {outputLocation()}{output location},
- and record, pause and stop recording via the \l setState() method. It also
- provides feedback on the \l {duration()}{duration} of the recording.
-
- The interface name of QMediaRecorderControl is \c org.qt-project.qt.mediarecordercontrol/5.0 as
- defined in QMediaRecorderControl_iid.
-
- \sa QMediaService::requestControl(), QMediaRecorder
-
-*/
-
-/*!
- \macro QMediaRecorderControl_iid
-
- \c org.qt-project.qt.mediarecordercontrol/5.0
-
- Defines the interface name of the QMediaRecorderControl class.
-
- \relates QMediaRecorderControl
-*/
-
-/*!
- Constructs a media recorder control with the given \a parent.
-*/
-
-QMediaRecorderControl::QMediaRecorderControl(QObject* parent)
- : QMediaControl(parent)
-{
-}
-
-/*!
- Destroys a media recorder control.
-*/
-
-QMediaRecorderControl::~QMediaRecorderControl()
-{
-}
-
-/*!
- \fn QUrl QMediaRecorderControl::outputLocation() const
-
- Returns the current output location being used.
-*/
-
-/*!
- \fn bool QMediaRecorderControl::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::State QMediaRecorderControl::state() const
-
- Return the current recording state.
-*/
-
-/*!
- \fn QMediaRecorder::Status QMediaRecorderControl::status() const
-
- Return the current recording status.
-*/
-
-/*!
- \fn qint64 QMediaRecorderControl::duration() const
-
- Return the current duration in milliseconds.
-*/
-
-/*!
- \fn void QMediaRecorderControl::setState(QMediaRecorder::State state)
-
- Set the media recorder \a state.
-*/
-
-/*!
- \fn void QMediaRecorderControl::applySettings()
-
- Commits the encoder settings and performs pre-initialization to reduce delays when recording
- is started.
-*/
-
-/*!
- \fn bool QMediaRecorderControl::isMuted() const
-
- Returns true if the recorder is muted, and false if it is not.
-*/
-
-/*!
- \fn void QMediaRecorderControl::setMuted(bool muted)
-
- Sets the \a muted state of a media recorder.
-*/
-
-/*!
- \fn qreal QMediaRecorderControl::volume() const
-
- Returns the audio volume of a media recorder control.
-*/
-
-/*!
- \fn void QMediaRecorderControl::setVolume(qreal volume)
-
- Sets the audio \a volume of a media recorder control.
-
- The volume is scaled linearly, ranging from \c 0 (silence) to \c 100 (full volume).
-*/
-
-/*!
- \fn void QMediaRecorderControl::stateChanged(QMediaRecorder::State state)
-
- Signals that the \a state of a media recorder has changed.
-*/
-
-/*!
- \fn void QMediaRecorderControl::statusChanged(QMediaRecorder::Status status)
-
- Signals that the \a status of a media recorder has changed.
-*/
-
-
-/*!
- \fn void QMediaRecorderControl::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.
-*/
-
-/*!
- \fn void QMediaRecorderControl::mutedChanged(bool muted)
-
- Signals that the \a muted state of a media recorder has changed.
-*/
-
-/*!
- \fn void QMediaRecorderControl::volumeChanged(qreal gain)
-
- Signals that the audio \a gain value has changed.
-*/
-
-/*!
- \fn void QMediaRecorderControl::actualLocationChanged(const QUrl &location)
-
- Signals that the actual media \a location has changed.
- This signal should be emitted at start of recording.
-*/
-
-/*!
- \fn void QMediaRecorderControl::error(int error, const QString &errorString)
-
- Signals that an \a error has occurred. The \a errorString describes the error.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qmediarecordercontrol.cpp"
diff --git a/src/multimedia/controls/qmediarecordercontrol.h b/src/multimedia/controls/qmediarecordercontrol.h
deleted file mode 100644
index a0529ce59..000000000
--- a/src/multimedia/controls/qmediarecordercontrol.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 QMEDIARECORDERCONTROL_H
-#define QMEDIARECORDERCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmediarecorder.h>
-
-QT_BEGIN_NAMESPACE
-
-class QUrl;
-QT_END_NAMESPACE
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QMediaRecorderControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- virtual ~QMediaRecorderControl();
-
- virtual QUrl outputLocation() const = 0;
- virtual bool setOutputLocation(const QUrl &location) = 0;
-
- virtual QMediaRecorder::State state() const = 0;
- virtual QMediaRecorder::Status status() const = 0;
-
- virtual qint64 duration() const = 0;
-
- virtual bool isMuted() const = 0;
- virtual qreal volume() const = 0;
-
- virtual void applySettings() = 0;
-
-Q_SIGNALS:
- void stateChanged(QMediaRecorder::State state);
- void statusChanged(QMediaRecorder::Status status);
- void durationChanged(qint64 position);
- void mutedChanged(bool muted);
- void volumeChanged(qreal volume);
- void actualLocationChanged(const QUrl &location);
- void error(int error, const QString &errorString);
-
-public Q_SLOTS:
- virtual void setState(QMediaRecorder::State state) = 0;
- virtual void setMuted(bool muted) = 0;
- virtual void setVolume(qreal volume) = 0;
-
-protected:
- explicit QMediaRecorderControl(QObject *parent = nullptr);
-};
-
-#define QMediaRecorderControl_iid "org.qt-project.qt.mediarecordercontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QMediaRecorderControl, QMediaRecorderControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif
diff --git a/src/multimedia/controls/qmediastreamscontrol.cpp b/src/multimedia/controls/qmediastreamscontrol.cpp
deleted file mode 100644
index 2db9eb6fc..000000000
--- a/src/multimedia/controls/qmediastreamscontrol.cpp
+++ /dev/null
@@ -1,161 +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 "qmediastreamscontrol.h"
-#include "qmediacontrol_p.h"
-
-QT_BEGIN_NAMESPACE
-
-static void qRegisterMediaStreamControlMetaTypes()
-{
- qRegisterMetaType<QMediaStreamsControl::StreamType>();
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterMediaStreamControlMetaTypes)
-
-
-/*!
- \class QMediaStreamsControl
- \obsolete
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
- \brief The QMediaStreamsControl class provides a media stream selection control.
-
-
- The QMediaStreamsControl class provides descriptions of the available media streams
- and allows individual streams to be activated and deactivated.
-
- The interface name of QMediaStreamsControl is \c org.qt-project.qt.mediastreamscontrol/5.0 as
- defined in QMediaStreamsControl_iid.
-
- \sa QMediaService::requestControl()
-*/
-
-/*!
- \macro QMediaStreamsControl_iid
-
- \c org.qt-project.qt.mediastreamscontrol/5.0
-
- Defines the interface name of the QMediaStreamsControl class.
-
- \relates QMediaStreamsControl
-*/
-
-/*!
- Constructs a new media streams control with the given \a parent.
-*/
-QMediaStreamsControl::QMediaStreamsControl(QObject *parent)
- :QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- Destroys a media streams control.
-*/
-QMediaStreamsControl::~QMediaStreamsControl()
-{
-}
-
-/*!
- \enum QMediaStreamsControl::StreamType
-
- Media stream type.
-
- \value AudioStream Audio stream.
- \value VideoStream Video stream.
- \value SubPictureStream Subpicture or teletext stream.
- \value UnknownStream The stream type is unknown.
- \value DataStream
-*/
-
-/*!
- \fn QMediaStreamsControl::streamCount()
-
- Returns the number of media streams.
-*/
-
-/*!
- \fn QMediaStreamsControl::streamType(int streamNumber)
-
- Return the type of media stream \a streamNumber.
-*/
-
-/*!
- \fn QMediaStreamsControl::metaData(int streamNumber, const QString &key)
-
- Returns the meta-data value of \a key for the given \a streamNumber.
-
- Useful metadata keys are QMediaMetaData::Title,
- QMediaMetaData::Description and QMediaMetaData::Language.
-*/
-
-/*!
- \fn QMediaStreamsControl::isActive(int streamNumber)
-
- Returns true if the media stream \a streamNumber is active.
-*/
-
-/*!
- \fn QMediaStreamsControl::setActive(int streamNumber, bool state)
-
- Sets the active \a state of media stream \a streamNumber.
-
- Setting the active state of a media stream to true will activate it. If any other stream
- of the same type was previously active it will be deactivated. Setting the active state fo a
- media stream to false will deactivate it.
-*/
-
-/*!
- \fn QMediaStreamsControl::streamsChanged()
-
- The signal is emitted when the available streams list is changed.
-*/
-
-/*!
- \fn QMediaStreamsControl::activeStreamsChanged()
-
- The signal is emitted when the active streams list is changed.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qmediastreamscontrol.cpp"
diff --git a/src/multimedia/controls/qmediastreamscontrol.h b/src/multimedia/controls/qmediastreamscontrol.h
deleted file mode 100644
index e2506882d..000000000
--- a/src/multimedia/controls/qmediastreamscontrol.h
+++ /dev/null
@@ -1,89 +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 QMEDIASTREAMSCONTROL_H
-#define QMEDIASTREAMSCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmultimedia.h>
-#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qmediaenumdebug.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QMediaStreamsControl : public QMediaControl
-{
- Q_OBJECT
- Q_ENUMS(SteamType)
-public:
- enum StreamType { UnknownStream, VideoStream, AudioStream, SubPictureStream, DataStream };
-
- virtual ~QMediaStreamsControl();
-
- virtual int streamCount() = 0;
- virtual StreamType streamType(int streamNumber) = 0;
-
- virtual QVariant metaData(int streamNumber, const QString &key) = 0;
-
- virtual bool isActive(int streamNumber) = 0;
- virtual void setActive(int streamNumber, bool state) = 0;
-
-Q_SIGNALS:
- void streamsChanged();
- void activeStreamsChanged();
-
-protected:
- explicit QMediaStreamsControl(QObject *parent = nullptr);
-};
-
-#define QMediaStreamsControl_iid "org.qt-project.qt.mediastreamscontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QMediaStreamsControl, QMediaStreamsControl_iid)
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QMediaStreamsControl::StreamType)
-
-Q_MEDIA_ENUM_DEBUG(QMediaStreamsControl, StreamType)
-
-#endif // QMEDIASTREAMSCONTROL_H
-
diff --git a/src/multimedia/controls/qmediavideoprobecontrol.cpp b/src/multimedia/controls/qmediavideoprobecontrol.cpp
deleted file mode 100644
index 4a85d56d0..000000000
--- a/src/multimedia/controls/qmediavideoprobecontrol.cpp
+++ /dev/null
@@ -1,102 +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 "qmediavideoprobecontrol.h"
-#include "qmediacontrol_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QMediaVideoProbeControl
- \obsolete
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
- \brief The QMediaVideoProbeControl class allows control over probing video frames in media objects.
-
- \l QVideoProbe is the client facing class for probing video - this class is implemented by
- media backends to provide this functionality.
-
- The interface name of QMediaVideoProbeControl is \c org.qt-project.qt.mediavideoprobecontrol/5.0 as
- defined in QMediaVideoProbeControl_iid.
-
- \sa QVideoProbe, QMediaService::requestControl(), QMediaPlayer, QCamera
-*/
-
-/*!
- \macro QMediaVideoProbeControl_iid
-
- \c org.qt-project.qt.mediavideoprobecontrol/5.0
-
- Defines the interface name of the QMediaVideoProbeControl class.
-
- \relates QMediaVideoProbeControl
-*/
-
-/*!
- Create a new media video probe control object with the given \a parent.
-*/
-QMediaVideoProbeControl::QMediaVideoProbeControl(QObject *parent)
- : QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*! Destroys this video probe control */
-QMediaVideoProbeControl::~QMediaVideoProbeControl()
-{
-}
-
-/*!
- \fn QMediaVideoProbeControl::videoFrameProbed(const QVideoFrame &frame)
-
- This signal should be emitted when a video \a frame is processed in the
- media service.
-*/
-
-/*!
- \fn QMediaVideoProbeControl::flush()
-
- This signal should be emitted when it is required to release all frames.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qmediavideoprobecontrol.cpp"
diff --git a/src/multimedia/controls/qmediavideoprobecontrol.h b/src/multimedia/controls/qmediavideoprobecontrol.h
deleted file mode 100644
index 363975055..000000000
--- a/src/multimedia/controls/qmediavideoprobecontrol.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 QMEDIAVIDEOPROBECONTROL_H
-#define QMEDIAVIDEOPROBECONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-
-QT_BEGIN_NAMESPACE
-
-class QVideoFrame;
-class Q_MULTIMEDIA_EXPORT QMediaVideoProbeControl : public QMediaControl
-{
- Q_OBJECT
-public:
- virtual ~QMediaVideoProbeControl();
-
-Q_SIGNALS:
- void videoFrameProbed(const QVideoFrame &frame);
- void flush();
-
-protected:
- explicit QMediaVideoProbeControl(QObject *parent = nullptr);
-};
-
-#define QMediaVideoProbeControl_iid "org.qt-project.qt.mediavideoprobecontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QMediaVideoProbeControl, QMediaVideoProbeControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif // QMEDIAVIDEOPROBECONTROL_H
diff --git a/src/multimedia/controls/qmetadatareadercontrol.cpp b/src/multimedia/controls/qmetadatareadercontrol.cpp
deleted file mode 100644
index f01ffec38..000000000
--- a/src/multimedia/controls/qmetadatareadercontrol.cpp
+++ /dev/null
@@ -1,149 +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 "qmediacontrol_p.h"
-#include <qmetadatareadercontrol.h>
-
-QT_BEGIN_NAMESPACE
-
-
-/*!
- \class QMetaDataReaderControl
- \obsolete
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
-
- \brief The QMetaDataReaderControl class provides read access to the
- meta-data of a QMediaService's media.
-
- If a QMediaService can provide read or write access to the meta-data of
- its current media it will implement QMetaDataReaderControl. This control
- provides functions for both retrieving and setting meta-data values.
- Meta-data may be addressed by the keys defined in the
- QMediaMetaData namespace.
-
- The functionality provided by this control is exposed to application
- code by the meta-data members of QMediaObject, and so meta-data access
- is potentially available in any of the media object classes. Any media
- service may implement QMetaDataReaderControl.
-
- The interface name of QMetaDataReaderControl is
- \c org.qt-project.qt.metadatareadercontrol/5.0 as defined in
- QMetaDataReaderControl_iid.
-
- \sa QMediaService::requestControl(), QMediaObject
-*/
-
-/*!
- \macro QMetaDataReaderControl_iid
-
- \c org.qt-project.qt.metadatareadercontrol/5.0
-
- Defines the interface name of the QMetaDataReaderControl class.
-
- \relates QMetaDataReaderControl
-*/
-
-/*!
- Construct a QMetaDataReaderControl with \a parent. This class is meant as a base class
- for service specific meta data providers so this constructor is protected.
-*/
-
-QMetaDataReaderControl::QMetaDataReaderControl(QObject *parent):
- QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- Destroy the meta-data object.
-*/
-
-QMetaDataReaderControl::~QMetaDataReaderControl()
-{
-}
-
-/*!
- \fn bool QMetaDataReaderControl::isMetaDataAvailable() const
-
- Identifies if meta-data is available from a media service.
-
- Returns true if the meta-data is available and false otherwise.
-*/
-
-/*!
- \fn QVariant QMetaDataReaderControl::metaData(const QString &key) const
-
- Returns the meta-data for the given \a key.
-*/
-
-/*!
- \fn QMetaDataReaderControl::availableMetaData() const
-
- Returns a list of keys there is meta-data available for.
-*/
-
-/*!
- \fn void QMetaDataReaderControl::metaDataChanged()
-
- Signal the changes of meta-data.
-
- If multiple meta-data elements are changed,
- metaDataChanged(const QString &key, const QVariant &value) signal is emitted
- for each of them with metaDataChanged() changed emitted once.
-*/
-
-/*!
- \fn void QMetaDataReaderControl::metaDataChanged(const QString &key, const QVariant &value)
-
- Signal the changes of one meta-data element \a value with the given \a key.
-*/
-
-/*!
- \fn void QMetaDataReaderControl::metaDataAvailableChanged(bool available)
-
- Signal the availability of meta-data has changed, \a available will
- be true if the multimedia object has meta-data.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qmetadatareadercontrol.cpp"
diff --git a/src/multimedia/controls/qmetadatareadercontrol.h b/src/multimedia/controls/qmetadatareadercontrol.h
deleted file mode 100644
index b13c7ea00..000000000
--- a/src/multimedia/controls/qmetadatareadercontrol.h
+++ /dev/null
@@ -1,81 +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 QMETADATAREADERCONTROL_H
-#define QMETADATAREADERCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmediaobject.h>
-
-#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qmultimedia.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QMetaDataReaderControl : public QMediaControl
-{
- Q_OBJECT
-public:
- ~QMetaDataReaderControl();
-
- virtual bool isMetaDataAvailable() const = 0;
-
- virtual QVariant metaData(const QString &key) const = 0;
- virtual QStringList availableMetaData() const = 0;
-
-Q_SIGNALS:
- void metaDataChanged();
- void metaDataChanged(const QString &key, const QVariant &value);
-
- void metaDataAvailableChanged(bool available);
-
-protected:
- explicit QMetaDataReaderControl(QObject *parent = nullptr);
-};
-
-#define QMetaDataReaderControl_iid "org.qt-project.qt.metadatareadercontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QMetaDataReaderControl, QMetaDataReaderControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif // QMETADATAPROVIDER_H
diff --git a/src/multimedia/controls/qmetadatawritercontrol.cpp b/src/multimedia/controls/qmetadatawritercontrol.cpp
deleted file mode 100644
index 6221edaa1..000000000
--- a/src/multimedia/controls/qmetadatawritercontrol.cpp
+++ /dev/null
@@ -1,169 +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 "qmediacontrol_p.h"
-#include <qmetadatawritercontrol.h>
-
-QT_BEGIN_NAMESPACE
-
-
-/*!
- \class QMetaDataWriterControl
- \obsolete
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
-
- \brief The QMetaDataWriterControl class provides write access to the
- meta-data of a QMediaService's media.
-
- If a QMediaService can provide write access to the meta-data of its
- current media it will implement QMetaDataWriterControl. This control
- provides functions for both retrieving and setting meta-data values.
- Meta-data may be addressed by the keys defined in the
- QMediaMetaData namespace.
-
- The functionality provided by this control is exposed to application code
- by the meta-data members of QMediaObject, and so meta-data access is
- potentially available in any of the media object classes. Any media
- service may implement QMetaDataControl.
-
- The interface name of QMetaDataWriterControl is \c org.qt-project.qt.metadatawritercontrol/5.0 as
- defined in QMetaDataWriterControl_iid.
-
- \sa QMediaService::requestControl(), QMediaObject
-*/
-
-/*!
- \macro QMetaDataWriterControl_iid
-
- \c org.qt-project.qt.metadatawritercontrol/5.0
-
- Defines the interface name of the QMetaDataWriterControl class.
-
- \relates QMetaDataWriterControl
-*/
-
-/*!
- Construct a QMetaDataWriterControl with \a parent. This class is meant as a base class
- for service specific meta data providers so this constructor is protected.
-*/
-
-QMetaDataWriterControl::QMetaDataWriterControl(QObject *parent):
- QMediaControl(*new QMediaControlPrivate, parent)
-{
-}
-
-/*!
- Destroy the meta-data writer control.
-*/
-
-QMetaDataWriterControl::~QMetaDataWriterControl()
-{
-}
-
-/*!
- \fn bool QMetaDataWriterControl::isMetaDataAvailable() const
-
- Identifies if meta-data is available from a media service.
-
- Returns true if the meta-data is available and false otherwise.
-*/
-
-/*!
- \fn bool QMetaDataWriterControl::isWritable() const
-
- Identifies if a media service's meta-data can be edited.
-
- Returns true if the meta-data is writable and false otherwise.
-*/
-
-/*!
- \fn QVariant QMetaDataWriterControl::metaData(const QString &key) const
-
- Returns the meta-data for the given \a key.
-*/
-
-/*!
- \fn void QMetaDataWriterControl::setMetaData(const QString &key, const QVariant &value)
-
- Sets the \a value of the meta-data element with the given \a key.
-*/
-
-/*!
- \fn QMetaDataWriterControl::availableMetaData() const
-
- Returns a list of keys there is meta-data available for.
-*/
-
-/*!
- \fn void QMetaDataWriterControl::metaDataChanged()
-
- Signal the changes of meta-data.
-
- If multiple meta-data elements are changed,
- metaDataChanged(const QString &key, const QVariant &value) signal is emitted
- for each of them with metaDataChanged() changed emitted once.
-*/
-
-/*!
- \fn void QMetaDataWriterControl::metaDataChanged(const QString &key, const QVariant &value)
-
- Signal the changes of one meta-data element \a value with the given \a key.
-*/
-
-/*!
- \fn void QMetaDataWriterControl::metaDataAvailableChanged(bool available)
-
- Signal the availability of meta-data has changed, \a available will
- be true if the multimedia object has meta-data.
-*/
-
-/*!
- \fn void QMetaDataWriterControl::writableChanged(bool writable)
-
- Signal a change in the writable status of meta-data, \a writable will be
- true if meta-data elements can be added or adjusted.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qmetadatawritercontrol.cpp"
diff --git a/src/multimedia/controls/qmetadatawritercontrol.h b/src/multimedia/controls/qmetadatawritercontrol.h
deleted file mode 100644
index a1d4449c3..000000000
--- a/src/multimedia/controls/qmetadatawritercontrol.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 QMETADATAWRITERCONTROL_H
-#define QMETADATAWRITERCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmediaobject.h>
-
-#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qmultimedia.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QMetaDataWriterControl : public QMediaControl
-{
- Q_OBJECT
-public:
- ~QMetaDataWriterControl();
-
- virtual bool isWritable() const = 0;
- virtual bool isMetaDataAvailable() const = 0;
-
- virtual QVariant metaData(const QString &key) const = 0;
- virtual void setMetaData(const QString &key, const QVariant &value) = 0;
- virtual QStringList availableMetaData() const = 0;
-
-Q_SIGNALS:
- void metaDataChanged();
- void metaDataChanged(const QString &key, const QVariant &value);
-
- void writableChanged(bool writable);
- void metaDataAvailableChanged(bool available);
-
-protected:
- explicit QMetaDataWriterControl(QObject *parent = nullptr);
-};
-
-#define QMetaDataWriterControl_iid "org.qt-project.qt.metadatawritercontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QMetaDataWriterControl, QMetaDataWriterControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif
diff --git a/src/multimedia/controls/qvideodeviceselectorcontrol.cpp b/src/multimedia/controls/qvideodeviceselectorcontrol.cpp
deleted file mode 100644
index 420ba9150..000000000
--- a/src/multimedia/controls/qvideodeviceselectorcontrol.cpp
+++ /dev/null
@@ -1,143 +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 "qvideodeviceselectorcontrol.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QVideoDeviceSelectorControl
- \obsolete
-
- \brief The QVideoDeviceSelectorControl class provides an video device selector media control.
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
- The QVideoDeviceSelectorControl class provides descriptions of the video devices
- available on a system and allows one to be selected as the endpoint of a
- media service.
-
- The interface name of QVideoDeviceSelectorControl is \c org.qt-project.qt.videodeviceselectorcontrol/5.0 as
- defined in QVideoDeviceSelectorControl_iid.
-*/
-
-/*!
- \macro QVideoDeviceSelectorControl_iid
-
- \c org.qt-project.qt.videodeviceselectorcontrol/5.0
-
- Defines the interface name of the QVideoDeviceSelectorControl class.
-
- \relates QVideoDeviceSelectorControl
-*/
-
-/*!
- Constructs a video device selector control with the given \a parent.
-*/
-QVideoDeviceSelectorControl::QVideoDeviceSelectorControl(QObject *parent)
- :QMediaControl(parent)
-{
-}
-
-/*!
- Destroys a video device selector control.
-*/
-QVideoDeviceSelectorControl::~QVideoDeviceSelectorControl()
-{
-}
-
-/*!
- \fn QVideoDeviceSelectorControl::deviceCount() const
-
- Returns the number of available video devices;
-*/
-
-/*!
- \fn QVideoDeviceSelectorControl::deviceName(int index) const
-
- Returns the name of the video device at \a index.
-*/
-
-/*!
- \fn QVideoDeviceSelectorControl::deviceDescription(int index) const
-
- Returns a description of the video device at \a index.
-*/
-
-/*!
- \fn QVideoDeviceSelectorControl::defaultDevice() const
-
- Returns the index of the default video device.
-*/
-
-/*!
- \fn QVideoDeviceSelectorControl::selectedDevice() const
-
- Returns the index of the selected video device.
-*/
-
-/*!
- \fn QVideoDeviceSelectorControl::setSelectedDevice(int index)
-
- Sets the selected video device \a index.
-*/
-
-/*!
- \fn QVideoDeviceSelectorControl::devicesChanged()
-
- Signals that the list of available video devices has changed.
-*/
-
-/*!
- \fn QVideoDeviceSelectorControl::selectedDeviceChanged(int index)
-
- Signals that the selected video device \a index has changed.
-*/
-
-/*!
- \fn QVideoDeviceSelectorControl::selectedDeviceChanged(const QString &name)
-
- Signals that the selected video device \a name has changed.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qvideodeviceselectorcontrol.cpp"
diff --git a/src/multimedia/controls/qvideodeviceselectorcontrol.h b/src/multimedia/controls/qvideodeviceselectorcontrol.h
deleted file mode 100644
index 4697196ce..000000000
--- a/src/multimedia/controls/qvideodeviceselectorcontrol.h
+++ /dev/null
@@ -1,82 +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 QVIDEODEVICESELECTORCONTROL_H
-#define QVIDEODEVICESELECTORCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QVideoDeviceSelectorControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- virtual ~QVideoDeviceSelectorControl();
-
- virtual int deviceCount() const = 0;
-
- virtual QString deviceName(int index) const = 0;
- virtual QString deviceDescription(int index) const = 0;
-
- virtual int defaultDevice() const = 0;
- virtual int selectedDevice() const = 0;
-
-public Q_SLOTS:
- virtual void setSelectedDevice(int index) = 0;
-
-Q_SIGNALS:
- void selectedDeviceChanged(int index);
- void selectedDeviceChanged(const QString &name);
- void devicesChanged();
-
-protected:
- explicit QVideoDeviceSelectorControl(QObject *parent = nullptr);
-};
-
-#define QVideoDeviceSelectorControl_iid "org.qt-project.qt.videodeviceselectorcontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QVideoDeviceSelectorControl, QVideoDeviceSelectorControl_iid)
-
-QT_END_NAMESPACE
-
-#endif // QVIDEODEVICESELECTORCONTROL_H
diff --git a/src/multimedia/controls/qvideoencodersettingscontrol.cpp b/src/multimedia/controls/qvideoencodersettingscontrol.cpp
deleted file mode 100644
index 64643f6db..000000000
--- a/src/multimedia/controls/qvideoencodersettingscontrol.cpp
+++ /dev/null
@@ -1,161 +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 "qvideoencodersettingscontrol.h"
-#include <QtCore/qstringlist.h>
-#include <QtCore/qvariant.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QVideoEncoderSettingsControl
- \obsolete
-
- \inmodule QtMultimedia
-
-
- \ingroup multimedia_control
-
- \brief The QVideoEncoderSettingsControl class provides access to the settings
- of a media service that performs video encoding.
-
- If a QMediaService supports encoding video data it will implement
- QVideoEncoderSettingsControl. This control provides information about the limits
- of restricted video encoder options and allows the selection of a set of
- video encoder settings as specified in a QVideoEncoderSettings object.
-
- The functionality provided by this control is exposed to application code
- through the QMediaRecorder class.
-
- The interface name of QVideoEncoderSettingsControl is \c org.qt-project.qt.videoencodersettingscontrol/5.0 as
- defined in QVideoEncoderSettingsControl_iid.
-
- \sa QMediaRecorder, QVideoEncoderSettings, QMediaService::requestControl()
-*/
-
-/*!
- \macro QVideoEncoderSettingsControl_iid
-
- \c org.qt-project.qt.videoencodersettingscontrol/5.0
-
- Defines the interface name of the QVideoEncoderSettingsControl class.
-
- \relates QVideoEncoderSettingsControl
-*/
-
-/*!
- Create a new video encoder settings control object with the given \a parent.
-*/
-QVideoEncoderSettingsControl::QVideoEncoderSettingsControl(QObject *parent)
- :QMediaControl(parent)
-{
-}
-
-/*!
- Destroys a video encoder settings control.
-*/
-QVideoEncoderSettingsControl::~QVideoEncoderSettingsControl()
-{
-}
-
-/*!
- \fn QVideoEncoderSettingsControl::supportedVideoCodecs() const
-
- Returns the list of supported video codecs.
-*/
-
-/*!
- \fn QVideoEncoderSettingsControl::videoCodecDescription(const QString &codec) const
-
- Returns a description of a video \a codec.
-*/
-
-/*!
- \fn QVideoEncoderSettingsControl::supportedResolutions(const QVideoEncoderSettings &settings = QVideoEncoderSettings(),
- bool *continuous = 0) const
-
- Returns a list of supported resolutions.
-
- If non null video \a settings parameter is passed,
- the returned list is reduced to resolution supported with partial settings like
- \l {QVideoEncoderSettings::setCodec()}{video codec} or
- \l {QVideoEncoderSettings::setFrameRate()}{frame rate} applied.
-
- If the encoder supports arbitrary resolutions within the supported resolutions range,
- *\a continuous is set to true, otherwise *\a continuous is set to false.
-
- \sa QVideoEncoderSettings::resolution()
-*/
-
-/*!
- \fn QVideoEncoderSettingsControl::supportedFrameRates(const QVideoEncoderSettings &settings = QVideoEncoderSettings(),
- bool *continuous = 0) const
-
- Returns a list of supported frame rates.
-
- If non null video \a settings parameter is passed,
- the returned list is reduced to frame rates supported with partial settings like
- \l {QVideoEncoderSettings::setCodec()}{video codec} or
- \l {QVideoEncoderSettings::setResolution()}{video resolution} applied.
-
- If the encoder supports arbitrary frame rates within the supported range,
- *\a continuous is set to true, otherwise *\a continuous is set to false.
-
- \sa QVideoEncoderSettings::frameRate()
-*/
-
-/*!
- \fn QVideoEncoderSettingsControl::videoSettings() const
-
- Returns the video encoder settings.
-
- The returned value may be different tha passed to QVideoEncoderSettingsControl::setVideoSettings()
- if the settings contains the default or undefined parameters.
- In this case if the undefined parameters are already resolved, they should be returned.
-*/
-
-/*!
- \fn QVideoEncoderSettingsControl::setVideoSettings(const QVideoEncoderSettings &settings)
-
- Sets the selected video encoder \a settings.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qvideoencodersettingscontrol.cpp"
diff --git a/src/multimedia/controls/qvideoencodersettingscontrol.h b/src/multimedia/controls/qvideoencodersettingscontrol.h
deleted file mode 100644
index ac13833d1..000000000
--- a/src/multimedia/controls/qvideoencodersettingscontrol.h
+++ /dev/null
@@ -1,88 +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 QVIDEOENCODERSETTINGSCONTROL_H
-#define QVIDEOENCODERSETTINGSCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtMultimedia/qmediarecorder.h>
-
-#include <QtCore/qpair.h>
-#include <QtCore/qsize.h>
-
-QT_BEGIN_NAMESPACE
-
-class QByteArray;
-QT_END_NAMESPACE
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QVideoEncoderSettingsControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- virtual ~QVideoEncoderSettingsControl();
-
- virtual QList<QSize> supportedResolutions(const QVideoEncoderSettings &settings,
- bool *continuous = nullptr) const = 0;
-
- virtual QList<qreal> supportedFrameRates(const QVideoEncoderSettings &settings,
- bool *continuous = nullptr) const = 0;
-
- virtual QStringList supportedVideoCodecs() const = 0;
- virtual QString videoCodecDescription(const QString &codec) const = 0;
-
- virtual QVideoEncoderSettings videoSettings() const = 0;
- virtual void setVideoSettings(const QVideoEncoderSettings &settings) = 0;
-
-protected:
- explicit QVideoEncoderSettingsControl(QObject *parent = nullptr);
-};
-
-#define QVideoEncoderSettingsControl_iid "org.qt-project.qt.videoencodersettingscontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QVideoEncoderSettingsControl, QVideoEncoderSettingsControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif
diff --git a/src/multimedia/controls/qvideorenderercontrol.cpp b/src/multimedia/controls/qvideorenderercontrol.cpp
deleted file mode 100644
index eee20d59e..000000000
--- a/src/multimedia/controls/qvideorenderercontrol.cpp
+++ /dev/null
@@ -1,109 +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 "qvideorenderercontrol.h"
-
-#include "qmediacontrol_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QVideoRendererControl
- \obsolete
-
- \inmodule QtMultimedia
- \brief The QVideoRendererControl class provides a media control for rendering video to a QAbstractVideoSurface.
-
-
- \ingroup multimedia_control
-
- Using the surface() property of QVideoRendererControl a
- QAbstractVideoSurface may be set as the video render target of a
- QMediaService.
-
- \snippet multimedia-snippets/video.cpp Video renderer control
-
- QVideoRendererControl is one of a number of possible video output controls.
-
- The interface name of QVideoRendererControl is \c org.qt-project.qt.videorenderercontrol/5.0 as
- defined in QVideoRendererControl_iid.
-
- \sa QMediaService::requestControl(), QVideoWidget
-*/
-
-/*!
- \macro QVideoRendererControl_iid
-
- \c org.qt-project.qt.videorenderercontrol/5.0
-
- Defines the interface name of the QVideoRendererControl class.
-
- \relates QVideoRendererControl
-*/
-
-/*!
- Constructs a new video renderer media end point with the given \a parent.
-*/
-QVideoRendererControl::QVideoRendererControl(QObject *parent)
- : QMediaControl(parent)
-{
-}
-
-/*!
- Destroys a video renderer media end point.
-*/
-QVideoRendererControl::~QVideoRendererControl()
-{
-}
-
-/*!
- \fn QVideoRendererControl::surface() const
-
- Returns the surface a video producer renders to.
-*/
-
-/*!
- \fn QVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
-
- Sets the \a surface a video producer renders to.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qvideorenderercontrol.cpp"
diff --git a/src/multimedia/controls/qvideorenderercontrol.h b/src/multimedia/controls/qvideorenderercontrol.h
deleted file mode 100644
index 87552271a..000000000
--- a/src/multimedia/controls/qvideorenderercontrol.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 QVIDEORENDERERCONTROL_H
-#define QVIDEORENDERERCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-
-QT_BEGIN_NAMESPACE
-
-class QAbstractVideoSurface;
-class Q_MULTIMEDIA_EXPORT QVideoRendererControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- ~QVideoRendererControl();
-
- virtual QAbstractVideoSurface *surface() const = 0;
- virtual void setSurface(QAbstractVideoSurface *surface) = 0;
-
-protected:
- explicit QVideoRendererControl(QObject *parent = nullptr);
-};
-
-#define QVideoRendererControl_iid "org.qt-project.qt.videorenderercontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QVideoRendererControl, QVideoRendererControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif // QVIDEORENDERERCONTROL_H
diff --git a/src/multimedia/controls/qvideowindowcontrol.cpp b/src/multimedia/controls/qvideowindowcontrol.cpp
deleted file mode 100644
index a6b2bf407..000000000
--- a/src/multimedia/controls/qvideowindowcontrol.cpp
+++ /dev/null
@@ -1,259 +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 "qvideowindowcontrol.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QVideoWindowControl
- \obsolete
-
- \inmodule QtMultimedia
-
- \ingroup multimedia_control
- \brief The QVideoWindowControl class provides a media control for rendering video to a window.
-
-
- The winId() property QVideoWindowControl allows a platform specific window
- ID to be set as the video render target of a QMediaService. The
- displayRect() property is used to set the region of the window the video
- should be rendered to, and the aspectRatioMode() property indicates how the
- video should be scaled to fit the displayRect().
-
- \snippet multimedia-snippets/video.cpp Video window control
-
- QVideoWindowControl is one of a number of possible video output controls.
-
- The interface name of QVideoWindowControl is \c org.qt-project.qt.videowindowcontrol/5.0 as
- defined in QVideoWindowControl_iid.
-
- \sa QMediaService::requestControl(), QVideoWidget
-*/
-
-/*!
- \macro QVideoWindowControl_iid
-
- \c org.qt-project.qt.videowindowcontrol/5.0
-
- Defines the interface name of the QVideoWindowControl class.
-
- \relates QVideoWindowControl
-*/
-
-/*!
- Constructs a new video window control with the given \a parent.
-*/
-QVideoWindowControl::QVideoWindowControl(QObject *parent)
- : QMediaControl(parent)
-{
-}
-
-/*!
- Destroys a video window control.
-*/
-QVideoWindowControl::~QVideoWindowControl()
-{
-}
-
-/*!
- \fn QVideoWindowControl::winId() const
-
- Returns the ID of the window a video overlay end point renders to.
-*/
-
-/*!
- \fn QVideoWindowControl::setWinId(WId id)
-
- Sets the \a id of the window a video overlay end point renders to.
-*/
-
-/*!
- \fn QVideoWindowControl::displayRect() const
- Returns the sub-rect of a window where video is displayed.
-*/
-
-/*!
- \fn QVideoWindowControl::setDisplayRect(const QRect &rect)
- Sets the sub-\a rect of a window where video is displayed.
-*/
-
-/*!
- \fn QVideoWindowControl::isFullScreen() const
-
- Identifies if a video overlay is a fullScreen overlay.
-
- Returns true if the video overlay is fullScreen, and false otherwise.
-*/
-
-/*!
- \fn QVideoWindowControl::setFullScreen(bool fullScreen)
-
- Sets whether a video overlay is a \a fullScreen overlay.
-*/
-
-/*!
- \fn QVideoWindowControl::fullScreenChanged(bool fullScreen)
-
- Signals that the \a fullScreen state of a video overlay has changed.
-*/
-
-/*!
- \fn QVideoWindowControl::repaint()
-
- Repaints the last frame.
-*/
-
-/*!
- \fn QVideoWindowControl::nativeSize() const
-
- Returns a suggested size for the video display based on the resolution and aspect ratio of the
- video.
-*/
-
-/*!
- \fn QVideoWindowControl::nativeSizeChanged()
-
- Signals that the native dimensions of the video have changed.
-*/
-
-
-/*!
- \fn QVideoWindowControl::aspectRatioMode() const
-
- Returns how video is scaled to fit the display region with respect to its aspect ratio.
-*/
-
-/*!
- \fn QVideoWindowControl::setAspectRatioMode(Qt::AspectRatioMode mode)
-
- Sets the aspect ratio \a mode which determines how video is scaled to the fit the display region
- with respect to its aspect ratio.
-*/
-
-/*!
- \fn QVideoWindowControl::brightness() const
-
- Returns the brightness adjustment applied to a video overlay.
-
- Valid brightness values range between -100 and 100, the default is 0.
-*/
-
-/*!
- \fn QVideoWindowControl::setBrightness(int brightness)
-
- Sets a \a brightness adjustment for a video overlay.
-
- Valid brightness values range between -100 and 100, the default is 0.
-*/
-
-/*!
- \fn QVideoWindowControl::brightnessChanged(int brightness)
-
- Signals that a video overlay's \a brightness adjustment has changed.
-*/
-
-/*!
- \fn QVideoWindowControl::contrast() const
-
- Returns the contrast adjustment applied to a video overlay.
-
- Valid contrast values range between -100 and 100, the default is 0.
-*/
-
-/*!
- \fn QVideoWindowControl::setContrast(int contrast)
-
- Sets the \a contrast adjustment for a video overlay.
-
- Valid contrast values range between -100 and 100, the default is 0.
-*/
-
-/*!
- \fn QVideoWindowControl::contrastChanged(int contrast)
-
- Signals that a video overlay's \a contrast adjustment has changed.
-*/
-
-/*!
- \fn QVideoWindowControl::hue() const
-
- Returns the hue adjustment applied to a video overlay.
-
- Value hue values range between -100 and 100, the default is 0.
-*/
-
-/*!
- \fn QVideoWindowControl::setHue(int hue)
-
- Sets a \a hue adjustment for a video overlay.
-
- Valid hue values range between -100 and 100, the default is 0.
-*/
-
-/*!
- \fn QVideoWindowControl::hueChanged(int hue)
-
- Signals that a video overlay's \a hue adjustment has changed.
-*/
-
-/*!
- \fn QVideoWindowControl::saturation() const
-
- Returns the saturation adjustment applied to a video overlay.
-
- Value saturation values range between -100 and 100, the default is 0.
-*/
-
-/*!
- \fn QVideoWindowControl::setSaturation(int saturation)
- Sets a \a saturation adjustment for a video overlay.
-
- Valid saturation values range between -100 and 100, the default is 0.
-*/
-
-/*!
- \fn QVideoWindowControl::saturationChanged(int saturation)
-
- Signals that a video overlay's \a saturation adjustment has changed.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qvideowindowcontrol.cpp"
diff --git a/src/multimedia/controls/qvideowindowcontrol.h b/src/multimedia/controls/qvideowindowcontrol.h
deleted file mode 100644
index 510a29989..000000000
--- a/src/multimedia/controls/qvideowindowcontrol.h
+++ /dev/null
@@ -1,106 +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 QVIDEOWINDOWCONTROL_H
-#define QVIDEOWINDOWCONTROL_H
-
-#include <QtMultimedia/qmediacontrol.h>
-#include <QtCore/qrect.h>
-#include <QtCore/qsize.h>
-#include <QtGui/qwindowdefs.h>
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QVideoWindowControl : public QMediaControl
-{
- Q_OBJECT
-
-public:
- ~QVideoWindowControl();
-
- virtual WId winId() const = 0;
- virtual void setWinId(WId id) = 0;
-
- virtual QRect displayRect() const = 0;
- virtual void setDisplayRect(const QRect &rect) = 0;
-
- virtual bool isFullScreen() const = 0;
- virtual void setFullScreen(bool fullScreen) = 0;
-
- virtual void repaint() = 0;
-
- virtual QSize nativeSize() const = 0;
-
- virtual Qt::AspectRatioMode aspectRatioMode() const = 0;
- virtual void setAspectRatioMode(Qt::AspectRatioMode mode) = 0;
-
- virtual int brightness() const = 0;
- virtual void setBrightness(int brightness) = 0;
-
- virtual int contrast() const = 0;
- virtual void setContrast(int contrast) = 0;
-
- virtual int hue() const = 0;
- virtual void setHue(int hue) = 0;
-
- virtual int saturation() const = 0;
- virtual void setSaturation(int saturation) = 0;
-
-Q_SIGNALS:
- void fullScreenChanged(bool fullScreen);
- void brightnessChanged(int brightness);
- void contrastChanged(int contrast);
- void hueChanged(int hue);
- void saturationChanged(int saturation);
- void nativeSizeChanged();
-
-protected:
- explicit QVideoWindowControl(QObject *parent = nullptr);
-};
-
-#define QVideoWindowControl_iid "org.qt-project.qt.videowindowcontrol/5.0"
-Q_MEDIA_DECLARE_CONTROL(QVideoWindowControl, QVideoWindowControl_iid)
-
-QT_END_NAMESPACE
-
-
-#endif
diff --git a/src/multimedia/darwin/qcoreaudiosessionmanager.mm b/src/multimedia/darwin/qcoreaudiosessionmanager.mm
new file mode 100644
index 000000000..cee955905
--- /dev/null
+++ b/src/multimedia/darwin/qcoreaudiosessionmanager.mm
@@ -0,0 +1,437 @@
+// 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>
+#import <Foundation/Foundation.h>
+
+QT_BEGIN_NAMESPACE
+
+@interface CoreAudioSessionObserver : NSObject
+{
+ CoreAudioSessionManager *m_sessionManager;
+ AVAudioSession *m_audioSession;
+}
+
+@property (readonly, getter=sessionManager) CoreAudioSessionManager *m_sessionManager;
+@property (readonly, getter=audioSession) AVAudioSession *m_audioSession;
+
+-(CoreAudioSessionObserver *)initWithAudioSessionManager:(CoreAudioSessionManager *)sessionManager;
+
+-(BOOL)activateAudio;
+-(BOOL)deactivateAudio;
+
+//Notification handlers
+-(void)audioSessionInterruption:(NSNotification *)notification;
+-(void)audioSessionRouteChange:(NSNotification *)notification;
+-(void)audioSessionMediaServicesWereReset:(NSNotification *)notification;
+
+@end //interface CoreAudioSessionObserver
+
+@implementation CoreAudioSessionObserver
+
+@synthesize m_sessionManager, m_audioSession;
+
+-(CoreAudioSessionObserver *)initWithAudioSessionManager:(CoreAudioSessionManager *)sessionManager
+{
+ if (!(self = [super init]))
+ return nil;
+
+ self->m_sessionManager = sessionManager;
+ self->m_audioSession = [AVAudioSession sharedInstance];
+
+ //Set up observers
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(audioSessionInterruption:)
+ name:AVAudioSessionInterruptionNotification
+ object:self->m_audioSession];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(audioSessionMediaServicesWereReset:)
+ name:AVAudioSessionMediaServicesWereResetNotification
+ object:self->m_audioSession];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(audioSessionRouteChange:)
+ name:AVAudioSessionRouteChangeNotification
+ object:self->m_audioSession];
+
+ return self;
+}
+
+-(void)dealloc
+{
+#ifdef QT_DEBUG_COREAUDIO
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ [[NSNotificationCenter defaultCenter] removeObserver:self
+ name:AVAudioSessionInterruptionNotification
+ object:self->m_audioSession];
+ [[NSNotificationCenter defaultCenter] removeObserver:self
+ name:AVAudioSessionMediaServicesWereResetNotification
+ object:self->m_audioSession];
+ [[NSNotificationCenter defaultCenter] removeObserver:self
+ name:AVAudioSessionRouteChangeNotification
+ object:self->m_audioSession];
+
+ [super dealloc];
+}
+
+-(BOOL)activateAudio
+{
+ NSError *error = nil;
+ BOOL success = [self->m_audioSession setActive:YES error:&error];
+ if (![self->m_audioSession setActive:YES error:&error]) {
+#ifdef QT_DEBUG_COREAUDIO
+ qDebug("audio session activation failed: %s", [[error localizedDescription] UTF8String]);
+ } else {
+ qDebug("audio session activated");
+#endif
+ }
+
+ return success;
+}
+
+-(BOOL)deactivateAudio
+{
+ NSError *error = nil;
+ BOOL success = [m_audioSession setActive:NO error:&error];
+#ifdef QT_DEBUG_COREAUDIO
+ if (!success) {
+ qDebug("%s", [[error localizedDescription] UTF8String]);
+ }
+#endif
+ return success;
+}
+
+-(void)audioSessionInterruption:(NSNotification *)notification
+{
+ NSNumber *type = [[notification userInfo] valueForKey:AVAudioSessionInterruptionTypeKey];
+ if ([type intValue] == AVAudioSessionInterruptionTypeBegan) {
+#ifdef QT_DEBUG_COREAUDIO
+ qDebug("audioSession Interuption begain");
+#endif
+ } else if ([type intValue] == AVAudioSessionInterruptionTypeEnded) {
+#ifdef QT_DEBUG_COREAUDIO
+ qDebug("audioSession Interuption ended");
+#endif
+ NSNumber *option = [[notification userInfo] valueForKey:AVAudioSessionInterruptionOptionKey];
+ if ([option intValue] == AVAudioSessionInterruptionOptionShouldResume) {
+#ifdef QT_DEBUG_COREAUDIO
+ qDebug("audioSession is active and immediately ready to be used.");
+#endif
+ } else {
+ [self activateAudio];
+ }
+ }
+}
+
+-(void)audioSessionMediaServicesWereReset:(NSNotification *)notification
+{
+ Q_UNUSED(notification);
+#ifdef QT_DEBUG_COREAUDIO
+ qDebug("audioSession Media Services were reset");
+#endif
+ //Reactivate audio when this occurs
+ [self activateAudio];
+}
+
+-(void)audioSessionRouteChange:(NSNotification *)notification
+{
+ NSNumber *reason = [[notification userInfo] valueForKey:AVAudioSessionRouteChangeReasonKey];
+ NSUInteger reasonEnum = [reason intValue];
+
+ if (reasonEnum == AVAudioSessionRouteChangeReasonUnknown) {
+#ifdef QT_DEBUG_COREAUDIO
+ qDebug("audioSession route changed. reason: unknown");
+#endif
+ } else if (reasonEnum == AVAudioSessionRouteChangeReasonNewDeviceAvailable) {
+#ifdef QT_DEBUG_COREAUDIO
+ qDebug("audioSession route changed. reason: new device available");
+#endif
+ } else if (reasonEnum == AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {
+#ifdef QT_DEBUG_COREAUDIO
+ qDebug("audioSession route changed. reason: old device unavailable");
+#endif
+ } else if (reasonEnum == AVAudioSessionRouteChangeReasonCategoryChange) {
+#ifdef QT_DEBUG_COREAUDIO
+ qDebug("audioSession route changed. reason: category changed");
+#endif
+ } else if (reasonEnum == AVAudioSessionRouteChangeReasonOverride) {
+#ifdef QT_DEBUG_COREAUDIO
+ qDebug("audioSession route changed. reason: override");
+#endif
+ } else if (reasonEnum == AVAudioSessionRouteChangeReasonWakeFromSleep) {
+#ifdef QT_DEBUG_COREAUDIO
+ qDebug("audioSession route changed. reason: woken from sleep");
+#endif
+ } else if (reasonEnum == AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory) {
+#ifdef QT_DEBUG_COREAUDIO
+ qDebug("audioSession route changed. reason: no suitable route for category");
+#endif
+ }
+
+ m_sessionManager->devicesAvailableChanged();
+}
+
+@end //implementation CoreAudioSessionObserver
+
+CoreAudioSessionManager::CoreAudioSessionManager() :
+ QObject(0)
+{
+ m_sessionObserver = [[CoreAudioSessionObserver alloc] initWithAudioSessionManager:this];
+}
+
+CoreAudioSessionManager::~CoreAudioSessionManager()
+{
+#ifdef QT_DEBUG_COREAUDIO
+ qDebug() << Q_FUNC_INFO;
+#endif
+ [m_sessionObserver release];
+}
+
+
+CoreAudioSessionManager &CoreAudioSessionManager::instance()
+{
+ static CoreAudioSessionManager instance;
+ return instance;
+}
+
+bool CoreAudioSessionManager::setActive(bool active)
+{
+ if (active) {
+ return [m_sessionObserver activateAudio];
+ } else {
+ return [m_sessionObserver deactivateAudio];
+ }
+}
+
+bool CoreAudioSessionManager::setCategory(CoreAudioSessionManager::AudioSessionCategorys category, CoreAudioSessionManager::AudioSessionCategoryOptions options)
+{
+ NSString *targetCategory = nil;
+
+ switch (category) {
+ case CoreAudioSessionManager::Ambient:
+ targetCategory = AVAudioSessionCategoryAmbient;
+ break;
+ case CoreAudioSessionManager::SoloAmbient:
+ targetCategory = AVAudioSessionCategorySoloAmbient;
+ break;
+ case CoreAudioSessionManager::Playback:
+ targetCategory = AVAudioSessionCategoryPlayback;
+ break;
+ case CoreAudioSessionManager::Record:
+ targetCategory = AVAudioSessionCategoryRecord;
+ break;
+ case CoreAudioSessionManager::PlayAndRecord:
+ targetCategory = AVAudioSessionCategoryPlayAndRecord;
+ break;
+ case CoreAudioSessionManager::AudioProcessing:
+#ifndef Q_OS_TVOS
+ targetCategory = AVAudioSessionCategoryAudioProcessing;
+#endif
+ break;
+ case CoreAudioSessionManager::MultiRoute:
+ targetCategory = AVAudioSessionCategoryMultiRoute;
+ break;
+ }
+
+ if (targetCategory == nil)
+ return false;
+
+ return [[m_sessionObserver audioSession] setCategory:targetCategory
+ withOptions:(AVAudioSessionCategoryOptions)options
+ error:nil];
+}
+
+bool CoreAudioSessionManager::setMode(CoreAudioSessionManager::AudioSessionModes mode)
+{
+ NSString *targetMode = nil;
+ switch (mode) {
+ case CoreAudioSessionManager::Default:
+ targetMode = AVAudioSessionModeDefault;
+ break;
+ case CoreAudioSessionManager::VoiceChat:
+ targetMode = AVAudioSessionModeVoiceChat;
+ break;
+ case CoreAudioSessionManager::GameChat:
+ targetMode = AVAudioSessionModeGameChat;
+ break;
+ case CoreAudioSessionManager::VideoRecording:
+ targetMode = AVAudioSessionModeVideoRecording;
+ break;
+ case CoreAudioSessionManager::Measurement:
+ targetMode = AVAudioSessionModeMeasurement;
+ break;
+ case CoreAudioSessionManager::MoviePlayback:
+ targetMode = AVAudioSessionModeMoviePlayback;
+ break;
+ }
+
+ if (targetMode == nil)
+ return false;
+
+ return [[m_sessionObserver audioSession] setMode:targetMode error:nil];
+
+}
+
+CoreAudioSessionManager::AudioSessionCategorys CoreAudioSessionManager::category()
+{
+ NSString *category = [[m_sessionObserver audioSession] category];
+ AudioSessionCategorys localCategory = Ambient;
+
+ if (category == AVAudioSessionCategoryAmbient) {
+ localCategory = Ambient;
+ } else if (category == AVAudioSessionCategorySoloAmbient) {
+ localCategory = SoloAmbient;
+ } else if (category == AVAudioSessionCategoryPlayback) {
+ localCategory = Playback;
+ } else if (category == AVAudioSessionCategoryRecord) {
+ localCategory = Record;
+ } else if (category == AVAudioSessionCategoryPlayAndRecord) {
+ localCategory = PlayAndRecord;
+#ifndef Q_OS_TVOS
+ } else if (category == AVAudioSessionCategoryAudioProcessing) {
+ localCategory = AudioProcessing;
+#endif
+ } else if (category == AVAudioSessionCategoryMultiRoute) {
+ localCategory = MultiRoute;
+ }
+
+ return localCategory;
+}
+
+CoreAudioSessionManager::AudioSessionModes CoreAudioSessionManager::mode()
+{
+ NSString *mode = [[m_sessionObserver audioSession] mode];
+ AudioSessionModes localMode = Default;
+
+ if (mode == AVAudioSessionModeDefault) {
+ localMode = Default;
+ } else if (mode == AVAudioSessionModeVoiceChat) {
+ localMode = VoiceChat;
+ } else if (mode == AVAudioSessionModeGameChat) {
+ localMode = GameChat;
+ } else if (mode == AVAudioSessionModeVideoRecording) {
+ localMode = VideoRecording;
+ } else if (mode == AVAudioSessionModeMeasurement) {
+ localMode = Measurement;
+ } else if (mode == AVAudioSessionModeMoviePlayback) {
+ localMode = MoviePlayback;
+ }
+
+ return localMode;
+}
+
+QList<QByteArray> CoreAudioSessionManager::inputDevices()
+{
+ //TODO: Add support for USB input devices
+ //Right now the default behavior on iOS is to have only one input route
+ //at a time.
+ QList<QByteArray> inputDevices;
+ inputDevices << "default";
+ return inputDevices;
+}
+
+QList<QByteArray> CoreAudioSessionManager::outputDevices()
+{
+ //TODO: Add support for USB output devices
+ //Right now the default behavior on iOS is to have only one output route
+ //at a time.
+ QList<QByteArray> outputDevices;
+ outputDevices << "default";
+ return outputDevices;
+}
+
+float CoreAudioSessionManager::currentIOBufferDuration()
+{
+ return [[m_sessionObserver audioSession] IOBufferDuration];
+}
+
+float CoreAudioSessionManager::preferredSampleRate()
+{
+ return [[m_sessionObserver audioSession] preferredSampleRate];
+}
+
+#ifdef QT_DEBUG_COREAUDIO
+QDebug operator<<(QDebug dbg, CoreAudioSessionManager::AudioSessionCategorys category)
+{
+ QDebug output = dbg.nospace();
+ switch (category) {
+ case CoreAudioSessionManager::Ambient:
+ output << "AudioSessionCategoryAmbient";
+ break;
+ case CoreAudioSessionManager::SoloAmbient:
+ output << "AudioSessionCategorySoloAmbient";
+ break;
+ case CoreAudioSessionManager::Playback:
+ output << "AudioSessionCategoryPlayback";
+ break;
+ case CoreAudioSessionManager::Record:
+ output << "AudioSessionCategoryRecord";
+ break;
+ case CoreAudioSessionManager::PlayAndRecord:
+ output << "AudioSessionCategoryPlayAndRecord";
+ break;
+ case CoreAudioSessionManager::AudioProcessing:
+ output << "AudioSessionCategoryAudioProcessing";
+ break;
+ case CoreAudioSessionManager::MultiRoute:
+ output << "AudioSessionCategoryMultiRoute";
+ break;
+ }
+ return output;
+}
+
+QDebug operator<<(QDebug dbg, CoreAudioSessionManager::AudioSessionCategoryOptions option)
+{
+ QDebug output = dbg.nospace();
+ switch (option) {
+ case CoreAudioSessionManager::None:
+ output << "AudioSessionCategoryOptionNone";
+ break;
+ case CoreAudioSessionManager::MixWithOthers:
+ output << "AudioSessionCategoryOptionMixWithOthers";
+ break;
+ case CoreAudioSessionManager::DuckOthers:
+ output << "AudioSessionCategoryOptionDuckOthers";
+ break;
+ case CoreAudioSessionManager::AllowBluetooth:
+ output << "AudioSessionCategoryOptionAllowBluetooth";
+ break;
+ case CoreAudioSessionManager::DefaultToSpeaker:
+ output << "AudioSessionCategoryOptionDefaultToSpeaker";
+ break;
+ }
+ return output;
+}
+
+QDebug operator<<(QDebug dbg, CoreAudioSessionManager::AudioSessionModes mode)
+{
+ QDebug output = dbg.nospace();
+ switch (mode) {
+ case CoreAudioSessionManager::Default:
+ output << "AudioSessionModeDefault";
+ break;
+ case CoreAudioSessionManager::VoiceChat:
+ output << "AudioSessionModeVoiceChat";
+ break;
+ case CoreAudioSessionManager::GameChat:
+ output << "AudioSessionModeGameChat";
+ break;
+ case CoreAudioSessionManager::VideoRecording:
+ output << "AudioSessionModeVideoRecording";
+ break;
+ case CoreAudioSessionManager::Measurement:
+ output << "AudioSessionModeMeasurement";
+ break;
+ case CoreAudioSessionManager::MoviePlayback:
+ output << "AudioSessionModeMoviePlayback";
+ break;
+ }
+ return output;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qcoreaudiosessionmanager_p.cpp"
diff --git a/src/multimedia/darwin/qcoreaudiosessionmanager_p.h b/src/multimedia/darwin/qcoreaudiosessionmanager_p.h
new file mode 100644
index 000000000..a6dfe88f4
--- /dev/null
+++ b/src/multimedia/darwin/qcoreaudiosessionmanager_p.h
@@ -0,0 +1,95 @@
+// 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
+
+//
+// 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>
+#ifdef QT_DEBUG_COREAUDIO
+# include <QtCore/QDebug>
+#endif
+
+@class CoreAudioSessionObserver;
+
+QT_BEGIN_NAMESPACE
+
+class CoreAudioSessionManager : public QObject
+{
+ Q_OBJECT
+public:
+ enum AudioSessionCategorys {
+ Ambient,
+ SoloAmbient,
+ Playback,
+ Record,
+ PlayAndRecord,
+ AudioProcessing,
+ MultiRoute
+ };
+ enum AudioSessionCategoryOptions {
+ None = 0,
+ MixWithOthers = 1,
+ DuckOthers = 2,
+ AllowBluetooth = 4,
+ DefaultToSpeaker = 8
+ };
+ enum AudioSessionModes {
+ Default,
+ VoiceChat,
+ GameChat,
+ VideoRecording,
+ Measurement,
+ MoviePlayback
+ };
+
+ static CoreAudioSessionManager& instance();
+
+ bool setActive(bool active);
+ bool setCategory(AudioSessionCategorys category, AudioSessionCategoryOptions options = None);
+ bool setMode(AudioSessionModes mode);
+
+ AudioSessionCategorys category();
+ AudioSessionModes mode();
+
+ QList<QByteArray> inputDevices();
+ QList<QByteArray> outputDevices();
+
+ float currentIOBufferDuration();
+ float preferredSampleRate();
+
+signals:
+ void activeChanged();
+ void categoryChanged();
+ void modeChanged();
+ void routeChanged();
+ void devicesAvailableChanged();
+
+private:
+ CoreAudioSessionManager();
+ ~CoreAudioSessionManager();
+ CoreAudioSessionManager(CoreAudioSessionManager const &copy);
+ CoreAudioSessionManager& operator =(CoreAudioSessionManager const &copy);
+
+ CoreAudioSessionObserver *m_sessionObserver;
+};
+
+#ifdef QT_DEBUG_COREAUDIO
+QDebug operator <<(QDebug dbg, CoreAudioSessionManager::AudioSessionCategorys category);
+QDebug operator <<(QDebug dbg, CoreAudioSessionManager::AudioSessionCategoryOptions option);
+QDebug operator <<(QDebug dbg, CoreAudioSessionManager::AudioSessionModes mode);
+#endif
+
+QT_END_NAMESPACE
+
+#endif // 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/darwin/qdarwinaudiosink.mm b/src/multimedia/darwin/qdarwinaudiosink.mm
new file mode 100644
index 000000000..9242bb2f0
--- /dev/null
+++ b/src/multimedia/darwin/qdarwinaudiosink.mm
@@ -0,0 +1,609 @@
+// 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 "qdarwinmediadevices_p.h"
+#include <qmediadevices.h>
+
+#include <QtCore/QDataStream>
+#include <QtCore/QTimer>
+#include <QtCore/QDebug>
+
+#include <AudioUnit/AudioUnit.h>
+#include <AudioToolbox/AudioToolbox.h>
+#if defined(Q_OS_MACOS)
+# include <AudioUnit/AudioComponent.h>
+#endif
+
+#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
+# include <QtMultimedia/private/qaudiohelpers_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static int audioRingBufferSize(int bufferSize, int maxPeriodSize)
+{
+ // TODO: review this code
+ return bufferSize
+ + (bufferSize % maxPeriodSize == 0 ? 0 : maxPeriodSize - (bufferSize % maxPeriodSize));
+}
+
+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)))
+{
+ 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;
+ qint64 framesRead = 0;
+
+ while (wecan && framesRead < maxFrames) {
+ CoreAudioRingBuffer::Region region = m_buffer->acquireReadRegion((maxFrames - framesRead) * m_bytesPerFrame);
+
+ if (region.second > 0) {
+ // Ensure that we only read whole frames.
+ region.second -= region.second % m_bytesPerFrame;
+
+ if (region.second > 0) {
+ memcpy(data + (framesRead * m_bytesPerFrame), region.first, region.second);
+ framesRead += region.second / m_bytesPerFrame;
+ } else
+ wecan = false; // If there is only a partial frame left we should exit.
+ }
+ else
+ wecan = false;
+
+ m_buffer->releaseReadRegion(region);
+ }
+
+ if (framesRead == 0 && m_deviceError)
+ framesRead = -1;
+
+ return framesRead;
+}
+
+qint64 QDarwinAudioSinkBuffer::writeBytes(const char *data, qint64 maxSize)
+{
+ bool wecan = true;
+ qint64 bytesWritten = 0;
+
+ maxSize -= maxSize % m_bytesPerFrame;
+ while (wecan && bytesWritten < maxSize) {
+ CoreAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(maxSize - bytesWritten);
+
+ if (region.second > 0) {
+ memcpy(region.first, data + bytesWritten, region.second);
+ bytesWritten += region.second;
+ }
+ else
+ wecan = false;
+
+ m_buffer->releaseWriteRegion(region);
+ }
+
+ if (bytesWritten > 0)
+ emit readyRead();
+
+ return bytesWritten;
+}
+
+int QDarwinAudioSinkBuffer::available() const
+{
+ return m_buffer->free();
+}
+
+bool QDarwinAudioSinkBuffer::deviceAtEnd() const
+{
+ return m_deviceAtEnd;
+}
+
+void QDarwinAudioSinkBuffer::reset()
+{
+ m_buffer->reset();
+ setFillingEnabled(false);
+ setPrefetchDevice(nullptr);
+}
+
+void QDarwinAudioSinkBuffer::setPrefetchDevice(QIODevice *device)
+{
+ 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);
+}
+
+QIODevice *QDarwinAudioSinkBuffer::prefetchDevice() const
+{
+ return m_device;
+}
+
+void QDarwinAudioSinkBuffer::setFillingEnabled(bool enabled)
+{
+ if (std::exchange(m_fillingEnabled, enabled) == enabled)
+ return;
+
+ if (!enabled)
+ m_fillTimer->stop();
+ else if (m_device) {
+ fillBuffer();
+ m_fillTimer->start();
+ }
+}
+
+void QDarwinAudioSinkBuffer::fillBuffer()
+{
+ const int free = m_buffer->free();
+ const int writeSize = free - (free % m_maxPeriodSize);
+
+ if (writeSize > 0) {
+ bool wecan = true;
+ int filled = 0;
+
+ while (!m_deviceError && wecan && filled < writeSize) {
+ CoreAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(writeSize - filled);
+
+ 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) {
+ setFillingEnabled(false);
+ region.second = 0;
+ m_deviceError = true;
+ }
+ }
+ else
+ wecan = false;
+
+ m_buffer->releaseWriteRegion(region);
+ }
+
+ if (filled > 0)
+ emit readyRead();
+ }
+}
+
+QDarwinAudioSinkDevice::QDarwinAudioSinkDevice(QDarwinAudioSinkBuffer *audioBuffer, QObject *parent)
+ : QIODevice(parent)
+ , m_audioBuffer(audioBuffer)
+{
+ open(QIODevice::WriteOnly | QIODevice::Unbuffered);
+}
+
+qint64 QDarwinAudioSinkDevice::readData(char *data, qint64 len)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(len);
+
+ return 0;
+}
+
+qint64 QDarwinAudioSinkDevice::writeData(const char *data, qint64 len)
+{
+ return m_audioBuffer->writeBytes(data, len);
+}
+
+QDarwinAudioSink::QDarwinAudioSink(const QAudioDevice &device, QObject *parent)
+ : QPlatformAudioSink(parent), m_audioDeviceInfo(device), m_stateMachine(*this)
+{
+ QAudioDevice di = device;
+ if (di.isNull())
+ di = QMediaDevices::defaultAudioOutput();
+#if defined(Q_OS_MACOS)
+ const QCoreAudioDeviceInfo *info = static_cast<const QCoreAudioDeviceInfo *>(di.handle());
+ Q_ASSERT(info);
+ m_audioDeviceId = info->deviceID();
+#endif
+ m_device = di.id();
+
+ m_clockFrequency = CoreAudioUtils::frequency() / 1000;
+
+ connect(this, &QDarwinAudioSink::stateChanged, this, &QDarwinAudioSink::updateAudioDevice);
+}
+
+QDarwinAudioSink::~QDarwinAudioSink()
+{
+ close();
+}
+
+void QDarwinAudioSink::start(QIODevice *device)
+{
+ reset();
+
+ if (!m_audioDeviceInfo.isFormatSupported(m_audioFormat) || !open()) {
+ m_stateMachine.setError(QAudio::OpenError);
+ return;
+ }
+
+ if (!device) {
+ m_stateMachine.setError(QAudio::IOError);
+ return;
+ }
+
+ m_audioBuffer->setPrefetchDevice(device);
+
+ m_pullMode = true;
+ m_totalFrames = 0;
+
+ m_stateMachine.start();
+}
+
+QIODevice *QDarwinAudioSink::start()
+{
+ reset();
+
+ if (!m_audioDeviceInfo.isFormatSupported(m_audioFormat) || !open()) {
+ m_stateMachine.setError(QAudio::OpenError);
+ return m_audioIO;
+ }
+
+ m_pullMode = false;
+ m_totalFrames = 0;
+
+ m_stateMachine.start(false);
+
+ return m_audioIO;
+}
+
+void QDarwinAudioSink::stop()
+{
+ 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();
+
+ 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()
+{
+ onAudioDeviceDrained();
+ m_stateMachine.stopOrUpdateError();
+}
+
+void QDarwinAudioSink::suspend()
+{
+ m_stateMachine.suspend();
+}
+
+void QDarwinAudioSink::resume()
+{
+ m_stateMachine.resume();
+}
+
+qsizetype QDarwinAudioSink::bytesFree() const
+{
+ return m_audioBuffer->available();
+}
+
+void QDarwinAudioSink::setBufferSize(qsizetype value)
+{
+ if (state() == QAudio::StoppedState)
+ m_internalBufferSize = value;
+}
+
+qsizetype QDarwinAudioSink::bufferSize() const
+{
+ return m_internalBufferSize;
+}
+
+qint64 QDarwinAudioSink::processedUSecs() const
+{
+ return m_totalFrames * 1000000 / m_audioFormat.sampleRate();
+}
+
+QAudio::Error QDarwinAudioSink::error() const
+{
+ return m_stateMachine.error();
+}
+
+QAudio::State QDarwinAudioSink::state() const
+{
+ return m_stateMachine.state();
+}
+
+void QDarwinAudioSink::setFormat(const QAudioFormat &format)
+{
+ if (state() == QAudio::StoppedState)
+ m_audioFormat = format;
+}
+
+QAudioFormat QDarwinAudioSink::format() const
+{
+ return m_audioFormat;
+}
+
+void QDarwinAudioSink::setVolume(qreal volume)
+{
+ m_cachedVolume = qBound(qreal(0.0), volume, qreal(1.0));
+ if (!m_isOpen)
+ return;
+
+#if defined(Q_OS_MACOS)
+ //on OS X the volume can be set directly on the AudioUnit
+ if (AudioUnitSetParameter(m_audioUnit,
+ kHALOutputParam_Volume,
+ kAudioUnitScope_Global,
+ 0 /* bus */,
+ m_cachedVolume,
+ 0) == noErr)
+ m_volume = m_cachedVolume;
+#endif
+}
+
+qreal QDarwinAudioSink::volume() const
+{
+ return m_cachedVolume;
+}
+
+void QDarwinAudioSink::inputReady()
+{
+ m_stateMachine.activateFromIdle();
+}
+
+OSStatus QDarwinAudioSink::renderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
+{
+ Q_UNUSED(ioActionFlags);
+ Q_UNUSED(inTimeStamp);
+ Q_UNUSED(inBusNumber);
+ Q_UNUSED(inNumberFrames);
+
+ QDarwinAudioSink* d = static_cast<QDarwinAudioSink*>(inRefCon);
+
+ const auto [drained, stopped] = d->m_stateMachine.getDrainedAndStopped();
+
+ if (drained && stopped) {
+ ioData->mBuffers[0].mDataByteSize = 0;
+ } 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);
+
+ if (framesRead > 0) {
+ ioData->mBuffers[0].mDataByteSize = framesRead * bytesPerFrame;
+ d->m_totalFrames += framesRead;
+
+#if defined(Q_OS_MACOS)
+ if (stopped) {
+ qreal oldVolume = d->m_cachedVolume;
+ // Decrease volume smoothly.
+ d->setVolume(d->m_volume / 2);
+ d->m_cachedVolume = oldVolume;
+ }
+#elif defined(Q_OS_IOS) || defined(Q_OS_TVOS)
+ // on iOS we have to adjust the sound volume ourselves
+ if (!qFuzzyCompare(d->m_cachedVolume, qreal(1.0f))) {
+ QAudioHelperInternal::qMultiplySamples(d->m_cachedVolume,
+ d->m_audioFormat,
+ ioData->mBuffers[0].mData, /* input */
+ ioData->mBuffers[0].mData, /* output */
+ ioData->mBuffers[0].mDataByteSize);
+ }
+#endif
+
+ }
+ else {
+ ioData->mBuffers[0].mDataByteSize = 0;
+ if (framesRead == 0)
+ d->onAudioDeviceIdle();
+ else
+ d->onAudioDeviceError();
+ }
+ }
+
+ return noErr;
+}
+
+bool QDarwinAudioSink::open()
+{
+#if defined(Q_OS_IOS)
+ // Set default category to Ambient (implies MixWithOthers). This makes sure audio stops playing
+ // if the screen is locked or if the Silent switch is toggled.
+ CoreAudioSessionManager::instance().setCategory(CoreAudioSessionManager::Ambient, CoreAudioSessionManager::None);
+ CoreAudioSessionManager::instance().setActive(true);
+#endif
+
+ if (error() != QAudio::NoError)
+ return false;
+
+ if (m_isOpen) {
+ setVolume(m_cachedVolume);
+ return true;
+ }
+
+ AudioComponentDescription componentDescription;
+ componentDescription.componentType = kAudioUnitType_Output;
+#if defined(Q_OS_MACOS)
+ componentDescription.componentSubType = kAudioUnitSubType_HALOutput;
+#else
+ componentDescription.componentSubType = kAudioUnitSubType_RemoteIO;
+#endif
+ componentDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
+ componentDescription.componentFlags = 0;
+ componentDescription.componentFlagsMask = 0;
+
+ AudioComponent component = AudioComponentFindNext(0, &componentDescription);
+ if (component == 0) {
+ qWarning() << "QAudioOutput: Failed to find Output component";
+ return false;
+ }
+
+ if (AudioComponentInstanceNew(component, &m_audioUnit) != noErr) {
+ qWarning() << "QAudioOutput: Unable to Open Output Component";
+ return false;
+ }
+
+ // register callback
+ AURenderCallbackStruct callback;
+ callback.inputProc = renderCallback;
+ callback.inputProcRefCon = this;
+
+ if (AudioUnitSetProperty(m_audioUnit,
+ kAudioUnitProperty_SetRenderCallback,
+ kAudioUnitScope_Global,
+ 0,
+ &callback,
+ sizeof(callback)) != noErr) {
+ qWarning() << "QAudioOutput: Failed to set AudioUnit callback";
+ return false;
+ }
+
+#if defined(Q_OS_MACOS)
+ //Set Audio Device
+ if (AudioUnitSetProperty(m_audioUnit,
+ kAudioOutputUnitProperty_CurrentDevice,
+ kAudioUnitScope_Global,
+ 0,
+ &m_audioDeviceId,
+ sizeof(m_audioDeviceId)) != noErr) {
+ qWarning() << "QAudioOutput: Unable to use configured device";
+ return false;
+ }
+#endif
+ UInt32 size;
+
+
+ // Set stream format
+ m_streamFormat = CoreAudioUtils::toAudioStreamBasicDescription(m_audioFormat);
+ size = sizeof(m_streamFormat);
+
+ if (AudioUnitSetProperty(m_audioUnit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Input,
+ 0,
+ &m_streamFormat,
+ size) != noErr) {
+ qWarning() << "QAudioOutput: Unable to Set Stream information";
+ return false;
+ }
+
+ // Allocate buffer
+ UInt32 numberOfFrames = 0;
+#if defined(Q_OS_MACOS)
+ size = sizeof(UInt32);
+ if (AudioUnitGetProperty(m_audioUnit,
+ kAudioDevicePropertyBufferFrameSize,
+ kAudioUnitScope_Global,
+ 0,
+ &numberOfFrames,
+ &size) != noErr) {
+ qWarning() << "QAudioSource: Failed to get audio period size";
+ return false;
+ }
+#else //iOS
+ Float32 bufferSize = CoreAudioSessionManager::instance().currentIOBufferDuration();
+ bufferSize *= m_streamFormat.mSampleRate;
+ numberOfFrames = bufferSize;
+#endif
+
+ m_periodSizeBytes = numberOfFrames * m_streamFormat.mBytesPerFrame;
+ if (m_internalBufferSize < m_periodSizeBytes * 2)
+ m_internalBufferSize = m_periodSizeBytes * 2;
+ else
+ m_internalBufferSize -= m_internalBufferSize % m_streamFormat.mBytesPerFrame;
+
+ 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.get(), this);
+
+ //Init
+ if (AudioUnitInitialize(m_audioUnit)) {
+ qWarning() << "QAudioOutput: Failed to initialize AudioUnit";
+ return false;
+ }
+
+ m_isOpen = true;
+
+ setVolume(m_cachedVolume);
+
+ return true;
+}
+
+void QDarwinAudioSink::close()
+{
+ if (m_audioUnit != 0) {
+ m_stateMachine.stop();
+
+ AudioUnitUninitialize(m_audioUnit);
+ AudioComponentInstanceDispose(m_audioUnit);
+ m_audioUnit = 0;
+ }
+
+ m_audioBuffer.reset();
+}
+
+void QDarwinAudioSink::onAudioDeviceIdle()
+{
+ const bool atEnd = m_audioBuffer->deviceAtEnd();
+ if (!m_stateMachine.updateActiveOrIdle(false, atEnd ? QAudio::NoError : QAudio::UnderrunError))
+ onAudioDeviceDrained();
+}
+
+void QDarwinAudioSink::onAudioDeviceDrained()
+{
+ if (m_stateMachine.onDrained())
+ m_drainSemaphore.release();
+}
+
+void QDarwinAudioSink::onAudioDeviceError()
+{
+ m_stateMachine.stop(QAudio::IOError);
+}
+
+void QDarwinAudioSink::updateAudioDevice()
+{
+ const auto state = m_stateMachine.state();
+
+ Q_ASSERT(m_audioBuffer);
+ Q_ASSERT(m_audioUnit);
+
+ if (state == QAudio::StoppedState)
+ m_audioBuffer->reset();
+ else
+ m_audioBuffer->setFillingEnabled(state != QAudio::SuspendedState);
+
+ const bool unitStarted = state == QAudio::ActiveState;
+ if (std::exchange(m_audioUnitStarted, unitStarted) != unitStarted)
+ (unitStarted ? AudioOutputUnitStart : AudioOutputUnitStop)(m_audioUnit);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qdarwinaudiosink_p.cpp"
diff --git a/src/multimedia/darwin/qdarwinaudiosink_p.h b/src/multimedia/darwin/qdarwinaudiosink_p.h
new file mode 100644
index 000000000..1fddcb205
--- /dev/null
+++ b/src/multimedia/darwin/qdarwinaudiosink_p.h
@@ -0,0 +1,170 @@
+// 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
+
+//
+// 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/qaudiostatemachine_p.h>
+
+#if defined(Q_OS_MACOS)
+# include <CoreAudio/CoreAudio.h>
+#endif
+#include <AudioUnit/AudioUnit.h>
+#include <CoreAudio/CoreAudioTypes.h>
+
+#include <QtCore/QIODevice>
+#include <qdarwinaudiodevice_p.h>
+#include <qsemaphore.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDarwinAudioSinkBuffer;
+class QTimer;
+class QCoreAudioDeviceInfo;
+class CoreAudioRingBuffer;
+
+class QDarwinAudioSinkBuffer : public QObject
+{
+ Q_OBJECT
+
+public:
+ QDarwinAudioSinkBuffer(int bufferSize, int maxPeriodSize, QAudioFormat const& audioFormat);
+ ~QDarwinAudioSinkBuffer();
+
+ qint64 readFrames(char *data, qint64 maxFrames);
+ qint64 writeBytes(const char *data, qint64 maxSize);
+
+ int available() const;
+
+ bool deviceAtEnd() const;
+
+ void reset();
+
+ void setPrefetchDevice(QIODevice *device);
+
+ QIODevice *prefetchDevice() const;
+
+ void setFillingEnabled(bool enabled);
+
+signals:
+ void readyRead();
+
+private slots:
+ void fillBuffer();
+
+private:
+ 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
+{
+public:
+ QDarwinAudioSinkDevice(QDarwinAudioSinkBuffer *audioBuffer, QObject *parent);
+
+ qint64 readData(char *data, qint64 len);
+ qint64 writeData(const char *data, qint64 len);
+
+ bool isSequential() const { return true; }
+
+private:
+ QDarwinAudioSinkBuffer *m_audioBuffer;
+};
+
+
+class QDarwinAudioSink : public QPlatformAudioSink
+{
+ Q_OBJECT
+
+public:
+ QDarwinAudioSink(const QAudioDevice &device, QObject *parent);
+ ~QDarwinAudioSink();
+
+ void start(QIODevice *device);
+ QIODevice *start();
+ 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 setFormat(const QAudioFormat &format);
+ QAudioFormat format() const;
+
+ void setVolume(qreal volume);
+ qreal volume() const;
+
+private slots:
+ void inputReady();
+ void updateAudioDevice();
+
+private:
+ enum ThreadState { Running, Draining, Stopped };
+
+ static OSStatus renderCallback(void *inRefCon,
+ AudioUnitRenderActionFlags *ioActionFlags,
+ const AudioTimeStamp *inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames,
+ AudioBufferList *ioData);
+
+ bool open();
+ void close();
+ void onAudioDeviceIdle();
+ void onAudioDeviceError();
+ void onAudioDeviceDrained();
+
+ QAudioDevice m_audioDeviceInfo;
+ QByteArray m_device;
+
+ static constexpr int DEFAULT_BUFFER_SIZE = 8 * 1024;
+
+ bool m_isOpen = false;
+ int m_internalBufferSize = DEFAULT_BUFFER_SIZE;
+ int m_periodSizeBytes = 0;
+ qint64 m_totalFrames = 0;
+ QAudioFormat m_audioFormat;
+ QIODevice *m_audioIO = nullptr;
+#if defined(Q_OS_MACOS)
+ AudioDeviceID m_audioDeviceId;
+#endif
+ AudioUnit m_audioUnit = 0;
+ bool m_audioUnitStarted = false;
+ Float64 m_clockFrequency = 0;
+ AudioStreamBasicDescription m_streamFormat;
+ std::unique_ptr<QDarwinAudioSinkBuffer> m_audioBuffer;
+ qreal m_cachedVolume = 1.;
+#if defined(Q_OS_MACOS)
+ qreal m_volume = 1.;
+#endif
+ bool m_pullMode = false;
+
+ QAudioStateMachine m_stateMachine;
+ QSemaphore m_drainSemaphore;
+};
+
+QT_END_NAMESPACE
+
+#endif // IOSAUDIOOUTPUT_H
diff --git a/src/multimedia/darwin/qdarwinaudiosource.mm b/src/multimedia/darwin/qdarwinaudiosource.mm
new file mode 100644
index 000000000..4c1345fb8
--- /dev/null
+++ b/src/multimedia/darwin/qdarwinaudiosource.mm
@@ -0,0 +1,942 @@
+// 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 "qdarwinmediadevices_p.h"
+#include <qmediadevices.h>
+
+#if defined(Q_OS_MACOS)
+# include <AudioUnit/AudioComponent.h>
+#endif
+
+#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
+# include "qcoreaudiosessionmanager_p.h"
+#endif
+
+#include <QtMultimedia/private/qaudiohelpers_p.h>
+#include <QtCore/QDataStream>
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+static const int DEFAULT_BUFFER_SIZE = 4 * 1024;
+
+QCoreAudioBufferList::QCoreAudioBufferList(const AudioStreamBasicDescription &streamFormat)
+ : m_owner(false)
+ , m_streamDescription(streamFormat)
+{
+ const bool isInterleaved = (m_streamDescription.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
+ const int numberOfBuffers = isInterleaved ? 1 : m_streamDescription.mChannelsPerFrame;
+
+ m_dataSize = 0;
+
+ m_bufferList = reinterpret_cast<AudioBufferList*>(malloc(sizeof(AudioBufferList) +
+ (sizeof(AudioBuffer) * numberOfBuffers)));
+
+ m_bufferList->mNumberBuffers = numberOfBuffers;
+ for (int i = 0; i < numberOfBuffers; ++i) {
+ m_bufferList->mBuffers[i].mNumberChannels = isInterleaved ? numberOfBuffers : 1;
+ m_bufferList->mBuffers[i].mDataByteSize = 0;
+ m_bufferList->mBuffers[i].mData = 0;
+ }
+}
+
+QCoreAudioBufferList::QCoreAudioBufferList(const AudioStreamBasicDescription &streamFormat, char *buffer, int bufferSize)
+ : m_owner(false)
+ , m_streamDescription(streamFormat)
+ , m_bufferList(0)
+{
+ m_dataSize = bufferSize;
+
+ m_bufferList = reinterpret_cast<AudioBufferList*>(malloc(sizeof(AudioBufferList) + sizeof(AudioBuffer)));
+
+ m_bufferList->mNumberBuffers = 1;
+ m_bufferList->mBuffers[0].mNumberChannels = 1;
+ m_bufferList->mBuffers[0].mDataByteSize = m_dataSize;
+ m_bufferList->mBuffers[0].mData = buffer;
+}
+
+QCoreAudioBufferList::QCoreAudioBufferList(const AudioStreamBasicDescription &streamFormat, int framesToBuffer)
+ : m_owner(true)
+ , m_streamDescription(streamFormat)
+ , m_bufferList(0)
+{
+ const bool isInterleaved = (m_streamDescription.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
+ const int numberOfBuffers = isInterleaved ? 1 : m_streamDescription.mChannelsPerFrame;
+
+ m_dataSize = framesToBuffer * m_streamDescription.mBytesPerFrame;
+
+ m_bufferList = reinterpret_cast<AudioBufferList*>(malloc(sizeof(AudioBufferList) +
+ (sizeof(AudioBuffer) * numberOfBuffers)));
+ m_bufferList->mNumberBuffers = numberOfBuffers;
+ for (int i = 0; i < numberOfBuffers; ++i) {
+ m_bufferList->mBuffers[i].mNumberChannels = isInterleaved ? numberOfBuffers : 1;
+ m_bufferList->mBuffers[i].mDataByteSize = m_dataSize;
+ m_bufferList->mBuffers[i].mData = malloc(m_dataSize);
+ }
+}
+
+QCoreAudioBufferList::~QCoreAudioBufferList()
+{
+ if (m_owner) {
+ for (UInt32 i = 0; i < m_bufferList->mNumberBuffers; ++i)
+ free(m_bufferList->mBuffers[i].mData);
+ }
+
+ free(m_bufferList);
+}
+
+char *QCoreAudioBufferList::data(int buffer) const
+{
+ return static_cast<char*>(m_bufferList->mBuffers[buffer].mData);
+}
+
+qint64 QCoreAudioBufferList::bufferSize(int buffer) const
+{
+ return m_bufferList->mBuffers[buffer].mDataByteSize;
+}
+
+int QCoreAudioBufferList::frameCount(int buffer) const
+{
+ return m_bufferList->mBuffers[buffer].mDataByteSize / m_streamDescription.mBytesPerFrame;
+}
+
+int QCoreAudioBufferList::packetCount(int buffer) const
+{
+ return m_bufferList->mBuffers[buffer].mDataByteSize / m_streamDescription.mBytesPerPacket;
+}
+
+int QCoreAudioBufferList::packetSize() const
+{
+ return m_streamDescription.mBytesPerPacket;
+}
+
+void QCoreAudioBufferList::reset()
+{
+ for (UInt32 i = 0; i < m_bufferList->mNumberBuffers; ++i) {
+ m_bufferList->mBuffers[i].mDataByteSize = m_dataSize;
+ m_bufferList->mBuffers[i].mData = 0;
+ }
+}
+
+QCoreAudioPacketFeeder::QCoreAudioPacketFeeder(QCoreAudioBufferList *abl)
+ : m_audioBufferList(abl)
+{
+ m_totalPackets = m_audioBufferList->packetCount();
+ m_position = 0;
+}
+
+bool QCoreAudioPacketFeeder::feed(AudioBufferList &dst, UInt32 &packetCount)
+{
+ if (m_position == m_totalPackets) {
+ dst.mBuffers[0].mDataByteSize = 0;
+ packetCount = 0;
+ return false;
+ }
+
+ if (m_totalPackets - m_position < packetCount)
+ packetCount = m_totalPackets - m_position;
+
+ dst.mBuffers[0].mDataByteSize = packetCount * m_audioBufferList->packetSize();
+ dst.mBuffers[0].mData = m_audioBufferList->data() + (m_position * m_audioBufferList->packetSize());
+
+ m_position += packetCount;
+
+ return true;
+}
+
+bool QCoreAudioPacketFeeder::empty() const
+{
+ return m_position == m_totalPackets;
+}
+
+QDarwinAudioSourceBuffer::QDarwinAudioSourceBuffer(int bufferSize, int maxPeriodSize, const AudioStreamBasicDescription &inputFormat, const AudioStreamBasicDescription &outputFormat, QObject *parent)
+ : QObject(parent)
+ , m_deviceError(false)
+ , m_device(0)
+ , m_audioConverter(0)
+ , m_inputFormat(inputFormat)
+ , m_outputFormat(outputFormat)
+ , m_volume(qreal(1.0f))
+{
+ m_maxPeriodSize = maxPeriodSize;
+ m_periodTime = m_maxPeriodSize / m_outputFormat.mBytesPerFrame * 1000 / m_outputFormat.mSampleRate;
+
+ m_buffer = new CoreAudioRingBuffer(bufferSize);
+
+ m_inputBufferList = new QCoreAudioBufferList(m_inputFormat);
+
+ m_flushTimer = new QTimer(this);
+ connect(m_flushTimer, SIGNAL(timeout()), this, SLOT(flushBuffer()));
+
+ if (CoreAudioUtils::toQAudioFormat(inputFormat) != CoreAudioUtils::toQAudioFormat(outputFormat)) {
+ if (AudioConverterNew(&m_inputFormat, &m_outputFormat, &m_audioConverter) != noErr) {
+ qWarning() << "QAudioSource: Unable to create an Audio Converter";
+ m_audioConverter = 0;
+ }
+ }
+
+ m_qFormat = CoreAudioUtils::toQAudioFormat(inputFormat); // we adjust volume before conversion
+}
+
+QDarwinAudioSourceBuffer::~QDarwinAudioSourceBuffer()
+{
+ delete m_buffer;
+}
+
+qreal QDarwinAudioSourceBuffer::volume() const
+{
+ return m_volume;
+}
+
+void QDarwinAudioSourceBuffer::setVolume(qreal v)
+{
+ m_volume = v;
+}
+
+qint64 QDarwinAudioSourceBuffer::renderFromDevice(AudioUnit audioUnit, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames)
+{
+ const bool pullMode = m_device == 0;
+
+ OSStatus err;
+ qint64 framesRendered = 0;
+
+ m_inputBufferList->reset();
+ err = AudioUnitRender(audioUnit,
+ ioActionFlags,
+ inTimeStamp,
+ inBusNumber,
+ inNumberFrames,
+ m_inputBufferList->audioBufferList());
+
+ // adjust volume, if necessary
+ if (!qFuzzyCompare(m_volume, qreal(1.0f))) {
+ QAudioHelperInternal::qMultiplySamples(m_volume,
+ m_qFormat,
+ m_inputBufferList->data(), /* input */
+ m_inputBufferList->data(), /* output */
+ m_inputBufferList->bufferSize());
+ }
+
+ if (m_audioConverter != 0) {
+ QCoreAudioPacketFeeder feeder(m_inputBufferList);
+
+ int copied = 0;
+ const int available = m_buffer->free();
+
+ while (err == noErr && !feeder.empty()) {
+ CoreAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(available - copied);
+
+ if (region.second == 0)
+ break;
+
+ AudioBufferList output;
+ output.mNumberBuffers = 1;
+ output.mBuffers[0].mNumberChannels = 1;
+ output.mBuffers[0].mDataByteSize = region.second;
+ output.mBuffers[0].mData = region.first;
+
+ UInt32 packetSize = region.second / m_outputFormat.mBytesPerPacket;
+ err = AudioConverterFillComplexBuffer(m_audioConverter,
+ converterCallback,
+ &feeder,
+ &packetSize,
+ &output,
+ 0);
+ region.second = output.mBuffers[0].mDataByteSize;
+ copied += region.second;
+
+ m_buffer->releaseWriteRegion(region);
+ }
+
+ framesRendered += copied / m_outputFormat.mBytesPerFrame;
+ }
+ else {
+ const int available = m_inputBufferList->bufferSize();
+ bool wecan = true;
+ int copied = 0;
+
+ while (wecan && copied < available) {
+ CoreAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(available - copied);
+
+ if (region.second > 0) {
+ memcpy(region.first, m_inputBufferList->data() + copied, region.second);
+ copied += region.second;
+ }
+ else
+ wecan = false;
+
+ m_buffer->releaseWriteRegion(region);
+ }
+
+ framesRendered = copied / m_outputFormat.mBytesPerFrame;
+ }
+
+ if (pullMode && framesRendered > 0)
+ emit readyRead();
+
+ return framesRendered;
+}
+
+qint64 QDarwinAudioSourceBuffer::readBytes(char *data, qint64 len)
+{
+ bool wecan = true;
+ qint64 bytesCopied = 0;
+
+ len -= len % m_maxPeriodSize;
+ while (wecan && bytesCopied < len) {
+ CoreAudioRingBuffer::Region region = m_buffer->acquireReadRegion(len - bytesCopied);
+
+ if (region.second > 0) {
+ memcpy(data + bytesCopied, region.first, region.second);
+ bytesCopied += region.second;
+ }
+ else
+ wecan = false;
+
+ m_buffer->releaseReadRegion(region);
+ }
+
+ return bytesCopied;
+}
+
+void QDarwinAudioSourceBuffer::setFlushDevice(QIODevice *device)
+{
+ if (m_device != device)
+ m_device = device;
+}
+
+void QDarwinAudioSourceBuffer::startFlushTimer()
+{
+ if (m_device != 0) {
+ // We use the period time for the timer, since that's
+ // around the buffer size (pre conversion >.>)
+ m_flushTimer->start(qMax(1, m_periodTime));
+ }
+}
+
+void QDarwinAudioSourceBuffer::stopFlushTimer()
+{
+ m_flushTimer->stop();
+}
+
+void QDarwinAudioSourceBuffer::flush(bool all)
+{
+ if (m_device == 0)
+ return;
+
+ const int used = m_buffer->used();
+ const int readSize = all ? used : used - (used % m_maxPeriodSize);
+
+ if (readSize > 0) {
+ bool wecan = true;
+ int flushed = 0;
+
+ while (!m_deviceError && wecan && flushed < readSize) {
+ CoreAudioRingBuffer::Region region = m_buffer->acquireReadRegion(readSize - flushed);
+
+ if (region.second > 0) {
+ int bytesWritten = m_device->write(region.first, region.second);
+ if (bytesWritten < 0) {
+ stopFlushTimer();
+ m_deviceError = true;
+ }
+ else {
+ region.second = bytesWritten;
+ flushed += bytesWritten;
+ wecan = bytesWritten != 0;
+ }
+ }
+ else
+ wecan = false;
+
+ m_buffer->releaseReadRegion(region);
+ }
+ }
+}
+
+void QDarwinAudioSourceBuffer::reset()
+{
+ m_buffer->reset();
+ m_deviceError = false;
+}
+
+int QDarwinAudioSourceBuffer::available() const
+{
+ return m_buffer->free();
+}
+
+int QDarwinAudioSourceBuffer::used() const
+{
+ return m_buffer->used();
+}
+
+void QDarwinAudioSourceBuffer::flushBuffer()
+{
+ flush();
+}
+
+OSStatus QDarwinAudioSourceBuffer::converterCallback(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void *inUserData)
+{
+ Q_UNUSED(inAudioConverter);
+ Q_UNUSED(outDataPacketDescription);
+
+ QCoreAudioPacketFeeder* feeder = static_cast<QCoreAudioPacketFeeder*>(inUserData);
+
+ if (!feeder->feed(*ioData, *ioNumberDataPackets))
+ return as_empty;
+
+ return noErr;
+}
+
+QDarwinAudioSourceDevice::QDarwinAudioSourceDevice(QDarwinAudioSourceBuffer *audioBuffer, QObject *parent)
+ : QIODevice(parent)
+ , m_audioBuffer(audioBuffer)
+{
+ open(QIODevice::ReadOnly | QIODevice::Unbuffered);
+ connect(m_audioBuffer, SIGNAL(readyRead()), this, SIGNAL(readyRead()));
+}
+
+qint64 QDarwinAudioSourceDevice::readData(char *data, qint64 len)
+{
+ return m_audioBuffer->readBytes(data, len);
+}
+
+qint64 QDarwinAudioSourceDevice::writeData(const char *data, qint64 len)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(len);
+
+ return 0;
+}
+
+QDarwinAudioSource::QDarwinAudioSource(const QAudioDevice &device, QObject *parent)
+ : QPlatformAudioSource(parent)
+ , m_audioDeviceInfo(device)
+ , m_isOpen(false)
+ , m_internalBufferSize(DEFAULT_BUFFER_SIZE)
+ , m_totalFrames(0)
+ , m_audioUnit(0)
+ , m_clockFrequency(CoreAudioUtils::frequency() / 1000)
+ , m_errorCode(QAudio::NoError)
+ , m_stateCode(QAudio::StoppedState)
+ , m_audioBuffer(nullptr)
+ , m_volume(1.0)
+{
+ QAudioDevice di = device;
+ if (di.isNull())
+ di = QMediaDevices::defaultAudioInput();
+#if defined(Q_OS_MACOS)
+ const QCoreAudioDeviceInfo *info = static_cast<const QCoreAudioDeviceInfo *>(di.handle());
+ Q_ASSERT(info);
+ m_audioDeviceId = info->deviceID();
+#endif
+ m_device = di.id();
+}
+
+
+QDarwinAudioSource::~QDarwinAudioSource()
+{
+ close();
+}
+
+bool QDarwinAudioSource::open()
+{
+#if defined(Q_OS_IOS)
+ CoreAudioSessionManager::instance().setCategory(CoreAudioSessionManager::PlayAndRecord, CoreAudioSessionManager::MixWithOthers);
+ CoreAudioSessionManager::instance().setActive(true);
+#endif
+
+ if (m_isOpen)
+ return true;
+
+ AudioComponentDescription componentDescription;
+ componentDescription.componentType = kAudioUnitType_Output;
+#if defined(Q_OS_MACOS)
+ componentDescription.componentSubType = kAudioUnitSubType_HALOutput;
+#else
+ componentDescription.componentSubType = kAudioUnitSubType_RemoteIO;
+#endif
+ componentDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
+ componentDescription.componentFlags = 0;
+ componentDescription.componentFlagsMask = 0;
+
+ AudioComponent component = AudioComponentFindNext(0, &componentDescription);
+ if (component == 0) {
+ qWarning() << "QAudioSource: Failed to find Output component";
+ return false;
+ }
+
+ if (AudioComponentInstanceNew(component, &m_audioUnit) != noErr) {
+ qWarning() << "QAudioSource: Unable to Open Output Component";
+ return false;
+ }
+
+ // Set mode
+ // switch to input mode
+ UInt32 enable = 1;
+ if (AudioUnitSetProperty(m_audioUnit,
+ kAudioOutputUnitProperty_EnableIO,
+ kAudioUnitScope_Input,
+ 1,
+ &enable,
+ sizeof(enable)) != noErr) {
+ qWarning() << "QAudioSource: Unable to switch to input mode (Enable Input)";
+ return false;
+ }
+
+ enable = 0;
+ if (AudioUnitSetProperty(m_audioUnit,
+ kAudioOutputUnitProperty_EnableIO,
+ kAudioUnitScope_Output,
+ 0,
+ &enable,
+ sizeof(enable)) != noErr) {
+ qWarning() << "QAudioSource: Unable to switch to input mode (Disable output)";
+ return false;
+ }
+
+ // register callback
+ AURenderCallbackStruct callback;
+ callback.inputProc = inputCallback;
+ callback.inputProcRefCon = this;
+
+ if (AudioUnitSetProperty(m_audioUnit,
+ kAudioOutputUnitProperty_SetInputCallback,
+ kAudioUnitScope_Global,
+ 0,
+ &callback,
+ sizeof(callback)) != noErr) {
+ qWarning() << "QAudioSource: Failed to set AudioUnit callback";
+ return false;
+ }
+
+#if defined(Q_OS_MACOS)
+ //Set Audio Device
+ if (AudioUnitSetProperty(m_audioUnit,
+ kAudioOutputUnitProperty_CurrentDevice,
+ kAudioUnitScope_Global,
+ 0,
+ &m_audioDeviceId,
+ sizeof(m_audioDeviceId)) != noErr) {
+ qWarning() << "QAudioSource: Unable to use configured device";
+ return false;
+ }
+#endif
+
+ //set format
+ m_streamFormat = CoreAudioUtils::toAudioStreamBasicDescription(m_audioFormat);
+
+#if defined(Q_OS_MACOS)
+ UInt32 size = 0;
+
+ if (m_audioFormat == m_audioDeviceInfo.preferredFormat()) {
+#endif
+
+ m_deviceFormat = m_streamFormat;
+ AudioUnitSetProperty(m_audioUnit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Output,
+ 1,
+ &m_deviceFormat,
+ sizeof(m_deviceFormat));
+#if defined(Q_OS_MACOS)
+ } else {
+ size = sizeof(m_deviceFormat);
+ if (AudioUnitGetProperty(m_audioUnit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Input,
+ 1,
+ &m_deviceFormat,
+ &size) != noErr) {
+ qWarning() << "QAudioSource: Unable to retrieve device format";
+ return false;
+ }
+
+ if (AudioUnitSetProperty(m_audioUnit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Output,
+ 1,
+ &m_deviceFormat,
+ sizeof(m_deviceFormat)) != noErr) {
+ qWarning() << "QAudioSource: Unable to set device format";
+ return false;
+ }
+ }
+#endif
+
+ //setup buffers
+ UInt32 numberOfFrames;
+#if defined(Q_OS_MACOS)
+ size = sizeof(UInt32);
+ if (AudioUnitGetProperty(m_audioUnit,
+ kAudioDevicePropertyBufferFrameSize,
+ kAudioUnitScope_Global,
+ 0,
+ &numberOfFrames,
+ &size) != noErr) {
+ qWarning() << "QAudioSource: Failed to get audio period size";
+ return false;
+ }
+ //BUG: numberOfFrames gets ignored after this point
+
+ AudioValueRange bufferRange;
+ size = sizeof(AudioValueRange);
+
+ if (AudioUnitGetProperty(m_audioUnit,
+ kAudioDevicePropertyBufferFrameSizeRange,
+ kAudioUnitScope_Global,
+ 0,
+ &bufferRange,
+ &size) != noErr) {
+ qWarning() << "QAudioSource: Failed to get audio period size range";
+ return false;
+ }
+
+ // See if the requested buffer size is permissible
+ numberOfFrames = qBound((UInt32)bufferRange.mMinimum, m_internalBufferSize / m_streamFormat.mBytesPerFrame, (UInt32)bufferRange.mMaximum);
+
+ // Set it back
+ if (AudioUnitSetProperty(m_audioUnit,
+ kAudioDevicePropertyBufferFrameSize,
+ kAudioUnitScope_Global,
+ 0,
+ &numberOfFrames,
+ sizeof(UInt32)) != noErr) {
+ qWarning() << "QAudioSource: Failed to set audio buffer size";
+ return false;
+ }
+#else //iOS
+ Float32 bufferSize = CoreAudioSessionManager::instance().currentIOBufferDuration();
+ bufferSize *= m_streamFormat.mSampleRate;
+ numberOfFrames = bufferSize;
+#endif
+
+ // Now allocate a few buffers to be safe.
+ m_periodSizeBytes = m_internalBufferSize = numberOfFrames * m_streamFormat.mBytesPerFrame;
+
+ {
+ QMutexLocker lock(m_audioBuffer);
+ m_audioBuffer = new QDarwinAudioSourceBuffer(m_internalBufferSize * 4,
+ m_periodSizeBytes,
+ m_deviceFormat,
+ m_streamFormat,
+ this);
+
+ m_audioBuffer->setVolume(m_volume);
+ }
+ m_audioIO = new QDarwinAudioSourceDevice(m_audioBuffer, this);
+
+ // Init
+ if (AudioUnitInitialize(m_audioUnit) != noErr) {
+ qWarning() << "QAudioSource: Failed to initialize AudioUnit";
+ return false;
+ }
+
+ m_isOpen = true;
+
+ return m_isOpen;
+
+}
+
+void QDarwinAudioSource::close()
+{
+ stop();
+ if (m_audioUnit != 0) {
+ AudioOutputUnitStop(m_audioUnit);
+ AudioUnitUninitialize(m_audioUnit);
+ AudioComponentInstanceDispose(m_audioUnit);
+ }
+
+ delete m_audioBuffer;
+ m_audioBuffer = nullptr;
+ m_isOpen = false;
+}
+
+void QDarwinAudioSource::start(QIODevice *device)
+{
+ QIODevice* op = device;
+
+ if (!m_audioDeviceInfo.isFormatSupported(m_audioFormat) || !open()) {
+ m_stateCode = QAudio::StoppedState;
+ m_errorCode = QAudio::OpenError;
+ return;
+ }
+
+ reset();
+ {
+ QMutexLocker lock(m_audioBuffer);
+ m_audioBuffer->reset();
+ m_audioBuffer->setFlushDevice(op);
+ }
+
+ if (op == 0)
+ op = m_audioIO;
+
+ // Start
+ m_totalFrames = 0;
+
+ m_stateCode = QAudio::IdleState;
+ m_errorCode = QAudio::NoError;
+ emit stateChanged(m_stateCode);
+
+ audioThreadStart();
+}
+
+
+QIODevice *QDarwinAudioSource::start()
+{
+ QIODevice* op = 0;
+
+ if (!m_audioDeviceInfo.isFormatSupported(m_audioFormat) || !open()) {
+ m_stateCode = QAudio::StoppedState;
+ m_errorCode = QAudio::OpenError;
+ return m_audioIO;
+ }
+
+ reset();
+ {
+ QMutexLocker lock(m_audioBuffer);
+ m_audioBuffer->reset();
+ m_audioBuffer->setFlushDevice(op);
+ }
+
+ if (op == 0)
+ op = m_audioIO;
+
+ // Start
+ m_totalFrames = 0;
+
+ m_stateCode = QAudio::IdleState;
+ m_errorCode = QAudio::NoError;
+ emit stateChanged(m_stateCode);
+
+ audioThreadStart();
+
+ return op;
+}
+
+
+void QDarwinAudioSource::stop()
+{
+ QMutexLocker lock(m_audioBuffer);
+ if (m_stateCode != QAudio::StoppedState) {
+ audioThreadStop();
+ m_audioBuffer->flush(true);
+
+ m_errorCode = QAudio::NoError;
+ m_stateCode = QAudio::StoppedState;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, m_stateCode));
+ }
+}
+
+
+void QDarwinAudioSource::reset()
+{
+ QMutexLocker lock(m_audioBuffer);
+ if (m_stateCode != QAudio::StoppedState) {
+ audioThreadStop();
+
+ m_errorCode = QAudio::NoError;
+ m_stateCode = QAudio::StoppedState;
+ m_audioBuffer->reset();
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, m_stateCode));
+ }
+}
+
+
+void QDarwinAudioSource::suspend()
+{
+ QMutexLocker lock(m_audioBuffer);
+ if (m_stateCode == QAudio::ActiveState || m_stateCode == QAudio::IdleState) {
+ audioThreadStop();
+
+ m_errorCode = QAudio::NoError;
+ m_stateCode = QAudio::SuspendedState;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, m_stateCode));
+ }
+}
+
+
+void QDarwinAudioSource::resume()
+{
+ QMutexLocker lock(m_audioBuffer);
+ if (m_stateCode == QAudio::SuspendedState) {
+ audioThreadStart();
+
+ m_errorCode = QAudio::NoError;
+ m_stateCode = QAudio::ActiveState;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, m_stateCode));
+ }
+}
+
+
+qsizetype QDarwinAudioSource::bytesReady() const
+{
+ QMutexLocker lock(m_audioBuffer);
+ if (!m_audioBuffer)
+ return 0;
+ return m_audioBuffer->used();
+}
+
+void QDarwinAudioSource::setBufferSize(qsizetype value)
+{
+ m_internalBufferSize = value;
+}
+
+
+qsizetype QDarwinAudioSource::bufferSize() const
+{
+ return m_internalBufferSize;
+}
+
+qint64 QDarwinAudioSource::processedUSecs() const
+{
+ return m_totalFrames * 1000000 / m_audioFormat.sampleRate();
+}
+
+QAudio::Error QDarwinAudioSource::error() const
+{
+ return m_errorCode;
+}
+
+
+QAudio::State QDarwinAudioSource::state() const
+{
+ return m_stateCode;
+}
+
+
+void QDarwinAudioSource::setFormat(const QAudioFormat &format)
+{
+ if (m_stateCode == QAudio::StoppedState)
+ m_audioFormat = format;
+}
+
+
+QAudioFormat QDarwinAudioSource::format() const
+{
+ return m_audioFormat;
+}
+
+
+void QDarwinAudioSource::setVolume(qreal volume)
+{
+ QMutexLocker lock(m_audioBuffer);
+ m_volume = volume;
+ if (m_audioBuffer)
+ m_audioBuffer->setVolume(m_volume);
+}
+
+
+qreal QDarwinAudioSource::volume() const
+{
+ return m_volume;
+}
+
+void QDarwinAudioSource::deviceStoppped()
+{
+ stopTimers();
+ emit stateChanged(m_stateCode);
+}
+
+void QDarwinAudioSource::audioThreadStart()
+{
+ startTimers();
+ m_audioThreadState.storeRelaxed(Running);
+ AudioOutputUnitStart(m_audioUnit);
+}
+
+void QDarwinAudioSource::audioThreadStop()
+{
+ stopTimers();
+ if (m_audioThreadState.testAndSetAcquire(Running, Stopped))
+ m_audioBuffer->wait();
+}
+
+void QDarwinAudioSource::audioDeviceStop()
+{
+ AudioOutputUnitStop(m_audioUnit);
+ m_audioThreadState.storeRelaxed(Stopped);
+ m_audioBuffer->wake();
+}
+
+void QDarwinAudioSource::audioDeviceActive()
+{
+ if (m_stateCode == QAudio::IdleState) {
+ QMutexLocker lock(m_audioBuffer);
+ m_stateCode = QAudio::ActiveState;
+ emit stateChanged(m_stateCode);
+ }
+}
+
+void QDarwinAudioSource::audioDeviceFull()
+{
+ if (m_stateCode == QAudio::ActiveState) {
+ QMutexLocker lock(m_audioBuffer);
+ m_errorCode = QAudio::UnderrunError;
+ m_stateCode = QAudio::IdleState;
+ emit stateChanged(m_stateCode);
+ }
+}
+
+void QDarwinAudioSource::audioDeviceError()
+{
+ if (m_stateCode == QAudio::ActiveState) {
+ QMutexLocker lock(m_audioBuffer);
+ audioDeviceStop();
+
+ m_errorCode = QAudio::IOError;
+ m_stateCode = QAudio::StoppedState;
+ QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection);
+ }
+}
+
+void QDarwinAudioSource::startTimers()
+{
+ m_audioBuffer->startFlushTimer();
+}
+
+void QDarwinAudioSource::stopTimers()
+{
+ m_audioBuffer->stopFlushTimer();
+}
+
+OSStatus QDarwinAudioSource::inputCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
+{
+ Q_UNUSED(ioData);
+
+ QDarwinAudioSource* d = static_cast<QDarwinAudioSource*>(inRefCon);
+
+ const int threadState = d->m_audioThreadState.loadAcquire();
+ if (threadState == Stopped)
+ d->audioDeviceStop();
+ else {
+ qint64 framesWritten;
+
+ {
+ QMutexLocker locker(d->m_audioBuffer);
+ framesWritten = d->m_audioBuffer->renderFromDevice(d->m_audioUnit,
+ ioActionFlags,
+ inTimeStamp,
+ inBusNumber,
+ inNumberFrames);
+ }
+
+ if (framesWritten > 0) {
+ d->m_totalFrames += framesWritten;
+ d->audioDeviceActive();
+ } else if (framesWritten == 0)
+ d->audioDeviceFull();
+ else if (framesWritten < 0)
+ d->audioDeviceError();
+ }
+
+ return noErr;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qdarwinaudiosource_p.cpp"
diff --git a/src/multimedia/darwin/qdarwinaudiosource_p.h b/src/multimedia/darwin/qdarwinaudiosource_p.h
new file mode 100644
index 000000000..87c3c1070
--- /dev/null
+++ b/src/multimedia/darwin/qdarwinaudiosource_p.h
@@ -0,0 +1,244 @@
+// 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
+
+//
+// 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 <qdarwinaudiodevice_p.h>
+
+#include <AudioUnit/AudioUnit.h>
+#include <CoreAudio/CoreAudioTypes.h>
+#include <AudioToolbox/AudioToolbox.h>
+
+#include <QtCore/QIODevice>
+#include <QtCore/QWaitCondition>
+#include <QtCore/QMutex>
+#include <QtCore/QTimer>
+
+QT_BEGIN_NAMESPACE
+
+class CoreAudioRingBuffer;
+class QCoreAudioPacketFeeder;
+class QDarwinAudioSourceBuffer;
+class QDarwinAudioSourceDevice;
+
+class QCoreAudioBufferList
+{
+public:
+ QCoreAudioBufferList(AudioStreamBasicDescription const& streamFormat);
+ QCoreAudioBufferList(AudioStreamBasicDescription const& streamFormat, char *buffer, int bufferSize);
+ QCoreAudioBufferList(AudioStreamBasicDescription const& streamFormat, int framesToBuffer);
+
+ ~QCoreAudioBufferList();
+
+ AudioBufferList* audioBufferList() const { return m_bufferList; }
+ char *data(int buffer = 0) const;
+ qint64 bufferSize(int buffer = 0) const;
+ int frameCount(int buffer = 0) const;
+ int packetCount(int buffer = 0) const;
+ int packetSize() const;
+ void reset();
+
+private:
+ bool m_owner;
+ int m_dataSize;
+ AudioStreamBasicDescription m_streamDescription;
+ AudioBufferList *m_bufferList;
+};
+
+class QCoreAudioPacketFeeder
+{
+public:
+ QCoreAudioPacketFeeder(QCoreAudioBufferList *abl);
+
+ bool feed(AudioBufferList& dst, UInt32& packetCount);
+ bool empty() const;
+
+private:
+ UInt32 m_totalPackets;
+ UInt32 m_position;
+ QCoreAudioBufferList *m_audioBufferList;
+};
+
+class QDarwinAudioSourceBuffer : public QObject
+{
+ Q_OBJECT
+
+public:
+ QDarwinAudioSourceBuffer(int bufferSize,
+ int maxPeriodSize,
+ AudioStreamBasicDescription const& inputFormat,
+ AudioStreamBasicDescription const& outputFormat,
+ QObject *parent);
+
+ ~QDarwinAudioSourceBuffer();
+
+ qreal volume() const;
+ void setVolume(qreal v);
+
+ qint64 renderFromDevice(AudioUnit audioUnit,
+ AudioUnitRenderActionFlags *ioActionFlags,
+ const AudioTimeStamp *inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames);
+
+ qint64 readBytes(char *data, qint64 len);
+
+ void setFlushDevice(QIODevice *device);
+
+ void startFlushTimer();
+ void stopFlushTimer();
+
+ void flush(bool all = false);
+ void reset();
+ int available() const;
+ int used() const;
+
+ void lock() { m_mutex.lock(); }
+ void unlock() { m_mutex.unlock(); }
+
+ void wait() { m_threadFinished.wait(&m_mutex); }
+ void wake() { m_threadFinished.wakeOne(); }
+
+signals:
+ void readyRead();
+
+private slots:
+ void flushBuffer();
+
+private:
+ QMutex m_mutex;
+ QWaitCondition m_threadFinished;
+
+ bool m_deviceError;
+ int m_maxPeriodSize;
+ int m_periodTime;
+ QIODevice *m_device;
+ QTimer *m_flushTimer;
+ CoreAudioRingBuffer *m_buffer;
+ QCoreAudioBufferList *m_inputBufferList;
+ AudioConverterRef m_audioConverter;
+ AudioStreamBasicDescription m_inputFormat;
+ AudioStreamBasicDescription m_outputFormat;
+ QAudioFormat m_qFormat;
+ qreal m_volume;
+
+ const static OSStatus as_empty = 'qtem';
+
+ // Converter callback
+ static OSStatus converterCallback(AudioConverterRef inAudioConverter,
+ UInt32 *ioNumberDataPackets,
+ AudioBufferList *ioData,
+ AudioStreamPacketDescription **outDataPacketDescription,
+ void *inUserData);
+};
+
+class QDarwinAudioSourceDevice : public QIODevice
+{
+ Q_OBJECT
+
+public:
+ QDarwinAudioSourceDevice(QDarwinAudioSourceBuffer *audioBuffer, QObject *parent);
+
+ qint64 readData(char *data, qint64 len);
+ qint64 writeData(const char *data, qint64 len);
+
+ bool isSequential() const { return true; }
+
+private:
+ QDarwinAudioSourceBuffer *m_audioBuffer;
+};
+
+class QDarwinAudioSource : public QPlatformAudioSource
+{
+ Q_OBJECT
+
+public:
+ QDarwinAudioSource(const QAudioDevice &device, QObject *parent);
+ ~QDarwinAudioSource();
+
+ void start(QIODevice *device);
+ QIODevice *start();
+ 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 setFormat(const QAudioFormat &format);
+ QAudioFormat format() const;
+
+ void setVolume(qreal volume);
+ qreal volume() const;
+
+private slots:
+ void deviceStoppped();
+
+private:
+ enum {
+ Running,
+ Stopped
+ };
+
+ bool open();
+ void close();
+
+ void audioThreadStart();
+ void audioThreadStop();
+
+ void audioDeviceStop();
+ void audioDeviceActive();
+ void audioDeviceFull();
+ void audioDeviceError();
+
+ void startTimers();
+ void stopTimers();
+
+ // Input callback
+ static OSStatus inputCallback(void *inRefCon,
+ AudioUnitRenderActionFlags *ioActionFlags,
+ const AudioTimeStamp *inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames,
+ AudioBufferList *ioData);
+
+ QAudioDevice m_audioDeviceInfo;
+ QByteArray m_device;
+ bool m_isOpen;
+ int m_periodSizeBytes;
+ int m_internalBufferSize;
+ qint64 m_totalFrames;
+ QAudioFormat m_audioFormat;
+ QIODevice *m_audioIO;
+ AudioUnit m_audioUnit;
+#if defined(Q_OS_MACOS)
+ AudioDeviceID m_audioDeviceId;
+#endif
+ Float64 m_clockFrequency;
+ QAudio::Error m_errorCode;
+ QAudio::State m_stateCode;
+ QDarwinAudioSourceBuffer *m_audioBuffer;
+ QAtomicInt m_audioThreadState;
+ AudioStreamBasicDescription m_streamFormat;
+ AudioStreamBasicDescription m_deviceFormat;
+ qreal m_volume;
+};
+
+QT_END_NAMESPACE
+
+#endif // IOSAUDIOINPUT_H
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/qtmultimedia.qdocconf b/src/multimedia/doc/qtmultimedia.qdocconf
index dfafd8715..97e6dc696 100644
--- a/src/multimedia/doc/qtmultimedia.qdocconf
+++ b/src/multimedia/doc/qtmultimedia.qdocconf
@@ -6,7 +6,9 @@ description = Qt Multimedia Documentation
version = $QT_VERSION
moduleheader = QtMultimediaDoc
-includepaths = -I .
+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
@@ -36,7 +38,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 +46,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
+# 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
new file mode 100644
index 000000000..c3937477b
--- /dev/null
+++ b/src/multimedia/doc/snippets/CMakeLists.txt
@@ -0,0 +1,15 @@
+# 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)
+
+add_executable(mytarget
+ multimedia-snippets/media.cpp
+)
+
+# ![0]
+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/doc_src_qtmultimedia.pro b/src/multimedia/doc/snippets/doc_src_qtmultimedia.pro
deleted file mode 100644
index 13da13011..000000000
--- a/src/multimedia/doc/snippets/doc_src_qtmultimedia.pro
+++ /dev/null
@@ -1,3 +0,0 @@
-#! [0]
-QT += multimedia
-#! [0]
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/audio.cpp b/src/multimedia/doc/snippets/multimedia-snippets/audio.cpp
index 57d3adfb4..565f7b29b 100644
--- a/src/multimedia/doc/snippets/multimedia-snippets/audio.cpp
+++ b/src/multimedia/doc/snippets/multimedia-snippets/audio.cpp
@@ -1,53 +1,19 @@
-/****************************************************************************
-**
-** 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>
#include <QTimer>
#include <QDebug>
+#include <qobject.h>
+#include <qfile.h>
-#include "qaudiodeviceinfo.h"
-#include "qaudioinput.h"
+#include "qaudiodevice.h"
+#include "qaudiosource.h"
#include "qaudiooutput.h"
-#include "qaudioprobe.h"
#include "qaudiodecoder.h"
#include "qmediaplayer.h"
+#include "qmediadevices.h"
class AudioInputExample : public QObject {
Q_OBJECT
@@ -62,7 +28,7 @@ public Q_SLOTS:
private:
//! [Audio input class members]
QFile destinationFile; // Class member
- QAudioInput* audio; // Class member
+ QAudioSource* audio; // Class member
//! [Audio input class members]
};
@@ -77,21 +43,17 @@ void AudioInputExample::setup()
// Set up the desired format, for example:
format.setSampleRate(8000);
format.setChannelCount(1);
- format.setSampleSize(8);
- format.setCodec("audio/pcm");
- format.setByteOrder(QAudioFormat::LittleEndian);
- format.setSampleType(QAudioFormat::UnSignedInt);
+ format.setSampleFormat(QAudioFormat::UInt8);
- QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
+ QAudioDevice info = QMediaDevices::defaultAudioInput();
if (!info.isFormatSupported(format)) {
qWarning() << "Default format not supported, trying to use the nearest.";
- format = info.nearestFormat(format);
}
- audio = new QAudioInput(format, this);
- connect(audio, SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleStateChanged(QAudio::State)));
+ audio = new QAudioSource(format, this);
+ 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
}
@@ -137,11 +99,12 @@ public:
public Q_SLOTS:
void handleStateChanged(QAudio::State newState);
+ void stopAudioOutput();
private:
//! [Audio output class members]
QFile sourceFile; // class member.
- QAudioOutput* audio; // class member.
+ QAudioSink* audio; // class member.
//! [Audio output class members]
};
@@ -156,32 +119,36 @@ void AudioOutputExample::setup()
// Set up the format, eg.
format.setSampleRate(8000);
format.setChannelCount(1);
- format.setSampleSize(8);
- format.setCodec("audio/pcm");
- format.setByteOrder(QAudioFormat::LittleEndian);
- format.setSampleType(QAudioFormat::UnSignedInt);
+ format.setSampleFormat(QAudioFormat::UInt8);
- QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
+ QAudioDevice info(QMediaDevices::defaultAudioOutput());
if (!info.isFormatSupported(format)) {
qWarning() << "Raw audio format not supported by backend, cannot play audio.";
return;
}
- audio = new QAudioOutput(format, this);
- connect(audio, SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleStateChanged(QAudio::State)));
+ audio = new QAudioSink(format, this);
+ 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:
@@ -204,18 +171,13 @@ void AudioDeviceInfo()
QAudioFormat format;
format.setSampleRate(44100);
// ... other format parameters
- format.setSampleType(QAudioFormat::SignedInt);
-
- QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
-
- if (!info.isFormatSupported(format))
- format = info.nearestFormat(format);
+ format.setSampleFormat(QAudioFormat::Int16);
//! [Setting audio format]
//! [Dumping audio formats]
- const auto deviceInfos = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
- for (const QAudioDeviceInfo &deviceInfo : deviceInfos)
- qDebug() << "Device name: " << deviceInfo.deviceName();
+ const auto devices = QMediaDevices::audioOutputs();
+ for (const QAudioDevice &device : devices)
+ qDebug() << "Device: " << device.description();
//! [Dumping audio formats]
}
@@ -234,16 +196,14 @@ void AudioDecodingExample::decode()
//! [Local audio decoding]
QAudioFormat desiredFormat;
desiredFormat.setChannelCount(2);
- desiredFormat.setCodec("audio/x-raw");
- desiredFormat.setSampleType(QAudioFormat::UnSignedInt);
+ desiredFormat.setSampleFormat(QAudioFormat::Int16);
desiredFormat.setSampleRate(48000);
- desiredFormat.setSampleSize(16);
QAudioDecoder *decoder = new QAudioDecoder(this);
decoder->setAudioFormat(desiredFormat);
- decoder->setSourceFilename("level1.mp3");
+ 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()
@@ -257,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/audiorecorder.cpp b/src/multimedia/doc/snippets/multimedia-snippets/audiorecorder.cpp
deleted file mode 100644
index bb9193b03..000000000
--- a/src/multimedia/doc/snippets/multimedia-snippets/audiorecorder.cpp
+++ /dev/null
@@ -1,211 +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 <QtWidgets>
-
-#include <qaudiorecorder.h>
-#include <qmediaservice.h>
-
-#include <QtMultimedia/qaudioformat.h>
-
-#include "audiorecorder.h"
-
-AudioRecorder::AudioRecorder()
-{
-//! [create-objs-1]
- capture = new QAudioRecorder();
-//! [create-objs-1]
-
- // set a default file
- capture->setOutputLocation(QUrl("test.raw"));
-
- QWidget *window = new QWidget;
- QGridLayout* layout = new QGridLayout;
-
- QLabel* deviceLabel = new QLabel;
- deviceLabel->setText("Devices");
- deviceBox = new QComboBox(this);
- deviceBox->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed);
-
- QLabel* codecLabel = new QLabel;
- codecLabel->setText("Codecs");
- codecsBox = new QComboBox(this);
- codecsBox->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed);
-
- QLabel* qualityLabel = new QLabel;
- qualityLabel->setText("Quality");
- qualityBox = new QComboBox(this);
- qualityBox->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed);
-
-//! [device-list]
- for(int i = 0; i < audiosource->deviceCount(); i++)
- deviceBox->addItem(audiosource->name(i));
-//! [device-list]
-
-//! [codec-list]
- QStringList codecs = capture->supportedAudioCodecs();
- for(int i = 0; i < codecs.count(); i++)
- codecsBox->addItem(codecs.at(i));
-//! [codec-list]
-
- qualityBox->addItem("Low");
- qualityBox->addItem("Medium");
- qualityBox->addItem("High");
-
- connect(capture, SIGNAL(durationChanged(qint64)), this, SLOT(updateProgress(qint64)));
- connect(capture, SIGNAL(stateChanged(QMediaRecorder::State)), this, SLOT(stateChanged(QMediaRecorder::State)));
-
- layout->addWidget(deviceLabel,0,0,Qt::AlignHCenter);
- connect(deviceBox,SIGNAL(activated(int)),SLOT(deviceChanged(int)));
- layout->addWidget(deviceBox,0,1,1,3,Qt::AlignLeft);
-
- layout->addWidget(codecLabel,1,0,Qt::AlignHCenter);
- connect(codecsBox,SIGNAL(activated(int)),SLOT(codecChanged(int)));
- layout->addWidget(codecsBox,1,1,Qt::AlignLeft);
-
- layout->addWidget(qualityLabel,1,2,Qt::AlignHCenter);
- connect(qualityBox,SIGNAL(activated(int)),SLOT(qualityChanged(int)));
- layout->addWidget(qualityBox,1,3,Qt::AlignLeft);
-
- fileButton = new QPushButton(this);
- fileButton->setText(tr("Output File"));
- connect(fileButton,SIGNAL(clicked()),SLOT(selectOutputFile()));
- layout->addWidget(fileButton,3,0,Qt::AlignHCenter);
-
- button = new QPushButton(this);
- button->setText(tr("Record"));
- connect(button,SIGNAL(clicked()),SLOT(toggleRecord()));
- layout->addWidget(button,3,3,Qt::AlignHCenter);
-
- recTime = new QLabel;
- recTime->setText("0 sec");
- layout->addWidget(recTime,4,0,Qt::AlignHCenter);
-
- window->setLayout(layout);
- setCentralWidget(window);
- window->show();
-
- active = false;
-}
-
-AudioRecorder::~AudioRecorder()
-{
- delete capture;
- delete audiosource;
-}
-
-void AudioRecorder::updateProgress(qint64 pos)
-{
- currentTime = pos;
- if(currentTime == 0) currentTime = 1;
- QString text = QString("%1 secs").arg(currentTime/1000);
- recTime->setText(text);
-}
-
-void AudioRecorder::stateChanged(QMediaRecorder::State state)
-{
- qWarning()<<"stateChanged() "<<state;
-}
-
-void AudioRecorder::deviceChanged(int idx)
-{
-//! [get-device]
- for(int i = 0; i < audiosource->deviceCount(); i++) {
- if(deviceBox->itemText(idx).compare(audiosource->name(i)) == 0)
- audiosource->setSelectedDevice(i);
- }
-//! [get-device]
-}
-
-void AudioRecorder::codecChanged(int idx)
-{
- Q_UNUSED(idx);
- //capture->setAudioCodec(codecsBox->itemText(idx));
-}
-
-void AudioRecorder::qualityChanged(int idx)
-{
- Q_UNUSED(idx);
- /*
- if(capture->audioCodec().compare("audio/pcm") == 0) {
- if(qualityBox->itemText(idx).compare("Low") == 0) {
- // 8000Hz mono is 8kbps
- capture->setAudioBitrate(8);
- } else if(qualityBox->itemText(idx).compare("Medium") == 0) {
- // 22050Hz mono is 44.1kbps
- capture->setAudioBitrate(44);
- } else if(qualityBox->itemText(idx).compare("High") == 0) {
- // 44100Hz mono is 88.2kbps
- capture->setAudioBitrate(88);
- }
- }
- */
-}
-
-//! [toggle-record]
-void AudioRecorder::toggleRecord()
-{
- if(!active) {
- recTime->setText("0 sec");
- currentTime = 0;
- capture->record();
-
- button->setText(tr("Stop"));
- active = true;
- } else {
- capture->stop();
- button->setText(tr("Record"));
- active = false;
- }
-}
-//! [toggle-record]
-
-void AudioRecorder::selectOutputFile()
-{
- QStringList fileNames;
-
- QFileDialog dialog(this);
-
- dialog.setFileMode(QFileDialog::AnyFile);
- if (dialog.exec())
- fileNames = dialog.selectedFiles();
-
- if(fileNames.size() > 0)
- capture->setOutputLocation(QUrl(fileNames.first()));
-}
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/camera.cpp b/src/multimedia/doc/snippets/multimedia-snippets/camera.cpp
index f851caadd..053af088f 100644
--- a/src/multimedia/doc/snippets/multimedia-snippets/camera.cpp
+++ b/src/multimedia/doc/snippets/multimedia-snippets/camera.cpp
@@ -1,66 +1,30 @@
-/****************************************************************************
-**
-** 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 */
#include "qcamera.h"
-#include "qcamerainfo.h"
-#include "qcameraviewfinder.h"
-#include "qcameraviewfindersettings.h"
+#include "qcameradevice.h"
#include "qmediarecorder.h"
-#include "qcameraimagecapture.h"
-#include "qcameraimageprocessing.h"
-#include "qabstractvideosurface.h"
+#include "qmediadevices.h"
+#include "qmediacapturesession.h"
+#include "qimagecapture.h"
+#include "qvideosink.h"
+#include <QtMultimediaWidgets/qvideowidget.h>
#include <QtGui/qscreen.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qimage.h>
/* Globals so that everything is consistent. */
QCamera *camera = 0;
-QCameraViewfinder *viewfinder = 0;
QMediaRecorder *recorder = 0;
-QCameraImageCapture *imageCapture = 0;
+QImageCapture *imageCapture = 0;
+QVideoWidget *viewfinder = 0;
//! [Camera overview check]
bool checkCameraAvailability()
{
- if (QCameraInfo::availableCameras().count() > 0)
+ if (QMediaDevices::videoInputs().count() > 0)
return true;
else
return false;
@@ -70,47 +34,37 @@ bool checkCameraAvailability()
void overview_viewfinder()
{
//! [Camera overview viewfinder]
+ QMediaCaptureSession captureSession;
camera = new QCamera;
- viewfinder = new QCameraViewfinder;
- camera->setViewfinder(viewfinder);
+ captureSession.setCamera(camera);
+ viewfinder = new QVideoWidget;
+ captureSession.setVideoOutput(viewfinder);
viewfinder->show();
- camera->start(); // to start the viewfinder
+ camera->start(); // to start the camera
//! [Camera overview viewfinder]
}
void overview_camera_by_position()
{
//! [Camera overview position]
- camera = new QCamera(QCamera::FrontFace);
+ camera = new QCamera(QCameraDevice::FrontFace);
//! [Camera overview position]
}
// -.-
-class MyVideoSurface : public QAbstractVideoSurface
-{
- QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const
- {
- Q_UNUSED(handleType);
- return QList<QVideoFrame::PixelFormat>();
- }
- bool present(const QVideoFrame &frame)
- {
- Q_UNUSED(frame);
- return true;
- }
-};
-
void overview_surface()
{
- MyVideoSurface *mySurface;
+ QVideoSink *mySink;
//! [Camera overview surface]
+ QMediaCaptureSession captureSession;
camera = new QCamera;
- mySurface = new MyVideoSurface;
- camera->setViewfinder(mySurface);
+ captureSession.setCamera(camera);
+ mySink = new QVideoSink;
+ captureSession.setVideoOutput(mySink);
camera->start();
- // MyVideoSurface::present(..) will be called with viewfinder frames
+ // MyVideoSink::setVideoFrame(..) will be called with video frames
//! [Camera overview surface]
}
@@ -121,18 +75,18 @@ void overview_viewfinder_orientation()
//! [Camera overview viewfinder orientation]
// Assuming a QImage has been created from the QVideoFrame that needs to be presented
QImage videoFrame;
- QCameraInfo cameraInfo(camera); // needed to get the camera sensor position and orientation
+ QCameraDevice cameraDevice(camera); // needed to get the camera sensor position and orientation
// Get the current display orientation
const QScreen *screen = QGuiApplication::primaryScreen();
const int screenAngle = screen->angleBetween(screen->nativeOrientation(), screen->orientation());
int rotation;
- if (cameraInfo.position() == QCamera::BackFace) {
- rotation = (cameraInfo.orientation() - screenAngle) % 360;
+ if (cameraDevice.position() == QCameraDevice::BackFace) {
+ rotation = (cameraDevice.orientation() - screenAngle) % 360;
} else {
// Front position, compensate the mirror
- rotation = (360 - cameraInfo.orientation() + screenAngle) % 360;
+ rotation = (360 - cameraDevice.orientation() + screenAngle) % 360;
}
// Rotate the frame so it always shows in the correct orientation
@@ -143,31 +97,36 @@ void overview_viewfinder_orientation()
void overview_still()
{
//! [Camera overview capture]
- imageCapture = new QCameraImageCapture(camera);
+ QMediaCaptureSession captureSession;
+ camera = new QCamera;
+ captureSession.setCamera(camera);
+ imageCapture = new QImageCapture;
+ captureSession.setImageCapture(imageCapture);
- camera->setCaptureMode(QCamera::CaptureStillImage);
camera->start(); // Viewfinder frames start flowing
- //on half pressed shutter button
- camera->searchAndLock();
-
//on shutter button pressed
imageCapture->capture();
-
- //on shutter button released
- camera->unlock();
//! [Camera overview capture]
}
void overview_movie()
{
//! [Camera overview movie]
+ QMediaCaptureSession captureSession;
camera = new QCamera;
+ captureSession.setCamera(camera);
recorder = new QMediaRecorder(camera);
+ captureSession.setRecorder(recorder);
- camera->setCaptureMode(QCamera::CaptureVideo);
camera->start();
+ // setup output format for the recorder
+ QMediaFormat format(QMediaFormat::MPEG4);
+ format.setVideoCodec(QMediaRecorder::VideoCodec::H264);
+ format.setAudioCodec(QMediaRecorder::AudioCodec::MP3);
+ recorder->setMediaFormat(settings);
+
//on shutter button pressed
recorder->record();
@@ -179,19 +138,19 @@ void overview_movie()
void camera_listing()
{
//! [Camera listing]
- const QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
- for (const QCameraInfo &cameraInfo : cameras)
- qDebug() << cameraInfo.deviceName();
+ const QList<QCameraDevice> cameras = QMediaDevices::videoInputs();
+ for (const QCameraDevice &cameraDevice : cameras)
+ qDebug() << cameraDevice.description();
//! [Camera listing]
}
void camera_selection()
{
//! [Camera selection]
- const QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
- for (const QCameraInfo &cameraInfo : cameras) {
- if (cameraInfo.deviceName() == "mycamera")
- camera = new QCamera(cameraInfo);
+ const QList<QCameraDevice> cameras = QMediaDevices::videoInputs();
+ for (const QCameraDevice &cameraDevice : cameras) {
+ if (cameraDevice.description() == "mycamera")
+ camera = new QCamera(cameraDevice);
}
//! [Camera selection]
}
@@ -200,95 +159,54 @@ void camera_info()
{
//! [Camera info]
QCamera myCamera;
- QCameraInfo cameraInfo(myCamera);
+ QCameraDevice cameraDevice = camera->cameraDevice();
- if (cameraInfo.position() == QCamera::FrontFace)
+ if (cameraDevice.position() == QCameraDevice::FrontFace)
qDebug() << "The camera is on the front face of the hardware system.";
- else if (cameraInfo.position() == QCamera::BackFace)
+ else if (cameraDevice.position() == QCameraDevice::BackFace)
qDebug() << "The camera is on the back face of the hardware system.";
-
- qDebug() << "The camera sensor orientation is " << cameraInfo.orientation() << " degrees.";
//! [Camera info]
}
void camera_blah()
{
//! [Camera]
+ QMediaCaptureSession captureSession;
camera = new QCamera;
+ captureSession.setCamera(camera);
- viewfinder = new QCameraViewfinder();
+ viewfinder = new QVideoWidget();
viewfinder->show();
+ captureSession.setVideoOutput(viewfinder);
- camera->setViewfinder(viewfinder);
-
- imageCapture = new QCameraImageCapture(camera);
+ imageCapture = new QImageCapture(camera);
+ captureSession.setImageCapture(imageCapture);
- camera->setCaptureMode(QCamera::CaptureStillImage);
camera->start();
//! [Camera]
//! [Camera keys]
- //on half pressed shutter button
- camera->searchAndLock();
-
//on shutter button pressed
imageCapture->capture();
-
- //on shutter button released
- camera->unlock();
//! [Camera keys]
}
void cameraimageprocessing()
{
- //! [Camera image whitebalance]
camera = new QCamera;
- QCameraImageProcessing *imageProcessing = camera->imageProcessing();
-
- if (imageProcessing->isAvailable()) {
- imageProcessing->setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceFluorescent);
- }
//! [Camera image whitebalance]
-
- //! [Camera image denoising]
- imageProcessing->setDenoisingLevel(-0.3); //reduce the amount of denoising applied
- //! [Camera image denoising]
+ camera->setWhiteBalanceMode(QCamera::WhiteBalanceFluorescent);
+ //! [Camera image whitebalance]
}
void camerafocus()
{
- //! [Camera custom zoom]
- QCameraFocus *focus = camera->focus();
- focus->setFocusPointMode(QCameraFocus::FocusPointCustom);
- focus->setCustomFocusPoint(QPointF(0.25f, 0.75f)); // A point near the bottom left, 25% away from the corner, near that shiny vase
- //! [Camera custom zoom]
-
- //! [Camera combined zoom]
- focus->zoomTo(3.0, 4.0); // Super zoom!
- //! [Camera combined zoom]
-
- //! [Camera focus zones]
- focus->setFocusPointMode(QCameraFocus::FocusPointAuto);
- const QList<QCameraFocusZone> zones = focus->focusZones();
- for (const QCameraFocusZone &zone : zones) {
- if (zone.status() == QCameraFocusZone::Focused) {
- // Draw a green box at zone.area()
- } else if (zone.status() == QCameraFocusZone::Selected) {
- // This area is selected for autofocusing, but is not in focus
- // Draw a yellow box at zone.area()
- }
- }
- //! [Camera focus zones]
-}
-
-void camera_viewfindersettings()
-{
- //! [Camera viewfinder settings]
- QCameraViewfinderSettings viewfinderSettings;
- viewfinderSettings.setResolution(640, 480);
- viewfinderSettings.setMinimumFrameRate(15.0);
- viewfinderSettings.setMaximumFrameRate(30.0);
-
- camera->setViewfinderSettings(viewfinderSettings);
- //! [Camera viewfinder settings]
+ //! [Camera custom focus]
+ camera->setFocusPointMode(QCamera::FocusModeManual);
+ camera->setCustomFocusPoint(QPointF(0.25f, 0.75f)); // A point near the bottom left, 25% away from the corner, near that shiny vase
+ //! [Camera custom focus]
+
+ //! [Camera zoom]
+ camera->setZoomFactor(3.0);
+ //! [Camera zoom]
}
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 5ba7fcc25..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>
@@ -44,17 +8,15 @@
#include "qmediaplaylist.h"
#include "qmediarecorder.h"
-#include "qmediaservice.h"
-#include "qmediaplayercontrol.h"
+#include "qplatformmediaplayer_p.h"
#include "qmediaplayer.h"
#include "qvideowidget.h"
-#include "qcameraimagecapture.h"
+#include "qimagecapture.h"
#include "qcamera.h"
#include "qcameraviewfinder.h"
-#include "qaudioprobe.h"
#include "qaudiorecorder.h"
-#include "qvideoprobe.h"
-#include <QAbstractVideoSurface>
+#include "qurl.h"
+#include <QVideoSink>
class MediaExample : public QObject {
Q_OBJECT
@@ -62,28 +24,22 @@ class MediaExample : public QObject {
void MediaControl();
void MediaPlayer();
void MediaRecorder();
- void AudioRecorder();
- void EncoderSettings();
- void ImageEncoderSettings();
- void AudioProbe();
- void VideoProbe();
+ void recorderSettings();
+ void imageSettings();
private:
// Common naming
- QMediaService *mediaService;
QVideoWidget *videoWidget;
QWidget *widget;
QMediaPlayer *player;
+ QAudioOutput *audioOutput;
QMediaPlaylist *playlist;
QMediaContent video;
QMediaRecorder *recorder;
QCamera *camera;
QCameraViewfinder *viewfinder;
- QCameraImageCapture *imageCapture;
+ QImageCapture *imageCapture;
QString fileName;
- QAudioRecorder *audioRecorder;
- QAudioProbe *audioProbe;
- QVideoProbe *videoProbe;
QMediaContent image1;
QMediaContent image2;
@@ -92,258 +48,62 @@ private:
void MediaExample::MediaControl()
{
- {
- //! [Request control]
- QMediaPlayerControl *control = qobject_cast<QMediaPlayerControl *>(
- mediaService->requestControl("org.qt-project.qt.mediaplayercontrol/5.0"));
- //! [Request control]
- Q_UNUSED(control);
- }
-
- {
- //! [Request control templated]
- QMediaPlayerControl *control = mediaService->requestControl<QMediaPlayerControl *>();
- //! [Request control templated]
- Q_UNUSED(control);
- }
}
-void MediaExample::EncoderSettings()
+void MediaExample::recorderSettings()
{
- //! [Audio encoder settings]
- QAudioEncoderSettings audioSettings;
- audioSettings.setCodec("audio/mpeg");
- audioSettings.setChannelCount(2);
-
- recorder->setAudioSettings(audioSettings);
- //! [Audio encoder settings]
+ //! [Media recorder settings]
+ QMediaFormat format(QMediaFormat::MPEG4);
+ format.setVideoCodec(QMediaRecorder::VideoCodec::H264);
+ format.setAudioCodec(QMediaRecorder::AudioCodec::MP3);
- //! [Video encoder settings]
- QVideoEncoderSettings videoSettings;
- videoSettings.setCodec("video/mpeg2");
- videoSettings.setResolution(640, 480);
-
- recorder->setVideoSettings(videoSettings);
- //! [Video encoder settings]
+ recorder->setMediaFormat(settings);
+ //! [Media recorder settings]
}
-void MediaExample::ImageEncoderSettings()
+void MediaExample::imageSettings()
{
- //! [Image encoder settings]
- QImageEncoderSettings imageSettings;
- imageSettings.setCodec("image/jpeg");
- imageSettings.setResolution(1600, 1200);
-
- imageCapture->setEncodingSettings(imageSettings);
- //! [Image encoder settings]
+ //! [Image recorder settings]
+ imageCapture->setFileFormat(QImageCapture::JPEG);
+ imageCapture->setResolution(1600, 1200);
+ //! [Image recorder settings]
}
void MediaExample::MediaPlayer()
{
//! [Player]
player = new QMediaPlayer;
- connect(player, SIGNAL(positionChanged(qint64)), this, SLOT(positionChanged(qint64)));
- player->setMedia(QUrl::fromLocalFile("/Users/me/Music/coolsong.mp3"));
- player->setVolume(50);
+ audioOutput = new QAudioOutput;
+ player->setAudioOutput(audioOutput);
+ connect(player, &QMediaPlayer::positionChanged, this, &MediaExample::positionChanged);
+ player->setSource(QUrl::fromLocalFile("/Users/me/Music/coolsong.mp3"));
+ audioOutput->setVolume(50);
player->play();
//! [Player]
//! [Local playback]
player = new QMediaPlayer;
+ audioOutput = new QAudioOutput;
+ player->setAudioOutput(audioOutput);
// ...
- player->setMedia(QUrl::fromLocalFile("/Users/me/Music/coolsong.mp3"));
- player->setVolume(50);
+ player->setSource(QUrl::fromLocalFile("/Users/me/Music/coolsong.mp3"));
+ audioOutput->setVolume(50);
player->play();
//! [Local playback]
-
- //! [Audio playlist]
- player = new QMediaPlayer;
-
- playlist = new QMediaPlaylist(player);
- playlist->addMedia(QUrl("http://example.com/myfile1.mp3"));
- playlist->addMedia(QUrl("http://example.com/myfile2.mp3"));
- // ...
- playlist->setCurrentIndex(1);
- player->play();
- //! [Audio playlist]
-
- //! [Movie playlist]
- playlist = new QMediaPlaylist;
- playlist->addMedia(QUrl("http://example.com/movie1.mp4"));
- playlist->addMedia(QUrl("http://example.com/movie2.mp4"));
- playlist->addMedia(QUrl("http://example.com/movie3.mp4"));
- playlist->setCurrentIndex(1);
-
- player = new QMediaPlayer;
- player->setPlaylist(playlist);
-
- videoWidget = new QVideoWidget;
- player->setVideoOutput(videoWidget);
- videoWidget->show();
-
- player->play();
- //! [Movie playlist]
-
- //! [Pipeline]
- player = new QMediaPlayer;
- player->setMedia(QUrl("gst-pipeline: videotestsrc ! autovideosink"));
- player->play();
- //! [Pipeline]
-
- //! [Pipeline Surface]
- class Surface : public QAbstractVideoSurface
- {
- public:
- Surface(QObject *p) : QAbstractVideoSurface(p) { }
- QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType) const override
- {
- // Make sure that the driver supports this pixel format.
- return QList<QVideoFrame::PixelFormat>() << QVideoFrame::Format_YUYV;
- }
-
- // Video frames are handled here.
- bool present(const QVideoFrame &) override { return true; }
- };
-
- player = new QMediaPlayer;
- player->setVideoOutput(new Surface(player));
- player->setMedia(QUrl("gst-pipeline: videotestsrc ! qtvideosink"));
- player->play();
- //! [Pipeline Surface]
-
- //! [Pipeline Widget]
- player = new QMediaPlayer;
- videoWidget = new QVideoWidget;
- videoWidget->show();
- player->setVideoOutput(videoWidget);
- player->setMedia(QUrl("gst-pipeline: videotestsrc ! xvimagesink name=\"qtvideosink\""));
- player->play();
- //! [Pipeline Widget]
-
- //! [Pipeline appsrc]
- QImage img("images/qt-logo.png");
- img = img.convertToFormat(QImage::Format_ARGB32);
- QByteArray ba(reinterpret_cast<const char *>(img.bits()), img.sizeInBytes());
- QBuffer buffer(&ba);
- buffer.open(QIODevice::ReadOnly);
- player = new QMediaPlayer;
- player->setMedia(QUrl("gst-pipeline: appsrc blocksize=4294967295 ! \
- video/x-raw,format=BGRx,framerate=30/1,width=200,height=147 ! \
- coloreffects preset=heat ! videoconvert ! video/x-raw,format=I420 ! jpegenc ! rtpjpegpay ! \
- udpsink host=127.0.0.1 port=5000"), &buffer);
- player->play();
-
- QMediaPlayer *receiver = new QMediaPlayer;
- videoWidget = new QVideoWidget;
- receiver->setVideoOutput(videoWidget);
- receiver->setMedia(QUrl("gst-pipeline: udpsrc port=5000 ! \
- application/x-rtp,encoding-name=JPEG,payload=26 ! rtpjpegdepay ! jpegdec ! \
- xvimagesink name=qtvideosink"));
- receiver->play();
- // Content will be shown in this widget.
- videoWidget->show();
- //! [Pipeline appsrc]
}
void MediaExample::MediaRecorder()
{
//! [Media recorder]
- recorder = new QMediaRecorder(camera);
-
- QAudioEncoderSettings audioSettings;
- audioSettings.setCodec("audio/amr");
- audioSettings.setQuality(QMultimedia::HighQuality);
-
- recorder->setAudioSettings(audioSettings);
-
- recorder->setOutputLocation(QUrl::fromLocalFile(fileName));
- recorder->record();
+ QMediaCaptureSession session;
+ QAudioInput audioInput;
+ session.setAudioInput(&input);
+ QMediaRecorder recorder;
+ session.setRecorder(&recorder);
+ recorder.setQuality(QMediaRecorder::HighQuality);
+ recorder.setOutputLocation(QUrl::fromLocalFile("test.mp3"));
+ recorder.record();
//! [Media recorder]
}
-void MediaExample::AudioRecorder()
-{
- //! [Audio recorder]
- audioRecorder = new QAudioRecorder;
-
- QAudioEncoderSettings audioSettings;
- audioSettings.setCodec("audio/amr");
- audioSettings.setQuality(QMultimedia::HighQuality);
-
- audioRecorder->setEncodingSettings(audioSettings);
-
- audioRecorder->setOutputLocation(QUrl::fromLocalFile("test.amr"));
- audioRecorder->record();
- //! [Audio recorder]
-
- //! [Audio recorder inputs]
- const QStringList inputs = audioRecorder->audioInputs();
- QString selectedInput = audioRecorder->defaultAudioInput();
-
- for (const QString &input : inputs) {
- QString description = audioRecorder->audioInputDescription(input);
- // show descriptions to user and allow selection
- selectedInput = input;
- }
-
- audioRecorder->setAudioInput(selectedInput);
- //! [Audio recorder inputs]
-}
-
-void MediaExample::AudioProbe()
-{
- //! [Audio probe]
- audioRecorder = new QAudioRecorder;
-
- QAudioEncoderSettings audioSettings;
- audioSettings.setCodec("audio/amr");
- audioSettings.setQuality(QMultimedia::HighQuality);
-
- audioRecorder->setEncodingSettings(audioSettings);
-
- audioRecorder->setOutputLocation(QUrl::fromLocalFile("test.amr"));
-
- audioProbe = new QAudioProbe(this);
- if (audioProbe->setSource(audioRecorder)) {
- // Probing succeeded, audioProbe->isValid() should be true.
- connect(audioProbe, SIGNAL(audioBufferProbed(QAudioBuffer)),
- this, SLOT(calculateLevel(QAudioBuffer)));
- }
-
- audioRecorder->record();
- // Now audio buffers being recorded should be signaled
- // by the probe, so we can do things like calculating the
- // audio power level, or performing a frequency transform
- //! [Audio probe]
-}
-
-void MediaExample::VideoProbe()
-{
- //! [Video probe]
- camera = new QCamera;
- viewfinder = new QCameraViewfinder();
- camera->setViewfinder(viewfinder);
-
- camera->setCaptureMode(QCamera::CaptureVideo);
-
- videoProbe = new QVideoProbe(this);
-
- if (videoProbe->setSource(camera)) {
- // Probing succeeded, videoProbe->isValid() should be true.
- connect(videoProbe, SIGNAL(videoFrameProbed(QVideoFrame)),
- this, SLOT(detectBarcodes(QVideoFrame)));
- }
-
- camera->start();
- // Viewfinder frames should now also be emitted by
- // the video probe, even in still image capture mode.
- // Another alternative is to install the probe on a
- // QMediaRecorder connected to the camera to get the
- // recorded frames, if they are different from the
- // viewfinder frames.
-
- //! [Video probe]
-}
-
-
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/multimedia-snippets.pro b/src/multimedia/doc/snippets/multimedia-snippets/multimedia-snippets.pro
deleted file mode 100644
index a46b20bd0..000000000
--- a/src/multimedia/doc/snippets/multimedia-snippets/multimedia-snippets.pro
+++ /dev/null
@@ -1,26 +0,0 @@
-# Doc snippets - compiled for truthiness
-
-TEMPLATE = lib
-TARGET = qtmmksnippets
-
-INCLUDEPATH += ../../../../src/global \
- ../../../../src/multimedia \
- ../../../../src/multimedia/audio \
- ../../../../src/multimedia/video \
- ../../../../src/multimedia/camera
-
-CONFIG += console
-
-QT += multimedia multimediawidgets widgets multimedia-private
-
-SOURCES += \
- audio.cpp \
- video.cpp \
- camera.cpp \
- media.cpp \
- qsound.cpp
-
-OTHER_FILES += \
- soundeffect.qml \
- qtvideosink.qml \
- multiple-videooutputs.qml
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/multiple-videooutputs.qml b/src/multimedia/doc/snippets/multimedia-snippets/multiple-videooutputs.qml
index e3c1587f6..0c673cc42 100644
--- a/src/multimedia/doc/snippets/multimedia-snippets/multiple-videooutputs.qml
+++ b/src/multimedia/doc/snippets/multimedia-snippets/multiple-videooutputs.qml
@@ -1,53 +1,19 @@
-/****************************************************************************
-**
-** 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 2.0
-import QtQuick.Window 2.2
-import QtMultimedia 5.15
+import QtQuick
+import QtQuick.Window
+import QtMultimedia
//! [complete]
Item {
MediaPlayer {
id: mediaplayer
- autoPlay: true
source: "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
videoOutput: [v1, v2]
+ audioOutput: AudioOutput {
+
+ }
}
VideoOutput {
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/qaudioprobe.cpp b/src/multimedia/doc/snippets/multimedia-snippets/qaudioprobe.cpp
deleted file mode 100644
index 8543395f3..000000000
--- a/src/multimedia/doc/snippets/multimedia-snippets/qaudioprobe.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-//! [desc]
-QAudioRecorder *recorder = new QAudioRecorder();
-QAudioProbe *probe = new QAudioProbe;
-
-// ... configure the audio recorder (skipped)
-
-connect(probe, SIGNAL(audioBufferProbed(QAudioBuffer)), this, SLOT(processBuffer(QAudioBuffer)));
-
-probe->setSource(recorder); // Returns true, hopefully.
-
-recorder->record(); // Now we can do things like calculating levels or performing an FFT
-//! [desc]
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/qsound.cpp b/src/multimedia/doc/snippets/multimedia-snippets/qsound.cpp
index fbc849c2e..644dcb228 100644
--- a/src/multimedia/doc/snippets/multimedia-snippets/qsound.cpp
+++ b/src/multimedia/doc/snippets/multimedia-snippets/qsound.cpp
@@ -1,69 +1,9 @@
- /****************************************************************************
-**
-** 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 "qsound.h"
#include "qsoundeffect.h"
-void qsoundsnippet() {
- //! [0]
- QSound::play("mysounds/bells.wav");
- //! [0]
-
-
- //! [1]
- QSound bells("mysounds/bells.wav");
- bells.play();
- //! [1]
-}
-
void qsoundeffectsnippet() {
//! [2]
QSoundEffect effect;
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/qtvideosink.qml b/src/multimedia/doc/snippets/multimedia-snippets/qtvideosink.qml
index a4ae07f30..eeac9c28e 100644
--- a/src/multimedia/doc/snippets/multimedia-snippets/qtvideosink.qml
+++ b/src/multimedia/doc/snippets/multimedia-snippets/qtvideosink.qml
@@ -1,55 +1,23 @@
-/****************************************************************************
-**
-** 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 2.0
-import QtMultimedia 5.12
+import QtQuick
+import QtMultimedia
//! [complete]
Item {
MediaPlayer {
id: mediaplayer
- source: "gst-pipeline: videotestsrc ! qtvideosink"
+ source: "file:///test.mp4"
+ videoOutput: videoOutput
+ audioOutput: AudioOutput {
+
+ }
}
VideoOutput {
+ id: videoOutput
anchors.fill: parent
- source: mediaplayer
}
MouseArea {
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/soundeffect.qml b/src/multimedia/doc/snippets/multimedia-snippets/soundeffect.qml
index c414aca56..e91e54e3c 100644
--- a/src/multimedia/doc/snippets/multimedia-snippets/soundeffect.qml
+++ b/src/multimedia/doc/snippets/multimedia-snippets/soundeffect.qml
@@ -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) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
-import QtMultimedia 5.5
+import QtQuick
+import QtMultimedia
//! [complete snippet]
Text {
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/video.cpp b/src/multimedia/doc/snippets/multimedia-snippets/video.cpp
index 46327e3d6..8cc3b41b3 100644
--- a/src/multimedia/doc/snippets/multimedia-snippets/video.cpp
+++ b/src/multimedia/doc/snippets/multimedia-snippets/video.cpp
@@ -1,95 +1,29 @@
-/****************************************************************************
-**
-** 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"
-#include "qmediaservice.h"
#include "qmediaplayer.h"
-#include "qabstractvideosurface.h"
-#include "qvideowidgetcontrol.h"
+#include "qvideosink.h"
#include "qvideowindowcontrol.h"
#include "qgraphicsvideoitem.h"
-#include "qmediaplaylist.h"
-#include "qvideosurfaceformat.h"
+#include "qvideoframeformat.h"
#include <QFormLayout>
#include <QGraphicsView>
-//! [Derived Surface]
-class MyVideoSurface : public QAbstractVideoSurface
-{
- QList<QVideoFrame::PixelFormat> supportedPixelFormats(
- QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const
- {
- Q_UNUSED(handleType);
-
- // Return the formats you will support
- return QList<QVideoFrame::PixelFormat>() << QVideoFrame::Format_RGB565;
- }
-
- bool present(const QVideoFrame &frame)
- {
- Q_UNUSED(frame);
- // Handle the frame and do your processing
-
- return true;
- }
-};
-//! [Derived Surface]
-
//! [Video producer]
class MyVideoProducer : public QObject
{
Q_OBJECT
- Q_PROPERTY(QAbstractVideoSurface *videoSurface READ videoSurface WRITE setVideoSurface)
+ Q_PROPERTY(QVideoSink *videoSink READ videoSink WRITE setVideoSink)
public:
- QAbstractVideoSurface* videoSurface() const { return m_surface; }
+ QVideoSink* videoSink() const { return m_sink; }
- void setVideoSurface(QAbstractVideoSurface *surface)
+ void setVideoSink(QVideoSink *sink)
{
- if (m_surface != surface && m_surface && m_surface->isActive()) {
- m_surface->stop();
- }
- m_surface = surface;
- if (m_surface)
- m_surface->start(m_format);
+ m_sink = sink;
}
// ...
@@ -97,13 +31,12 @@ public:
public slots:
void onNewVideoContentReceived(const QVideoFrame &frame)
{
- if (m_surface)
- m_surface->present(frame);
+ if (m_sink)
+ m_sink->setVideoFrame(frame);
}
private:
- QAbstractVideoSurface *m_surface;
- QVideoSurfaceFormat m_format;
+ QVideoSink *m_sink;
};
//! [Video producer]
@@ -113,7 +46,6 @@ class VideoExample : public QObject {
Q_OBJECT
public:
void VideoGraphicsItem();
- void VideoRendererControl();
void VideoWidget();
void VideoWindowControl();
void VideoWidgetControl();
@@ -121,46 +53,32 @@ public:
private:
// Common naming
- QMediaService *mediaService;
- QMediaPlaylist *playlist;
QVideoWidget *videoWidget;
QWidget *widget;
QFormLayout *layout;
- QAbstractVideoSurface *myVideoSurface;
+ QVideoSink *myVideoSink;
QMediaPlayer *player;
QMediaContent video;
QGraphicsView *graphicsView;
};
-void VideoExample::VideoRendererControl()
-{
- //! [Video renderer control]
- QVideoRendererControl *rendererControl = mediaService->requestControl<QVideoRendererControl *>();
- rendererControl->setSurface(myVideoSurface);
- //! [Video renderer control]
-}
-
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]
player->stop();
//! [Setting surface in player]
- player->setVideoOutput(myVideoSurface);
+ player->setVideoOutput(myVideoSink);
//! [Setting surface in player]
}
@@ -168,7 +86,7 @@ void VideoExample::VideoSurface()
{
//! [Widget Surface]
QImage img = QImage("images/qt-logo.png").convertToFormat(QImage::Format_ARGB32);
- QVideoSurfaceFormat format(img.size(), QVideoFrame::Format_ARGB32);
+ QVideoFrameFormat format(img.size(), QVideoFrameFormat::Format_ARGB8888);
videoWidget = new QVideoWidget;
videoWidget->videoSurface()->start(format);
videoWidget->videoSurface()->present(img);
@@ -180,30 +98,10 @@ void VideoExample::VideoSurface()
graphicsView->scene()->addItem(item);
graphicsView->show();
QImage img = QImage("images/qt-logo.png").convertToFormat(QImage::Format_ARGB32);
- QVideoSurfaceFormat format(img.size(), QVideoFrame::Format_ARGB32);
- item->videoSurface()->start(format);
- item->videoSurface()->present(img);
+ item->videoSink()->setVideoFrame(QVideoFrame(img));
//! [GraphicsVideoItem Surface]
}
-void VideoExample::VideoWidgetControl()
-{
- //! [Video widget control]
- QVideoWidgetControl *widgetControl = mediaService->requestControl<QVideoWidgetControl *>();
- layout->addWidget(widgetControl->videoWidget());
- //! [Video widget control]
-}
-
-void VideoExample::VideoWindowControl()
-{
- //! [Video window control]
- QVideoWindowControl *windowControl = mediaService->requestControl<QVideoWindowControl *>();
- windowControl->setWinId(widget->winId());
- windowControl->setDisplayRect(widget->rect());
- windowControl->setAspectRatioMode(Qt::KeepAspectRatio);
- //! [Video window control]
-}
-
void VideoExample::VideoGraphicsItem()
{
//! [Video graphics item]
@@ -214,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/snippets/snippets.pro b/src/multimedia/doc/snippets/snippets.pro
deleted file mode 100644
index 31a3a0992..000000000
--- a/src/multimedia/doc/snippets/snippets.pro
+++ /dev/null
@@ -1,3 +0,0 @@
-TEMPLATE = subdirs
-
-SUBDIRS += multimedia-snippets
diff --git a/src/multimedia/doc/src/audiooverview.qdoc b/src/multimedia/doc/src/audiooverview.qdoc
index d39738da4..40a6318a6 100644
--- a/src/multimedia/doc/src/audiooverview.qdoc
+++ b/src/multimedia/doc/src/audiooverview.qdoc
@@ -1,136 +1,130 @@
-/****************************************************************************
-**
-** 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 audiooverview.html
\title Audio Overview
-\brief Audio playback, recording and processing
+\inlineimage sound-wave-small.jpg
+\brief Playback, recording and processing of Audio.
+\ingroup explanations-graphicsandmultimedia
\section1 Audio Features
-Qt Multimedia offers a range of audio classes, covering both low and
-high level approaches to audio input, output and processing. In
-addition to traditional audio usage, the \l{Qt Audio Engine QML Types}{Qt Audio Engine}
-QML types offer high level 3D positional audio for QML applications.
-See that documentation for more information.
+Qt Multimedia offers a range of audio classes that cover both low and
+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 \l QMediaPlayer C++ class, or the \l {Audio} and \l {MediaPlayer} QML types.
+
+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 does depend
-on the operating system environment, and also what media plugins the user
-may have installed.
+\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
-You can also put files (even remote URLs) into a playlist:
- \snippet multimedia-snippets/media.cpp Audio playlist
+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 \l {QAudioRecorder} class allows you
-to compress audio data from an input device and record it.
- \snippet multimedia-snippets/media.cpp Audio recorder
+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.
-\section2 Low Latency Sound Effects
+A session recording audio from the default microphone would look as follows in C++:
+
+ \snippet multimedia-snippets/media.cpp Media recorder
-In addition to the raw access to sound devices described above, the QSoundEffect class (and
-\l {SoundEffect} QML type) offers a slightly higher level way to play
-sounds. These classes allow you to specify a WAV format file which can
-then be played with low latency when necessary. Both QSoundEffect and
-SoundEffect have essentially the same API.
+In QML, the same can be achieved by:
-You can adjust the number of \l {QSoundEffect::loopCount()}{loops} a sound effect is played, as well as
-the \l {QSoundEffect::setVolume()}{volume} (or \l {QSoundEffect::setMuted()}{muting}) of the effect.
+\qml
+CaptureSession {
+ audioInput: AudioInput {}
+ mediaRecorder: MediaRecorder {
+ id: recorder
+ outputLocation: "file:///path/to/test.mp3"
+ }
+ Component.onCompleted: { recorder.record() }
+}
+\endqml
-For older, Qt 4.x based applications \l QSound is also available. Applications
-are recommended to use QSoundEffect where possible.
+QMediaCaptureSession also provides support for more complex use cases such as image
+capturing or video recording.
-\section2 Monitoring Audio Data During Playback or Recording
+\section2 Low Latency Sound Effects
-The \l QAudioProbe class allows you to monitor audio data being played or
-recorded in the higher level classes like \l QMediaPlayer, \l QCamera and
-\l QAudioRecorder. After creating your high level class, you can simply
-set the source of the probe to your class, and receive audio buffers as they
-are processed. This is useful for several audio processing tasks, particularly
-for visualization or adjusting gain. You cannot modify the buffers, and
-they may arrive at a slightly different time than the media pipeline
-processes them.
+In addition to \l{raw access} to sound devices, the QSoundEffect
+class (and \l{SoundEffect} QML type) offers a more abstract way to play
+sounds. This class allows you to specify a \b{WAV format} file, which can
+then be played with low latency when necessary.
-Here's an example of installing a probe during recording:
- \snippet multimedia-snippets/media.cpp Audio probe
+You can adjust the:
+\list
+ \li \l{QSoundEffect::loopCount()}{Number of loops} in which a sound effect
+ is played.
+ \li \l{QSoundEffect::setVolume()}{Volume} of the sound effect.
+ \li \l{QSoundEffect::setMuted()}{Muting} of the sound effect.
+\endlist
+\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
+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
can support different types of raw audio data.
-The QAudioOutput class offers raw audio data output, while QAudioInput
-offers raw audio data input. Both classes have adjustable buffers and
-latency, so they are suitable for both low latency use cases (like games
-or VOIP) and high latency (like music playback). The available hardware
+The QAudioSink class offers raw audio data output, while QAudioSource
+offers raw audio data input. The available hardware
determines what audio outputs and inputs are available.
\section3 Push and Pull
The low level audio classes can operate in two modes - \c push and \c pull.
In \c pull mode, the audio device is started by giving it a QIODevice. For
-an output device, the QAudioOutput class will pull data from the QIODevice
+an output device, the QAudioSink class will pull data from the QIODevice
(using \l QIODevice::read()) when more audio data is required. Conversely,
-for \c pull mode with QAudioInput, when audio data is available then the
+for \c pull mode with QAudioSource, when audio data is available then the
data will be written directly to the QIODevice.
In \c push mode, the audio device provides a QIODevice instance that
-can be written or read to as needed. Typically this results in simpler
+can be written or read to as needed. Typically, this results in simpler
code but more buffering, which may affect latency.
\section2 Decoding Compressed Audio to Memory
+
In some cases you may want to decode a compressed audio file and do further
-processing yourself (for example, mixing multiple samples or using custom
-digital signal processing algorithms). QAudioDecoder supports decoding local
+processing yourself. For example, mixing multiple samples or using custom
+digital signal processing algorithms. QAudioDecoder supports decoding local
files or data streams from QIODevice instances.
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
@@ -142,4 +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 69631fdab..b93954d6d 100644
--- a/src/multimedia/doc/src/cameraoverview.qdoc
+++ b/src/multimedia/doc/src/cameraoverview.qdoc
@@ -1,82 +1,82 @@
-/****************************************************************************
-**
-** 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 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 webcameras.
+can access images and videos from mobile device cameras or web cameras.
There are both C++ and QML APIs for common tasks.
\section1 Camera Features
-In order to use the camera classes a quick overview of the way a camera
-works is needed. If you're already familiar with this, you can skip ahead to
+In order to use the camera classes, a quick overview of the way a camera
+works is needed. If you're already familiar with this, you can skip ahead to
\l {camera-tldr}{Camera implementation details}.
+For a more detailed explanations of how a camera works, see the following YouTube
+clip.
+
+\youtube qS1FmgPVLqw
\section2 The Lens Assembly
+
At one end of the camera assembly is the lens assembly (one or
-more lenses, arranged to focus light onto the sensor). The lenses
-themselves can sometimes be moved to adjust things like focus and zoom,
-or they might be fixed in an arrangement to give a good balance between
-objects in focus, and cost.
+more lenses, arranged to focus light onto the sensor). The lenses
+themselves can sometimes be moved to adjust things like focus and zoom. They
+might also be fixed in an arrangement for a good balance between maintaining
+focus and cost.
+
+\image how-focus-works.gif "An animation of how focus works"
+
+\image Zoom.gif "An animation of how zoom works."
Some lens assemblies can automatically be adjusted so that
an object at different distances from the camera can be kept in focus.
This is usually done by measuring how sharp a particular area of the
-frame is, and by adjusting the lens assembly until it is maximally
-sharp. In some cases the camera will always use the center of the
-frame for this. Other cameras may also allow the region to focus
-to be specified (for "touch to zoom", or "face zoom" features).
+frame is, and then adjusting the lens assembly to find the peak sharpness. In
+some cases, the camera will always use the center of the frame for this.
+In other cases, a camera may also allow this target focus region to be specified.
+Some examples of this feature include:
+\list
+\li Face zoom: Using computer vision to detect and use one or more faces as the
+target.
+\li Touch to zoom: Enabling the user to manually select an area via the preview
+screen.
+\endlist
\section2 The Sensor
Once light arrives at the sensor, it gets converted into digital pixels.
This process can depend on a number of things but ultimately comes down
-to two things - how long the conversion is allowed to take, and how
-bright the light is. The longer a conversion can take, the better the
-quality. Using a flash can assist with letting more light hit the sensor,
+to two things:
+\list
+\li The length of time conversion is allowed to take. Also known as exposure
+time.
+\li How bright the light is.
+\endlist
+
+The longer a conversion is allowed to take, the better the resulting image
+quality. Using a flash can assist with letting more light hit the sensor,
allowing it to convert pixels faster, giving better quality for the same
-amount of time. Conversely, allowing a longer conversion time can let you
-take photos in darker environments, as long as the camera is steady.
+amount of time. Conversely, allowing a longer conversion time can let you
+take photos in darker environments, \b{as long as the camera is steady}. If the
+camera moves while the sensor is recording, the resulting image is blurred.
\section2 Image Processing
After the image has been captured by the sensor, the camera firmware performs
various image processing tasks on it to compensate for various sensor
-characteristics, current lighting, and desired image properties. Faster sensor
-pixel conversion times tend to introduce digital noise, so some amount of image
-processing can be done to remove this based on the camera sensor settings.
+characteristics, current lighting, and desired image properties. Faster sensor
+pixel conversion times may introduce digital noise, so some amount of image
+processing can be done to remove this, based on the camera sensor settings.
The color of the image can also be adjusted at this stage to compensate for
different light sources - fluorescent lights and sunlight give very different
appearances to the same object, so the image can be adjusted based on the
white balance of the picture (due to the different color temperatures of the
light sources).
+\image image_processing.png "5 examples of various image processing techniques."
Some forms of "special effects" can also be performed at this stage. Black
and white, sepia, or "negative" style images can be produced.
@@ -84,31 +84,24 @@ and white, sepia, or "negative" style images can be produced.
\section2 Recording for Posterity
Finally, once a perfectly focused, exposed and processed image has been
created, it can be put to good use. Camera images can be further processed
-by application code (for example, to detect barcodes, or to stitch together a
+by application code (for example, to detect bar-codes, or to stitch together a
panoramic image), or saved to a common format like JPEG, or used to create a movie.
Many of these tasks have classes to assist them.
\target camera-tldr
\section1 Camera Implementation Details
-\section2 Detecting and Selecting Camera
+\section2 Detecting and Selecting a Camera
-Before using the camera APIs, you should check that a camera is available at runtime. If there
-is none, you could for example disable camera related features in your application. To perform this
-check in C++, use the \l QCameraInfo::availableCameras() function, as shown in the example below:
+Before using the camera APIs, you should check that a camera is available at
+runtime. If there is none available, you could disable camera related features
+in your application. To perform this check in C++, use the
+\l QMediaDevices::videoInputs() function, as shown in the example below:
- \snippet multimedia-snippets/camera.cpp Camera overview check
-
-In QML, use the \l{QtMultimedia::QtMultimedia::availableCameras}{QtMultimedia.availableCameras}
-property:
-\qml
-Item {
- property bool isCameraAvailable: QtMultimedia.availableCameras.length > 0
-}
-\endqml
+ \snippet multimedia-snippets/camera.cpp Camera overview check
-After determining whether a camera is available, access it using the \l QCamera class in C++ or
-the \l Camera type in QML.
+Access a camera using the \l QCamera class in C++ or the \l Camera
+type in QML.
When multiple cameras are available, you can specify which one to use.
@@ -116,22 +109,19 @@ In C++:
\snippet multimedia-snippets/camera.cpp Camera selection
-In QML, you can set the \c Camera \l{Camera::deviceId}{deviceId} property. All available IDs can
-be retrieved from \l{QtMultimedia::QtMultimedia::availableCameras}{QtMultimedia.availableCameras}:
-
-\qml
-Camera {
- deviceId: QtMultimedia.availableCameras[0].deviceId
-}
-\endqml
-
-You can also select the camera by its physical position on the system rather than its device ID.
-This is useful on mobile devices, which often have a front-facing and a back-facing camera.
+In QML, you can select the camera by setting the \l{Camera::cameraDevice} property.
+You can also select a camera by its physical position on the system rather than
+by camera info. This is useful on mobile devices, which often have a
+front-facing and a back-facing camera.
In C++:
\snippet multimedia-snippets/camera.cpp Camera overview position
+
+In QML, you can set the \c Camera \l{Camera::cameraDevice}{cameraDevice} property.
+Available cameras can be retrieved with MediaDevices.videoInputs
+
In QML:
\qml
@@ -140,66 +130,65 @@ Camera {
}
\endqml
-If neither device ID nor position is specified, the default camera will be used. On desktop
-platforms, the default camera is set by the user in the system settings. On a mobile device, the
-back-facing camera is usually the default camera. You can get information about the default camera
-using \l QCameraInfo::defaultCamera() in C++ or
-\l{QtMultimedia::QtMultimedia::defaultCamera}{QtMultimedia.defaultCamera} in QML.
-\section2 Viewfinder
+If both QCameraDevice and position aren't specified, the default camera
+will be used. On desktop platforms, the default camera is set by the
+user in the system settings. On a mobile device, the back-facing camera
+is usually the default camera. You can get the default camera with
+QMediaDevices::defaultVideoInput() or MediaDevices.defaultVideoInput
+in QML.
+
+\section2 Preview
While not strictly necessary, it's often useful to be able to see
-what the camera is pointing at. Most digital cameras allow an image
-feed from the camera sensor at a lower resolution (usually up to
-the size of the display of the camera) so you can compose
-a photo or video, and then switch to a slower but higher resolution
-mode for capturing the image.
+what the camera is pointing at. This is known as a preview.
Depending on whether you're using QML or C++, you can do this in multiple ways.
-In QML, you can use \l Camera and \l VideoOutput together to show a
-simple viewfinder:
+In QML, you can use \l Camera and videoOutput together to monitor a
+captureSession.
\qml
-VideoOutput {
- source: camera
+Item {
+ VideoOutput {
+ id: output
+ anchors.fill: parent
+ }
+ CaptureSession {
+ videoOutput: output
- Camera {
- id: camera
- // You can adjust various settings in here
+ Camera {
+ // You can adjust various settings in here
+ }
}
}
\endqml
In C++, your choice depends on whether you are using widgets, or QGraphicsView.
-The \l QCameraViewfinder class is used in the widgets case, and \l QGraphicsVideoItem
+The \l QVideoWidget class is used in the widgets case, and \l QGraphicsVideoItem
is useful for QGraphicsView.
\snippet multimedia-snippets/camera.cpp Camera overview viewfinder
-For advanced usage (like processing viewfinder frames as they come, to detect
-objects or patterns), you can also derive from \l QAbstractVideoSurface and
-set that as the viewfinder for the QCamera object. In this case you will
-need to render the viewfinder image yourself.
+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 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 viewfinder 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
-After setting up a viewfinder and finding something photogenic,
-to capture an image we need to initialize a new QCameraImageCapture
-object. All that is then needed is to start the camera, lock it so
-that things are in focus and the settings are not different from the
-viewfinder while the image capture occurs, capture the image, and
-finally unlock the camera ready for the next photo.
+After setting up a viewfinder and finding something photogenic, to capture an
+image we need to initialize a new QImageCapture object. All that is then
+needed is to start the camera and capture the image.
\snippet multimedia-snippets/camera.cpp Camera overview capture
@@ -213,90 +202,68 @@ well as creating a viewfinder, we will also initialize a media recorder object.
\snippet multimedia-snippets/camera.cpp Camera overview movie
-Signals from the \e mediaRecorder can be connected to slots to react to
-changes in the state of the recorder or error events. Recording itself
-starts with the \l {QMediaRecorder::record()}{record()} function of
-mediaRecorder being called, this causes the signal \l
-{QMediaRecorder::stateChanged()}{stateChanged()} to be emitted. The
-recording process can be changed with the \l {QMediaRecorder::record()}{record()},
-\l {QMediaRecorder::stop()}{stop()} and \l {QMediaRecorder::setMuted()}{setMuted()}
-slots in \l QMediaRecorder.
+Signals from the \e QMediaRecorder can be connected to slots to react to
+changes in the state of the encoding process or error events. Recording
+starts when \l QMediaRecorder::record() is called. This causes the signal
+\l{QMediaRecorder::}{recorderStateChanged()} to be emitted. Recording is
+controlled by the record(), stop(), and pause() slots of QMediaRecorder.
\section2 Controlling the Imaging Pipeline
-Now that the basics of capturing images or movies are covered, there are a number
+Now that the basics of capturing images and movies are covered, there are a number
of ways to control the imaging pipeline to implement some interesting techniques.
As explained earlier, several physical and electronic elements combine to determine
the final images, and you can control them with different classes.
\section3 Focus and Zoom
-Focusing (and zoom) is managed primarily by the \l QCameraFocus class.
-QCameraFocus allows the developer to set the general policy by means of the
-enums for the \l {QCameraFocus::FocusMode}{FocusMode} and the
-\l {QCameraFocus::FocusPointMode}{FocusPointMode}. \l {QCameraFocus::FocusMode}{FocusMode}
-deals with settings such as \l {QCameraFocus::FocusMode}{AutoFocus},
-\l {QCameraFocus::FocusMode}{ContinuousFocus} and \l {QCameraFocus::FocusMode}{InfinityFocus},
-whereas \l {QCameraFocus::FocusMode}{FocusPointMode} deals with the
-various focus zones within the view that are used for autofocus modes. \l {QCameraFocus::FocusMode}{FocusPointMode}
-has support for face recognition (where the camera supports it), center focus and a custom
-focus where the focus point can be specified.
+QCamera allows you to set the general focus policy by means of the
+enums for the \l {QCamera::FocusMode}{FocusMode}. \l {QCamera::FocusMode}{FocusMode}
+deals with settings such as \l {QCamera::FocusModeAuto},
+and \l {QCamera::FocusModeInfinity}.
-For camera hardware that supports it, \l {QCameraFocus::FocusMode}{Macro focus} allows
-imaging of things that are close to the sensor. This is useful in applications like
-barcode recognition, or business card scanning.
+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 optical or
-digital zoom. In general, optical zoom is higher quality, but more expensive to
-manufacture, so the available zoom range might be limited (or fixed to unity).
+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}{minimumZoomFactor()}
+and \l{QCamera::maximumZoomFactor}{maximumZoomFactor()}.
-\section3 Exposure, Aperture, Shutter Speed and Flash
+\section3 Exposure, Shutter Speed and Flash
There are a number of settings that affect the amount of light that hits the
-camera sensor, and hence the quality of the resulting image. The \l QCameraExposure
-class allows you to adjust these settings. You can use this class to implement
-some techniques like High Dynamic Range (HDR) photos by locking the exposure
-parameters (with \l {QCamera::searchAndLock()}), or motion blur by setting slow shutter speeds
-with small apertures.
-
-The main settings for automatic image taking are the \l {QCameraExposure::ExposureMode}{exposure mode}
-and \l {QCameraExposure::FlashMode}{flash mode}. Several other settings (aperture, ISO setting,
- shutter speed) are usually managed automatically but can also be overridden if desired.
-
-You can also adjust the \l {QCameraExposure::meteringMode()} to control which parts
-of the camera frame to measure exposure at. Some camera implementations also allow
-you to specify a specific point that should be used for exposure metering - this is
-useful if you can let the user touch or click on an interesting part of the viewfinder,
-and then use this point so that the image exposure is best at that point.
-
-Finally, you can control the flash hardware (if present) using this class. In some cases
-the hardware may also double as a torch (typically when the flash is LED based, rather than
-a xenon or other bulb). See also \l {Torch} for an easy to use API for
-torch functionality.
+camera sensor, and hence the quality of the resulting image.
+
+The main settings for automatic image taking are the
+\l {QCamera::ExposureMode}{exposure mode} and \l {QCamera::FlashMode}{flash mode}.
+Several other settings (such as: ISO setting and exposure time) are usually
+managed automatically, but can also be overridden if desired.
+
+Finally, you can control the flash hardware (if present) using this class. In
+some cases the hardware may also double as a torch.
\target camera_image_processing
\section3 Image Processing
-The QCameraImageProcessing class lets you adjust the image processing
-part of the pipeline. This includes the \l {QCameraImageProcessing::WhiteBalanceMode}{white balance}
-(or color temperature), \l {QCameraImageProcessing::contrast()}{contrast},
-\l {QCameraImageProcessing::saturation()}{saturation}, \l {QCameraImageProcessing::setSharpeningLevel()}{sharpening}
-and \l {QCameraImageProcessing::setDenoisingLevel()}{denoising}. Most cameras support automatic settings
-for all of these, so you shouldn't need to adjust them unless the user wants a specific setting.
+The QCamera class lets you adjust the image processing part of the pipeline.
+These settings include:
+\list
+ \li \l {QCamera::WhiteBalanceMode}{white balance}
+ (also known as color temperature)
+\endlist
-If you're taking a series of images (for example, to stitch them together for
-a panoramic image), you should lock the image processing settings so that all the
-images taken appear similar with \e {QCamera::searchAndLock(QCamera::LockWhiteBalance)}/
+Most cameras support automatic settings for all of these, so you shouldn't need
+to adjust them unless the user wants a specific setting.
\section3 Canceling Asynchronous Operations
-Various operations such as image capture and auto focusing occur
-asynchrously. These operations can often be canceled by the start of a new
-operation as long as this is supported by the camera. For image capture,
-the operation can be canceled by calling
-\l {QCameraImageCapture::cancelCapture()}{cancelCapture()}. For AutoFocus,
-autoexposure or white balance cancellation can be done by calling
-\e {QCamera::unlock(QCamera::LockFocus)}.
+Various operations, such as image capture and auto focusing, occur asynchronously.
+These operations can often be canceled by the start of a new operation, as long
+as this is supported by the camera.
\section1 Examples
diff --git a/src/multimedia/doc/src/changes.qdoc b/src/multimedia/doc/src/changes.qdoc
deleted file mode 100644
index fd7188fa3..000000000
--- a/src/multimedia/doc/src/changes.qdoc
+++ /dev/null
@@ -1,140 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-/*!
-
-\page changes.html
-\title Changes in Qt Multimedia
-\brief A description of changes in this version of Qt Multimedia
-
-
-The Qt Multimedia module in Qt 5 combines (and replaces) two older modules, namely the
-Qt Multimedia module from Qt 4.x, and Qt Multimedia Kit module from Qt Mobility.
-Existing code that uses Qt Multimedia from Qt 4 can be ported with minimal effort, but
-porting code that uses Qt Multimedia Kit may be a more involved process. The
-\l {changed features} section highlights changes relevant to porting.
-
-Also, note that widget-based classes, such as \l QVideoWidget, are now in a separate
-module called Qt Multimedia Widgets.
-
-\section1 New features in Qt 5.0
-
-There are a number of new features in Qt Multimedia:
-\list
-\li Expanded QML API
-\li In addition to the \l Video QML type, there is now the option of using \l MediaPlayer and \l VideoOutput together
-\li QML \l Torch class
-\li New \l QAudioRecorder class
-\li Volume support for QAudioOutput and QAudioInput
-\li More examples and documentation
-\li QSound moved from Qt GUI to Qt Multimedia
-\li QSoundEffect available to C++ now, as well as QML
-\li Various other API improvements and bugfixes
-\endlist
-
-
-\section1 Removed features
-
-A number of classes or features previously offered in Qt Multimedia or Qt Multimedia Kit have
-been removed.
-
-\table 70%
- \header
- \li Removed feature
- \li Notes
- \row
- \li QMediaImageViewer
- \li This class (and related controls and services) were removed since
- their functionality was not suitable for many applications
-\endtable
-
-\section1 Changed features
-
-A number of classes previously offered in Qt Multimedia or Qt Multimedia Kit have
-changed in ways that may affect previously written code. This table highlights such changes.
-
-\table 70%
- \header
- \li Changed feature
- \li Notes
- \row
- \li \c qmake project file changes
- \li Previously, to use Qt Multimedia Kit, the \c qmake project file must contain
- \code
- CONFIG += mobility
- MOBILITY += multimedia
- \endcode
- Now, you only need to write
- \code
- QT += multimedia
- \endcode
- Or, if you want to use the widget classes,
- \code
- QT += multimedia multimediawidgets
- \endcode
- \row
- \li Namespaces
- \li The \c QtMultimediaKit namespace has been renamed to QMultimedia. This
- affects a few enumerations, namely \c SupportEstimate, \c EncodingQuality,
- \c EncodingMode and \c AvailabilityStatus. Searching and replacing
- \c QtMultimediaKit with \c QMultimedia will greatly aid porting efforts. Metadata
- have been split off into their own namespace, QMediaMetaData.
- \row
- \li Metadata types
- \li In Qt Multimedia Kit, pre-defined metadata keys were enumerations in the
- \c QtMultimediaKit namespace. These pre-defined keys have been changed to
- string literals in the \c QMediaMetaData namespace, for consistency with
- extended keys.
- \row
- \li Metadata accessor methods
- \li In Qt Multimedia Kit, there were two different families of methods to access
- metadata. Functions such as \c QMediaObject::metaData() operated on pre-defined
- metadata using enumerated keys, while functions such as
- \c QMediaObject::extendedMetaData() operated on extended metadata using
- string keys. Qt 5 combines both families into one (e.g. QMediaObject::metaData()),
- which can operate on both pre-defined and extended metadata, using string keys.
- \row
- \li Qt Metatype registration
- \li Qt 5 registers many more classes and types with the meta-object system than before.
- If you have previously applied Q_DECLARE_METATYPE macros to any Qt Multimedia class,
- you will probably need to remove them.
- \row
- \li QSoundEffect availability
- \li The SoundEffect QML type was publicly accessible in Qt Multimeda Kit,
- and now the C++ version is officially public too. If your code contains the
- previously undocumented QSoundEffect, you may need to update it.
- \row
- \li Camera controls
- \li A large number of the camera controls (QCameraImageProcessingControl,
- QCameraFocusControl, etc.) have been updated to address a number of
- design flaws. In particular, a number of discrete
- accessor methods have been collapsed into parametrized methods, and
- the ranges or data types of some parameters have been adjusted.
-
-\endtable
-
-*/
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 860f14270..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/snippets/frequencymonitor/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/snippets/frequencymonitor/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/snippets/frequencymonitor/qml/frequencymonitor/FrequencyItem.qml
+\quotefromfile video/qmlvideo/frequencymonitor/FrequencyItem.qml
\skipto import FrequencyMonitor
\printuntil id: root
\dots
@@ -39,5 +39,3 @@ and its data is displayed by defining a QML item called FrequencyItem, like this
The result looks like this:
\image video-qml-paint-rate.png
-
-
diff --git a/src/multimedia/doc/src/images/Zoom.gif b/src/multimedia/doc/src/images/Zoom.gif
new file mode 100644
index 000000000..dfba0faf1
--- /dev/null
+++ b/src/multimedia/doc/src/images/Zoom.gif
Binary files differ
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/images/how-focus-works.gif b/src/multimedia/doc/src/images/how-focus-works.gif
new file mode 100644
index 000000000..a691b49ac
--- /dev/null
+++ b/src/multimedia/doc/src/images/how-focus-works.gif
Binary files differ
diff --git a/src/multimedia/doc/src/images/image_processing.png b/src/multimedia/doc/src/images/image_processing.png
new file mode 100644
index 000000000..2a52fbce3
--- /dev/null
+++ b/src/multimedia/doc/src/images/image_processing.png
Binary files differ
diff --git a/src/multimedia/doc/src/images/noun_Media_166644.svg b/src/multimedia/doc/src/images/noun_Media_166644.svg
new file mode 100644
index 000000000..cc2fa8d83
--- /dev/null
+++ b/src/multimedia/doc/src/images/noun_Media_166644.svg
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ x="0px"
+ y="0px"
+ viewBox="0 0 97.908676 59.1375"
+ enable-background="new 0 0 100 100"
+ xml:space="preserve"
+ id="svg26"
+ sodipodi:docname="noun_Media_166644.svg"
+ width="97.908676"
+ height="59.137501"
+ inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)"><metadata
+ id="metadata32"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+ id="defs30" /><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="2560"
+ inkscape:window-height="1377"
+ id="namedview28"
+ showgrid="false"
+ inkscape:zoom="8.064"
+ inkscape:cx="32.007416"
+ inkscape:cy="20.413416"
+ inkscape:window-x="1912"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg26"
+ inkscape:document-rotation="0" /><g
+ transform="matrix(0.13985577,0,0,-0.1432582,-21.001292,1300.868)"
+ id="g20"><path
+ d="m 467.5,9080.3 c -2.1,-0.6 -3.7,-1.9 -4.6,-3.7 -0.7,-1.4 -0.8,-6.7 -0.8,-48.2 v -46.6 h 7.1 7.1 v 23.6 23.6 h 105.1 105.1 v -47.8 c 0,-26.2 0.1,-47.8 0.4,-47.8 0.2,0 3.2,0.6 6.7,1.4 l 6.4,1.3 0.1,69.7 c 0.1,68.3 0.1,69.7 -0.8,71.2 -0.5,0.9 -1.7,2 -2.6,2.5 -1.5,0.8 -6.9,0.9 -114.9,1 -62.1,0.2 -113.6,0 -114.3,-0.2 z m 32.5,-25.6 v -11.8 h -11.8 -11.8 v 11.8 11.8 h 11.8 11.8 z m 37.4,0 v -11.8 h -11.6 -11.6 v 11.8 11.8 h 11.6 11.6 z m 37.5,0 v -11.8 h -11.6 -11.6 v 11.8 11.8 h 11.6 11.6 z m 37.4,0 v -11.8 h -11.6 -11.6 v 11.8 11.8 h 11.6 11.6 z m 37.4,0 v -11.8 h -11.6 -11.6 v 11.8 11.8 h 11.6 11.6 z m 36.9,0 v -11.8 H 675.3 664 v 11.8 11.8 h 11.3 11.3 z"
+ id="path2" /><path
+ d="m 546,9008.9 c -1.2,-0.5 -2.5,-1.7 -3.1,-2.6 -1,-1.6 -1,-2.4 -1,-53.2 0,-46.4 0.1,-51.8 0.8,-53.3 1.1,-2.2 3.4,-3.6 6.2,-3.6 2,0 5.2,1.9 43.5,25.4 22.7,14 41.8,25.9 42.4,26.4 2.7,2.4 2.5,7.2 -0.2,9.8 -2.5,2.3 -83.1,51.5 -84.8,51.8 -1.2,0.2 -2.4,0 -3.8,-0.7 z m 41.8,-38.4 c 21.8,-13.4 28.3,-17.6 27.8,-18 -0.7,-0.7 -58.2,-36.1 -59.2,-36.5 -0.6,-0.2 -0.7,5.8 -0.7,37 v 37.3 l 1.9,-1.1 c 1,-0.7 14.6,-9.1 30.2,-18.7 z"
+ id="path4" /><path
+ d="m 179,8967.7 c -2.5,-0.4 -7.7,-2.3 -10.3,-3.6 -8.4,-4.4 -14.3,-11.9 -17.3,-21.7 l -1.1,-3.6 -0.1,-80.3 c -0.1,-54.6 0,-81.7 0.4,-84.8 1.8,-16.1 13.6,-28.6 29.5,-31.1 2.2,-0.4 49.5,-0.5 149.2,-0.5 120.1,0 146.6,0.1 149.7,0.7 10.8,2 20,8.9 24.9,18.7 3.9,7.9 3.6,2.1 3.6,93.6 0,90.9 0.2,85.5 -3.4,93 -4.6,9.6 -12.9,16.3 -23.3,19 -3.8,1 -5.4,1 -152.1,0.9 -81.8,-0.1 -149,-0.2 -149.7,-0.3 z m 297.5,-14 c 7.9,-1.7 14.6,-8.5 16.1,-16.7 0.7,-3.7 0.7,-159.8 0,-163.7 -1.4,-7.8 -7.3,-14.2 -14.8,-16.2 -2.9,-0.8 -13.8,-0.8 -150.6,-0.7 l -147.5,0.1 -3.3,1.6 c -4.4,2.1 -8.3,6 -10.3,10.3 l -1.6,3.3 -0.1,82.2 c -0.1,81.1 -0.1,82.3 0.9,85.5 2.2,7.1 9,13.2 16.2,14.4 0.7,0.1 66.8,0.2 146.8,0.3 104.9,0.1 146.3,0 148.2,-0.4 z"
+ id="path6" /><path
+ d="m 194,8929.6 c -0.8,-0.5 -1.9,-1.7 -2.3,-2.6 -0.8,-1.5 -0.9,-5.9 -0.9,-72.1 v -70.5 l 1.1,-1.7 c 0.7,-1 2,-2 3.4,-2.6 2.3,-1 2.3,-1 4.6,0 1.4,0.6 2.8,1.6 3.4,2.6 l 1.1,1.7 v 70.4 c 0,78 0.2,72.6 -3.2,74.7 -1.9,1.4 -5.2,1.4 -7.2,0.1 z"
+ id="path8" /><path
+ d="m 412.5,8929.8 c -3,-1 -7.1,-5 -8.5,-8.1 -1.1,-2.5 -1.2,-3.1 -1.2,-13.2 0,-12.4 0.3,-13.9 4.3,-18.1 4.3,-4.5 4.4,-4.6 27.4,-4.6 23,0 23.1,0 27.4,4.6 4,4.2 4.3,5.7 4.3,18.1 0,10.1 0,10.7 -1.2,13.2 -1.5,3.2 -5.6,7.1 -8.7,8.2 -3.3,1 -40.6,1 -43.8,-0.1 z m 39.5,-21.6 v -8.4 H 434.5 417 l -0.1,7.9 c 0,4.3 0,8.1 0.1,8.5 0.2,0.5 3.7,0.6 17.6,0.5 l 17.4,-0.1 z"
+ id="path10" /><path
+ d="m 318.8,8917.6 c -9.3,-1.5 -19.2,-5.4 -26.7,-10.4 -4.8,-3.2 -12.8,-11 -16.2,-15.8 -8.2,-11.4 -12.4,-24.3 -12.4,-38.3 0,-17 6.2,-32.4 17.8,-44.7 16.4,-17.2 40.3,-24.2 63.3,-18.4 25.8,6.5 44.8,28 48.6,54.9 0.7,5.1 0.3,16.2 -0.7,21.2 -2.9,13 -8.7,23.8 -18,33 -9.3,9.3 -19.3,14.8 -32.5,17.8 -5.7,1.2 -17.5,1.6 -23.2,0.7 z m 16.7,-13.8 c 6.7,-0.6 15.6,-4.1 22.5,-8.8 4.5,-3 10.1,-8.9 13.5,-14.1 10,-15.5 11,-34.7 2.5,-51.2 -6.7,-13 -18.1,-22.2 -32.9,-26.2 -3.2,-0.9 -5.2,-1.1 -12.4,-1.1 -10,0 -13.8,0.7 -21.5,4.3 -10.8,5.1 -18.7,12.7 -24,22.9 -4.3,8.3 -6.1,16.5 -5.6,26 0.4,7.1 1.7,12.7 4.5,18.6 3,6.2 5.2,9.5 9.9,14.3 8.3,8.7 19.6,14.2 31.7,15.4 3.7,0.5 5.6,0.5 11.8,-0.1 z"
+ id="path12" /><path
+ d="m 326,8893.5 c -0.8,-0.3 -2,-1.3 -2.7,-2 -1,-1.1 -1.2,-1.8 -1.2,-4.5 0,-3.1 0.1,-3.2 1.8,-4.8 1.3,-1.2 2.4,-1.7 4.2,-1.9 9.7,-1.1 13.8,-2.8 19,-7.6 4.8,-4.4 8.2,-11.6 8.3,-17 0,-4.7 2.1,-8.2 5.4,-9.1 3.7,-1 8,1.6 8.7,5.3 0.5,2.6 -0.5,10 -1.9,14.1 -2.3,6.8 -5.4,11.6 -10.5,16.5 -6.3,6.1 -13.1,9.6 -21.6,11 -5.4,0.8 -7.6,0.8 -9.5,0 z"
+ id="path14" /><path
+ d="m 752.2,8933.3 c -49.4,-10.4 -90.3,-19.3 -90.9,-19.7 -0.6,-0.4 -1.6,-1.3 -2,-2.1 -0.8,-1.3 -0.9,-6 -1.1,-81.5 l -0.2,-80.2 -3.3,2.7 c -4.3,3.4 -10.8,6.8 -16.3,8.5 -4.1,1.3 -5,1.4 -13,1.4 -7.9,0 -9,-0.1 -12.9,-1.3 -16.9,-5.2 -28.9,-17.6 -33.7,-35 -0.6,-2.4 -0.8,-5 -0.8,-11.4 0,-7.7 0.1,-8.8 1.4,-12.8 5.4,-17.7 19.6,-30.6 37.5,-33.7 4.6,-0.8 15.7,-0.4 19.9,0.7 17.2,4.7 29.5,17.1 34.6,35.1 l 1.1,3.8 0.1,65 0.1,65 81.2,17.7 c 44.7,9.7 81.4,17.5 81.6,17.3 0.2,-0.2 0.4,-21.2 0.5,-46.7 0.1,-45.5 0.1,-46.3 -0.8,-45.6 -0.5,0.4 -2.5,1.9 -4.3,3.2 -11,8.4 -26.3,11.5 -39.9,8 -4.5,-1.1 -12.1,-4.6 -15.7,-7.3 -13.4,-9.7 -20.8,-25.1 -19.8,-41.4 0.7,-12 5,-21.9 13.3,-30.5 9.3,-9.6 20.8,-14.5 34,-14.5 13,0 24.7,4.9 34,14.3 5.7,5.8 9.7,12.8 12.2,21.7 l 1.1,3.8 0.1,104.4 c 0.1,98.8 0,104.5 -0.7,106.1 -1.2,2.2 -3,3.5 -5.4,3.8 -1.5,0.1 -32.1,-6.2 -91.9,-18.8 z m 84.1,-21.2 v -24.4 l -1.1,-0.2 c -3,-0.7 -159.4,-34.7 -161,-35 l -1.8,-0.3 0.1,25 0.1,25 81,17.1 c 44.6,9.4 81.4,17.1 81.9,17.1 0.7,0.1 0.8,-1.4 0.8,-24.3 z m -27.8,-133.7 c 10,-1.8 19.4,-8.9 23.8,-17.9 2.6,-5.2 3.5,-9.4 3.6,-14.8 0,-5.9 -0.8,-9.4 -3.4,-15 -3.8,-8 -11.2,-14.4 -19.8,-17.2 -6.8,-2.3 -16.7,-1.7 -23.5,1.2 -9.2,4.1 -16.7,13 -19.2,22.8 -1.1,4.4 -0.7,13.9 0.7,18.3 1.6,4.8 4.4,9.2 8.5,13.3 7.7,7.8 18.7,11.3 29.3,9.3 z m -176.8,-30.7 c 9.8,-2.1 18.5,-9 23,-18.2 5.5,-11.5 4.2,-24.4 -3.7,-35.1 -5.7,-7.7 -16.2,-12.9 -26.1,-12.9 -10.2,0 -20.8,5.1 -26.7,12.9 -7.8,10.3 -9.2,23.6 -3.6,35.1 3.5,7.2 8.7,12.3 16.1,15.9 6.2,2.9 13.9,3.8 21,2.3 z"
+ id="path16" /><path
+ d="m 521.7,8874 v -6.9 h 7.9 7.9 v -11.6 -11.5 h -7.9 -7.9 v -7.1 -7.1 h 61.5 61.5 v 7.1 7.1 h -9.1 -9.1 v 11.6 11.6 h 9.1 9.1 v 6.9 6.9 h -61.5 -61.5 z m 53.2,-18.5 V 8844 h -11.6 -11.6 v 11.6 11.6 h 11.6 11.6 z m 37.4,0 V 8844 h -11.6 -11.6 v 11.6 11.6 h 11.6 11.6 z"
+ id="path18" /></g></svg>
diff --git a/src/multimedia/doc/src/images/qS1FmgPVL.jpg b/src/multimedia/doc/src/images/qS1FmgPVL.jpg
new file mode 100644
index 000000000..4dc2bb7c2
--- /dev/null
+++ b/src/multimedia/doc/src/images/qS1FmgPVL.jpg
Binary files differ
diff --git a/src/multimedia/doc/src/images/sound-wave-small.jpg b/src/multimedia/doc/src/images/sound-wave-small.jpg
new file mode 100644
index 000000000..1a873d94d
--- /dev/null
+++ b/src/multimedia/doc/src/images/sound-wave-small.jpg
Binary files differ
diff --git a/src/multimedia/doc/src/multimedia-overview.qdoc b/src/multimedia/doc/src/multimedia-overview.qdoc
new file mode 100644
index 000000000..6da54a7e2
--- /dev/null
+++ b/src/multimedia/doc/src/multimedia-overview.qdoc
@@ -0,0 +1,142 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+
+
+/*!
+\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
+advantage of a platform's multimedia capabilities, such as media playback and
+the use of camera devices.
+
+\section1 Features
+
+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
+\li Decode audio media files into memory for processing.
+\endlist
+
+\section1 Multimedia Components
+
+The Qt Multimedia APIs are categorized into three main components. More
+information specific to each component is available in the overview pages. You
+can also take a look at some \l{Multimedia Recipes}{recipes}.
+
+\list
+\li \l {Audio Overview}
+\li \l {Video Overview}
+\li \l {Camera Overview}
+\li \l {Spatial Audio Overview} (Technology Preview)
+\endlist
+
+\section1 Multimedia Recipes
+
+For some quick recipes, see this table:
+
+\table 70%
+ \header
+ \li Use case
+ \li Examples
+ \li QML Types
+ \li C++ Classes
+ \row
+ \li Playing a sound effect
+ \li
+ \li \l{SoundEffect}
+ \li QSoundEffect
+ \row
+ \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{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}
+ \li
+ \li QAudioSource
+ \row
+ \li Recording encoded audio data
+ \li \l{Audio Recorder Example}{audiorecorder}
+ \li \l{CaptureSession}, \l{AudioInput}, \l{MediaRecorder}
+ \li QMediaCaptureSession, QAudioInput, QMediaRecorder
+ \row
+ \li Discovering audio and video devices
+ \li \l{Audio Devices Example}{audiodevices}
+ \li \l{MediaDevices}, \l{audioDevice}, \l{cameraDevice}
+ \li QMediaDevices, QAudioDevice, QCameraDevice
+ \row
+ \li Video Playback
+ \li \l{Media Player Example}{player},
+ \l{QML Media Player Example}{mediaplayer}
+ \li \l MediaPlayer, \l VideoOutput, \l Video
+ \li QMediaPlayer, QVideoWidget, QGraphicsVideoItem
+ \row
+ \li Capturing audio and video
+ \li \l {Camera Example}{camera},
+ \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 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 Video Recorder}{recorder}
+ \li \l CaptureSession, \l Camera, \l MediaRecorder
+ \li QMediaCaptureSession, QCamera, QMediaRecorder
+\endtable
+
+\section1 Limitations
+
+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
+
+If you previously used Qt Multimedia in Qt 5, see
+\l{Changes to Qt Multimedia} for more information on what has changed, and what
+you might need to change when porting code to Qt 6.
+
+\section1 Reference Documentation
+
+\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/multimedia.qdoc b/src/multimedia/doc/src/multimedia.qdoc
deleted file mode 100644
index dcf394c87..000000000
--- a/src/multimedia/doc/src/multimedia.qdoc
+++ /dev/null
@@ -1,186 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-/*!
-\page multimediaoverview.html
-\title Multimedia
-\brief A set of APIs for working with audio, video and camera devices.
-
-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
-advantage of a platform's multimedia capabilities such as media playback and
-the use of camera devices.
-
-\section1 Features
-
-Here are some examples of what can be done with Qt Multimedia APIs:
-
-\list
-\li Access raw audio devices for input and output
-\li Play low latency sound effects
-\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
-\li Play 3D positional audio with \l{Qt Audio Engine QML Types}{Qt Audio Engine}
-\li Decode audio media files into memory for processing
-\li Accessing video frames or audio buffers as they are played or recorded
-\endlist
-
-\section1 Multimedia Components
-
-Qt's multimedia APIs are categorized into four main components. More
-information (including background information and class references) is
-available here:
-
-\list
-\li \l {Audio Overview}
-\li \l {Video Overview}
-\li \l {Camera Overview}
-\endlist
-
-\section1 Multimedia Recipes
-
-For some quick recipes, look at the overviews above and consult this table:
-
-\table 70%
- \header
- \li Use case
- \li Examples
- \li QML Types
- \li C++ Classes
- \row
- \li Playing a sound effect
- \li
- \li
- \li QSoundEffect
- \row
- \li Playing low latency audio
- \li \l{Audio Input Example}{audioinput},
- \l{Spectrum Example}{spectrum}
- \li
- \li QAudioOutput
- \row
- \li Playing encoded audio (MP3, AAC etc)
- \li \l{Media Player Example}{player}
- \li \l Audio, \l {MediaPlayer}
- \li QMediaPlayer
- \row
- \li Accessing raw audio input data
- \li \l{Spectrum Example}{spectrum},
- \l{Audio Input Example}{audioinput}
- \li
- \li QAudioInput
- \row
- \li Recording encoded audio data
- \li \l{Audio Recorder Example}{audiorecorder}
- \li
- \li QAudioRecorder
- \row
- \li Discovering raw audio devices
- \li \l{Audio Devices Example}{audiodevices}
- \li
- \li QAudioDeviceInfo
- \row
- \li Video Playback
- \li \l{Media Player Example}{player},
- \l{QML Video Example}{qmlvideo},
- \l{QML Video Shader Effects Example}{qmlvideofx}
- \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, QAbstractVideoSurface, QVideoFrame
- \row
- \li Accessing camera viewfinder
- \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, QAbstractVideoSurface, QVideoFrame
- \row
- \li Capturing photos
- \li \l {Camera Example}{camera},
- \l {QML Camera Example}{declarative-camera}
- \li \l Camera
- \li QCamera, QCameraImageCapture
- \row
- \li Capturing movies
- \li \l {Camera Example}{camera},
- \l {QML Camera Example}{declarative-camera}
- \li \l Camera
- \li QCamera, QMediaRecorder
- \row
- \li 3D sound sources
- \li
- \li \l {AudioEngine Example}{Audio Engine}
- \li \l {AudioEngine}, \l Sound
- \li
-\endtable
-
-\section1 Limitations
-
-The Qt Multimedia APIs build upon the multimedia framework of the underlying
-platform. This can mean that support for various codecs or containers can vary
-between machines, depending on what the end user has installed.
-
-\section1 Advanced Usage
-
-For developers wishing to access some platform specific settings, or to port the
-Qt Multimedia APIs to a new platform or technology, see \l{Multimedia Backend
-Development}.
-
-\section1 Changes from Previous Versions
-
-If you previously used Qt Multimedia in Qt 4, or used Qt Multimedia Kit in
-Qt Mobility, please see \l {Changes in Qt Multimedia} for more information on
-what changed, and what you might need to change when porting code.
-
-\section1 Reference Documentation
-
-\section2 QML Types
-The QML types are accessed by using:
-\code
-import QtMultimedia 5.8
-\endcode
-\annotatedlist multimedia_qml
-The following types are accessed by using \l{Qt Audio Engine QML Types}{Qt Audio Engine}:
-\qml \QtMinorVersion
-import QtAudioEngine 1.\1
-\endqml
-\annotatedlist multimedia_audioengine
-
-\section2 Multimedia Classes
-
-\annotatedlist multimedia
-
-*/
diff --git a/src/multimedia/doc/src/multimediabackend.qdoc b/src/multimedia/doc/src/multimediabackend.qdoc
deleted file mode 100644
index 48d598999..000000000
--- a/src/multimedia/doc/src/multimediabackend.qdoc
+++ /dev/null
@@ -1,139 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-
-/*!
-
-\title Multimedia Backend Development
-\page multimediabackend.html
-\brief Information for implementing a new multimedia backend.
-\ingroup mobility
-
-\tableofcontents
-
-\section1 Overview
-
-A multimedia backend provides the glue between platform-specific libraries, and
-Qt Multimedia. In some cases the available cross-platform Multimedia APIs or
-implementations are not sufficient, or not immediately available on a certain
-platform. Alternatively, the multimedia implementation on a platform might expose
-certain extra properties or functionality that other platforms do not, or a finer
-degree of control might be possible. For these cases, it is possible to use
-extended controls directly.
-\omit
-In addition, if you plan to port the Qt Multimedia APIs to a new platform, you do
-this by implementing certain control and service classes, as detailed below.
-
-\section1 Extending the API
-
-For the developer who wishes to extend the functionality of the Qt Multimedia
-classes there are several classes of particular importance. The classes
-providing default functionality are QMediaService, QMediaServiceProvider and
-QMediaControl. Some of these classes are not in the public API since they
-are very seldom useful to application developers.
-
-To extend the Multimedia API you would use the following three classes or
-classes derived from them.
-
- \list
- \li QMediaServiceProvider is used by the top level client class to
- request a service. The top level class knowing what kind of service it needs.
-
- \li \l QMediaService provides a service and when asked by the top level
- object, say a component, will return a QMediaControl object.
-
- \li \l QMediaControl allows the control of the service using a known interface.
- \endlist
-
-Consider a developer creating, for example, a media player class called MyPlayer.
-It may have special requirements beyond ordinary media players and so may
-need a custom service and a custom control. We can subclass QMediaServiceProvider
-to create our MyServiceProvider class. Also we will create a
-MyMediaService, and the MyMediaControl to manipulate the media service.
-
-The MyPlayer object calls MyServiceProvider::requestService() to get an
-instance of MyMediaService. Then the MyPlayer object calls this service
-object it has just received and calling \l {QMediaService::requestControl()}{requestControl()}
-it will receive the control object derived from QMediaControl.
-
-Now we have all the parts necessary for our media application. We have the service
-provider, the service it provides and the control used to manipulate the
-service. Since our MyPlayer object has instances of the service and its
-control then it would be possible for these to be used by associated classes
-that could do additional actions, perhaps with their own control since the
-parameter to requestControl() is a zero-terminated string, \e {const char *},
-for the interface.
-
-\section2 Adding a Media Service Provider
-
-In general, adding a new media service provider is outside the scope of this documentation.
-For best results, consult the existing provider source code, and seek assistance on the relevant
-mailing lists and IRC channels.
-
-The base class for creating new service providers is \l{QMediaServiceProvider}.
-The user must implement the \l{QMediaServiceProvider::requestService()}{requestService()}
-function
-
-\code
- QMediaService* requestService(const QByteArray &type, const QMediaServiceProviderHint &hint);
-\endcode
-
-The details of implementation will depend on the provider. Looking at the
-class \l QMediaServiceProvider for the default implementation. Notice that
-\l {QMediaServiceProvider::requestService()}{requestService()} uses the
-\l QMediaServiceProviderHint to look for the appropriate plugin and then to
-insert it into the plugin map. However, for a specific service provider there
-is probably no need for this approach, it will simply depend on what the
-developer wants to implement.
-
-Other methods that may be overloaded
-\code
- void releaseService(QMediaService *service);
-
- QtMediaServices::SupportEstimate hasSupport(const QByteArray &serviceType,
- const QString &mimeType,
- const QStringList& codecs,
- int flags) const;
-
- QStringList supportedMimeTypes(const QByteArray &serviceType, int flags) const;
-
- QList<QByteArray> devices(const QByteArray &serviceType) const;
-
- QString deviceDescription(const QByteArray &serviceType, const QByteArray &device);
-\endcode
-
-The choice of what needs to be done depends on what the developer wishes to do with the service.
-
-\endomit
-
-\section2 Classes for service implementers.
-
-\annotatedlist multimedia_control
-
-*/
-
-
diff --git a/src/multimedia/doc/src/platform-notes-apple.qdoc b/src/multimedia/doc/src/platform-notes-apple.qdoc
new file mode 100644
index 000000000..a9bca07c2
--- /dev/null
+++ b/src/multimedia/doc/src/platform-notes-apple.qdoc
@@ -0,0 +1,19 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtmultimedia-apple.html
+\title Qt Multimedia on macOS and iOS
+\brief Platform notes for iOS
+
+This page covers the availability of Qt Multimedia features on iOS and macOS.
+
+\section1 Limitations
+
+Since Qt Multimedia for iOS uses the camera and microphone, the \c Info.plist
+assigned to QMAKE_INFO_PLIST in the project file must contain the keys
+\c NSCameraUsageDescription and \c NSMicrophoneUsageDescription. Otherwise, the
+application will abort on startup. See \l{Info.plist} documentation from Apple
+for more information regarding this key.
+
+*/
diff --git a/src/multimedia/doc/src/platform-notes-gstreamer-on-android.qdoc b/src/multimedia/doc/src/platform-notes-gstreamer-on-android.qdoc
deleted file mode 100644
index 51836d99a..000000000
--- a/src/multimedia/doc/src/platform-notes-gstreamer-on-android.qdoc
+++ /dev/null
@@ -1,59 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
-
-/*!
-\page platform-notes-gstreamer-on-android.html
-\title Qt Multimedia GStreamer on Android
-\brief Platform notes for GStreamer on Android
-\since 5.14
-
-This page covers the availability of GStreamer on Android.
-
-\section1 Limitations
-
-Since GStreamer is licensed under LGPL and distributed in archives (and should be statically linked),
-Qt Multimedia does not provide support of GStreamer on Android by default.
-
-Therefore GStreamer support must be explicitly enabled by configuring Qt with the \c -gstreamer option.
-
-\section1 Setup
-
-The GStreamer project provides prebuilt binaries which you can download and unzip into any location of your choice.
-
-The environment variable \c GSTREAMER_ROOT_ANDROID should be set to the location where you unzipped the downloaded package.
-
-\section1 Application
-
-Qt Multimedia does not contain any plugins and all needed plugins must be included
-and registered in applications manually by \c GST_PLUGIN_STATIC_DECLARE and \c GST_PLUGIN_STATIC_REGISTER
-after \c gst_init().
-
-Please refer to the official manual on how to statically link plugins to an application.
-
-https://gstreamer.freedesktop.org/documentation/gstreamer/gstplugin.html?gi-language=c#GST_PLUGIN_STATIC_REGISTER
-
-*/
diff --git a/src/multimedia/doc/src/platform-notes-ios.qdoc b/src/multimedia/doc/src/platform-notes-ios.qdoc
deleted file mode 100644
index db5cd6d5a..000000000
--- a/src/multimedia/doc/src/platform-notes-ios.qdoc
+++ /dev/null
@@ -1,43 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
-
-/*!
-\page qtmultimedia-ios.html
-\title Qt Multimedia on iOS
-\brief Platform notes for iOS
-
-This page covers the availability of Qt Multimedia features on iOS.
-
-\section1 Limitations
-
-Since Qt Multimedia for iOS uses the camera, the \c Info.plist assigned to
-QMAKE_INFO_PLIST in the project file must contain the key
-\c NSCameraUsageDescription. Otherwise the application will
-abort on startup. See Info.plist documentation from Apple for more information
-regarding this key.
-
-*/
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/platform-notes-windows.qdoc b/src/multimedia/doc/src/platform-notes-windows.qdoc
deleted file mode 100644
index a69e96d99..000000000
--- a/src/multimedia/doc/src/platform-notes-windows.qdoc
+++ /dev/null
@@ -1,62 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-/*!
-\page qtmultimedia-windows.html
-\title Qt Multimedia on Windows
-\brief Platform notes for Windows
-
-This page covers the availability of Qt Multimedia features on Windows.
-
-\section1 Implementation
-
-Qt Multimedia features for Windows are implemented in two plugins; one
-using the Microsoft DirectShow API, and another using WMF (Windows Media
-Foundation) framework. DirectShow API was introduced in Windows 98, and
-gradually deprecated from Windows XP onwards. Media Foundation framework
-was introduced in Windows Vista as a replacement for DirectShow and other
-multimedia APIs. Consequently, WMF plugin in Qt is supported only for
-Windows Vista and later versions of the operating system.
-
-The environment variable \c QT_MULTIMEDIA_PREFERRED_PLUGINS can be used to
-control the priority of the plugins. For example, setting it to
-"windowsmediafoundation" or "directshow" will cause the corresponding plugin
-to be the preferred one.
-
-\section1 Limitations
-
-The WMF plugin in Qt does not currently provide a camera backend. Instead,
-limited support for camera features is provided by the DirectShow
-plugin. Basic features such as displaying a viewfinder and capturing a
-still image are supported, however, majority of camera controls are not
-implemented.
-
-Video recording is currently not supported. Additionally, the DirectShow
-plugin does not support any low-level video functionality such as
-monitoring video frames being played or recorded using \l QVideoProbe or
-related classes.
-*/
diff --git a/src/multimedia/doc/src/plugins/qml-multimedia.qdoc b/src/multimedia/doc/src/plugins/qml-multimedia.qdoc
deleted file mode 100644
index b6df70973..000000000
--- a/src/multimedia/doc/src/plugins/qml-multimedia.qdoc
+++ /dev/null
@@ -1,216 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-/*!
- \page qml-multimedia.html
-
- \title Qt Multimedia QML API
-
- \brief A QML API for the Qt Multimedia module.
-
-
- \section1 Overview
-
- The Qt Multimedia module gives developers a simplified way to use audio and video playback, and access camera functionality. The Multimedia QML API provides a QML friendly interface to these features.
-
- \section1 Types
-
- \section2 Audio
-
- \l Audio is an easy way to add audio playback to a Qt Quick
- scene. Qt Multimedia provides properties for control, methods (functions) and signals.
-
- The code extract below shows the creation and use of an Audio instance.
-
- \qml
-
- Item {
- width: 640
- height: 360
-
- Audio {
- id: playMusic
- source: "music.wav"
- }
-
- MouseArea {
- id: playArea
- anchors.fill: parent
- onPressed: { playMusic.play() }
- }
- }
-
- \endqml
-
- The snippet above shows how the inclusion of \e playMusic enables audio features on the type that contains it. So that when the parent's MouseArea is clicked the \l {Audio::play()}{play()} method of Audio is run. Other typical audio control methods are available such as \l {Audio::pause}{pause()} and \l {Audio::stop()}{stop()}.
-
- Much of the getting / setting of \l Audio parameters is done through properties. These include
- \table 70%
- \header
- \li Property
- \li Description
- \row
- \li \l {Audio::source}{source}
- \li The source URL of the media.
- \row
- \li \l {Audio::autoLoad}{autoLoad}
- \li Indicates if loading of media should begin immediately.
- \row
- \li \l{Audio::playing}{playing}
- \li Indicates that the media is playing.
- \row
- \li \l {Audio::paused}{paused}
- \li The media is paused.
- \row
- \li \l{Audio::status}{status}
- \li The status of media loading.
- \row
- \li \l{Audio::duration}{duration}
- \li Amount of time in milliseconds the media will play.
- \row
- \li \l{Audio::position}{position}
- \li Current position in the media in milliseconds of play.
- \row
- \li \l{Audio::volume}{volume}
- \li Audio output volume: from 0.0 (silent) to 1.0 (maximum)
- \row
- \li \l{Audio::muted}{muted}
- \li Indicates audio is muted.
- \row
- \li \l{Audio::bufferProgress}{bufferProgress}
- \li Indicates how full the data buffer is: 0.0 (empty) to 1.0 (full).
- \row
- \li \l{Audio::seekable}{seekable}
- \li Indicates whether the audio position can be changed.
- \row
- \li \l{Audio::playbackRate}{playbackRate}
- \li The rate at which audio is played at as a multiple of the normal rate.
- \row
- \li \l{Audio::error}{error}
- \li An error code for the error state including NoError
- \row
- \li \l{Audio::errorString}{errorString}
- \li A description of the current error condition.
- \endtable
-
- The set of signals available allow the developer to create custom behavior when the following events occur,
-
- \table 70%
- \header
- \li Signal
- \li Description
- \row
- \li \l{Audio::playing}{playing}
- \li Called when playback is started, or when resumed from paused state.
- \row
- \li \l{Audio::paused}{paused}
- \li Called when playback is paused.
- \row
- \li \l{Audio::stopped}{stopped}
- \li Called when playback is stopped.
- \row
- \li \l{Audio::error}{error}
- \li Called when the specified error occurs.
- \endtable
-
- \section2 Camera
-
- \l Camera enables still image and video capture using
- QML. It has a number of properties that help setting it up.
-
- The details of using a \l Camera are described in further depth
- in the \l {Camera Overview} and in the corresponding reference documentation.
-
- \section2 Video
-
- Adding video playback, with sound, to a Qt Quick scene is also easy. The process is very similar to that of Audio above, in fact \l {Video} shares many of the property names, methods and signals. Here is the equivalent sample code to implement video playback in a scene
-
- \qml
-
- Video {
- id: video
- width : 800
- height : 600
- source: "video.avi"
-
- MouseArea {
- anchors.fill: parent
- onClicked: {
- video.play()
- }
- }
-
- focus: true
- Keys.onSpacePressed: video.paused = !video.paused
- Keys.onLeftPressed: video.position -= 5000
- Keys.onRightPressed: video.position += 5000
- }
-
- \endqml
-
- There are similar features like \l {Video::play()}{play()} with new
- features specific to video.
-
- In the above sample when the parent of MouseArea is clicked, an area of 800x600 pixels with an id of 'video', the source "video.avi" will play in that area. Notice also that signals for the \l Keys have been defined so that a spacebar will toggle the pause button; the left arrow will move the current position in the video to 5 seconds previously; and the right arrow will advance the current position in the video by 5 seconds.
-
- Most of the differences will obviously be about video control and information. There are many properties associated with \l {Video}, most of them deal with meta-data, control of the video media and aspects of presentation.
-
- \section2 SoundEffect
-
- \l SoundEffect provides a way to play short sound effects, like in video games. Multiple sound effect instances can be played simultaneously.
- You should use \l Audio for music playback.
-
- \qml
-
- Item {
- width: 640
- height: 360
-
- SoundEffect {
- id: effect
- source: "test.wav"
- }
- MouseArea {
- id: playArea
- anchors.fill: parent
- onPressed: { effect.play() }
- }
- }
-
- \endqml
-
-
- In the above sample the sound effect will be played when the MouseArea is clicked.
-
- For a complete description of this type, see \l SoundEffect
-
- \section1 Multimedia QML Types
-
- \annotatedlist multimedia_qml
-*/
-
-
diff --git a/src/multimedia/doc/src/qm-external-pages.qdoc b/src/multimedia/doc/src/qm-external-pages.qdoc
new file mode 100644
index 000000000..8a28780c0
--- /dev/null
+++ b/src/multimedia/doc/src/qm-external-pages.qdoc
@@ -0,0 +1,232 @@
+// 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
+ \title gstreamer
+*/
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Pixel_Format
+ \title pixel format
+*/
+
+/*!
+ \externalpage https://developer.apple.com/documentation/bundleresources/information_property_list
+ \title Info.plist
+*/
+
+/*!
+ \externalpage https://www.wix.com/blog/photography/2018/10/04/photography-terms/
+ \title photo glossary
+*/
+
+/*!
+ \externalpage https://doc.qt.io/qt-6/qtqml-syntax-imports.html
+ \title qtqml import syntax
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Sonification
+ \title Sonification
+*/
+
+/*!
+ \externalpage http://www.sengpielaudio.com/calculator-loudness.htm
+ \title loudness
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
+ \title ISO 639-2 code
+*/
+
+/*!
+ \externalpage https://www.dr-lex.be/info-stuff/volumecontrols.html
+ \title volume controls
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Hyperfocal_distance
+ \title hyperfocal
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Depth_of_field
+ \title DOF
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Media_type#Mime.types
+ \title MIME type
+*/
+
+/*!
+ \externalpage https://doc.qt.io/qt-5/qml-qtmultimedia-audio.html
+ \title Audio QML Type
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Windows_Media_Audio
+ \title Windows Media Audio
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Advanced_Audio_Coding
+ \title Advanced Audio Coding
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/ALAC
+ \title Apple Lossless Audio Codec
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Matroska
+ \title Matroska (MKV)
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Windows_Media_Video
+ \title Windows Media Video
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/MP3
+ \title MPEG-1 Audio Layer III or MPEG-2 Audio Layer III
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/WAV
+ \title Waveform Audio File Format
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Ogg
+ \title Ogg
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/MPEG-4
+ \title MPEG-4
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Audio_Video_Interleave
+ \title Audio Video Interleave
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/QuickTime
+ \title QuickTime
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/WebM
+ \title WebM
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/MPEG-4_Part_3
+ \title MPEG-4 Part 3 or MPEG-4 Audio (formally ISO/IEC 14496-3)
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/FLAC
+ \title Free Lossless Audio Codec
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Dolby_Digital
+ \title Dolby Digital
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Dolby_Digital_Plus
+ \title Dolby Digital Plus (EAC3)
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Opus_(audio_format)
+ \title Opus Audio Format
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Dolby_TrueHD
+ \title Dolby TrueHD
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Vorbis
+ \title Ogg Vorbis
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/VP8
+ \title VP8
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/MPEG-2
+ \title MPEG-2
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/MPEG-1
+ \title MPEG-1
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/High_Efficiency_Video_Coding
+ \title High Efficiency Video Coding (HEVC)
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Advanced_Video_Coding
+ \title Advanced Video Coding
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/AV1
+ \title AOMedia Video 1
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Motion_JPEG
+ \title MotionJPEG
+*/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/VP9
+ \title VP9
+*/
+
+/*!
+ \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
new file mode 100644
index 000000000..ad5ebab74
--- /dev/null
+++ b/src/multimedia/doc/src/qt6-changes.qdoc
@@ -0,0 +1,145 @@
+// 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
+ \title Changes to Qt Multimedia
+ \ingroup changes-qt-5-to-6
+ \brief Migrate Qt Multimedia to Qt 6.
+
+ Qt 6 is a result of the conscious effort to make the framework more
+ efficient and easy to use.
+
+ We try to maintain binary and source compatibility for all the public
+ APIs in each release. But some changes were inevitable in an effort to
+ make Qt a better framework.
+
+The module has been refactored significantly and has changed classification,
+from essential to add-on. The Qt Multimedia module in Qt 6 replaces the
+Qt Multimedia module from Qt 5.x. Existing code that uses Qt Multimedia from
+Qt 5 can be ported with limited effort.
+
+
+\section1 New features in Qt 6
+
+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 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.
+\endlist
+
+
+\section1 Removed features
+
+\table 70%
+ \header
+ \li Removed feature
+ \li Notes or suggested alternative
+ \row
+ \li Playlist in QMediaPlayer
+ \li QMediaPlayer does not do any playlist handling anymore in Qt 6.
+ \row
+ \li QMediaPlayList
+ \li This class has been removed from the API. It does however still exist
+ as part of the \l{Media Player Example}.
+ \row
+ \li QAudioProbe and QVideoProbe
+ \li The audio and video probing API has been removed.
+ \row
+ \li QAudioRecorder
+ \li Use the QMediaCaptureSession or CaptureSession QML type.
+ \row
+ \li \l{Audio QML type}
+ \li Use MediaPlayer QML type.
+ \row
+ \li QMediaObject and QMediaBindableInterface
+ \li These classes have been removed in favor of a more direct API for
+ setting up connections between objects using, for example, setVideoOutput
+ and QMediaCaptureSession.
+ \row
+ \li QCameraViewFinderSettings
+ \li This class has been removed. Use QCameraFormat to define the
+ resolution and frame rate the camera should be using.
+ \row
+ \li QMediaContent
+ \li The class has been removed. Use QUrl for individual media files instead.
+ \row
+ \li QSound
+ \li Use QSoundEffect instead.
+ \row
+ \li QVideoFilterRunnable
+ \li Use \l{shader effects} in QML instead or access the QVideoFrame's
+ content in C++.
+ \row
+ \li Public back-end API
+ \li The back-end API of Qt Multimedia is private in Qt 6. This improves
+ response time for supporting new multimedia use cases. Any classes that
+ contain the words "Control" or "Abstract" in the class name in Qt 5 are
+ now private in Qt 6.
+ \row
+ \li Back-end plugins
+ \li Qt Multimedia in Qt 6 does not use a plugin infrastructure for its
+ back ends anymore.
+ This means that users no longer need to ship those back ends with their
+ application. Instead, the back end being used is determined at compile
+ time based on the underlying operating system. Qt uses \l gstreamer on
+ Linux, WMF on Windows, AVFoundation on macOS and iOS and the Android
+ multimedia APIs on Android.
+\endtable
+
+\section1 Changed features
+
+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.
+
+\table 70%
+ \header
+ \li Changed feature
+ \li Notes
+ \row
+ \li Handling of Camera resolutions and frame rates
+ \li Handling of these has been simplified and a new QCameraFormat class
+ helps with selecting the correct resolution and frame rate for the camera.
+ \row
+ \li Video output handling on the C++ side has changed significantly.
+ \li QAbstractVideoSurface has been replaced by the QVideoSink class, and
+ generic rendering support has been enhanced to cover all \l{pixel format}s
+ supported by Qt Multimedia.
+ \row
+ \li Metadata types
+ \li QMediaMetaData has changed significantly: mainly moving from string
+ based to enum based keys, and reducing the set of supported keys to the
+ ones that can be supported on most platforms.
+ \row
+ \li QMediaFormat
+ \li Handling of formats for encoded media and the settings for the media
+ recorder have changed significantly. Qt 5 provides a string-based
+ API, a separated file format, and audio and video codecs into three classes.
+ However, Qt 6 unifies the formats in the QMediaFormat class. Additional
+ settings are directly specified in QMediaRecorder. Setting up file formats
+ and codecs is now implemented with enums and no longer uses strings. This
+ puts some limitations on the set of codecs that can be used, but helps
+ provide a consistent cross-platform API.
+ \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/qtaudioengine.qdoc b/src/multimedia/doc/src/qtaudioengine.qdoc
deleted file mode 100644
index c45d4e8af..000000000
--- a/src/multimedia/doc/src/qtaudioengine.qdoc
+++ /dev/null
@@ -1,59 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-/*!
-\qmlmodule QtAudioEngine 1.\QtMinorVersion
-\title Qt Audio Engine QML Types
-\ingroup qmlmodules
-\brief Provides QML types for 3D positional audio playback and content management.
-
-Qt Audio Engine is part of the \l{Qt Multimedia} module. Qt Audio
-Engine provides types for 3D positional audio playback and content management.
-
-The QML types can be imported into your application using the following import
-statement in your .qml file:
-\qml \QtMinorVersion
-import QtAudioEngine 1.\1
-\endqml
-
-\section1 Qt Audio Engine Features
-
-Qt Audio Engine enables developers to organize wave files into discrete \l Sound
-with different \l {PlayVariation}{play variations}, group sound controls by \l
-{AudioCategory} categories and define \l {AttenuationModelLinear}{attenuation
-models} and various 3D audio settings all in one place. Playback of \l
-{SoundInstance}{sound instances} can be conveniently activated by in-app events
-and managed by QtAudioEngine or controlled by explicitly defining \l
-SoundInstance for easier QML bindings.
-
-\section1 Examples
-\list
- \li \l {AudioEngine Example}{Audio Engine}
-\endlist
-
-\section1 QML Types
-*/
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 f75ecbfe2..b0c4ea732 100644
--- a/src/multimedia/doc/src/qtmultimedia-cpp.qdoc
+++ b/src/multimedia/doc/src/qtmultimedia-cpp.qdoc
@@ -1,48 +1,21 @@
-/****************************************************************************
-**
-** 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
\title Qt Multimedia Module C++ Classes
\ingroup modules
\qtvariable multimedia
+ \qtcmakepackage Multimedia
\brief The \l {Qt Multimedia} module provides audio, video and camera
functionality.
- To enable Qt Multimedia in a project, add this directive into the
- C++ files:
-
- \snippet doc_src_qtmultimedia.cpp 0
-
- To link against the C++ libraries, add the following to your \c qmake project
- file:
-
- \snippet doc_src_qtmultimedia.pro 0
+ \include module-use.qdocinc using qt module
+ \code
+ find_package(Qt6 REQUIRED COMPONENTS Multimedia)
+ target_link_libraries(mytarget PRIVATE Qt6::Multimedia)
+ \endcode
*/
/*!
@@ -54,7 +27,7 @@
QML alternatives. If your application is serving complex use cases such as
decoding media files, accessing video or audio buffers, use the C++
alternative. For more details about the complex audio, video, and camera use
- cases supported by the C++ classes, refer to \l {Multimedia}{Multimedia Overview}.
+ cases supported by the C++ classes, refer to \l {Qt Multimedia}{Multimedia Overview}.
\section1 Namespaces
\annotatedlist multimedia-namespaces
@@ -66,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 13c686978..74646b84c 100644
--- a/src/multimedia/doc/src/qtmultimedia-index.qdoc
+++ b/src/multimedia/doc/src/qtmultimedia-index.qdoc
@@ -1,186 +1,288 @@
-/****************************************************************************
-**
-** 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 qtmultimedia-index.html
\title Qt Multimedia
- \brief The Qt Multimedia module provides APIs for audio, video and
- camera-related functionality.
+ \image noun_Media_166644.svg "image of multimedia icons, courtesy of misirlou from the Noun Project"
+ \brief The Qt Multimedia module provides APIs for playing back and recording
+ audiovisual content
- Qt Multimedia is an essential 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. The included
- \l{Qt Audio Engine QML Types}{Qt Audio Engine} provides types for
- 3D positional audio playback and content management.
+ Qt Multimedia is an add-on module that provides a rich set of QML types
+ 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{QtMultimedia}{Qt Multimedia}
- \li Provides API for multimedia-specific use cases.
+ \li \l{Multimedia Overview}{Qt Multimedia}
+ \li Provides an API for multimedia-specific use cases.
\row
- \li \l{QtMultimediaWidgets}{Qt Multimedia Widgets}
- \li Provides the widget-based multimedia API.
+ \li \l{Qt Multimedia Widgets}
+ \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}.
- The QML types can be imported into your applciation using the following
- import statement in your \c {.qml} file.
+ If you are new to Qt Multimedia, the QML types can be
+ \l{qtqml import syntax}{imported} into an application using the following
+ statement in your \c {.qml} file.
- \qml \QtMinorVersion
- import QtMultimedia 5.\1
+ \qml
+ import QtMultimedia
\endqml
- If you intend to use the C++ classes in your application, include the C++
- definitions using the following directive:
+ 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
- #include <QtMultimedia>
- #include <QtMultimediaWidgets>
- \endcode
+ \code
+ find_package(Qt6 REQUIRED COMPONENTS Multimedia)
+ target_link_libraries(my_project PRIVATE Qt6::Multimedia)
+ \endcode
- \note If you are using a few classes from this module, we recommend
- including those specific classes only instead of the module.
+ See \l {Building Qt Multimedia from sources} for guidance on building
+ Qt Multimedia from sources.
- To link against the corresponding C++ libraries, add the following to your
- \c {qmake} project file:
+ \section1 Overviews and important topics
- \code
- QT += multimedia multimediawidgets
- \endcode
+ \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 and C++ Classes
+ \section1 QML types
- The following is a list of important QML types and C++ classes provided by
- this module:
+ The following table outlines some important QML types.
\table
\header
\li Type
\li Description
\row
- \li \l {QtMultimedia::Audio}{Audio}
- \li Add audio playback functionality to a scene
+ \li \l{MediaPlayer}
+ \li Add audio/video playback functionality to a scene.
\row
- \li \l {QtMultimedia::Playlist}{Playlist}
- \li For specifying a list of media to be played.
+ \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 MediaPlayer
- \li Add media playback functionality to a scene. It is same as Audio type,
- but can be used for video playback with the VideoOutput type.
+ \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 \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
+
+ The following table outlines some important C++ classes
+
\table
\header
\li Class
\li Description
\row
- \li QAudioOutput
- \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 QAudioRecorder
- \li Record media content from an audio source.
+ \li QMediaCaptureSession
+ \li Capture audio and video.
\row
\li QCamera
- \li Access camera viewfinder.
+ \li Access a camera connected to the system
\row
- \li QCameraImageCapture
+ \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.
+ \li Record media content from a capture session.
\row
- \li QMediaPlayer
- \li Playback media from a source.
+ \li QVideoSink
+ \li Access and render individual video frames.
+ \row
+ \li QAudioSink
+ \li Sends raw audio data to an audio output device.
\row
- \li QMediaPlaylist
- \li List of media to be played.
+ \li QScreenCapture
+ \li Captures a screen.
\row
- \li QAbstractVideoSurface
- \li Base class for video presentation.
+ \li QWindowCapture
+ \li Captures a top-level window.
\endtable
- \section1 Licenses and Attributions
+ 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.
- The Qt Quick 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,
+ \section1 Licenses and attributions
+
+ 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.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 Multimedia - overview of multimedia support in Qt
- \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.
- The \l{Qt Multimedia Backends} wiki provides a summary of features
- supported by each platform plugin made available by this module. The
- following topics provide more platform-specific information.
+ \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 Windows}{Windows}
- \li \l{Qt Multimedia on iOS}{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 and macOS platforms, Qt's FFmpeg media backend
+ uses dynamic linking to the FFmpeg libraries. Windows and macOS
+ applications must therefore bundle FFmpeg binaries in their
+ installer, and make them visible to the application at runtime. On
+ Windows, we recommend to store the FFmpeg dlls in the same directory
+ as the application's executable file, because this guarantees that
+ the correct build of FFmpeg is being used if multiple versions are
+ available on the system. All necessary FFmpeg libraries are shipped
+ with the Qt Online Installer and are automatically deployed if the
+ windeployqt or macdeployqt tools are used to create the deployment.
+ Applications can also deploy their own build of FFmpeg, as long as
+ the FFmpeg major version matches the version used by Qt.
+
+ \note See \l{Licenses and Attributions} regarding what components are removed
+ in the package shipped by Qt.
+
+ \section3 Native backends
+ These are:
\list
- \li \l{Qt Multimedia QML Types}{QML Types}
- \li \l{Qt Multimedia C++ Classes}{C++ Classes}
- \endlist
+ \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.
+ \note MediaCodec on Android is deprecated as of Qt 6.8 and will be removed
+ in Qt 7.0.
+
+ \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 Qt Audio Engine
- \list
- \li \l{Qt Audio Engine QML Types}{QML Types}
- \endlist
+ \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
new file mode 100644
index 000000000..0d61a8917
--- /dev/null
+++ b/src/multimedia/doc/src/qtmultimedia-qml-types.qdoc
@@ -0,0 +1,45 @@
+// 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.
+
+The QML types for \l{Qt Multimedia} support the basic use cases such as:
+\list
+ \li audio and video playback,
+ \li access camera functionality,
+ \li record video,
+ \li and access camera settings.
+\endlist
+
+\section1 QML Types
+
+Qt Multimedia QML types can be imported into your application using the
+following import statement in your .qml file:
+
+\qml
+import QtMultimedia
+\endqml
+
+\generatelist qmltypesbymodule QtMultimedia
+
+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/qtmultimedia5.qdoc b/src/multimedia/doc/src/qtmultimedia5.qdoc
deleted file mode 100644
index 461cc716f..000000000
--- a/src/multimedia/doc/src/qtmultimedia5.qdoc
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-/*!
-\qmlmodule QtMultimedia 5.\QtMinorVersion
-\title Qt Multimedia QML Types
-\ingroup qmlmodules
-\brief Provides QML types for multimedia support.
-
-The QML types for \l{Qt Multimedia} support the basic use cases such as:
-\list
- \li audio and video playback,
- \li access camera functionality,
- \li record video,
- \li and access camera settings.
-\endlist
-
-\section1 QML Types
-
-Qt Multimedia QML types can be imported into your application using the
-following import statement in your .qml file:
-
-\qml \QtMinorVersion
-import QtMultimedia 5.\1
-\endqml
-
-\generatelist qmltypesbymodule QtMultimedia
-
-\section2 Qt Audio Engine
-
-\l {QtAudioEngine}{Qt Audio Engine} provides types for 3D positional audio
-playback and content management. These types can be imported into your
-application using the following import statement in your .qml file:
-
-\qml \QtMinorVersion
-import QtAudioEngine 1.\1
-\endqml
-
-\generatelist qmltypesbymodule QtAudioEngine
-
-\noautolist
-*/
diff --git a/src/multimedia/doc/src/videooverview.qdoc b/src/multimedia/doc/src/videooverview.qdoc
index c3fa50f04..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
@@ -54,69 +31,73 @@ And an example with QGraphicsVideoItem:
\section2 Playing Video in QML
-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.
-
-Alternatively there is also a higher level \l Video type that
-acts as a single, visual element to play video and control playback.
+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 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
Qt Multimedia offers a number of low level classes to make handling
-video frames a bit easier. These classes are primarily used when
+video frames a bit easier. These classes are primarily used when
writing code that processes video or camera frames (for example,
detecting barcodes, or applying a fancy vignette effect), or needs
to display video in a special way that is otherwise unsupported.
The \l QVideoFrame class encapsulates a video frame and allows the
contents to be mapped into system memory for manipulation or
-processing, while deriving a class from \l QAbstractVideoSurface
+processing. Using your own QVideoSink
allows you to receive these frames from \l QMediaPlayer and
\l QCamera.
-\snippet multimedia-snippets/video.cpp Derived Surface
+\section2 Recording Video
+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
-and with an instance of this surface, \c myVideoSurface, you can set
-the surface as the \l {QMediaPlayer::setVideoOutput()}{video output} for QMediaPlayer.
+What media formats are supported ultimately depends on the configuration of the
+target system.
-\snippet multimedia-snippets/video.cpp Setting surface in player
+\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.
-Several of the built-in Qt classes offer this functionality
-as well, so if you decode video in your application, you can present
-it to classes that offer a \l QVideoRendererControl class, and in QML
-you can set a custom object for the source of a \l VideoOutput
-with either a writable \c videoSurface property (that the instance will
-set it's internal video surface to) or a readable \c mediaObject property
-with a QMediaObject derived class that implements the \l QVideoRendererControl
-interface.
+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.
-The following snippet shows a class that has a writable \c videoSurface property
-and receives frames through a public slot \c onNewVideoContentReceived(). These
-frames are then presented on the surface set in \c setVideoSurface().
+\section2 Android
+See \l{Android supported media formats} for this information.
-\snippet multimedia-snippets/video.cpp Video producer
+\section2 Linux
+On Linux this is about installing the correct \l{GStreamer} plugins.
-\section2 Recording Video
-You can use the \l QMediaRecorder class in conjunction with other
-classes to record video to disk. Primarily this is used with
-the camera, so consult the \l {Camera Overview} for more information.
-
-\section2 Monitoring Video Frames
-You can use the \l QVideoProbe class to access video frames as they
-flow through different parts of a media pipeline when using other
-classes like \l QMediaPlayer, \l QMediaRecorder or \l QCamera. After
-creating the high level media class, you can set the source of the
-video probe to that instance. This can be useful for performing
-some video processing tasks (like barcode recognition, or object
-detection) while the video is rendered normally. You can not affect
-the video frames using this class, and they may arrive at a slightly
-different time than they are being rendered.
-
-Here's an example of installing a video probe while recording the camera:
- \snippet multimedia-snippets/media.cpp Video probe
+\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/multimedia.pro b/src/multimedia/multimedia.pro
deleted file mode 100644
index 10d49ef59..000000000
--- a/src/multimedia/multimedia.pro
+++ /dev/null
@@ -1,98 +0,0 @@
-TARGET = QtMultimedia
-QT = core-private network gui-private
-
-MODULE_PLUGIN_TYPES = \
- mediaservice \
- audio \
- video/bufferpool \
- video/gstvideorenderer \
- video/videonode \
- playlistformats \
- resourcepolicy
-
-QMAKE_DOCS = $$PWD/doc/qtmultimedia.qdocconf
-
-INCLUDEPATH *= .
-
-PRIVATE_HEADERS += \
- qtmultimediaglobal_p.h \
- qmediacontrol_p.h \
- qmediaobject_p.h \
- qmediapluginloader_p.h \
- qmediaservice_p.h \
- qmediaserviceprovider_p.h \
- qmediaresourcepolicyplugin_p.h \
- qmediaresourcepolicy_p.h \
- qmediaresourceset_p.h \
- qmediastoragelocation_p.h \
- qmultimediautils_p.h
-
-PUBLIC_HEADERS += \
- qtmultimediaglobal.h \
- qmediabindableinterface.h \
- qmediacontrol.h \
- qmediaenumdebug.h \
- qmediametadata.h \
- qmediaobject.h \
- qmediaservice.h \
- qmediaserviceproviderplugin.h \
- qmediatimerange.h \
- qmultimedia.h
-
-SOURCES += \
- qmediabindableinterface.cpp \
- qmediacontrol.cpp \
- qmediametadata.cpp \
- qmediaobject.cpp \
- qmediapluginloader.cpp \
- qmediaservice.cpp \
- qmediaserviceprovider.cpp \
- qmediatimerange.cpp \
- qmediaresourcepolicyplugin_p.cpp \
- qmediaresourcepolicy_p.cpp \
- qmediaresourceset_p.cpp \
- qmediastoragelocation.cpp \
- qmultimedia.cpp \
- qmultimediautils.cpp
-
-CONFIG += simd optimize_full
-
-include(audio/audio.pri)
-include(camera/camera.pri)
-include(controls/controls.pri)
-include(playback/playback.pri)
-include(recording/recording.pri)
-include(video/video.pri)
-
-ANDROID_BUNDLED_JAR_DEPENDENCIES = \
- jar/Qt$${QT_MAJOR_VERSION}AndroidMultimedia.jar:org.qtproject.qt.android.multimedia.QtMultimediaUtils
-ANDROID_LIB_DEPENDENCIES = \
- plugins/mediaservice/libplugins_mediaservice_qtmedia_android.so \
- lib/libQt5MultimediaQuick.so:Qt5Quick
-ANDROID_BUNDLED_FILES += \
- lib/libQt5MultimediaQuick.so
-ANDROID_PERMISSIONS += \
- android.permission.CAMERA \
- android.permission.RECORD_AUDIO
-ANDROID_FEATURES += \
- android.hardware.camera \
- android.hardware.camera.autofocus \
- android.hardware.microphone
-
-MODULE_WINRT_CAPABILITIES_DEVICE += \
- microphone \
- webcam
-
-qtConfig(gstreamer) {
- ANDROID_LIB_DEPENDENCIES += \
- plugins/mediaservice/libgstcamerabin.so \
- plugins/mediaservice/libgstmediacapture.so \
- plugins/mediaservice/libgstmediaplayer.so \
- plugins/mediaservice/libgstaudiodecoder.so
-}
-
-win32: LIBS_PRIVATE += -luuid
-
-HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS
-
-load(qt_module)
diff --git a/src/multimedia/platform/qgstreamer_platformspecificinterface.cpp b/src/multimedia/platform/qgstreamer_platformspecificinterface.cpp
new file mode 100644
index 000000000..06ce46e3c
--- /dev/null
+++ b/src/multimedia/platform/qgstreamer_platformspecificinterface.cpp
@@ -0,0 +1,27 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtMultimedia/private/qgstreamer_platformspecificinterface_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QGStreamerPlatformSpecificInterface::~QGStreamerPlatformSpecificInterface() = default;
+
+QGStreamerPlatformSpecificInterface *QGStreamerPlatformSpecificInterface::instance()
+{
+ return dynamic_cast<QGStreamerPlatformSpecificInterface *>(
+ QPlatformMediaIntegration::instance()->platformSpecificInterface());
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qgstreamer_platformspecificinterface_p.h b/src/multimedia/platform/qgstreamer_platformspecificinterface_p.h
new file mode 100644
index 000000000..1a086f5a4
--- /dev/null
+++ b/src/multimedia/platform/qgstreamer_platformspecificinterface_p.h
@@ -0,0 +1,46 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef GSTREAMER_PLATFORMSPECIFICINTERFACE_P_H
+#define GSTREAMER_PLATFORMSPECIFICINTERFACE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtMultimedia/private/qplatformmediaintegration_p.h>
+
+typedef struct _GstPipeline GstPipeline; // NOLINT (bugprone-reserved-identifier)
+typedef struct _GstElement GstElement; // NOLINT (bugprone-reserved-identifier)
+
+QT_BEGIN_NAMESPACE
+
+class Q_MULTIMEDIA_EXPORT QGStreamerPlatformSpecificInterface
+ : public QAbstractPlatformSpecificInterface
+{
+public:
+ ~QGStreamerPlatformSpecificInterface() override;
+
+ static QGStreamerPlatformSpecificInterface *instance();
+
+ virtual QAudioDevice makeCustomGStreamerAudioInput(const QByteArray &gstreamerPipeline) = 0;
+ virtual QAudioDevice makeCustomGStreamerAudioOutput(const QByteArray &gstreamerPipeline) = 0;
+ virtual QCamera *makeCustomGStreamerCamera(const QByteArray &gstreamerPipeline,
+ QObject *parent) = 0;
+
+ // Note: ownership of GstElement is not transferred
+ virtual QCamera *makeCustomGStreamerCamera(GstElement *, QObject *parent) = 0;
+
+ virtual GstPipeline *gstPipeline(QMediaPlayer *) = 0;
+ virtual GstPipeline *gstPipeline(QMediaCaptureSession *) = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // GSTREAMER_PLATFORMSPECIFICINTERFACE_P_H
diff --git a/src/multimedia/platform/qplatformaudiobufferinput.cpp b/src/multimedia/platform/qplatformaudiobufferinput.cpp
new file mode 100644
index 000000000..883b11fc0
--- /dev/null
+++ b/src/multimedia/platform/qplatformaudiobufferinput.cpp
@@ -0,0 +1,10 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qplatformaudiobufferinput_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QT_END_NAMESPACE
+
+#include "moc_qplatformaudiobufferinput_p.cpp"
diff --git a/src/multimedia/platform/qplatformaudiobufferinput_p.h b/src/multimedia/platform/qplatformaudiobufferinput_p.h
new file mode 100644
index 000000000..55636ce06
--- /dev/null
+++ b/src/multimedia/platform/qplatformaudiobufferinput_p.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QPLATFORMAUDIOBUFFERINPUT_P_H
+#define QPLATFORMAUDIOBUFFERINPUT_P_H
+
+#include "qaudioformat.h"
+#include "qaudiobuffer.h"
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QMediaInputEncoderInterface;
+
+class Q_MULTIMEDIA_EXPORT QPlatformAudioBufferInputBase : public QObject
+{
+ Q_OBJECT
+Q_SIGNALS:
+ void newAudioBuffer(const QAudioBuffer &buffer);
+};
+
+class Q_MULTIMEDIA_EXPORT QPlatformAudioBufferInput : public QPlatformAudioBufferInputBase
+{
+ Q_OBJECT
+public:
+ QPlatformAudioBufferInput(const QAudioFormat &format = {}) : m_format(format) { }
+
+ const QAudioFormat &audioFormat() const { return m_format; }
+
+ QMediaInputEncoderInterface *encoderInterface() const { return m_encoderInterface; }
+ void setEncoderInterface(QMediaInputEncoderInterface *interface)
+ {
+ m_encoderInterface = interface;
+ }
+
+Q_SIGNALS:
+ void encoderUpdated();
+
+private:
+ QMediaInputEncoderInterface *m_encoderInterface = nullptr;
+ QAudioFormat m_format;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPLATFORMAUDIOBUFFERINPUT_P_H
diff --git a/src/multimedia/platform/qplatformaudiodecoder.cpp b/src/multimedia/platform/qplatformaudiodecoder.cpp
new file mode 100644
index 000000000..0bf472410
--- /dev/null
+++ b/src/multimedia/platform/qplatformaudiodecoder.cpp
@@ -0,0 +1,81 @@
+// 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) { }
+
+QPlatformAudioDecoder::~QPlatformAudioDecoder() = default;
+
+void QPlatformAudioDecoder::error(int error, const QString &errorString)
+{
+ if (error == m_error && errorString == m_errorString)
+ return;
+ m_error = QAudioDecoder::Error(error);
+ m_errorString = errorString;
+
+ if (m_error != QAudioDecoder::NoError) {
+ setIsDecoding(false);
+ emit q->error(m_error);
+ }
+}
+
+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);
+}
+
+void QPlatformAudioDecoder::bufferReady()
+{
+ if (QThread::currentThread() != q->thread())
+ QMetaObject::invokeMethod(q, "bufferReady", Qt::QueuedConnection);
+ else
+ emit q->bufferReady();
+}
+
+void QPlatformAudioDecoder::sourceChanged()
+{
+ emit q->sourceChanged();
+}
+
+void QPlatformAudioDecoder::formatChanged(const QAudioFormat &format)
+{
+ emit q->formatChanged(format);
+}
+
+void QPlatformAudioDecoder::finished()
+{
+ durationChanged(-1);
+ setIsDecoding(false);
+ emit q->finished();
+}
+
+void QPlatformAudioDecoder::positionChanged(qint64 position)
+{
+ if (m_position == position)
+ return;
+ m_position = position;
+ emit q->positionChanged(position);
+}
+
+void QPlatformAudioDecoder::durationChanged(qint64 duration)
+{
+ if (m_duration == duration)
+ return;
+ m_duration = duration;
+ emit q->durationChanged(duration);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qplatformaudiodecoder_p.cpp"
diff --git a/src/multimedia/platform/qplatformaudiodecoder_p.h b/src/multimedia/platform/qplatformaudiodecoder_p.h
new file mode 100644
index 000000000..1159a37ca
--- /dev/null
+++ b/src/multimedia/platform/qplatformaudiodecoder_p.h
@@ -0,0 +1,92 @@
+// 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
+
+//
+// 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/qaudiobuffer.h>
+#include <QtMultimedia/qaudiodecoder.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qurl.h>
+#include <QtCore/private/qglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+class Q_MULTIMEDIA_EXPORT QPlatformAudioDecoder : public QObject
+{
+ Q_OBJECT
+
+public:
+ virtual QUrl source() const = 0;
+ virtual void setSource(const QUrl &fileName) = 0;
+
+ virtual QIODevice* sourceDevice() const = 0;
+ virtual void setSourceDevice(QIODevice *device) = 0;
+
+ virtual void start() = 0;
+ virtual void stop() = 0;
+
+ virtual QAudioFormat audioFormat() const = 0;
+ virtual void setAudioFormat(const QAudioFormat &format) = 0;
+
+ virtual QAudioBuffer read() = 0;
+ virtual bool bufferAvailable() const { return m_bufferAvailable; }
+
+ virtual qint64 position() const { return m_position; }
+ virtual qint64 duration() const { return m_duration; }
+
+ void formatChanged(const QAudioFormat &format);
+
+ void sourceChanged();
+
+ void error(int error, const QString &errorString);
+ void clearError() { error(QAudioDecoder::NoError, QString()); }
+
+ void bufferReady();
+ void bufferAvailableChanged(bool available);
+ void setIsDecoding(bool running = true) {
+ if (m_isDecoding == running)
+ return;
+ m_isDecoding = running;
+ emit q->isDecodingChanged(m_isDecoding);
+ }
+ void finished();
+ bool isDecoding() const { return m_isDecoding; }
+
+ void positionChanged(qint64 position);
+ void durationChanged(qint64 duration);
+
+ 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
+
+#endif // QAUDIODECODERCONTROL_H
diff --git a/src/multimedia/platform/qplatformaudioinput_p.h b/src/multimedia/platform/qplatformaudioinput_p.h
new file mode 100644
index 000000000..d6497c06e
--- /dev/null
+++ b/src/multimedia/platform/qplatformaudioinput_p.h
@@ -0,0 +1,46 @@
+// 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
+
+//
+// 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 <functional>
+
+QT_BEGIN_NAMESPACE
+
+class QAudioInput;
+
+class Q_MULTIMEDIA_EXPORT QPlatformAudioInput
+{
+public:
+ explicit QPlatformAudioInput(QAudioInput *qq) : q(qq) { }
+ virtual ~QPlatformAudioInput() = default;
+
+ virtual void setAudioDevice(const QAudioDevice & /*device*/) { }
+ virtual void setMuted(bool /*muted*/) {}
+ virtual void setVolume(float /*volume*/) {}
+
+ QAudioInput *q = nullptr;
+ QAudioDevice device;
+ float volume = 1.;
+ bool muted = false;
+ std::function<void()> disconnectFunction;
+};
+
+QT_END_NAMESPACE
+
+
+#endif // QPLATFORMAUDIOINPUT_H
diff --git a/src/multimedia/platform/qplatformaudiooutput_p.h b/src/multimedia/platform/qplatformaudiooutput_p.h
new file mode 100644
index 000000000..b8f5af6f3
--- /dev/null
+++ b/src/multimedia/platform/qplatformaudiooutput_p.h
@@ -0,0 +1,44 @@
+// 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
+
+//
+// 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>
+
+QT_BEGIN_NAMESPACE
+
+class QAudioOutput;
+
+class Q_MULTIMEDIA_EXPORT QPlatformAudioOutput
+{
+public:
+ explicit QPlatformAudioOutput(QAudioOutput *qq) : q(qq) { }
+ virtual ~QPlatformAudioOutput() = default;
+
+ virtual void setAudioDevice(const QAudioDevice &/*device*/) {}
+ virtual void setMuted(bool /*muted*/) {}
+ virtual void setVolume(float /*volume*/) {}
+
+ QAudioOutput *q = nullptr;
+ QAudioDevice device;
+ float volume = 1.;
+ bool muted = false;
+ std::function<void()> disconnectFunction;
+};
+
+QT_END_NAMESPACE
+
+
+#endif // QPLATFORMAUDIOOUTPUT_H
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
new file mode 100644
index 000000000..d03c19d67
--- /dev/null
+++ b/src/multimedia/platform/qplatformcamera.cpp
@@ -0,0 +1,233 @@
+// 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
+
+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...
+
+ auto makeCriteria = [this](const QCameraFormat &fmt) {
+ constexpr float MinSufficientFrameRate = 29.f;
+
+ 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));
+
+ 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
+ };
+
+ 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);
+ });
+
+ return found == formats.end() ? QCameraFormat{} : *found;
+}
+
+QVideoFrameFormat QPlatformCamera::frameFormat() const
+{
+ QVideoFrameFormat result(m_cameraFormat.resolution(),
+ m_framePixelFormat == QVideoFrameFormat::Format_Invalid
+ ? m_cameraFormat.pixelFormat()
+ : m_framePixelFormat);
+ result.setStreamFrameRate(m_cameraFormat.maxFrameRate());
+ return result;
+}
+
+void QPlatformCamera::supportedFeaturesChanged(QCamera::Features f)
+{
+ if (m_supportedFeatures == f)
+ return;
+ m_supportedFeatures = f;
+ emit m_camera->supportedFeaturesChanged();
+}
+
+void QPlatformCamera::minimumZoomFactorChanged(float factor)
+{
+ if (m_minZoom == factor)
+ return;
+ m_minZoom = factor;
+ emit m_camera->minimumZoomFactorChanged(factor);
+}
+
+void QPlatformCamera::maximumZoomFactorChanged(float factor)
+{
+ if (m_maxZoom == factor)
+ return;
+ m_maxZoom = factor;
+ emit m_camera->maximumZoomFactorChanged(factor);
+}
+
+void QPlatformCamera::focusModeChanged(QCamera::FocusMode mode)
+{
+ if (m_focusMode == mode)
+ return;
+ m_focusMode = mode;
+ emit m_camera->focusModeChanged();
+}
+
+void QPlatformCamera::customFocusPointChanged(const QPointF &point)
+{
+ if (m_customFocusPoint == point)
+ return;
+ m_customFocusPoint = point;
+ emit m_camera->customFocusPointChanged();
+}
+
+
+void QPlatformCamera::zoomFactorChanged(float zoom)
+{
+ if (m_zoomFactor == zoom)
+ return;
+ m_zoomFactor = zoom;
+ emit m_camera->zoomFactorChanged(zoom);
+}
+
+
+void QPlatformCamera::focusDistanceChanged(float d)
+{
+ if (m_focusDistance == d)
+ return;
+ m_focusDistance = d;
+ emit m_camera->focusDistanceChanged(m_focusDistance);
+}
+
+
+void QPlatformCamera::flashReadyChanged(bool ready)
+{
+ if (m_flashReady == ready)
+ return;
+ m_flashReady = ready;
+ emit m_camera->flashReady(m_flashReady);
+}
+
+void QPlatformCamera::flashModeChanged(QCamera::FlashMode mode)
+{
+ if (m_flashMode == mode)
+ return;
+ m_flashMode = mode;
+ emit m_camera->flashModeChanged();
+}
+
+void QPlatformCamera::torchModeChanged(QCamera::TorchMode mode)
+{
+ if (m_torchMode == mode)
+ return;
+ m_torchMode = mode;
+ emit m_camera->torchModeChanged();
+}
+
+void QPlatformCamera::exposureModeChanged(QCamera::ExposureMode mode)
+{
+ if (m_exposureMode == mode)
+ return;
+ m_exposureMode = mode;
+ emit m_camera->exposureModeChanged();
+}
+
+void QPlatformCamera::exposureCompensationChanged(float compensation)
+{
+ if (m_exposureCompensation == compensation)
+ return;
+ m_exposureCompensation = compensation;
+ emit m_camera->exposureCompensationChanged(compensation);
+}
+
+void QPlatformCamera::exposureCompensationRangeChanged(float min, float max)
+{
+ if (m_minExposureCompensation == min && m_maxExposureCompensation == max)
+ return;
+ m_minExposureCompensation = min;
+ m_maxExposureCompensation = max;
+ // tell frontend
+}
+
+void QPlatformCamera::isoSensitivityChanged(int iso)
+{
+ if (m_iso == iso)
+ return;
+ m_iso = iso;
+ emit m_camera->isoSensitivityChanged(iso);
+}
+
+void QPlatformCamera::exposureTimeChanged(float speed)
+{
+ if (m_exposureTime == speed)
+ return;
+ m_exposureTime = speed;
+ emit m_camera->exposureTimeChanged(speed);
+}
+
+void QPlatformCamera::whiteBalanceModeChanged(QCamera::WhiteBalanceMode mode)
+{
+ if (m_whiteBalance == mode)
+ return;
+ m_whiteBalance = mode;
+ emit m_camera->whiteBalanceModeChanged();
+}
+
+void QPlatformCamera::colorTemperatureChanged(int temperature)
+{
+ Q_ASSERT(temperature >= 0);
+ Q_ASSERT((temperature > 0 && whiteBalanceMode() == QCamera::WhiteBalanceManual) ||
+ (temperature == 0 && whiteBalanceMode() == QCamera::WhiteBalanceAuto));
+ if (m_colorTemperature == temperature)
+ return;
+ m_colorTemperature = temperature;
+ emit m_camera->colorTemperatureChanged();
+}
+
+int QPlatformCamera::colorTemperatureForWhiteBalance(QCamera::WhiteBalanceMode mode)
+{
+ switch (mode) {
+ case QCamera::WhiteBalanceAuto:
+ break;
+ case QCamera::WhiteBalanceManual:
+ case QCamera::WhiteBalanceSunlight:
+ return 5600;
+ case QCamera::WhiteBalanceCloudy:
+ return 6000;
+ case QCamera::WhiteBalanceShade:
+ return 7000;
+ case QCamera::WhiteBalanceTungsten:
+ return 3200;
+ case QCamera::WhiteBalanceFluorescent:
+ return 4000;
+ case QCamera::WhiteBalanceFlash:
+ return 5500;
+ case QCamera::WhiteBalanceSunset:
+ return 3000;
+ }
+ return 0;
+}
+
+void QPlatformCamera::updateError(QCamera::Error error, const QString &errorString)
+{
+ QMetaObject::invokeMethod(this, [this, error, errorString]() {
+ m_error.setAndNotify(error, errorString, *this);
+ });
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qplatformcamera_p.cpp"
diff --git a/src/multimedia/platform/qplatformcamera_p.h b/src/multimedia/platform/qplatformcamera_p.h
new file mode 100644
index 000000000..341bf9121
--- /dev/null
+++ b/src/multimedia/platform/qplatformcamera_p.h
@@ -0,0 +1,165 @@
+// 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
+// -------------
+//
+// 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 "private/qerrorinfo_p.h"
+#include <QtMultimedia/qcamera.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_MULTIMEDIA_EXPORT QPlatformCamera : public QPlatformVideoSource
+{
+ Q_OBJECT
+
+public:
+ virtual void setCamera(const QCameraDevice &camera) = 0;
+ virtual bool setCameraFormat(const QCameraFormat &/*format*/) { return false; }
+ QCameraFormat cameraFormat() const { return m_cameraFormat; }
+
+ virtual bool isFocusModeSupported(QCamera::FocusMode mode) const { return mode == QCamera::FocusModeAuto; }
+ virtual void setFocusMode(QCamera::FocusMode /*mode*/) {}
+
+ virtual void setCustomFocusPoint(const QPointF &/*point*/) {}
+
+ virtual void setFocusDistance(float) {}
+
+ // smaller 0: zoom instantly, rate in power-of-two/sec
+ virtual void zoomTo(float /*newZoomFactor*/, float /*rate*/ = -1.) {}
+
+ virtual void setFlashMode(QCamera::FlashMode /*mode*/) {}
+ virtual bool isFlashModeSupported(QCamera::FlashMode mode) const { return mode == QCamera::FlashOff; }
+ virtual bool isFlashReady() const { return false; }
+
+ virtual void setTorchMode(QCamera::TorchMode /*mode*/) {}
+ virtual bool isTorchModeSupported(QCamera::TorchMode mode) const { return mode == QCamera::TorchOff; }
+
+ virtual void setExposureMode(QCamera::ExposureMode) {}
+ virtual bool isExposureModeSupported(QCamera::ExposureMode mode) const { return mode == QCamera::ExposureAuto; }
+ virtual void setExposureCompensation(float) {}
+ virtual int isoSensitivity() const { return 100; }
+ virtual void setManualIsoSensitivity(int) {}
+ virtual void setManualExposureTime(float) {}
+ virtual float exposureTime() const { return -1.; }
+
+ virtual bool isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const { return mode == QCamera::WhiteBalanceAuto; }
+ 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; }
+ QPointF focusPoint() const { return m_customFocusPoint; }
+
+ float minZoomFactor() const { return m_minZoom; }
+ float maxZoomFactor() const { return m_maxZoom; }
+ float zoomFactor() const { return m_zoomFactor; }
+ QPointF customFocusPoint() const { return m_customFocusPoint; }
+ float focusDistance() const { return m_focusDistance; }
+
+ QCamera::FlashMode flashMode() const { return m_flashMode; }
+ QCamera::TorchMode torchMode() const { return m_torchMode; }
+
+ QCamera::ExposureMode exposureMode() const { return m_exposureMode; }
+ float exposureCompensation() const { return m_exposureCompensation; }
+ int manualIsoSensitivity() const { return m_iso; }
+ int minIso() const { return m_minIso; }
+ int maxIso() const { return m_maxIso; }
+ float manualExposureTime() const { return m_exposureTime; }
+ float minExposureTime() const { return m_minExposureTime; }
+ float maxExposureTime() const { return m_maxExposureTime; }
+ QCamera::WhiteBalanceMode whiteBalanceMode() const { return m_whiteBalance; }
+ int colorTemperature() const { return m_colorTemperature; }
+
+ void supportedFeaturesChanged(QCamera::Features);
+ void minimumZoomFactorChanged(float factor);
+ void maximumZoomFactorChanged(float);
+ void focusModeChanged(QCamera::FocusMode mode);
+ void customFocusPointChanged(const QPointF &point);
+ void focusDistanceChanged(float d);
+ void zoomFactorChanged(float zoom);
+ void flashReadyChanged(bool);
+ void flashModeChanged(QCamera::FlashMode mode);
+ void torchModeChanged(QCamera::TorchMode mode);
+ void exposureModeChanged(QCamera::ExposureMode mode);
+ void exposureCompensationChanged(float compensation);
+ void exposureCompensationRangeChanged(float min, float max);
+ void isoSensitivityChanged(int iso);
+ void minIsoChanged(int iso) { m_minIso = iso; }
+ void maxIsoChanged(int iso) { m_maxIso = iso; }
+ void exposureTimeChanged(float speed);
+ void minExposureTimeChanged(float secs) { m_minExposureTime = secs; }
+ void maxExposureTimeChanged(float secs) { m_maxExposureTime = secs; }
+ void whiteBalanceModeChanged(QCamera::WhiteBalanceMode mode);
+ void colorTemperatureChanged(int temperature);
+
+ static int colorTemperatureForWhiteBalance(QCamera::WhiteBalanceMode mode);
+
+ QCamera::Error error() const { return m_error.code(); }
+ QString errorString() const final { return m_error.description(); }
+
+ void updateError(QCamera::Error error, const QString &errorString);
+
+Q_SIGNALS:
+ void errorOccurred(QCamera::Error error, const QString &errorString);
+
+protected:
+ explicit QPlatformCamera(QCamera *parent);
+
+ 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 = {};
+ QCamera::FocusMode m_focusMode = QCamera::FocusModeAuto;
+ float m_minZoom = 1.;
+ float m_maxZoom = 1.;
+ float m_zoomFactor = 1.;
+ float m_focusDistance = 1.;
+ QPointF m_customFocusPoint{-1, -1};
+ bool m_flashReady = false;
+ QCamera::FlashMode m_flashMode = QCamera::FlashOff;
+ QCamera::TorchMode m_torchMode = QCamera::TorchOff;
+ QCamera::ExposureMode m_exposureMode = QCamera::ExposureAuto;
+ float m_exposureCompensation = 0.;
+ float m_minExposureCompensation = 0.;
+ float m_maxExposureCompensation = 0.;
+ int m_iso = -1;
+ int m_minIso = -1;
+ int m_maxIso = -1;
+ float m_exposureTime = -1.;
+ float m_minExposureTime = -1.;
+ float m_maxExposureTime = -1.;
+ QCamera::WhiteBalanceMode m_whiteBalance = QCamera::WhiteBalanceAuto;
+ int m_colorTemperature = 0;
+ QErrorInfo<QCamera::Error> m_error;
+};
+
+QT_END_NAMESPACE
+
+
+#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
new file mode 100644
index 000000000..5d8349256
--- /dev/null
+++ b/src/multimedia/platform/qplatformimagecapture.cpp
@@ -0,0 +1,27 @@
+// 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
+
+QPlatformImageCapture::QPlatformImageCapture(QImageCapture *parent)
+ : QObject(parent),
+ m_imageCapture(parent)
+{
+}
+
+QString QPlatformImageCapture::msgCameraNotReady()
+{
+ return QImageCapture::tr("Camera is not ready.");
+}
+
+QString QPlatformImageCapture::msgImageCaptureNotSet()
+{
+ return QImageCapture::tr("No instance of QImageCapture set on QMediaCaptureSession.");
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qplatformimagecapture_p.cpp"
diff --git a/src/multimedia/platform/qplatformimagecapture_p.h b/src/multimedia/platform/qplatformimagecapture_p.h
new file mode 100644
index 000000000..5bfb15ced
--- /dev/null
+++ b/src/multimedia/platform/qplatformimagecapture_p.h
@@ -0,0 +1,97 @@
+// 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
+
+//
+// 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/qimagecapture.h>
+#include <QtMultimedia/qmediametadata.h>
+#include <QtMultimedia/qimagecapture.h>
+#include <QtCore/private/qglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QImage;
+class QPlatformMediaCaptureSession;
+
+class QImageEncoderSettingsPrivate;
+class Q_MULTIMEDIA_EXPORT QImageEncoderSettings
+{
+ QImageCapture::FileFormat m_format = QImageCapture::UnspecifiedFormat;
+ QSize m_resolution;
+ QImageCapture::Quality m_quality = QImageCapture::NormalQuality;
+
+public:
+ bool operator==(const QImageEncoderSettings &other) {
+ return m_format == other.m_format &&
+ m_resolution == other.m_resolution &&
+ m_quality == other.m_quality;
+ }
+ bool operator!=(const QImageEncoderSettings &other) { return !operator==(other); }
+
+ QImageCapture::FileFormat format() const { return m_format; }
+ void setFormat(QImageCapture::FileFormat f) { m_format = f; }
+
+ QSize resolution() const { return m_resolution; }
+ void setResolution(const QSize &s) { m_resolution = s; }
+ void setResolution(int width, int height) { m_resolution = QSize(width, height); }
+
+ QImageCapture::Quality quality() const { return m_quality; }
+ void setQuality(QImageCapture::Quality quality) { m_quality = quality; }
+};
+
+class Q_MULTIMEDIA_EXPORT QPlatformImageCapture : public QObject
+{
+ Q_OBJECT
+
+public:
+ virtual bool isReadyForCapture() const = 0;
+
+ virtual int capture(const QString &fileName) = 0;
+ virtual int captureToBuffer() = 0;
+
+ virtual QImageEncoderSettings imageSettings() const = 0;
+ virtual void setImageSettings(const QImageEncoderSettings &settings) = 0;
+
+ virtual void setMetaData(const QMediaMetaData &m) { m_metaData = m; }
+ QMediaMetaData metaData() const { return m_metaData; }
+
+ QImageCapture *imageCapture() { return m_imageCapture; }
+
+ static QString msgCameraNotReady();
+ static QString msgImageCaptureNotSet();
+
+Q_SIGNALS:
+ void readyForCaptureChanged(bool ready);
+
+ void imageExposed(int requestId);
+ void imageCaptured(int requestId, const QImage &preview);
+ void imageMetadataAvailable(int id, const QMediaMetaData &);
+ void imageAvailable(int requestId, const QVideoFrame &buffer);
+ void imageSaved(int requestId, const QString &fileName);
+
+ void error(int id, int error, const QString &errorString);
+
+protected:
+ explicit QPlatformImageCapture(QImageCapture *parent = nullptr);
+private:
+ QImageCapture *m_imageCapture = nullptr;
+ QMediaMetaData m_metaData;
+};
+
+QT_END_NAMESPACE
+
+
+#endif // QCAMERAIMAGECAPTURECONTROL_H
+
diff --git a/src/multimedia/platform/qplatformmediacapture.cpp b/src/multimedia/platform/qplatformmediacapture.cpp
new file mode 100644
index 000000000..13bcbd63b
--- /dev/null
+++ b/src/multimedia/platform/qplatformmediacapture.cpp
@@ -0,0 +1,37 @@
+// 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 <QtMultimedia/qaudiodevice.h>
+#include <QtMultimedia/qaudioinput.h>
+#include <QtMultimedia/qmediacapturesession.h>
+#include <QtMultimedia/private/qplatformcamera_p.h>
+#include <QtMultimedia/private/qplatformmediacapture_p.h>
+#include <QtMultimedia/private/qmediacapturesession_p.h>
+#include <QtMultimedia/private/qplatformsurfacecapture_p.h>
+#include <QtMultimedia/private/qplatformvideoframeinput_p.h>
+#include <QtMultimedia/private/qtmultimediaglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+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(videoFrameInput());
+ 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
new file mode 100644
index 000000000..8d6afc90e
--- /dev/null
+++ b/src/multimedia/platform/qplatformmediacapture_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 QPLATFORMMEDIACAPTURE_H
+#define QPLATFORMMEDIACAPTURE_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/qobject.h>
+
+QT_BEGIN_NAMESPACE
+class QPlatformCamera;
+class QPlatformImageCapture;
+class QPlatformMediaRecorder;
+class QAudioDevice;
+class QCameraDevice;
+class QVideoSink;
+class QPlatformAudioInput;
+class QPlatformAudioOutput;
+class QMediaCaptureSession;
+class QPlatformSurfaceCapture;
+class QPlatformVideoSource;
+class QPlatformAudioBufferInput;
+class QPlatformVideoFrameInput;
+
+class Q_MULTIMEDIA_EXPORT QPlatformMediaCaptureSession : public QObject
+{
+ Q_OBJECT
+public:
+ QPlatformMediaCaptureSession() = default;
+ ~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 QPlatformVideoFrameInput *videoFrameInput() { return nullptr; }
+ virtual void setVideoFrameInput(QPlatformVideoFrameInput *) { }
+
+ virtual QPlatformImageCapture *imageCapture() = 0;
+ virtual void setImageCapture(QPlatformImageCapture *) {}
+
+ virtual QPlatformMediaRecorder *mediaRecorder() = 0;
+ virtual void setMediaRecorder(QPlatformMediaRecorder *) {}
+
+ virtual void setAudioInput(QPlatformAudioInput *input) = 0;
+
+ virtual void setAudioBufferInput(QPlatformAudioBufferInput *) { }
+
+ virtual void setVideoPreview(QVideoSink * /*sink*/) {}
+
+ 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 videoFrameInputChanged();
+ void imageCaptureChanged();
+ void encoderChanged();
+
+private:
+ QMediaCaptureSession *m_session = nullptr;
+};
+
+QT_END_NAMESPACE
+
+
+#endif // QPLATFORMMEDIAINTERFACE_H
diff --git a/src/multimedia/platform/qplatformmediadevices.cpp b/src/multimedia/platform/qplatformmediadevices.cpp
new file mode 100644
index 000000000..a6029228d
--- /dev/null
+++ b/src/multimedia/platform/qplatformmediadevices.cpp
@@ -0,0 +1,114 @@
+// 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 "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;
+
+QList<QAudioDevice> QPlatformMediaDevices::audioInputs() const
+{
+ return {};
+}
+
+QList<QAudioDevice> QPlatformMediaDevices::audioOutputs() const
+{
+ return {};
+}
+
+QPlatformAudioSource *QPlatformMediaDevices::createAudioSource(const QAudioDevice &, QObject *)
+{
+ return nullptr;
+}
+QPlatformAudioSink *QPlatformMediaDevices::createAudioSink(const QAudioDevice &, QObject *)
+{
+ return nullptr;
+}
+
+QPlatformAudioSource *QPlatformMediaDevices::audioInputDevice(const QAudioFormat &format,
+ const QAudioDevice &deviceInfo,
+ QObject *parent)
+{
+ QAudioDevice info = deviceInfo;
+ if (info.isNull())
+ info = audioInputs().value(0);
+
+ QPlatformAudioSource* p = !info.isNull() ? createAudioSource(info, parent) : nullptr;
+ if (p)
+ p->setFormat(format);
+ return p;
+}
+
+QPlatformAudioSink *QPlatformMediaDevices::audioOutputDevice(const QAudioFormat &format,
+ const QAudioDevice &deviceInfo,
+ QObject *parent)
+{
+ QAudioDevice info = deviceInfo;
+ if (info.isNull())
+ info = audioOutputs().value(0);
+
+ QPlatformAudioSink* p = !info.isNull() ? createAudioSink(info, parent) : nullptr;
+ if (p)
+ p->setFormat(format);
+ return p;
+}
+
+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
new file mode 100644
index 000000000..0de41a973
--- /dev/null
+++ b/src/multimedia/platform/qplatformmediadevices_p.h
@@ -0,0 +1,63 @@
+// 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
+
+//
+// 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 <qlist.h>
+#include <qobject.h>
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+class QAudioDevice;
+class QPlatformAudioSource;
+class QPlatformAudioSink;
+class QAudioFormat;
+
+class Q_MULTIMEDIA_EXPORT QPlatformMediaDevices : public QObject
+{
+ Q_OBJECT
+public:
+ QPlatformMediaDevices();
+ ~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
+
+
+#endif // QPLATFORMMEDIADEVICES_H
diff --git a/src/multimedia/platform/qplatformmediaformatinfo.cpp b/src/multimedia/platform/qplatformmediaformatinfo.cpp
new file mode 100644
index 000000000..e69b32ed3
--- /dev/null
+++ b/src/multimedia/platform/qplatformmediaformatinfo.cpp
@@ -0,0 +1,76 @@
+// 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>
+
+QT_BEGIN_NAMESPACE
+
+QPlatformMediaFormatInfo::QPlatformMediaFormatInfo() = default;
+
+QPlatformMediaFormatInfo::~QPlatformMediaFormatInfo() = default;
+
+QList<QMediaFormat::FileFormat> QPlatformMediaFormatInfo::supportedFileFormats(const QMediaFormat &constraints, QMediaFormat::ConversionMode m) const
+{
+ QSet<QMediaFormat::FileFormat> formats;
+
+ const auto &codecMap = (m == QMediaFormat::Encode) ? encoders : decoders;
+ for (const auto &m : codecMap) {
+ if (constraints.audioCodec() != QMediaFormat::AudioCodec::Unspecified && !m.audio.contains(constraints.audioCodec()))
+ continue;
+ if (constraints.videoCodec() != QMediaFormat::VideoCodec::Unspecified && !m.video.contains(constraints.videoCodec()))
+ continue;
+ formats.insert(m.format);
+ }
+ return formats.values();
+}
+
+QList<QMediaFormat::AudioCodec> QPlatformMediaFormatInfo::supportedAudioCodecs(const QMediaFormat &constraints, QMediaFormat::ConversionMode m) const
+{
+ QSet<QMediaFormat::AudioCodec> codecs;
+
+ const auto &codecMap = (m == QMediaFormat::Encode) ? encoders : decoders;
+ for (const auto &m : codecMap) {
+ if (constraints.fileFormat() != QMediaFormat::UnspecifiedFormat && m.format != constraints.fileFormat())
+ continue;
+ if (constraints.videoCodec() != QMediaFormat::VideoCodec::Unspecified && !m.video.contains(constraints.videoCodec()))
+ continue;
+ for (const auto &c : m.audio)
+ codecs.insert(c);
+ }
+ return codecs.values();
+}
+
+QList<QMediaFormat::VideoCodec> QPlatformMediaFormatInfo::supportedVideoCodecs(const QMediaFormat &constraints, QMediaFormat::ConversionMode m) const
+{
+ QSet<QMediaFormat::VideoCodec> codecs;
+
+ const auto &codecMap = (m == QMediaFormat::Encode) ? encoders : decoders;
+ for (const auto &m : codecMap) {
+ if (constraints.fileFormat() != QMediaFormat::UnspecifiedFormat && m.format != constraints.fileFormat())
+ continue;
+ if (constraints.audioCodec() != QMediaFormat::AudioCodec::Unspecified && !m.audio.contains(constraints.audioCodec()))
+ continue;
+ for (const auto &c : m.video)
+ codecs.insert(c);
+ }
+ return codecs.values();
+}
+
+bool QPlatformMediaFormatInfo::isSupported(const QMediaFormat &format, QMediaFormat::ConversionMode m) const
+{
+ const auto &codecMap = (m == QMediaFormat::Encode) ? encoders : decoders;
+
+ for (const auto &m : codecMap) {
+ if (m.format != format.fileFormat())
+ continue;
+ if (!m.audio.contains(format.audioCodec()))
+ continue;
+ if (format.videoCodec() != QMediaFormat::VideoCodec::Unspecified && !m.video.contains(format.videoCodec()))
+ continue;
+ return true;
+ }
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qplatformmediaformatinfo_p.h b/src/multimedia/platform/qplatformmediaformatinfo_p.h
new file mode 100644
index 000000000..4229a3c4c
--- /dev/null
+++ b/src/multimedia/platform/qplatformmediaformatinfo_p.h
@@ -0,0 +1,50 @@
+// 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
+
+//
+// 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 <qimagecapture.h>
+#include <qmediaformat.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_MULTIMEDIA_EXPORT QPlatformMediaFormatInfo
+{
+public:
+ QPlatformMediaFormatInfo();
+ virtual ~QPlatformMediaFormatInfo();
+
+ QList<QMediaFormat::FileFormat> supportedFileFormats(const QMediaFormat &constraints, QMediaFormat::ConversionMode m) const;
+ QList<QMediaFormat::AudioCodec> supportedAudioCodecs(const QMediaFormat &constraints, QMediaFormat::ConversionMode m) const;
+ QList<QMediaFormat::VideoCodec> supportedVideoCodecs(const QMediaFormat &constraints, QMediaFormat::ConversionMode m) const;
+
+ bool isSupported(const QMediaFormat &format, QMediaFormat::ConversionMode m) const;
+
+ struct CodecMap {
+ QMediaFormat::FileFormat format;
+ QList<QMediaFormat::AudioCodec> audio;
+ QList<QMediaFormat::VideoCodec> video;
+ };
+ QList<CodecMap> encoders;
+ QList<CodecMap> decoders;
+
+ QList<QImageCapture::FileFormat> imageFormats;
+};
+
+QT_END_NAMESPACE
+
+
+#endif // QPLATFORMMEDIAFORMATINFO_H
diff --git a/src/multimedia/platform/qplatformmediaintegration.cpp b/src/multimedia/platform/qplatformmediaintegration.cpp
new file mode 100644
index 000000000..b9aa1e258
--- /dev/null
+++ b/src/multimedia/platform/qplatformmediaintegration.cpp
@@ -0,0 +1,222 @@
+// 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"
+#include <qatomic.h>
+#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>
+
+#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:
+ QFallbackIntegration() : QPlatformMediaIntegration(QLatin1String("fallback"))
+ {
+ qWarning("No QtMultimedia backends found. Only QMediaDevices, QAudioDevice, QSoundEffect, QAudioSink, and QAudioSource are available.");
+ }
+};
+
+Q_STATIC_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
+
+#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
+
+ 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";
+ }
+
+ std::unique_ptr<QPlatformMediaIntegration> instance;
+};
+
+Q_APPLICATION_STATIC(InstanceHolder, s_instanceHolder);
+
+} // namespace
+
+QT_BEGIN_NAMESPACE
+
+QPlatformMediaIntegration *QPlatformMediaIntegration::instance()
+{
+ return s_instanceHolder->instance.get();
+}
+
+QList<QCameraDevice> QPlatformMediaIntegration::videoInputs()
+{
+ auto devices = videoDevices();
+ return devices ? devices->videoDevices() : QList<QCameraDevice>{};
+}
+
+QMaybe<std::unique_ptr<QPlatformAudioResampler>>
+QPlatformMediaIntegration::createAudioResampler(const QAudioFormat &, const QAudioFormat &)
+{
+ return notAvailable;
+}
+
+QMaybe<QPlatformAudioInput *> QPlatformMediaIntegration::createAudioInput(QAudioInput *q)
+{
+ return new QPlatformAudioInput(q);
+}
+
+QMaybe<QPlatformAudioOutput *> QPlatformMediaIntegration::createAudioOutput(QAudioOutput *q)
+{
+ return new QPlatformAudioOutput(q);
+}
+
+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;
+}
+
+QVideoFrame QPlatformMediaIntegration::convertVideoFrame(QVideoFrame &,
+ const QVideoFrameFormat &)
+{
+ return {};
+}
+
+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
new file mode 100644
index 000000000..d03d0c794
--- /dev/null
+++ b/src/multimedia/platform/qplatformmediaintegration_p.h
@@ -0,0 +1,139 @@
+// 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
+
+//
+// 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/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;
+class QPlatformMediaDevices;
+class QPlatformMediaCaptureSession;
+class QPlatformMediaPlayer;
+class QPlatformAudioDecoder;
+class QPlatformAudioResampler;
+class QPlatformCamera;
+class QPlatformSurfaceCapture;
+class QPlatformMediaRecorder;
+class QPlatformImageCapture;
+class QPlatformMediaFormatInfo;
+class QObject;
+class QPlatformVideoSink;
+class QVideoSink;
+class QAudioInput;
+class QAudioOutput;
+class QPlatformAudioInput;
+class QPlatformAudioOutput;
+class QPlatformVideoDevices;
+class QCapturableWindow;
+class QPlatformCapturableWindows;
+class QVideoFrame;
+
+class Q_MULTIMEDIA_EXPORT QAbstractPlatformSpecificInterface
+{
+public:
+ virtual ~QAbstractPlatformSpecificInterface() = default;
+};
+
+class Q_MULTIMEDIA_EXPORT QPlatformMediaIntegration : public QObject
+{
+ Q_OBJECT
+ inline static const QString notAvailable = QStringLiteral("Not available");
+public:
+ static QPlatformMediaIntegration *instance();
+
+ explicit QPlatformMediaIntegration(QLatin1String);
+ virtual ~QPlatformMediaIntegration();
+ 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
+
+ // Convert a QVideoFrame to the destination format
+ virtual QVideoFrame convertVideoFrame(QVideoFrame &, const QVideoFrameFormat &);
+
+ virtual QAbstractPlatformSpecificInterface *platformSpecificInterface() { return nullptr; }
+
+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;
+
+ mutable std::unique_ptr<QPlatformMediaFormatInfo> m_formatInfo;
+ mutable std::once_flag m_formatInfoOnceFlg;
+
+ std::unique_ptr<QPlatformMediaDevices> m_mediaDevices;
+ std::once_flag m_mediaDevicesOnceFlag;
+
+ const QLatin1String m_backendName;
+};
+
+QT_END_NAMESPACE
+
+
+#endif // QPLATFORMMEDIAINTERFACE_H
diff --git a/src/multimedia/platform/qplatformmediaplayer.cpp b/src/multimedia/platform/qplatformmediaplayer.cpp
new file mode 100644
index 000000000..00840f074
--- /dev/null
+++ b/src/multimedia/platform/qplatformmediaplayer.cpp
@@ -0,0 +1,40 @@
+// 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
+
+QPlatformMediaPlayer::QPlatformMediaPlayer(QMediaPlayer *parent) : player(parent)
+{
+ QPlatformMediaIntegration::instance()->mediaDevices()->prepareAudio();
+}
+
+QPlatformMediaPlayer::~QPlatformMediaPlayer() = default;
+
+void QPlatformMediaPlayer::stateChanged(QMediaPlayer::PlaybackState newState)
+{
+ if (newState == m_state)
+ return;
+ m_state = newState;
+ player->d_func()->setState(newState);
+}
+
+void QPlatformMediaPlayer::mediaStatusChanged(QMediaPlayer::MediaStatus status)
+{
+ if (m_status == status)
+ return;
+ m_status = status;
+ player->d_func()->setStatus(status);
+}
+
+void QPlatformMediaPlayer::error(int error, const QString &errorString)
+{
+ player->d_func()->setError(QMediaPlayer::Error(error), errorString);
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/platform/qplatformmediaplayer_p.h b/src/multimedia/platform/qplatformmediaplayer_p.h
new file mode 100644
index 000000000..f8815958b
--- /dev/null
+++ b/src/multimedia/platform/qplatformmediaplayer_p.h
@@ -0,0 +1,170 @@
+// 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
+// -------------
+//
+// 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 QMEDIAPLAYERCONTROL_H
+#define QMEDIAPLAYERCONTROL_H
+
+#include <QtMultimedia/qmediaplayer.h>
+#include <QtMultimedia/qmediatimerange.h>
+#include <QtMultimedia/qaudiodevice.h>
+#include <QtMultimedia/qmediametadata.h>
+
+#include <QtCore/qpair.h>
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMediaStreamsControl;
+class QPlatformAudioOutput;
+
+class Q_MULTIMEDIA_EXPORT QPlatformMediaPlayer
+{
+public:
+ virtual ~QPlatformMediaPlayer();
+ virtual QMediaPlayer::PlaybackState state() const { return m_state; }
+ virtual QMediaPlayer::MediaStatus mediaStatus() const { return m_status; };
+
+ virtual qint64 duration() const = 0;
+
+ virtual qint64 position() const { return m_position; }
+ virtual void setPosition(qint64 position) = 0;
+
+ virtual float bufferProgress() const = 0;
+
+ virtual bool isAudioAvailable() const { return m_audioAvailable; }
+ virtual bool isVideoAvailable() const { return m_videoAvailable; }
+
+ virtual bool isSeekable() const { return m_seekable; }
+
+ virtual QMediaTimeRange availablePlaybackRanges() const = 0;
+
+ virtual qreal playbackRate() const = 0;
+ virtual void setPlaybackRate(qreal rate) = 0;
+
+ virtual QUrl media() const = 0;
+ virtual const QIODevice *mediaStream() const = 0;
+ virtual void setMedia(const QUrl &media, QIODevice *stream) = 0;
+
+ virtual void play() = 0;
+ virtual void pause() = 0;
+ virtual void stop() = 0;
+
+ virtual bool streamPlaybackSupported() const { return false; }
+
+ virtual void setAudioOutput(QPlatformAudioOutput *) {}
+
+ virtual void setAudioBufferOutput(QAudioBufferOutput *) { }
+
+ virtual QMediaMetaData metaData() const { return {}; }
+
+ virtual void setVideoSink(QVideoSink * /*sink*/) = 0;
+
+ // media streams
+ enum TrackType : uint8_t { VideoStream, AudioStream, SubtitleStream, NTrackTypes };
+
+ virtual int trackCount(TrackType) { return 0; };
+ virtual QMediaMetaData trackMetaData(TrackType /*type*/, int /*streamNumber*/) { return QMediaMetaData(); }
+ virtual int activeTrack(TrackType) { return -1; }
+ virtual void setActiveTrack(TrackType, int /*streamNumber*/) {}
+
+ void durationChanged(std::chrono::milliseconds ms) { durationChanged(ms.count()); }
+ void durationChanged(qint64 duration) { emit player->durationChanged(duration); }
+ void positionChanged(std::chrono::milliseconds ms) { positionChanged(ms.count()); }
+ void positionChanged(qint64 position) {
+ if (m_position == position)
+ return;
+ m_position = position;
+ emit player->positionChanged(position);
+ }
+ void audioAvailableChanged(bool audioAvailable) {
+ if (m_audioAvailable == audioAvailable)
+ return;
+ m_audioAvailable = audioAvailable;
+ emit player->hasAudioChanged(audioAvailable);
+ }
+ void videoAvailableChanged(bool videoAvailable) {
+ if (m_videoAvailable == videoAvailable)
+ return;
+ m_videoAvailable = videoAvailable;
+ emit player->hasVideoChanged(videoAvailable);
+ }
+ void seekableChanged(bool seekable) {
+ if (m_seekable == seekable)
+ return;
+ m_seekable = seekable;
+ emit player->seekableChanged(seekable);
+ }
+ 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() const { return m_loops; }
+ virtual void setLoops(int loops)
+ {
+ if (m_loops == loops)
+ return;
+ m_loops = loops;
+ Q_EMIT player->loopsChanged();
+ }
+
+protected:
+ explicit QPlatformMediaPlayer(QMediaPlayer *parent = nullptr);
+
+private:
+ QMediaPlayer *player = nullptr;
+ QMediaPlayer::MediaStatus m_status = QMediaPlayer::NoMedia;
+ QMediaPlayer::PlaybackState m_state = QMediaPlayer::StoppedState;
+ bool m_seekable = false;
+ bool m_videoAvailable = false;
+ bool m_audioAvailable = false;
+ int m_loops = 1;
+ int m_currentLoop = 0;
+ qint64 m_position = 0;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+inline QDebug operator<<(QDebug dbg, QPlatformMediaPlayer::TrackType type)
+{
+ QDebugStateSaver save(dbg);
+ dbg.nospace();
+
+ switch (type) {
+ case QPlatformMediaPlayer::TrackType::AudioStream:
+ return dbg << "AudioStream";
+ case QPlatformMediaPlayer::TrackType::VideoStream:
+ return dbg << "VideoStream";
+ case QPlatformMediaPlayer::TrackType::SubtitleStream:
+ return dbg << "SubtitleStream";
+ default:
+ Q_UNREACHABLE_RETURN(dbg);
+ }
+}
+#endif
+
+QT_END_NAMESPACE
+
+
+#endif // QMEDIAPLAYERCONTROL_H
+
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..30dba0a45
--- /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()
+{
+ updateError(QMediaRecorder::FormatError, QMediaRecorder::tr("Pause not supported"));
+}
+
+void QPlatformMediaRecorder::resume()
+{
+ updateError(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::updateError(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/qplatformmediarecorder_p.h b/src/multimedia/platform/qplatformmediarecorder_p.h
new file mode 100644
index 000000000..ab6af759d
--- /dev/null
+++ b/src/multimedia/platform/qplatformmediarecorder_p.h
@@ -0,0 +1,161 @@
+// 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
+// -------------
+//
+// 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 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
+
+class QUrl;
+QT_END_NAMESPACE
+
+QT_BEGIN_NAMESPACE
+
+class Q_MULTIMEDIA_EXPORT QMediaEncoderSettings
+{
+ QMediaRecorder::EncodingMode m_encodingMode = QMediaRecorder::ConstantQualityEncoding;
+ QMediaRecorder::Quality m_quality = QMediaRecorder::NormalQuality;
+
+ QMediaFormat m_format;
+ int m_audioBitrate = -1;
+ int m_audioSampleRate = -1;
+ int m_audioChannels = -1;
+
+ QSize m_videoResolution = QSize(-1, -1);
+ int m_videoFrameRate = -1;
+ int m_videoBitRate = -1;
+public:
+
+ QMediaFormat mediaFormat() const { return m_format; }
+ void setMediaFormat(const QMediaFormat &format) { m_format = format; }
+ void resolveFormat(QMediaFormat::ResolveFlags flags = QMediaFormat::NoFlags)
+ { m_format.resolveForEncoding(flags); }
+
+ QMediaFormat::FileFormat fileFormat() const { return mediaFormat().fileFormat(); }
+ QMediaFormat::VideoCodec videoCodec() const { return mediaFormat().videoCodec(); }
+ QMediaFormat::AudioCodec audioCodec() const { return mediaFormat().audioCodec(); }
+ QMimeType mimeType() const { return mediaFormat().mimeType(); }
+
+ QMediaRecorder::EncodingMode encodingMode() const { return m_encodingMode; }
+ void setEncodingMode(QMediaRecorder::EncodingMode mode) { m_encodingMode = mode; }
+
+ QMediaRecorder::Quality quality() const { return m_quality; }
+ void setQuality(QMediaRecorder::Quality quality) { m_quality = quality; }
+
+ QSize videoResolution() const { return m_videoResolution; }
+ void setVideoResolution(const QSize &size) { m_videoResolution = size; }
+
+ qreal videoFrameRate() const { return m_videoFrameRate; }
+ void setVideoFrameRate(qreal rate) { m_videoFrameRate = rate; }
+
+ int videoBitRate() const { return m_videoBitRate; }
+ void setVideoBitRate(int bitrate) { m_videoBitRate = bitrate; }
+
+ int audioBitRate() const { return m_audioBitrate; }
+ void setAudioBitRate(int bitrate) { m_audioBitrate = bitrate; }
+
+ int audioChannelCount() const { return m_audioChannels; }
+ void setAudioChannelCount(int channels) { m_audioChannels = channels; }
+
+ int audioSampleRate() const { return m_audioSampleRate; }
+ void setAudioSampleRate(int rate) { m_audioSampleRate = rate; }
+
+ bool operator==(const QMediaEncoderSettings &other) const
+ {
+ return m_format == other.m_format &&
+ m_encodingMode == other.m_encodingMode &&
+ m_quality == other.m_quality &&
+ m_audioBitrate == other.m_audioBitrate &&
+ m_audioSampleRate == other.m_audioSampleRate &&
+ m_audioChannels == other.m_audioChannels &&
+ m_videoResolution == other.m_videoResolution &&
+ m_videoFrameRate == other.m_videoFrameRate &&
+ m_videoBitRate == other.m_videoBitRate;
+ }
+
+ bool operator!=(const QMediaEncoderSettings &other) const
+ { return !operator==(other); }
+};
+
+class Q_MULTIMEDIA_EXPORT QPlatformMediaRecorder
+{
+public:
+ virtual ~QPlatformMediaRecorder() {}
+
+ virtual bool isLocationWritable(const QUrl &location) const = 0;
+
+ virtual QMediaRecorder::RecorderState state() const { return m_state; }
+ virtual void record(QMediaEncoderSettings &settings) = 0;
+ virtual void pause();
+ virtual void resume();
+ virtual void stop() = 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.code(); }
+ QString errorString() const { return m_error.description(); }
+
+ QUrl outputLocation() const { return m_outputLocation; }
+ virtual void setOutputLocation(const QUrl &location) { m_outputLocation = location; }
+ QUrl actualLocation() const { return m_actualLocation; }
+ void clearActualLocation() { m_actualLocation.clear(); }
+ void clearError() { updateError(QMediaRecorder::NoError, QString()); }
+
+ QIODevice *outputDevice() const { return m_outputDevice; }
+ void setOutputDevice(QIODevice *device) { m_outputDevice = device; }
+
+ virtual void updateAutoStop() { }
+
+protected:
+ explicit QPlatformMediaRecorder(QMediaRecorder *parent);
+
+ void stateChanged(QMediaRecorder::RecorderState state);
+ void durationChanged(qint64 position);
+ void actualLocationChanged(const QUrl &location);
+ void updateError(QMediaRecorder::Error error, const QString &errorString);
+ void metaDataChanged();
+
+ QMediaRecorder *mediaRecorder() { return q; }
+
+ QString findActualLocation(const QMediaEncoderSettings &settings) const;
+
+private:
+ QMediaRecorder *q = nullptr;
+ 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;
+};
+
+QT_END_NAMESPACE
+
+#endif
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..e4c59c6f4
--- /dev/null
+++ b/src/multimedia/platform/qplatformsurfacecapture_p.h
@@ -0,0 +1,87 @@
+// 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 final;
+
+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 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/qplatformvideoframeinput.cpp b/src/multimedia/platform/qplatformvideoframeinput.cpp
new file mode 100644
index 000000000..d90306345
--- /dev/null
+++ b/src/multimedia/platform/qplatformvideoframeinput.cpp
@@ -0,0 +1,10 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qplatformvideoframeinput_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QT_END_NAMESPACE
+
+#include "moc_qplatformvideoframeinput_p.cpp"
diff --git a/src/multimedia/platform/qplatformvideoframeinput_p.h b/src/multimedia/platform/qplatformvideoframeinput_p.h
new file mode 100644
index 000000000..45714492c
--- /dev/null
+++ b/src/multimedia/platform/qplatformvideoframeinput_p.h
@@ -0,0 +1,55 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QPLATFORMVIDEOFRAMEINPUT_P_H
+#define QPLATFORMVIDEOFRAMEINPUT_P_H
+
+#include "qplatformvideosource_p.h"
+#include "qmetaobject.h"
+#include "qpointer.h"
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QMediaInputEncoderInterface;
+
+class Q_MULTIMEDIA_EXPORT QPlatformVideoFrameInput : public QPlatformVideoSource
+{
+ Q_OBJECT
+public:
+ QPlatformVideoFrameInput(QVideoFrameFormat format = {}) : m_format(std::move(format)) { }
+
+ void setActive(bool) final { }
+ bool isActive() const final { return true; }
+
+ QVideoFrameFormat frameFormat() const final { return m_format; }
+
+ QString errorString() const final { return {}; }
+
+ QMediaInputEncoderInterface *encoderInterface() const { return m_encoderInterface; }
+ void setEncoderInterface(QMediaInputEncoderInterface *interface)
+ {
+ m_encoderInterface = interface;
+ }
+
+Q_SIGNALS:
+ void encoderUpdated();
+
+private:
+ QMediaInputEncoderInterface *m_encoderInterface = nullptr;
+ QVideoFrameFormat m_format;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPLATFORMVIDEOFRAMEINPUT_P_H
diff --git a/src/multimedia/platform/qplatformvideosink.cpp b/src/multimedia/platform/qplatformvideosink.cpp
new file mode 100644
index 000000000..abf82af0f
--- /dev/null
+++ b/src/multimedia/platform/qplatformvideosink.cpp
@@ -0,0 +1,78 @@
+// 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
+
+QPlatformVideoSink::QPlatformVideoSink(QVideoSink *parent) : QObject(parent), m_sink(parent) { }
+
+QPlatformVideoSink::~QPlatformVideoSink() = default;
+
+QSize QPlatformVideoSink::nativeSize() const
+{
+ QMutexLocker locker(&m_mutex);
+ return m_nativeSize;
+}
+
+void QPlatformVideoSink::setNativeSize(QSize s)
+{
+ {
+ QMutexLocker locker(&m_mutex);
+ if (m_nativeSize == s)
+ return;
+ m_nativeSize = s;
+ }
+ emit m_sink->videoSizeChanged();
+}
+
+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);
+}
+
+QVideoFrame QPlatformVideoSink::currentVideoFrame() const
+{
+ QMutexLocker locker(&m_mutex);
+ return m_currentVideoFrame;
+}
+
+void QPlatformVideoSink::setSubtitleText(const QString &subtitleText)
+{
+ {
+ QMutexLocker locker(&m_mutex);
+ if (m_subtitleText == subtitleText)
+ return;
+ m_subtitleText = subtitleText;
+ }
+ emit m_sink->subtitleTextChanged(subtitleText);
+}
+
+QString QPlatformVideoSink::subtitleText() const
+{
+ QMutexLocker locker(&m_mutex);
+ return m_subtitleText;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qplatformvideosink_p.cpp"
diff --git a/src/multimedia/platform/qplatformvideosink_p.h b/src/multimedia/platform/qplatformvideosink_p.h
new file mode 100644
index 000000000..53eca374f
--- /dev/null
+++ b/src/multimedia/platform/qplatformvideosink_p.h
@@ -0,0 +1,84 @@
+// 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
+
+//
+// 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 <QtCore/qobject.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qmutex.h>
+#include <QtGui/qwindowdefs.h>
+#include <qvideosink.h>
+#include <qvideoframe.h>
+#include <qdebug.h>
+#include <private/qglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// Required for QDoc workaround
+class QString;
+
+class Q_MULTIMEDIA_EXPORT QPlatformVideoSink : public QObject
+{
+ Q_OBJECT
+
+public:
+ ~QPlatformVideoSink() override;
+
+ virtual void setRhi(QRhi * /*rhi*/) {}
+
+ virtual void setWinId(WId) {}
+ virtual void setDisplayRect(const QRect &) {};
+ virtual void setFullScreen(bool) {}
+ virtual void setAspectRatioMode(Qt::AspectRatioMode) {}
+
+ 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 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);
+
+Q_SIGNALS:
+ void rhiChanged(QRhi *rhi);
+
+private:
+ QVideoSink *m_sink = nullptr;
+ mutable QMutex m_mutex;
+ QSize m_nativeSize;
+ QString m_subtitleText;
+ QVideoFrame m_currentVideoFrame;
+};
+
+QT_END_NAMESPACE
+
+
+#endif
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..b11524226
--- /dev/null
+++ b/src/multimedia/platform/qplatformvideosource_p.h
@@ -0,0 +1,58 @@
+// 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 *) { }
+
+ virtual QString errorString() const = 0;
+
+ bool hasError() const { return !errorString().isEmpty(); }
+
+Q_SIGNALS:
+ void newVideoFrame(const QVideoFrame &);
+ void activeChanged(bool);
+ void errorChanged();
+};
+
+QT_END_NAMESPACE
+
+#endif // QPLATFORMVIDEOSOURCE_P_H
diff --git a/src/multimedia/playback/playback.pri b/src/multimedia/playback/playback.pri
deleted file mode 100644
index 81a3b298f..000000000
--- a/src/multimedia/playback/playback.pri
+++ /dev/null
@@ -1,24 +0,0 @@
-INCLUDEPATH += playback
-
-PUBLIC_HEADERS += \
- playback/qmediacontent.h \
- playback/qmediaplayer.h \
- playback/qmediaplaylist.h
-
-PRIVATE_HEADERS += \
- playback/qmediaplaylist_p.h \
- playback/qmediaplaylistprovider_p.h \
- playback/qmediaplaylistioplugin_p.h \
- playback/qmediaplaylistnavigator_p.h \
- playback/qmedianetworkplaylistprovider_p.h \
- playback/qplaylistfileparser_p.h
-
-SOURCES += \
- playback/qmedianetworkplaylistprovider.cpp \
- playback/qmediacontent.cpp \
- playback/qmediaplayer.cpp \
- playback/qmediaplaylist.cpp \
- playback/qmediaplaylistioplugin.cpp \
- playback/qmediaplaylistnavigator.cpp \
- playback/qmediaplaylistprovider.cpp \
- playback/qplaylistfileparser.cpp
diff --git a/src/multimedia/playback/qmediacontent.cpp b/src/multimedia/playback/qmediacontent.cpp
deleted file mode 100644
index 08ce49587..000000000
--- a/src/multimedia/playback/qmediacontent.cpp
+++ /dev/null
@@ -1,249 +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/qurl.h>
-#include <QtCore/qvariant.h>
-#include <QtCore/QPointer>
-
-#include <qmediaplaylist.h>
-#include "qmediacontent.h"
-
-QT_BEGIN_NAMESPACE
-
-static void qRegisterMediaContentMetaTypes()
-{
- qRegisterMetaType<QMediaContent>();
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterMediaContentMetaTypes)
-
-
-class QMediaContentPrivate : public QSharedData
-{
-public:
- QMediaContentPrivate():
- isPlaylistOwned(false)
- {}
-
- QMediaContentPrivate(const QNetworkRequest &r):
- isPlaylistOwned(false)
- {
- requests << r;
- }
-
- QMediaContentPrivate(const QMediaContentPrivate &other):
- QSharedData(other),
- requests(other.requests),
- playlist(other.playlist),
- isPlaylistOwned(false)
- {}
-
- QMediaContentPrivate(QMediaPlaylist *pls, const QUrl &url, bool isOwn):
- playlist(pls),
- isPlaylistOwned(isOwn)
- {
- requests << QNetworkRequest(url);
- }
-
- ~QMediaContentPrivate()
- {
- if (isPlaylistOwned && !playlist.isNull())
- playlist.data()->deleteLater();
- }
-
- bool operator ==(const QMediaContentPrivate &other) const
- {
- return requests == other.requests && playlist == other.playlist;
- }
-
- QList<QNetworkRequest> requests;
- QPointer<QMediaPlaylist> playlist;
- bool isPlaylistOwned;
-private:
- QMediaContentPrivate& operator=(const QMediaContentPrivate &other);
-};
-
-
-/*!
- \class QMediaContent
-
- \brief The QMediaContent class provides access to the resource relating to a media content.
-
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_playback
-
- QMediaContent is used within the multimedia framework as the logical handle
- to media content. A QMediaContent object contains a \l {QNetworkRequest}
- which provides the URL of the content.
-
- A non-null QMediaContent will always have a reference to
- the content available through the request() method.
-
- Alternatively QMediaContent can represent a playlist and contain a pointer to a
- valid QMediaPlaylist object. In this case URL is optional and can either be empty
- or point to the playlist URL.
-*/
-
-
-/*!
- Constructs a null QMediaContent.
-*/
-
-QMediaContent::QMediaContent()
-{
-}
-
-/*!
- Constructs a media content with \a url providing a reference to the content.
-*/
-
-QMediaContent::QMediaContent(const QUrl &url):
- d(new QMediaContentPrivate)
-{
- d->requests << QNetworkRequest(url);
-}
-
-/*!
- Constructs a media content with \a request providing a reference to the content.
-
- This constructor can be used to reference media content via network protocols such as HTTP.
- This may include additional information required to obtain the resource, such as Cookies or HTTP headers.
-*/
-
-QMediaContent::QMediaContent(const QNetworkRequest &request):
- d(new QMediaContentPrivate)
-{
- d->requests << request;
-}
-
-/*!
- Constructs a copy of the media content \a other.
-*/
-
-QMediaContent::QMediaContent(const QMediaContent &other):
- d(other.d)
-{
-}
-
-/*!
- Constructs a media content with \a playlist.
-
- \a contentUrl of a playlist is an optional parameter and can be empty.
-
- Set \a takeOwnership to true if you want QMediaContent to take ownership of the playlist.
- \a takeOwnership is set to false by default.
-*/
-
-QMediaContent::QMediaContent(QMediaPlaylist *playlist, const QUrl &contentUrl, bool takeOwnership):
- d(new QMediaContentPrivate(playlist, contentUrl, takeOwnership))
-{
-}
-
-/*!
- Destroys the media content object.
-*/
-
-QMediaContent::~QMediaContent()
-{
-}
-
-/*!
- Assigns the value of \a other to this media content.
-*/
-
-QMediaContent& QMediaContent::operator=(const QMediaContent &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Returns true if \a other is equivalent to this media content; false otherwise.
-*/
-
-bool QMediaContent::operator==(const QMediaContent &other) const
-{
- return (d.constData() == 0 && other.d.constData() == nullptr) ||
- (d.constData() != 0 && other.d.constData() != nullptr &&
- *d.constData() == *other.d.constData());
-}
-
-/*!
- Returns true if \a other is not equivalent to this media content; false otherwise.
-*/
-
-bool QMediaContent::operator!=(const QMediaContent &other) const
-{
- return !(*this == other);
-}
-
-/*!
- Returns true if this media content is null (uninitialized); false otherwise.
-*/
-
-bool QMediaContent::isNull() const
-{
- return d.constData() == nullptr;
-}
-
-/*!
- \since 5.14
-
- Returns a QNetworkRequest that represents the resource for this media content.
-*/
-
-QNetworkRequest QMediaContent::request() const
-{
- return (d && !d->requests.isEmpty()) ? d->requests.first() : QNetworkRequest();
-}
-
-/*!
- Returns a playlist for this media content or 0 if this QMediaContent is not a playlist.
-*/
-
-QMediaPlaylist *QMediaContent::playlist() const
-{
- return d.constData() != nullptr
- ? d->playlist.data()
- : nullptr;
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/multimedia/playback/qmediacontent.h b/src/multimedia/playback/qmediacontent.h
deleted file mode 100644
index 983df47ef..000000000
--- a/src/multimedia/playback/qmediacontent.h
+++ /dev/null
@@ -1,81 +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 QMEDIACONTENT_H
-#define QMEDIACONTENT_H
-
-#include <QtCore/qmetatype.h>
-#include <QtCore/qshareddata.h>
-
-#include <QNetworkRequest>
-#include <QtMultimedia/qtmultimediaglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-class QMediaPlaylist;
-
-class QMediaContentPrivate;
-class Q_MULTIMEDIA_EXPORT QMediaContent
-{
-public:
- QMediaContent();
- QMediaContent(const QUrl &contentUrl);
- QMediaContent(const QNetworkRequest &contentRequest);
- QMediaContent(const QMediaContent &other);
- QMediaContent(QMediaPlaylist *playlist, const QUrl &contentUrl = QUrl(), bool takeOwnership = false);
- ~QMediaContent();
-
- QMediaContent& operator=(const QMediaContent &other);
-
- bool operator==(const QMediaContent &other) const;
- bool operator!=(const QMediaContent &other) const;
-
- bool isNull() const;
- QNetworkRequest request() const;
-
- QMediaPlaylist *playlist() const;
-private:
- QSharedDataPointer<QMediaContentPrivate> d;
-};
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QMediaContent)
-
-#endif // QMEDIACONTENT_H
diff --git a/src/multimedia/playback/qmedianetworkplaylistprovider.cpp b/src/multimedia/playback/qmedianetworkplaylistprovider.cpp
deleted file mode 100644
index 03bdb0e73..000000000
--- a/src/multimedia/playback/qmedianetworkplaylistprovider.cpp
+++ /dev/null
@@ -1,284 +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 "qmedianetworkplaylistprovider_p.h"
-#include "qmediaplaylistprovider_p.h"
-#include "qmediacontent.h"
-#include "qmediaobject_p.h"
-#include "qplaylistfileparser_p.h"
-#include "qrandom.h"
-
-QT_BEGIN_NAMESPACE
-
-class QMediaNetworkPlaylistProviderPrivate: public QMediaPlaylistProviderPrivate
-{
- Q_DECLARE_NON_CONST_PUBLIC(QMediaNetworkPlaylistProvider)
-public:
- bool load(const QNetworkRequest &request);
-
- QPlaylistFileParser parser;
- QList<QMediaContent> resources;
-
- void _q_handleParserError(QPlaylistFileParser::ParserError err, const QString &);
- void _q_handleNewItem(const QVariant& content);
-
- QMediaNetworkPlaylistProvider *q_ptr;
-};
-
-bool QMediaNetworkPlaylistProviderPrivate::load(const QNetworkRequest &request)
-{
- parser.abort();
- parser.start(request);
-
- return true;
-}
-
-void QMediaNetworkPlaylistProviderPrivate::_q_handleParserError(QPlaylistFileParser::ParserError err, const QString &errorMessage)
-{
- Q_Q(QMediaNetworkPlaylistProvider);
-
- QMediaPlaylist::Error playlistError = QMediaPlaylist::NoError;
-
- switch (err) {
- case QPlaylistFileParser::NoError:
- return;
- case QPlaylistFileParser::FormatError:
- playlistError = QMediaPlaylist::FormatError;
- break;
- case QPlaylistFileParser::FormatNotSupportedError:
- playlistError = QMediaPlaylist::FormatNotSupportedError;
- break;
- case QPlaylistFileParser::ResourceError:
- // fall through
- case QPlaylistFileParser::NetworkError:
- playlistError = QMediaPlaylist::NetworkError;
- break;
- }
-
- parser.abort();
-
- emit q->loadFailed(playlistError, errorMessage);
-}
-
-void QMediaNetworkPlaylistProviderPrivate::_q_handleNewItem(const QVariant& content)
-{
- Q_Q(QMediaNetworkPlaylistProvider);
-
- QUrl url;
- switch (content.metaType().id() ) {
- case QMetaType::QUrl:
- url = content.toUrl();
- break;
- case QMetaType::QVariantMap:
- url = content.toMap().value(QLatin1String("url")).toUrl();
- break;
- default:
- return;
- }
-
- q->addMedia(QMediaContent(url));
-}
-
-QMediaNetworkPlaylistProvider::QMediaNetworkPlaylistProvider(QObject *parent)
- :QMediaPlaylistProvider(*new QMediaNetworkPlaylistProviderPrivate, parent)
-{
- d_func()->q_ptr = this;
- connect(&d_func()->parser, SIGNAL(newItem(QVariant)),
- this, SLOT(_q_handleNewItem(QVariant)));
- connect(&d_func()->parser, SIGNAL(finished()), this, SIGNAL(loaded()));
- connect(&d_func()->parser, SIGNAL(error(QPlaylistFileParser::ParserError,QString)),
- this, SLOT(_q_handleParserError(QPlaylistFileParser::ParserError,QString)));
-}
-
-QMediaNetworkPlaylistProvider::~QMediaNetworkPlaylistProvider()
-{
-}
-
-bool QMediaNetworkPlaylistProvider::isReadOnly() const
-{
- return false;
-}
-
-bool QMediaNetworkPlaylistProvider::load(const QNetworkRequest &request, const char *format)
-{
- Q_UNUSED(format);
- return d_func()->load(request);
-}
-
-int QMediaNetworkPlaylistProvider::mediaCount() const
-{
- return d_func()->resources.size();
-}
-
-QMediaContent QMediaNetworkPlaylistProvider::media(int pos) const
-{
- return d_func()->resources.value(pos);
-}
-
-bool QMediaNetworkPlaylistProvider::addMedia(const QMediaContent &content)
-{
- Q_D(QMediaNetworkPlaylistProvider);
-
- int pos = d->resources.count();
-
- emit mediaAboutToBeInserted(pos, pos);
- d->resources.append(content);
- emit mediaInserted(pos, pos);
-
- return true;
-}
-
-bool QMediaNetworkPlaylistProvider::addMedia(const QList<QMediaContent> &items)
-{
- Q_D(QMediaNetworkPlaylistProvider);
-
- if (items.isEmpty())
- return true;
-
- int pos = d->resources.count();
- int end = pos+items.count()-1;
-
- emit mediaAboutToBeInserted(pos, end);
- d->resources.append(items);
- emit mediaInserted(pos, end);
-
- return true;
-}
-
-
-bool QMediaNetworkPlaylistProvider::insertMedia(int pos, const QMediaContent &content)
-{
- Q_D(QMediaNetworkPlaylistProvider);
-
- emit mediaAboutToBeInserted(pos, pos);
- d->resources.insert(pos, content);
- emit mediaInserted(pos,pos);
-
- return true;
-}
-
-bool QMediaNetworkPlaylistProvider::insertMedia(int pos, const QList<QMediaContent> &items)
-{
- Q_D(QMediaNetworkPlaylistProvider);
-
- if (items.isEmpty())
- return true;
-
- const int last = pos+items.count()-1;
-
- emit mediaAboutToBeInserted(pos, last);
- for (int i=0; i<items.count(); i++)
- d->resources.insert(pos+i, items.at(i));
- emit mediaInserted(pos, last);
-
- return true;
-}
-
-bool QMediaNetworkPlaylistProvider::moveMedia(int from, int to)
-{
- Q_D(QMediaNetworkPlaylistProvider);
-
- Q_ASSERT(from >= 0 && from < mediaCount());
- Q_ASSERT(to >= 0 && to < mediaCount());
-
- if (from == to)
- return false;
-
- const QMediaContent media = d->resources.at(from);
- return removeMedia(from, from) && insertMedia(to, media);
-}
-
-bool QMediaNetworkPlaylistProvider::removeMedia(int fromPos, int toPos)
-{
- Q_D(QMediaNetworkPlaylistProvider);
-
- Q_ASSERT(fromPos >= 0);
- Q_ASSERT(fromPos <= toPos);
- Q_ASSERT(toPos < mediaCount());
-
- emit mediaAboutToBeRemoved(fromPos, toPos);
- d->resources.erase(d->resources.begin()+fromPos, d->resources.begin()+toPos+1);
- emit mediaRemoved(fromPos, toPos);
-
- return true;
-}
-
-bool QMediaNetworkPlaylistProvider::removeMedia(int pos)
-{
- Q_D(QMediaNetworkPlaylistProvider);
-
- emit mediaAboutToBeRemoved(pos, pos);
- d->resources.removeAt(pos);
- emit mediaRemoved(pos, pos);
-
- return true;
-}
-
-bool QMediaNetworkPlaylistProvider::clear()
-{
- Q_D(QMediaNetworkPlaylistProvider);
- if (!d->resources.isEmpty()) {
- int lastPos = mediaCount()-1;
- emit mediaAboutToBeRemoved(0, lastPos);
- d->resources.clear();
- emit mediaRemoved(0, lastPos);
- }
-
- return true;
-}
-
-void QMediaNetworkPlaylistProvider::shuffle()
-{
- Q_D(QMediaNetworkPlaylistProvider);
- if (!d->resources.isEmpty()) {
- QList<QMediaContent> resources;
-
- while (!d->resources.isEmpty()) {
- resources.append(d->resources.takeAt(QRandomGenerator::global()->bounded(int(d->resources.size()))));
- }
-
- d->resources = resources;
- emit mediaChanged(0, mediaCount()-1);
- }
-
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qmedianetworkplaylistprovider_p.cpp"
diff --git a/src/multimedia/playback/qmedianetworkplaylistprovider_p.h b/src/multimedia/playback/qmedianetworkplaylistprovider_p.h
deleted file mode 100644
index 6b5220935..000000000
--- a/src/multimedia/playback/qmedianetworkplaylistprovider_p.h
+++ /dev/null
@@ -1,96 +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 QMEDIANETWORKPAYLISTPROVIDER_P_H
-#define QMEDIANETWORKPAYLISTPROVIDER_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 "qmediaplaylistprovider_p.h"
-
-QT_BEGIN_NAMESPACE
-
-
-class QMediaNetworkPlaylistProviderPrivate;
-class Q_MULTIMEDIA_EXPORT QMediaNetworkPlaylistProvider : public QMediaPlaylistProvider
-{
- Q_OBJECT
-public:
- QMediaNetworkPlaylistProvider(QObject *parent = nullptr);
- ~QMediaNetworkPlaylistProvider();
-
- bool load(const QNetworkRequest &request, const char *format = nullptr) override;
-
- int mediaCount() const override;
- QMediaContent media(int pos) const override;
-
- bool isReadOnly() const override;
-
- bool addMedia(const QMediaContent &content) override;
- bool addMedia(const QList<QMediaContent> &items) override;
- bool insertMedia(int pos, const QMediaContent &content) override;
- bool insertMedia(int pos, const QList<QMediaContent> &items) override;
- bool moveMedia(int from, int to) override;
- bool removeMedia(int pos) override;
- bool removeMedia(int start, int end) override;
- bool clear() override;
-
-public Q_SLOTS:
- void shuffle() override;
-
-private:
- Q_DISABLE_COPY(QMediaNetworkPlaylistProvider)
- Q_DECLARE_PRIVATE(QMediaNetworkPlaylistProvider)
- Q_PRIVATE_SLOT(d_func(), void _q_handleParserError(QPlaylistFileParser::ParserError err, const QString &))
- Q_PRIVATE_SLOT(d_func(), void _q_handleNewItem(const QVariant& content))
-};
-
-QT_END_NAMESPACE
-
-
-#endif // QMEDIANETWORKPAYLISTSOURCE_P_H
diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp
index 6c32e110b..644c2d094 100644
--- a/src/multimedia/playback/qmediaplayer.cpp
+++ b/src/multimedia/playback/qmediaplayer.cpp
@@ -1,372 +1,156 @@
-/****************************************************************************
-**
-** 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 "qmediaplayer.h"
-#include "qvideosurfaces_p.h"
-#include "qvideosurfaceoutput_p.h"
-
-#include "qmediaobject_p.h"
-#include <qmediaservice.h>
-#include <qmediaplayercontrol.h>
-#include <qmediaserviceprovider_p.h>
-#include <qmediaplaylist.h>
-#include <qmediaplaylistcontrol_p.h>
-#include <qmediaplaylistsourcecontrol_p.h>
-#include <qaudiorolecontrol.h>
-#include <qcustomaudiorolecontrol.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 "qmediaplayer_p.h"
+
+#include <private/qmultimediautils_p.h>
+#include <private/qplatformmediaintegration_p.h>
+#include <private/qaudiobufferoutput_p.h>
+#include <qvideosink.h>
+#include <qaudiooutput.h>
#include <QtCore/qcoreevent.h>
#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 <QDir>
+#include <QtCore/qcoreapplication.h>
+
+#if defined(Q_OS_ANDROID)
+# include <QtCore/qjniobject.h>
+#endif
QT_BEGIN_NAMESPACE
/*!
\class QMediaPlayer
- \brief The QMediaPlayer class allows the playing of a media source.
+ \brief The QMediaPlayer class allows the playing of a media files.
\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 such content as songs, movies and internet radio. The content
- to playback is specified as a QMediaContent object, which can be thought of as a
- main or canonical URL with additional information attached. When provided
- with a QMediaContent playback may be able to commence.
+ to playback audio of video media files. The content
+ to playback is specified as a QUrl object.
\snippet multimedia-snippets/media.cpp Player
- QVideoWidget can be used with QMediaPlayer for video rendering and QMediaPlaylist
- for accessing playlist functionality.
+ QVideoWidget can be used with QMediaPlayer for video rendering.
- \snippet multimedia-snippets/media.cpp Movie playlist
-
- Since QMediaPlayer is a QMediaObject, you can use several of the QMediaObject
- functions for things like:
-
- \list
- \li Accessing the currently playing media's metadata (\l {QMediaObject::metaData()} and \l {QMediaMetaData}{predefined meta-data keys})
- \li Checking to see if the media playback service is currently available (\l {QMediaObject::availability()})
- \endlist
-
- \sa QMediaObject, QMediaService, QVideoWidget, QMediaPlaylist
+ \sa QVideoWidget
*/
-static void qRegisterMediaPlayerMetaTypes()
-{
- qRegisterMetaType<QMediaPlayer::State>("QMediaPlayer::State");
- qRegisterMetaType<QMediaPlayer::MediaStatus>("QMediaPlayer::MediaStatus");
- qRegisterMetaType<QMediaPlayer::Error>("QMediaPlayer::Error");
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterMediaPlayerMetaTypes)
-
-#define MAX_NESTED_PLAYLISTS 16
-
-class QMediaPlayerPrivate : public QMediaObjectPrivate
-{
- Q_DECLARE_NON_CONST_PUBLIC(QMediaPlayer)
-
-public:
- QMediaPlayerPrivate()
- : provider(nullptr)
- , control(nullptr)
- , audioRoleControl(nullptr)
- , customAudioRoleControl(nullptr)
- , playlist(nullptr)
- , state(QMediaPlayer::StoppedState)
- , status(QMediaPlayer::UnknownMediaStatus)
- , error(QMediaPlayer::NoError)
- , ignoreNextStatusChange(-1)
- , nestedPlaylists(0)
- , hasStreamPlaybackFeature(false)
- {}
-
- QMediaServiceProvider *provider;
- QMediaPlayerControl* control;
- QAudioRoleControl *audioRoleControl;
- QCustomAudioRoleControl *customAudioRoleControl;
- QString errorString;
-
- QPointer<QObject> videoOutput;
- QMediaPlaylist *playlist;
- QVideoSurfaceOutput surfaceOutput;
- QMediaContent qrcMedia;
- QScopedPointer<QFile> qrcFile;
-
- QMediaContent rootMedia;
- QMediaContent pendingPlaylist;
- QMediaPlayer::State state;
- QMediaPlayer::MediaStatus status;
- QMediaPlayer::Error error;
- int ignoreNextStatusChange;
- int nestedPlaylists;
- bool hasStreamPlaybackFeature;
-
- QMediaPlaylist *parentPlaylist(QMediaPlaylist *pls);
- bool isInChain(const QUrl &url);
-
- void setMedia(const QMediaContent &media, QIODevice *stream = nullptr);
-
- void setPlaylist(QMediaPlaylist *playlist);
- void setPlaylistMedia();
- void loadPlaylist();
- void disconnectPlaylist();
- void connectPlaylist();
-
- void _q_stateChanged(QMediaPlayer::State state);
- void _q_mediaStatusChanged(QMediaPlayer::MediaStatus status);
- void _q_error(int error, const QString &errorString);
- void _q_updateMedia(const QMediaContent&);
- void _q_playlistDestroyed();
- void _q_handleMediaChanged(const QMediaContent&);
- void _q_handlePlaylistLoaded();
- void _q_handlePlaylistLoadFailed();
-};
-
-QMediaPlaylist *QMediaPlayerPrivate::parentPlaylist(QMediaPlaylist *pls)
-{
- // This function finds a parent playlist for an item in the active chain of playlists.
- // Every item in the chain comes from currentMedia() of its parent.
- // We don't need to travers the whole tree of playlists,
- // but only the subtree of active ones.
- for (QMediaPlaylist *current = rootMedia.playlist(); current && current != pls; current = current->currentMedia().playlist())
- if (current->currentMedia().playlist() == pls)
- return current;
- return nullptr;
-}
-
-bool QMediaPlayerPrivate::isInChain(const QUrl &url)
-{
- // Check whether a URL is already in the chain of playlists.
- // Also see a comment in parentPlaylist().
- for (QMediaPlaylist *current = rootMedia.playlist(); current && current != playlist; current = current->currentMedia().playlist())
- if (current->currentMedia().request().url() == url) {
- return true;
+/*!
+ \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 {}
}
- return false;
-}
-
-void QMediaPlayerPrivate::_q_stateChanged(QMediaPlayer::State ps)
-{
- Q_Q(QMediaPlayer);
-
- // Backend switches into stopped state every time new media is about to be loaded.
- // If media player has a playlist loaded make sure player doesn' stop.
- if (playlist && playlist->currentIndex() != -1 && ps != state && ps == QMediaPlayer::StoppedState) {
- if (control->mediaStatus() == QMediaPlayer::EndOfMedia ||
- control->mediaStatus() == QMediaPlayer::InvalidMedia) {
- // if media player is not stopped, and
- // we have finished playback for the current media,
- // advance to the next item in the playlist
- Q_ASSERT(state != QMediaPlayer::StoppedState);
- playlist->next();
- return;
- } else if (control->mediaStatus() == QMediaPlayer::LoadingMedia) {
- return;
+ 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
+ }
- if (ps != state) {
- state = ps;
-
- if (ps == QMediaPlayer::PlayingState)
- q->addPropertyWatch("position");
- else
- q->removePropertyWatch("position");
+ VideoOutput {
+ id: videoOutput
+ anchors.fill: parent
+ }
- emit q->stateChanged(ps);
+ MouseArea {
+ anchors.fill: parent
+ onPressed: mediaplayer.play();
+ }
}
-}
+ \endqml
-void QMediaPlayerPrivate::_q_mediaStatusChanged(QMediaPlayer::MediaStatus s)
+ \sa AudioOutput, VideoOutput
+*/
+
+void QMediaPlayerPrivate::setState(QMediaPlayer::PlaybackState toState)
{
Q_Q(QMediaPlayer);
- if (int(s) == ignoreNextStatusChange) {
- ignoreNextStatusChange = -1;
- return;
- }
-
- if (s != status) {
- status = s;
-
- switch (s) {
- case QMediaPlayer::StalledMedia:
- case QMediaPlayer::BufferingMedia:
- q->addPropertyWatch("bufferStatus");
- break;
- default:
- q->removePropertyWatch("bufferStatus");
- break;
- }
-
- emit q->mediaStatusChanged(s);
+ 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);
}
}
-void QMediaPlayerPrivate::_q_error(int error, const QString &errorString)
+void QMediaPlayerPrivate::setStatus(QMediaPlayer::MediaStatus s)
{
Q_Q(QMediaPlayer);
- if (error == int(QMediaPlayer::MediaIsPlaylist)) {
- loadPlaylist();
- } else {
- this->error = QMediaPlayer::Error(error);
- this->errorString = errorString;
- emit q->error(this->error);
-
- if (playlist)
- playlist->next();
- }
+ emit q->mediaStatusChanged(s);
}
-void QMediaPlayerPrivate::_q_updateMedia(const QMediaContent &media)
+void QMediaPlayerPrivate::setError(QMediaPlayer::Error error, const QString &errorString)
{
Q_Q(QMediaPlayer);
- if (!control)
- return;
-
- // check if the current playlist is a top-level playlist
- Q_ASSERT(playlist);
- if (media.isNull() && playlist != rootMedia.playlist()) {
- // switch back to parent playlist
- QMediaPlaylist *pls = parentPlaylist(playlist);
- Q_ASSERT(pls);
- disconnectPlaylist();
- playlist = pls;
- connectPlaylist();
-
- Q_ASSERT(!pendingPlaylist.playlist());
- nestedPlaylists--;
- Q_ASSERT(nestedPlaylists >= 0);
-
- playlist->next();
- return;
- }
-
- if (media.playlist()) {
- if (nestedPlaylists < MAX_NESTED_PLAYLISTS) {
- nestedPlaylists++;
- Q_ASSERT(!pendingPlaylist.playlist());
-
- // disconnect current playlist
- disconnectPlaylist();
- // new playlist signals are connected
- // in the call to setPlaylist() in _q_handlePlaylistLoaded()
- playlist = media.playlist();
- emit q->currentMediaChanged(media);
- _q_handlePlaylistLoaded();
- return;
- } else if (playlist) {
- playlist->next();
- }
- return;
- }
-
- const QMediaPlayer::State currentState = state;
-
- setMedia(media, nullptr);
-
- if (!media.isNull()) {
- switch (currentState) {
- case QMediaPlayer::PlayingState:
- control->play();
- break;
- case QMediaPlayer::PausedState:
- control->pause();
- break;
- default:
- break;
- }
- }
-
- _q_stateChanged(control->state());
-}
-
-void QMediaPlayerPrivate::_q_playlistDestroyed()
-{
- playlist = nullptr;
- setMedia(QMediaContent(), nullptr);
+ this->error.setAndNotify(error, errorString, *q);
}
-void QMediaPlayerPrivate::setMedia(const QMediaContent &media, QIODevice *stream)
+void QMediaPlayerPrivate::setMedia(const QUrl &media, QIODevice *stream)
{
- Q_Q(QMediaPlayer);
-
if (!control)
return;
- QScopedPointer<QFile> file;
+ std::unique_ptr<QFile> file;
- // Backends can't play qrc files directly.
- // If the backend supports StreamPlayback, we pass a QFile for that resource.
+ // Back ends can't play qrc files directly.
+ // If the back end supports StreamPlayback, we pass a QFile for that resource.
// If it doesn't, we copy the data to a temporary file and pass its path.
- if (!media.isNull() && !stream && media.request().url().scheme() == QLatin1String("qrc")) {
+ if (!media.isEmpty() && !stream && media.scheme() == QLatin1String("qrc")) {
qrcMedia = media;
- file.reset(new QFile(QLatin1Char(':') + media.request().url().path()));
+ file.reset(new QFile(QLatin1Char(':') + media.path()));
if (!file->open(QFile::ReadOnly)) {
- QMetaObject::invokeMethod(q, "_q_error", Qt::QueuedConnection,
- Q_ARG(int, QMediaPlayer::ResourceError),
- Q_ARG(QString, QMediaPlayer::tr("Attempting to play invalid Qt resource")));
- QMetaObject::invokeMethod(q, "_q_mediaStatusChanged", Qt::QueuedConnection,
- Q_ARG(QMediaPlayer::MediaStatus, QMediaPlayer::InvalidMedia));
file.reset();
- // Ignore the next NoMedia status change, we just want to clear the current media
- // on the backend side since we can't load the new one and we want to be in the
- // InvalidMedia status.
- ignoreNextStatusChange = QMediaPlayer::NoMedia;
- control->setMedia(QMediaContent(), nullptr);
-
- } else if (hasStreamPlaybackFeature) {
- control->setMedia(media, file.data());
+ control->setMedia(QUrl(), nullptr);
+ control->mediaStatusChanged(QMediaPlayer::InvalidMedia);
+ control->error(QMediaPlayer::ResourceError, QMediaPlayer::tr("Attempting to play invalid Qt resource"));
+
+ } else if (control->streamPlaybackSupported()) {
+ control->setMedia(media, file.get());
} else {
#if QT_CONFIG(temporaryfile)
#if defined(Q_OS_ANDROID)
- QString tempFileName = QDir::tempPath() + media.request().url().path();
+ QString tempFileName = QDir::tempPath() + media.path();
QDir().mkpath(QFileInfo(tempFileName).path());
QTemporaryFile *tempFile = QTemporaryFile::createNativeFile(*file);
if (!tempFile->rename(tempFileName))
@@ -374,14 +158,21 @@ void QMediaPlayerPrivate::setMedia(const QMediaContent &media, QIODevice *stream
#else
QTemporaryFile *tempFile = new QTemporaryFile;
- // Preserve original file extension, some backends might not load the file if it doesn't
+ // Preserve original file extension, some back ends might not load the file if it doesn't
// have an extension.
const QString suffix = QFileInfo(*file).suffix();
if (!suffix.isEmpty())
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));
@@ -392,253 +183,53 @@ void QMediaPlayerPrivate::setMedia(const QMediaContent &media, QIODevice *stream
tempFile->close();
#endif
file.reset(tempFile);
- control->setMedia(QMediaContent(QUrl::fromLocalFile(file->fileName())), nullptr);
+ control->setMedia(QUrl(QUrl::fromLocalFile(file->fileName())), nullptr);
#else
qWarning("Qt was built with -no-feature-temporaryfile: playback from resource file is not supported!");
#endif
}
} else {
- qrcMedia = QMediaContent();
- control->setMedia(media, stream);
- }
-
- qrcFile.swap(file); // Cleans up any previous file
-}
-
-void QMediaPlayerPrivate::_q_handleMediaChanged(const QMediaContent &media)
-{
- Q_Q(QMediaPlayer);
-
- emit q->currentMediaChanged(qrcMedia.isNull() ? media : qrcMedia);
-}
-
-void QMediaPlayerPrivate::setPlaylist(QMediaPlaylist *pls)
-{
- disconnectPlaylist();
- playlist = pls;
-
- setPlaylistMedia();
-}
-
-void QMediaPlayerPrivate::setPlaylistMedia()
-{
- // This function loads current playlist media into backend.
- // If current media is a playlist, the function recursively
- // loads media from the playlist.
- // It also makes sure the correct playlist signals are connected.
- Q_Q(QMediaPlayer);
-
- if (playlist) {
- connectPlaylist();
- if (playlist->currentMedia().playlist()) {
- if (nestedPlaylists < MAX_NESTED_PLAYLISTS) {
- emit q->currentMediaChanged(playlist->currentMedia());
- // rewind nested playlist to start
- playlist->currentMedia().playlist()->setCurrentIndex(0);
- nestedPlaylists++;
- setPlaylist(playlist->currentMedia().playlist());
- } else {
- playlist->next();
- }
- return;
- } else {
- // If we've just switched to a new playlist,
- // then last emitted currentMediaChanged was a playlist.
- // Make sure we emit currentMediaChanged if new playlist has
- // the same media as the previous one:
- // sample.m3u
- // test.wav -- processed by backend
- // nested.m3u -- processed by frontend
- // test.wav -- processed by backend,
- // media is not changed,
- // frontend needs to emit currentMediaChanged
- bool isSameMedia = (q->currentMedia() == playlist->currentMedia());
- setMedia(playlist->currentMedia(), nullptr);
- if (isSameMedia) {
- emit q->currentMediaChanged(q->currentMedia());
- }
+ qrcMedia = QUrl();
+ QUrl url = qMediaFromUserInput(media);
+ if (url.scheme() == QLatin1String("content") && !stream) {
+ file.reset(new QFile(media.url()));
+ stream = file.get();
}
- } else {
- setMedia(QMediaContent(), nullptr);
- }
-}
-
-void QMediaPlayerPrivate::loadPlaylist()
-{
- Q_Q(QMediaPlayer);
- Q_ASSERT(pendingPlaylist.isNull());
-
- // Do not load a playlist if there are more than MAX_NESTED_PLAYLISTS in the chain already,
- // or if the playlist URL is already in the chain, i.e. do not allow recursive playlists and loops.
- if (nestedPlaylists < MAX_NESTED_PLAYLISTS
- && !q->currentMedia().request().url().isEmpty()
- && !isInChain(q->currentMedia().request().url()))
- {
- pendingPlaylist = QMediaContent(new QMediaPlaylist, q->currentMedia().request().url(), true);
- QObject::connect(pendingPlaylist.playlist(), SIGNAL(loaded()), q, SLOT(_q_handlePlaylistLoaded()));
- QObject::connect(pendingPlaylist.playlist(), SIGNAL(loadFailed()), q, SLOT(_q_handlePlaylistLoadFailed()));
- pendingPlaylist.playlist()->load(pendingPlaylist.request());
- } else if (playlist) {
- playlist->next();
- }
-}
-void QMediaPlayerPrivate::disconnectPlaylist()
-{
- Q_Q(QMediaPlayer);
- if (playlist) {
- QObject::disconnect(playlist, SIGNAL(currentMediaChanged(QMediaContent)),
- q, SLOT(_q_updateMedia(QMediaContent)));
- QObject::disconnect(playlist, SIGNAL(destroyed()), q, SLOT(_q_playlistDestroyed()));
- q->unbind(playlist);
+ control->setMedia(url, stream);
}
-}
-void QMediaPlayerPrivate::connectPlaylist()
-{
- Q_Q(QMediaPlayer);
- if (playlist) {
- q->bind(playlist);
- QObject::connect(playlist, SIGNAL(currentMediaChanged(QMediaContent)),
- q, SLOT(_q_updateMedia(QMediaContent)));
- QObject::connect(playlist, SIGNAL(destroyed()), q, SLOT(_q_playlistDestroyed()));
- }
+ qrcFile.swap(file); // Cleans up any previous file
}
-void QMediaPlayerPrivate::_q_handlePlaylistLoaded()
+QList<QMediaMetaData> QMediaPlayerPrivate::trackMetaData(QPlatformMediaPlayer::TrackType s) const
{
- Q_Q(QMediaPlayer);
-
- if (pendingPlaylist.playlist()) {
- Q_ASSERT(!q->currentMedia().playlist());
- // if there is an active playlist
- if (playlist) {
- Q_ASSERT(playlist->currentIndex() >= 0);
- disconnectPlaylist();
- playlist->insertMedia(playlist->currentIndex() + 1, pendingPlaylist);
- playlist->removeMedia(playlist->currentIndex());
- nestedPlaylists++;
- } else {
- Q_ASSERT(!rootMedia.playlist());
- rootMedia = pendingPlaylist;
- emit q->mediaChanged(rootMedia);
+ QList<QMediaMetaData> tracks;
+ if (control) {
+ int count = control->trackCount(s);
+ for (int i = 0; i < count; ++i) {
+ tracks.append(control->trackMetaData(s, i));
}
-
- playlist = pendingPlaylist.playlist();
- emit q->currentMediaChanged(pendingPlaylist);
- }
- pendingPlaylist = QMediaContent();
-
- playlist->next();
- setPlaylistMedia();
-
- switch (state) {
- case QMediaPlayer::PausedState:
- control->pause();
- break;
- case QMediaPlayer::PlayingState:
- control->play();
- break;
- case QMediaPlayer::StoppedState:
- break;
- }
-}
-
-void QMediaPlayerPrivate::_q_handlePlaylistLoadFailed()
-{
- pendingPlaylist = QMediaContent();
-
- if (!control)
- return;
-
- if (playlist)
- playlist->next();
- else
- setMedia(QMediaContent(), nullptr);
-}
-
-static QMediaService *playerService(QMediaPlayer::Flags flags)
-{
- QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider();
- if (flags) {
- QMediaServiceProviderHint::Features features;
- if (flags & QMediaPlayer::LowLatency)
- features |= QMediaServiceProviderHint::LowLatencyPlayback;
-
- if (flags & QMediaPlayer::StreamPlayback)
- features |= QMediaServiceProviderHint::StreamPlayback;
-
- if (flags & QMediaPlayer::VideoSurface)
- features |= QMediaServiceProviderHint::VideoSurface;
-
- return provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER,
- QMediaServiceProviderHint(features));
}
-
- return provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER);
+ return tracks;
}
-
/*!
- Construct a QMediaPlayer instance
- parented to \a parent and with \a flags.
+ Constructs a QMediaPlayer instance as a child of \a{parent}.
*/
-QMediaPlayer::QMediaPlayer(QObject *parent, QMediaPlayer::Flags flags):
- QMediaObject(*new QMediaPlayerPrivate,
- parent,
- playerService(flags))
+QMediaPlayer::QMediaPlayer(QObject *parent)
+ : QObject(*new QMediaPlayerPrivate, parent)
{
Q_D(QMediaPlayer);
- d->provider = QMediaServiceProvider::defaultServiceProvider();
- if (d->service == nullptr) {
- d->error = ServiceMissingError;
+ auto maybeControl = QPlatformMediaIntegration::instance()->createPlayer(this);
+ if (maybeControl) {
+ d->control = maybeControl.value();
+ d->state = d->control->state();
} else {
- d->control = qobject_cast<QMediaPlayerControl*>(d->service->requestControl(QMediaPlayerControl_iid));
- if (d->control != nullptr) {
- connect(d->control, SIGNAL(mediaChanged(QMediaContent)), SLOT(_q_handleMediaChanged(QMediaContent)));
- connect(d->control, SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(_q_stateChanged(QMediaPlayer::State)));
- connect(d->control, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
- SLOT(_q_mediaStatusChanged(QMediaPlayer::MediaStatus)));
- connect(d->control, SIGNAL(error(int,QString)), SLOT(_q_error(int,QString)));
-
- connect(d->control, &QMediaPlayerControl::durationChanged, this, &QMediaPlayer::durationChanged);
- connect(d->control, &QMediaPlayerControl::positionChanged, this, &QMediaPlayer::positionChanged);
- connect(d->control, &QMediaPlayerControl::audioAvailableChanged, this, &QMediaPlayer::audioAvailableChanged);
- connect(d->control, &QMediaPlayerControl::videoAvailableChanged, this, &QMediaPlayer::videoAvailableChanged);
- connect(d->control, &QMediaPlayerControl::volumeChanged, this, &QMediaPlayer::volumeChanged);
- connect(d->control, &QMediaPlayerControl::mutedChanged, this, &QMediaPlayer::mutedChanged);
- connect(d->control, &QMediaPlayerControl::seekableChanged, this, &QMediaPlayer::seekableChanged);
- connect(d->control, &QMediaPlayerControl::playbackRateChanged, this, &QMediaPlayer::playbackRateChanged);
- connect(d->control, &QMediaPlayerControl::bufferStatusChanged, this, &QMediaPlayer::bufferStatusChanged);
-
- d->state = d->control->state();
- d->status = d->control->mediaStatus();
-
- if (d->state == PlayingState)
- addPropertyWatch("position");
-
- if (d->status == StalledMedia || d->status == BufferingMedia)
- addPropertyWatch("bufferStatus");
-
- d->hasStreamPlaybackFeature = d->provider->supportedFeatures(d->service).testFlag(QMediaServiceProviderHint::StreamPlayback);
-
- d->audioRoleControl = qobject_cast<QAudioRoleControl*>(d->service->requestControl(QAudioRoleControl_iid));
- if (d->audioRoleControl) {
- connect(d->audioRoleControl, &QAudioRoleControl::audioRoleChanged,
- this, &QMediaPlayer::audioRoleChanged);
-
- d->customAudioRoleControl = qobject_cast<QCustomAudioRoleControl *>(
- d->service->requestControl(QCustomAudioRoleControl_iid));
- if (d->customAudioRoleControl) {
- connect(d->customAudioRoleControl,
- &QCustomAudioRoleControl::customAudioRoleChanged,
- this,
- &QMediaPlayer::customAudioRoleChanged);
- }
- }
- }
+ qWarning() << "Failed to initialize QMediaPlayer" << maybeControl.error();
+ d->setError(QMediaPlayer::ResourceError, maybeControl.error());
}
}
@@ -651,86 +242,56 @@ QMediaPlayer::~QMediaPlayer()
{
Q_D(QMediaPlayer);
- d->disconnectPlaylist();
- // Disconnect everything to prevent notifying
- // when a receiver is already destroyed.
- disconnect();
+ // prevents emitting audioOutputChanged and videoOutputChanged.
+ QSignalBlocker blocker(this);
- if (d->service) {
- if (d->control)
- d->service->releaseControl(d->control);
- if (d->audioRoleControl)
- d->service->releaseControl(d->audioRoleControl);
- if (d->customAudioRoleControl)
- d->service->releaseControl(d->customAudioRoleControl);
+ // 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;
- d->provider->releaseService(d->service);
- }
+ setAudioOutput(nullptr);
+
+ d->setVideoSink(nullptr);
+ delete d->control;
}
-QMediaContent QMediaPlayer::media() const
+QUrl QMediaPlayer::source() const
{
Q_D(const QMediaPlayer);
- return d->rootMedia;
+ return d->source;
}
/*!
Returns the stream source of media data.
- This is only valid if a stream was passed to setMedia().
+ This is only valid if a stream was passed to setSource().
- \sa setMedia()
+ \sa setSource()
*/
-const QIODevice *QMediaPlayer::mediaStream() const
-{
- Q_D(const QMediaPlayer);
-
- // When playing a resource file, we might have passed a QFile to the backend. Hide it from
- // the user.
- if (d->control && d->qrcMedia.isNull())
- return d->control->mediaStream();
-
- return nullptr;
-}
-
-QMediaPlaylist *QMediaPlayer::playlist() const
+const QIODevice *QMediaPlayer::sourceDevice() const
{
Q_D(const QMediaPlayer);
- return d->rootMedia.playlist();
+ return d->stream;
}
-QMediaContent QMediaPlayer::currentMedia() const
-{
- Q_D(const QMediaPlayer);
-
- // When playing a resource file, don't return the backend's current media, which
- // can be a temporary file.
- if (!d->qrcMedia.isNull())
- return d->qrcMedia;
-
- if (d->control)
- return d->control->media();
-
- return QMediaContent();
-}
+/*!
+ \property QMediaPlayer::playbackState
-void QMediaPlayer::setPlaylist(QMediaPlaylist *playlist)
-{
- QMediaContent m(playlist, QUrl(), false);
- setMedia(m);
-}
+ Returns the \l{QMediaPlayer::}{PlaybackState}.
-QMediaPlayer::State QMediaPlayer::state() const
+ \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
- && d->status == QMediaPlayer::EndOfMedia
+ if (d->control
+ && d->control->mediaStatus() == QMediaPlayer::EndOfMedia
&& d->state != d->control->state()) {
return d->control->state();
}
@@ -740,546 +301,790 @@ QMediaPlayer::State QMediaPlayer::state() const
QMediaPlayer::MediaStatus QMediaPlayer::mediaStatus() const
{
- return d_func()->status;
+ Q_D(const QMediaPlayer);
+ return d->control ? d->control->mediaStatus() : NoMedia;
}
+/*!
+ Returns the duration of the current media in ms.
+
+ Returns 0 if the media player doesn't have a valid media file or stream.
+ For live streams, the duration usually changes during playback as more
+ data becomes available.
+*/
qint64 QMediaPlayer::duration() const
{
Q_D(const QMediaPlayer);
-
- if (d->control != nullptr)
- return d->control->duration();
-
- return -1;
+ return d->control ? d->control->duration() : 0;
}
+/*!
+ Returns the current position inside the media being played back in ms.
+
+ Returns 0 if the media player doesn't have a valid media file or stream.
+ For live streams, the duration usually changes during playback as more
+ data becomes available.
+*/
qint64 QMediaPlayer::position() const
{
Q_D(const QMediaPlayer);
+ return d->control ? d->control->position() : 0;
+}
- if (d->control != nullptr)
- return d->control->position();
+/*!
+ Returns a number between 0 and 1 when buffering data.
- return 0;
-}
+ 0 means that there is no buffered data available, playback is usually
+ stalled in this case. Playback will resume once the buffer reaches 1,
+ meaning enough data has been buffered to be able to resume playback.
-int QMediaPlayer::volume() const
+ bufferProgress() will always return 1 for local files.
+*/
+float QMediaPlayer::bufferProgress() const
{
Q_D(const QMediaPlayer);
+ return d->control ? d->control->bufferProgress() : 0;
+}
- if (d->control != nullptr)
- return d->control->volume();
+/*!
+ Returns a QMediaTimeRange describing the currently buffered data.
- return 0;
-}
+ When streaming media from a remote source, different parts of the media
+ file can be available locally. The returned QMediaTimeRange object describes
+ the time ranges that are buffered and available for immediate playback.
-bool QMediaPlayer::isMuted() const
+ \sa QMediaTimeRange
+*/
+QMediaTimeRange QMediaPlayer::bufferedTimeRange() const
{
Q_D(const QMediaPlayer);
+ return d->control ? d->control->availablePlaybackRanges() : QMediaTimeRange{};
+}
- if (d->control != nullptr)
- return d->control->isMuted();
+/*!
+ \qmlproperty bool QtMultimedia::MediaPlayer::hasAudio
- return false;
-}
+ This property holds whether the media contains audio.
+*/
-int QMediaPlayer::bufferStatus() const
+/*!
+ \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->bufferStatus();
+/*!
+ \qmlproperty bool QtMultimedia::MediaPlayer::hasVideo
- return 0;
-}
+ This property holds whether the media contains video.
+*/
-bool QMediaPlayer::isAudioAvailable() const
+/*!
+ \property QMediaPlayer::hasVideo
+ \brief This property holds whether the media contains video.
+*/
+bool QMediaPlayer::hasVideo() const
{
Q_D(const QMediaPlayer);
+ return d->control && d->control->isVideoAvailable();
+}
- if (d->control != nullptr)
- return d->control->isAudioAvailable();
+/*!
+ Returns true if the media is seekable. Most file based media files are seekable,
+ but live streams usually are not.
- return false;
+ \sa position
+*/
+bool QMediaPlayer::isSeekable() const
+{
+ Q_D(const QMediaPlayer);
+ return d->control && d->control->isSeekable();
}
-bool QMediaPlayer::isVideoAvailable() const
+bool QMediaPlayer::isPlaying() const
{
Q_D(const QMediaPlayer);
-
- if (d->control != nullptr)
- return d->control->isVideoAvailable();
-
- return false;
+ return d->state == QMediaPlayer::PlayingState;
}
-bool QMediaPlayer::isSeekable() const
+/*!
+ Returns the current playback rate.
+*/
+qreal QMediaPlayer::playbackRate() const
{
Q_D(const QMediaPlayer);
+ return d->control ? d->control->playbackRate() : 0.;
+}
+
+/*!
+ \enum QMediaPlayer::Loops
- if (d->control != nullptr)
- return d->control->isSeekable();
+ Some predefined constants for the \l loops property.
- return false;
-}
+ \value Infinite Loop forever.
+ \value Once Play the media once (the default).
+*/
-qreal QMediaPlayer::playbackRate() const
+/*!
+ \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.
+
+ 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;
+}
- if (d->control != nullptr)
- return d->control->playbackRate();
-
- return 0.0;
+void QMediaPlayer::setLoops(int loops)
+{
+ Q_D(QMediaPlayer);
+ if (loops == 0)
+ return;
+ if (d->control)
+ d->control->setLoops(loops);
}
/*!
Returns the current error state.
*/
-
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();
}
-//public Q_SLOTS:
/*!
- 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);
- if (d->control == nullptr) {
- QMetaObject::invokeMethod(this, "_q_error", Qt::QueuedConnection,
- Q_ARG(int, QMediaPlayer::ServiceMissingError),
- Q_ARG(QString, tr("The QMediaPlayer object does not have a valid service")));
+ if (!d->control)
return;
- }
-
- //if playlist control is available, the service should advance itself
- if (d->rootMedia.playlist() && !d->rootMedia.playlist()->isEmpty()) {
- // switch to playing state
- if (d->state != QMediaPlayer::PlayingState)
- d->_q_stateChanged(QMediaPlayer::PlayingState);
-
- if (d->rootMedia.playlist()->currentIndex() == -1) {
- if (d->playlist != d->rootMedia.playlist())
- d->setPlaylist(d->rootMedia.playlist());
- Q_ASSERT(d->playlist == d->rootMedia.playlist());
-
- emit currentMediaChanged(d->rootMedia);
- d->playlist->setCurrentIndex(0);
- }
- }
// 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();
-
- // If media player didn't stop in response to control.
- // This happens if we have an active playlist and control
- // media status is
- // QMediaPlayer::LoadingMedia, QMediaPlayer::InvalidMedia, or QMediaPlayer::EndOfMedia
- // see QMediaPlayerPrivate::_q_stateChanged()
- if (d->playlist && d->state != QMediaPlayer::StoppedState) {
- d->state = QMediaPlayer::StoppedState;
- removePropertyWatch("position");
- emit stateChanged(QMediaPlayer::StoppedState);
- }
}
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));
}
-void QMediaPlayer::setVolume(int v)
+void QMediaPlayer::setPlaybackRate(qreal rate)
{
Q_D(QMediaPlayer);
- if (d->control == nullptr)
- return;
-
- int clamped = qBound(0, v, 100);
- if (clamped == volume())
- return;
-
- d->control->setVolume(clamped);
+ if (d->control)
+ d->control->setPlaybackRate(rate);
}
-void QMediaPlayer::setMuted(bool muted)
-{
- Q_D(QMediaPlayer);
-
- if (d->control == nullptr || muted == isMuted())
- return;
+/*!
+ \qmlproperty url QtMultimedia::MediaPlayer::source
- d->control->setMuted(muted);
-}
+ This property holds the source URL of the media.
-void QMediaPlayer::setPlaybackRate(qreal rate)
-{
- Q_D(QMediaPlayer);
+ \snippet multimedia-snippets/qtvideosink.qml complete
- if (d->control != nullptr)
- d->control->setPlaybackRate(rate);
-}
+ \sa QMediaPlayer::setSource()
+*/
/*!
- Sets the current \a media source.
-
- If a \a stream is supplied; media data will be read from it instead of resolving the media
- source. In this case the url should be provided to resolve additional information
- about the media such as mime type. The \a stream must be open and readable.
- For macOS the \a stream should be also seekable.
+ Sets the current \a source.
- Setting the media to a null QMediaContent will cause the player to discard all
+ 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
the mediaStatusChanged() and error() signals to be notified when the media is loaded and
when an error occurs during loading.
- Since Qt 5.12.2, the url scheme \c gst-pipeline provides custom pipelines
- for the GStreamer backend.
+ \note FFmpeg, used by the FFmpeg media backend, restricts use of nested protocols for
+ security reasons. In controlled environments where all inputs are trusted, the list of
+ approved protocols can be overridden using the QT_FFMPEG_PROTOCOL_WHITELIST environment
+ variable. This environment variable is Qt's private API and can change between patch
+ releases without notice.
+*/
- \snippet multimedia-snippets/media.cpp Pipeline
+void QMediaPlayer::setSource(const QUrl &source)
+{
+ Q_D(QMediaPlayer);
+ stop();
+
+ if (d->source == source && d->stream == nullptr)
+ return;
- If QAbstractVideoSurface is used as the video output,
- \c qtvideosink can be used as a video sink element directly in the pipeline.
- After that the surface will receive the video frames in QAbstractVideoSurface::present().
+ d->source = source;
+ d->stream = nullptr;
- \snippet multimedia-snippets/media.cpp Pipeline Surface
+ d->setMedia(source, nullptr);
+ emit sourceChanged(d->source);
+}
- If QVideoWidget is used as the video output
- and the pipeline contains a video sink element named \c qtvideosink,
- current QVideoWidget will be used to render the video.
+/*!
+ Sets the current source \a device.
- \snippet multimedia-snippets/media.cpp Pipeline Widget
+ The media data will be read from \a device. The \a sourceUrl can be provided
+ to resolve additional information about the media, mime type etc. The
+ \a device must be open and readable.
- If the pipeline contains appsrc element, it will be used to push data from \a stream.
+ For macOS the \a device should also be seek-able.
- \snippet multimedia-snippets/media.cpp Pipeline appsrc
+ \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 the mediaStatusChanged() and error() signals to
+ be notified when the media is loaded, and if an error occurs during loading.
*/
-
-void QMediaPlayer::setMedia(const QMediaContent &media, QIODevice *stream)
+void QMediaPlayer::setSourceDevice(QIODevice *device, const QUrl &sourceUrl)
{
Q_D(QMediaPlayer);
stop();
- QMediaContent oldMedia = d->rootMedia;
- d->disconnectPlaylist();
- d->playlist = nullptr;
- d->rootMedia = media;
- d->nestedPlaylists = 0;
+ if (d->source == sourceUrl && d->stream == device)
+ return;
- if (oldMedia != media)
- emit mediaChanged(d->rootMedia);
+ d->source = sourceUrl;
+ d->stream = device;
- if (media.playlist()) {
- // reset playlist to the 1st item
- media.playlist()->setCurrentIndex(0);
- d->setPlaylist(media.playlist());
- } else {
- d->setMedia(media, stream);
- }
+ d->setMedia(d->source, device);
+ emit sourceChanged(d->source);
}
/*!
- \internal
+ Sets an audio buffer \a output to the media player.
+
+ If \l QAudioBufferOutput is specified and the media source
+ contains an audio stream, the media player, it will emit
+ the signal \l{QAudioBufferOutput::audioBufferReceived} with
+ audio buffers containing decoded audio data. At the end of
+ the audio stream, \c QMediaPlayer emits an empty \l QAudioBuffer.
+
+ \c QMediaPlayer emits outputs frames at the same time as it
+ pushes the matching data to the audio output if it's specified.
+ However, the sound can be played with a small delay due to
+ audio bufferization.
*/
-
-bool QMediaPlayer::bind(QObject *obj)
+void QMediaPlayer::setAudioBufferOutput(QAudioBufferOutput *output)
{
- return QMediaObject::bind(obj);
+ Q_D(QMediaPlayer);
+
+ QAudioBufferOutput *oldOutput = d->audioBufferOutput;
+ if (oldOutput == output)
+ return;
+
+ d->audioBufferOutput = output;
+
+ if (output) {
+ auto oldPlayer = QAudioBufferOutputPrivate::exchangeMediaPlayer(*oldOutput, this);
+ if (oldPlayer)
+ oldPlayer->setAudioBufferOutput(nullptr);
+ }
+
+ if (d->control)
+ d->control->setAudioBufferOutput(output);
+
+ emit audioBufferOutputChanged();
}
/*!
- \internal
+ Get \l QAudioBufferOutput that has been set to the media player.
*/
-
-void QMediaPlayer::unbind(QObject *obj)
+QAudioBufferOutput *QMediaPlayer::audioBufferOutput() const
{
- QMediaObject::unbind(obj);
+ Q_D(const QMediaPlayer);
+ return d->audioBufferOutput;
}
/*!
- Returns the level of support a media player has for a \a mimeType and a set of \a codecs.
+ \qmlproperty AudioOutput QtMultimedia::MediaPlayer::audioOutput
+
+ This property holds the target audio output.
+ Accepts one AudioOutput elements.
- The \a flags argument allows additional requirements such as performance indicators to be
- specified.
+ \sa QMediaPlayer::setAudioOutput()
*/
-QMultimedia::SupportEstimate QMediaPlayer::hasSupport(const QString &mimeType,
- const QStringList& codecs,
- Flags flags)
-{
- return QMediaServiceProvider::defaultServiceProvider()->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER),
- mimeType,
- codecs,
- flags);
-}
+
/*!
- \deprecated
- Returns a list of MIME types supported by the media player.
+ \property QMediaPlayer::audioOutput
+ \brief The audio output device used by the media player.
- The \a flags argument causes the resultant list to be restricted to MIME types which can be supported
- given additional requirements, such as performance indicators.
+ The current audio output to be used when playing back media. Setting
+ a new audio output will replace the currently used output.
- This function may not return useful results on some platforms, and support for a specific file of a
- given mime type is not guaranteed even if the mime type is in general supported. In addition, in some
- cases this function will need to load all available media plugins and query them for their support, which
- may take some time.
+ Setting this property to \c nullptr will disable any audio output.
*/
-QStringList QMediaPlayer::supportedMimeTypes(Flags flags)
+void QMediaPlayer::setAudioOutput(QAudioOutput *output)
+{
+ Q_D(QMediaPlayer);
+ auto oldOutput = d->audioOutput;
+ if (oldOutput == output)
+ return;
+ d->audioOutput = output;
+ 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();
+}
+
+QAudioOutput *QMediaPlayer::audioOutput() const
{
- return QMediaServiceProvider::defaultServiceProvider()->supportedMimeTypes(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER),
- flags);
+ Q_D(const QMediaPlayer);
+ return d->audioOutput;
}
/*!
- \fn void QMediaPlayer::setVideoOutput(QVideoWidget* output)
+ \qmlproperty list<mediaMetaData> QtMultimedia::MediaPlayer::audioTracks
- Attach a QVideoWidget video \a output to the media player.
+ This property holds a list of metadata.
+ Each index refers to an audio track.
- If the media player has already video output attached,
- it will be replaced with a new one.
+ The metadata holds properties describing the individual tracks. For
+ audio tracks the \l{QMediaMetaData}{Language} is usually the most
+ important property.
+
+ \sa mediaMetaData
*/
-void QMediaPlayer::setVideoOutput(QVideoWidget *output)
-{
- Q_D(QMediaPlayer);
- if (d->videoOutput)
- unbind(d->videoOutput);
+/*!
+ \property QMediaPlayer::audioTracks
+
+ Lists the set of available audio tracks inside the media.
- // We don't know (in this library) that QVideoWidget inherits QObject
- QObject *outputObject = reinterpret_cast<QObject*>(output);
+ The QMediaMetaData returned describes the properties of individual
+ tracks.
- d->videoOutput = outputObject && bind(outputObject) ? outputObject : nullptr;
+ Different audio tracks can for example contain audio in different languages.
+*/
+QList<QMediaMetaData> QMediaPlayer::audioTracks() const
+{
+ Q_D(const QMediaPlayer);
+ return d->trackMetaData(QPlatformMediaPlayer::AudioStream);
}
/*!
- \fn void QMediaPlayer::setVideoOutput(QGraphicsVideoItem* output)
+ \qmlproperty list<mediaMetaData> QtMultimedia::MediaPlayer::videoTracks
- Attach a QGraphicsVideoItem video \a output to the media player.
+ This property holds a list of metadata.
+ Each index refers to a video track.
- If the media player has already video output attached,
- it will be replaced with a new one.
+ The metadata holds properties describing the individual tracks.
+
+ \sa mediaMetaData
*/
-void QMediaPlayer::setVideoOutput(QGraphicsVideoItem *output)
-{
- Q_D(QMediaPlayer);
- if (d->videoOutput)
- unbind(d->videoOutput);
+/*!
+ \property QMediaPlayer::videoTracks
- // We don't know (in this library) that QGraphicsVideoItem (multiply) inherits QObject
- // but QObject inheritance depends on QObject coming first, so try this out.
- QObject *outputObject = reinterpret_cast<QObject*>(output);
+ Lists the set of available video tracks inside the media.
- d->videoOutput = outputObject && bind(outputObject) ? outputObject : nullptr;
+ The QMediaMetaData returned describes the properties of individual
+ tracks.
+*/
+QList<QMediaMetaData> QMediaPlayer::videoTracks() const
+{
+ Q_D(const QMediaPlayer);
+ return d->trackMetaData(QPlatformMediaPlayer::VideoStream);
}
/*!
- Sets a video \a surface as the video output of a media player.
+ \qmlproperty list<mediaMetaData> QtMultimedia::MediaPlayer::subtitleTracks
- If a video output has already been set on the media player the new surface
- will replace it.
+ 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
*/
-void QMediaPlayer::setVideoOutput(QAbstractVideoSurface *surface)
+/*!
+ \property QMediaPlayer::subtitleTracks
+
+ Lists the set of available subtitle tracks inside the media.
+
+ The QMediaMetaData returned describes the properties of individual
+ tracks.
+*/
+QList<QMediaMetaData> QMediaPlayer::subtitleTracks() const
{
- Q_D(QMediaPlayer);
+ Q_D(const QMediaPlayer);
+ return d->trackMetaData(QPlatformMediaPlayer::SubtitleStream);
+}
+
+/*!
+ \qmlproperty int QtMultimedia::MediaPlayer::activeAudioTrack
- d->surfaceOutput.setVideoSurface(surface);
+ This property holds the track number of the currently active audio track.
+ Set to \c{-1} to disable audio track.
- if (d->videoOutput != &d->surfaceOutput) {
- if (d->videoOutput)
- unbind(d->videoOutput);
+ The default property value is \c{0}: the first audio track.
+*/
- d->videoOutput = nullptr;
+/*!
+ \property QMediaPlayer::activeAudioTrack
+ \brief Returns the currently active audio track.
- if (surface && bind(&d->surfaceOutput))
- d->videoOutput = &d->surfaceOutput;
- } else if (!surface) {
- //unbind the surfaceOutput if null surface is set
- unbind(&d->surfaceOutput);
- d->videoOutput = nullptr;
- }
+ 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);
+ return d->control ? d->control->activeTrack(QPlatformMediaPlayer::AudioStream) : 0;
}
/*!
- \since 5.15
- Sets multiple video surfaces as the video output of a media player.
- This allows the media player to render video frames on different surfaces.
-
- All video surfaces must support at least one shared \c QVideoFrame::PixelFormat.
+ \since 6.2
+ \qmlproperty int QtMultimedia::MediaPlayer::activeVideoTrack
- If a video output has already been set on the media player the new surfaces
- will replace it.
+ This property holds the track number of the currently active video audio track.
+ Set to \c{-1} to disable video track.
- \sa QAbstractVideoSurface::supportedPixelFormats
+ The default property value is \c{0}: the first video track.
*/
-void QMediaPlayer::setVideoOutput(const QList<QAbstractVideoSurface *> &surfaces)
+/*!
+ \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
{
- setVideoOutput(!surfaces.empty() ? new QVideoSurfaces(surfaces, this) : nullptr);
+ Q_D(const QMediaPlayer);
+ return d->control ? d->control->activeTrack(QPlatformMediaPlayer::VideoStream) : -1;
}
-/*! \reimp */
-QMultimedia::AvailabilityStatus QMediaPlayer::availability() const
+/*!
+ \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.
+*/
+
+/*!
+ \property QMediaPlayer::activeSubtitleTrack
+ \brief Returns the currently active subtitle track.
+
+ Set \a index to \c -1 to disable subtitles.
+
+ 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);
if (!d->control)
- return QMultimedia::ServiceMissing;
+ return;
- return QMediaObject::availability();
+ if (activeAudioTrack() == index)
+ return;
+ d->control->setActiveTrack(QPlatformMediaPlayer::AudioStream, index);
}
-QAudio::Role QMediaPlayer::audioRole() const
+void QMediaPlayer::setActiveVideoTrack(int index)
{
- Q_D(const QMediaPlayer);
-
- if (d->audioRoleControl != nullptr)
- return d->audioRoleControl->audioRole();
+ Q_D(QMediaPlayer);
+ if (!d->control)
+ return;
- return QAudio::UnknownRole;
+ if (activeVideoTrack() == index)
+ return;
+ d->control->setActiveTrack(QPlatformMediaPlayer::VideoStream, index);
}
-void QMediaPlayer::setAudioRole(QAudio::Role audioRole)
+void QMediaPlayer::setActiveSubtitleTrack(int index)
{
Q_D(QMediaPlayer);
+ if (!d->control)
+ return;
- if (d->audioRoleControl) {
- if (d->customAudioRoleControl != nullptr && d->audioRoleControl->audioRole() != audioRole) {
- d->customAudioRoleControl->setCustomAudioRole(QString());
- }
-
- d->audioRoleControl->setAudioRole(audioRole);
- }
+ if (activeSubtitleTrack() == index)
+ return;
+ d->control->setActiveTrack(QPlatformMediaPlayer::SubtitleStream, index);
}
/*!
- Returns a list of supported audio roles.
+ \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.
- If setting the audio role is not supported, an empty list is returned.
+ A media player can only have one video output attached, so
+ setting this property will replace the previously connected
+ video output.
- \since 5.6
- \sa audioRole
+ Setting this property to \c nullptr will disable video output.
*/
-QList<QAudio::Role> QMediaPlayer::supportedAudioRoles() const
+QObject *QMediaPlayer::videoOutput() const
{
Q_D(const QMediaPlayer);
+ return d->videoOutput;
+}
+
+void QMediaPlayer::setVideoOutput(QObject *output)
+{
+ Q_D(QMediaPlayer);
+ if (d->videoOutput == output)
+ return;
- if (d->audioRoleControl)
- return d->audioRoleControl->supportedAudioRoles();
+ auto *sink = qobject_cast<QVideoSink *>(output);
+ if (!sink && output) {
+ auto *mo = output->metaObject();
+ mo->invokeMethod(output, "videoSink", Q_RETURN_ARG(QVideoSink *, sink));
+ }
+ d->videoOutput = output;
+ d->setVideoSink(sink);
+}
- return QList<QAudio::Role>();
+/*!
+ Sets \a sink to be the QVideoSink instance to
+ retrieve video data.
+*/
+void QMediaPlayer::setVideoSink(QVideoSink *sink)
+{
+ Q_D(QMediaPlayer);
+ d->videoOutput = nullptr;
+ d->setVideoSink(sink);
}
-QString QMediaPlayer::customAudioRole() const
+/*!
+ Returns the QVideoSink instance.
+*/
+QVideoSink *QMediaPlayer::videoSink() const
{
Q_D(const QMediaPlayer);
+ return d->videoSink;
+}
- if (audioRole() != QAudio::CustomRole)
- return QString();
- if (d->customAudioRoleControl != nullptr)
- return d->customAudioRoleControl->customAudioRole();
+#if 0
+/*
+ \since 5.15
+ Sets multiple video sinks as the video output of a media player.
+ This allows the media player to render video frames on several outputs.
- return QString();
+ If a video output has already been set on the media player the new surfaces
+ will replace it.
+*/
+void QMediaPlayer::setVideoOutput(const QList<QVideoSink *> &sinks)
+{
+ // ### IMPLEMENT ME
+ Q_UNUSED(sinks);
+// setVideoOutput(!surfaces.empty() ? new QVideoSurfaces(surfaces, this) : nullptr);
}
+#endif
-void QMediaPlayer::setCustomAudioRole(const QString &audioRole)
+/*!
+ Returns true if the media player is supported on this platform.
+*/
+bool QMediaPlayer::isAvailable() const
{
- Q_D(QMediaPlayer);
-
- if (d->customAudioRoleControl) {
- Q_ASSERT(d->audioRoleControl);
- setAudioRole(QAudio::CustomRole);
- d->customAudioRoleControl->setCustomAudioRole(audioRole);
- }
+ Q_D(const QMediaPlayer);
+ return bool(d->control);
}
/*!
- Returns a list of supported custom audio roles. An empty list may
- indicate that the supported custom audio roles aren't known. The
- list may not be complete.
+ \qmlproperty mediaMetaData QtMultimedia::MediaPlayer::metaData
+
+ Returns meta data for the current media used by the media player.
- \since 5.11
- \sa customAudioRole
+ 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.
*/
-QStringList QMediaPlayer::supportedCustomAudioRoles() const
-{
- Q_D(const QMediaPlayer);
- if (d->customAudioRoleControl)
- return d->customAudioRoleControl->supportedCustomAudioRoles();
+/*!
+ \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 its creation date.
- return QStringList();
+ \note The Windows implementation provides metadata only for media located on the local file
+ system.
+*/
+QMediaMetaData QMediaPlayer::metaData() const
+{
+ Q_D(const QMediaPlayer);
+ return d->control ? d->control->metaData() : QMediaMetaData{};
}
// Enums
/*!
- \enum QMediaPlayer::State
+ \enum QMediaPlayer::PlaybackState
Defines the current state of a media player.
\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.
- \value UnknownMediaStatus The status of the media cannot be determined.
- \value NoMedia There is no current media. The player is in the StoppedState.
+ \value NoMedia The is no current media. The player is in the StoppedState.
\value LoadingMedia The current media is being loaded. The player may be in any state.
\value LoadedMedia The current media has been loaded. The player is in the StoppedState.
\value StalledMedia Playback of the current media has stalled due to insufficient buffering or
@@ -1294,6 +1099,54 @@ QStringList QMediaPlayer::supportedCustomAudioRoles() 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.
@@ -1304,23 +1157,24 @@ QStringList QMediaPlayer::supportedCustomAudioRoles() const
be possible, but without an audio or video component.
\value NetworkError A network error occurred.
\value AccessDeniedError There are not the appropriate permissions to play a media resource.
- \value ServiceMissingError A valid playback service was not found, playback cannot proceed.
- \omitvalue MediaIsPlaylist
*/
-// Signals
/*!
- \fn QMediaPlayer::error(QMediaPlayer::Error error)
+ \qmlsignal QtMultimedia::MediaPlayer::errorOccurred(error, errorString)
- Signals that an \a error condition has occurred.
+ This signal is emitted when an \a error has occurred. The \a errorString
+ parameter may contain more detailed information about the error.
- \sa errorString()
+ \sa QMediaPlayer::Error
*/
/*!
- \fn void QMediaPlayer::stateChanged(State state)
+ \fn QMediaPlayer::errorOccurred(QMediaPlayer::Error error, const QString &errorString)
+
+ Signals that an \a error condition has occurred, with \a errorString
+ containing a description of the error.
- Signal the \a state of the Player object has changed.
+ \sa errorString()
*/
/*!
@@ -1332,19 +1186,9 @@ QStringList QMediaPlayer::supportedCustomAudioRoles() const
*/
/*!
- \fn void QMediaPlayer::mediaChanged(const QMediaContent &media);
+ \fn void QMediaPlayer::sourceChanged(const QUrl &media);
Signals that the media source has been changed to \a media.
-
- \sa media(), currentMediaChanged()
-*/
-
-/*!
- \fn void QMediaPlayer::currentMediaChanged(const QMediaContent &media);
-
- Signals that the current playing content has been changed to \a media.
-
- \sa currentMedia(), mediaChanged()
*/
/*!
@@ -1359,33 +1203,8 @@ QStringList QMediaPlayer::supportedCustomAudioRoles() const
Signals the \a seekable status of the player object has changed.
*/
-/*!
- \fn void QMediaPlayer::audioRoleChanged(QAudio::Role role)
-
- Signals that the audio \a role of the media player has changed.
-
- \since 5.6
-*/
-
-/*!
- \fn void QMediaPlayer::customAudioRoleChanged(const QString &role)
-
- Signals that the audio \a role of the media player has changed.
-
- \since 5.11
-*/
-
// Properties
/*!
- \property QMediaPlayer::state
- \brief the media player's playback state.
-
- By default this property is QMediaPlayer::Stopped
-
- \sa mediaStatus(), play(), pause(), stop()
-*/
-
-/*!
\property QMediaPlayer::error
\brief a string describing the last error condition.
@@ -1393,50 +1212,22 @@ QStringList QMediaPlayer::supportedCustomAudioRoles() const
*/
/*!
- \property QMediaPlayer::media
+ \property QMediaPlayer::source
\brief the active media source being used by the player object.
- The player object will use the QMediaContent for selection of the content to
+ The player object will use the QUrl for selection of the content to
be played.
- By default this property has a null QMediaContent.
+ By default this property has a null QUrl.
- Setting this property to a null QMediaContent will cause the player to discard all
+ Setting this property 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.
- \sa QMediaContent, currentMedia()
+ \sa QUrl
*/
/*!
- \property QMediaPlayer::currentMedia
- \brief the current active media content being played by the player object.
- This value could be different from QMediaPlayer::media property if a playlist is used.
- In this case currentMedia indicates the current media content being processed
- by the player, while QMediaPlayer::media property contains the original playlist.
-
- \sa QMediaContent, media()
-*/
-
-/*!
- \property QMediaPlayer::playlist
- \brief the media playlist being used by the player object.
-
- The player object will use the current playlist item for selection of the content to
- be played.
-
- By default this property is set to null.
-
- If the media playlist is used as a source, QMediaPlayer::currentMedia is updated with
- a current playlist item. The current source should be selected with
- QMediaPlaylist::setCurrentIndex(int) instead of QMediaPlayer::setMedia(),
- otherwise the current playlist will be discarded.
-
- \sa QMediaContent
-*/
-
-
-/*!
\property QMediaPlayer::mediaStatus
\brief the status of the current media stream.
@@ -1445,7 +1236,15 @@ QStringList QMediaPlayer::supportedCustomAudioRoles() const
By default this property is QMediaPlayer::NoMedia
- \sa state
+*/
+
+/*!
+ \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}.
*/
/*!
@@ -1459,40 +1258,47 @@ QStringList QMediaPlayer::supportedCustomAudioRoles() const
*/
/*!
- \property QMediaPlayer::position
- \brief the playback position of the current media.
+ \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 signal positionChanged(), the interval between updates
- can be set with QMediaObject's method setNotifyInterval().
+ indicated with the positionChanged() signal.
+
+ If the \l seekable property is true, this property can be set to milliseconds.
*/
/*!
- \property QMediaPlayer::volume
- \brief the current playback volume.
-
- The playback volume is scaled linearly, ranging from \c 0 (silence) to \c 100 (full volume).
- Values outside this range will be clamped.
+ \property QMediaPlayer::position
+ \brief the playback position of the current media.
- By default the volume is \c 100.
+ 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.
- UI volume controls should usually be scaled nonlinearly. 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.
+ If the \l seekable property is true, this property can be set to milliseconds.
*/
/*!
- \property QMediaPlayer::muted
- \brief the muted state of the current media.
+ \qmlproperty real QtMultimedia::MediaPlayer::bufferProgress
- The value will be true if the playback volume is muted; otherwise false.
-*/
+ 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::bufferStatus
+ \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%
@@ -1504,24 +1310,9 @@ QStringList QMediaPlayer::supportedCustomAudioRoles() const
*/
/*!
- \property QMediaPlayer::audioAvailable
- \brief the audio availabilty status for the current media.
-
- As the life time of QMediaPlayer can be longer than the playback of one
- QMediaContent, this property may change over time, the
- audioAvailableChanged signal can be used to monitor it's status.
-*/
-
-/*!
- \property QMediaPlayer::videoAvailable
- \brief the video availability status for the current media.
+ \qmlproperty bool QtMultimedia::MediaPlayer::seekable
- If available, the QVideoWidget class can be used to view the video. As the
- life time of QMediaPlayer can be longer than the playback of one
- QMediaContent, this property may change over time, the
- videoAvailableChanged signal can be used to monitor it's status.
-
- \sa QVideoWidget, QMediaContent
+ This property holds whether the \l position of the media can be changed.
*/
/*!
@@ -1534,108 +1325,77 @@ QStringList QMediaPlayer::supportedCustomAudioRoles() const
*/
/*!
- \property QMediaPlayer::playbackRate
- \brief the playback rate of the current media.
+ \qmlproperty bool QtMultimedia::MediaPlayer::playing
+ \since 6.5
- 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.
+ Indicates whether the media is currently playing.
- Not all playback services support change of the playback rate. It is
- framework defined as to the status and quality of audio and video
- while fast forwarding or rewinding.
+ \sa playbackState
*/
/*!
- \property QMediaPlayer::audioRole
- \brief the role of the audio stream played by the media player.
+ \property QMediaPlayer::playing
+ \brief Whether the media is playing.
+ \since 6.5
- It can be set to specify the type of audio being played, allowing the system to make
- appropriate decisions when it comes to volume, routing or post-processing.
-
- The audio role must be set before calling setMedia().
-
- customAudioRole is cleared when this property is set to anything other than
- QAudio::CustomRole.
-
- \since 5.6
- \sa supportedAudioRoles()
+ \sa playbackState, PlayingState
*/
/*!
- \property QMediaPlayer::customAudioRole
- \brief the role of the audio stream played by the media player.
-
- It can be set to specify the type of audio being played when the backend supports
- audio roles unknown to Qt. Specifying a role allows the system to make appropriate
- decisions when it comes to volume, routing or post-processing.
+ \qmlproperty real QtMultimedia::MediaPlayer::playbackRate
- The audio role must be set before calling setMedia().
+ This property holds the rate at which media is played at as a multiple of
+ the normal rate.
- audioRole is set to QAudio::CustomRole when this property is set.
+ For more information, see \l{QMediaPlayer::playbackRate}.
- \since 5.11
- \sa supportedCustomAudioRoles()
+ Defaults to \c{1.0}.
*/
/*!
- \fn void QMediaPlayer::durationChanged(qint64 duration)
-
- Signal the duration of the content has changed to \a duration, expressed in milliseconds.
-*/
+ \property QMediaPlayer::playbackRate
+ \brief the playback rate of the current media.
-/*!
- \fn void QMediaPlayer::positionChanged(qint64 position)
+ 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.
- Signal the position of the content has changed to \a position, expressed in
- milliseconds.
+ Not all playback services support change of the playback rate. It is
+ framework defined as to the status and quality of audio and video
+ while fast forwarding or rewinding.
*/
/*!
- \fn void QMediaPlayer::volumeChanged(int volume)
+ \fn void QMediaPlayer::durationChanged(qint64 duration)
- Signal the playback volume has changed to \a volume.
+ Signals the duration of the content has changed to \a duration, expressed in milliseconds.
*/
/*!
- \fn void QMediaPlayer::mutedChanged(bool muted)
+ \fn void QMediaPlayer::positionChanged(qint64 position)
- Signal the mute state has changed to \a muted.
+ Signals the position of the content has changed to \a position, expressed in
+ milliseconds.
*/
/*!
- \fn void QMediaPlayer::videoAvailableChanged(bool videoAvailable)
+ \fn void QMediaPlayer::hasVideoChanged(bool videoAvailable)
- Signal the availability of visual content has changed to \a videoAvailable.
+ Signals the availability of visual content has changed to \a videoAvailable.
*/
/*!
- \fn void QMediaPlayer::audioAvailableChanged(bool available)
+ \fn void QMediaPlayer::hasAudioChanged(bool available)
Signals the availability of audio content has changed to \a available.
*/
/*!
- \fn void QMediaPlayer::bufferStatusChanged(int percentFilled)
-
- Signal the amount of the local buffer filled as a percentage by \a percentFilled.
-*/
-
-/*!
- \enum QMediaPlayer::Flag
-
- \value LowLatency The player is expected to be used with simple audio formats,
- but playback should start without significant delay.
- Such playback service can be used for beeps, ringtones, etc.
-
- \value StreamPlayback The player is expected to play QIODevice based streams.
- If passed to QMediaPlayer constructor, the service supporting
- streams playback will be chosen.
+ \fn void QMediaPlayer::bufferProgressChanged(float filled)
- \value VideoSurface The player is expected to be able to render to a
- QAbstractVideoSurface \l {setVideoOutput()}{output}.
+ Signals the amount of the local buffer \a filled as a number between 0 and 1.
*/
QT_END_NAMESPACE
diff --git a/src/multimedia/playback/qmediaplayer.h b/src/multimedia/playback/qmediaplayer.h
index 66a60b508..e0d1fec75 100644
--- a/src/multimedia/playback/qmediaplayer.h
+++ b/src/multimedia/playback/qmediaplayer.h
@@ -1,95 +1,69 @@
-/****************************************************************************
-**
-** 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
+#include <QtCore/qobject.h>
+#include <QtCore/qurl.h>
#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qmediaobject.h>
-#include <QtMultimedia/qmediacontent.h>
#include <QtMultimedia/qmediaenumdebug.h>
-#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qtaudio.h>
QT_BEGIN_NAMESPACE
-
-class QAbstractVideoSurface;
-class QMediaPlaylist;
-class QVideoWidget;
-class QGraphicsVideoItem;
+class QVideoSink;
+class QAudioOutput;
+class QAudioDevice;
+class QMediaMetaData;
+class QMediaTimeRange;
+class QAudioBufferOutput;
class QMediaPlayerPrivate;
-class Q_MULTIMEDIA_EXPORT QMediaPlayer : public QMediaObject
+class Q_MULTIMEDIA_EXPORT QMediaPlayer : public QObject
{
Q_OBJECT
- Q_PROPERTY(QMediaContent media READ media WRITE setMedia NOTIFY mediaChanged)
- Q_PROPERTY(QMediaContent currentMedia READ currentMedia NOTIFY currentMediaChanged)
- Q_PROPERTY(QMediaPlaylist* playlist READ playlist WRITE setPlaylist)
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged)
Q_PROPERTY(qint64 position READ position WRITE setPosition NOTIFY positionChanged)
- Q_PROPERTY(int volume READ volume WRITE setVolume NOTIFY volumeChanged)
- Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
- Q_PROPERTY(int bufferStatus READ bufferStatus NOTIFY bufferStatusChanged)
- Q_PROPERTY(bool audioAvailable READ isAudioAvailable NOTIFY audioAvailableChanged)
- Q_PROPERTY(bool videoAvailable READ isVideoAvailable NOTIFY videoAvailableChanged)
+ Q_PROPERTY(float bufferProgress READ bufferProgress NOTIFY bufferProgressChanged)
+ 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(State state READ state NOTIFY stateChanged)
+ 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(QAudio::Role audioRole READ audioRole WRITE setAudioRole NOTIFY audioRoleChanged)
- Q_PROPERTY(QString customAudioRole READ customAudioRole WRITE setCustomAudioRole NOTIFY customAudioRoleChanged)
- Q_PROPERTY(QString error READ errorString)
- Q_ENUMS(State)
- Q_ENUMS(MediaStatus)
- Q_ENUMS(Error)
+ Q_PROPERTY(QMediaMetaData metaData READ metaData NOTIFY metaDataChanged)
+ Q_PROPERTY(Error error READ error NOTIFY errorChanged)
+ Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged)
+ Q_PROPERTY(QObject *videoOutput READ videoOutput WRITE setVideoOutput NOTIFY videoOutputChanged)
+ Q_PROPERTY(QAudioOutput *audioOutput READ audioOutput WRITE setAudioOutput NOTIFY
+ audioOutputChanged)
+
+ Q_PROPERTY(QList<QMediaMetaData> audioTracks READ audioTracks NOTIFY tracksChanged)
+ Q_PROPERTY(QList<QMediaMetaData> videoTracks READ videoTracks NOTIFY tracksChanged)
+ Q_PROPERTY(QList<QMediaMetaData> subtitleTracks READ subtitleTracks NOTIFY tracksChanged)
+
+ Q_PROPERTY(int activeAudioTrack READ activeAudioTrack WRITE setActiveAudioTrack NOTIFY
+ activeTracksChanged)
+ Q_PROPERTY(int activeVideoTrack READ activeVideoTrack WRITE setActiveVideoTrack NOTIFY
+ activeTracksChanged)
+ Q_PROPERTY(int activeSubtitleTrack READ activeSubtitleTrack WRITE setActiveSubtitleTrack NOTIFY
+ activeTracksChanged)
public:
- enum State
+ enum PlaybackState
{
StoppedState,
PlayingState,
PausedState
};
+ Q_ENUM(PlaybackState)
enum MediaStatus
{
- UnknownMediaStatus,
NoMedia,
LoadingMedia,
LoadedMedia,
@@ -99,14 +73,7 @@ public:
EndOfMedia,
InvalidMedia
};
-
- enum Flag
- {
- LowLatency = 0x01,
- StreamPlayback = 0x02,
- VideoSurface = 0x04
- };
- Q_DECLARE_FLAGS(Flags, Flag)
+ Q_ENUM(MediaStatus)
enum Error
{
@@ -114,56 +81,72 @@ public:
ResourceError,
FormatError,
NetworkError,
- AccessDeniedError,
- ServiceMissingError,
- MediaIsPlaylist
+ AccessDeniedError
};
+ Q_ENUM(Error)
- explicit QMediaPlayer(QObject *parent = nullptr, Flags flags = Flags());
+ enum Loops
+ {
+ Infinite = -1,
+ Once = 1
+ };
+ Q_ENUM(Loops)
+
+ explicit QMediaPlayer(QObject *parent = nullptr);
~QMediaPlayer();
- static QMultimedia::SupportEstimate hasSupport(const QString &mimeType,
- const QStringList& codecs = QStringList(),
- Flags flags = Flags());
- static QStringList supportedMimeTypes(Flags flags = Flags());
+ QList<QMediaMetaData> audioTracks() const;
+ QList<QMediaMetaData> videoTracks() const;
+ QList<QMediaMetaData> subtitleTracks() const;
+
+ int activeAudioTrack() const;
+ int activeVideoTrack() const;
+ int activeSubtitleTrack() const;
+
+ void setActiveAudioTrack(int index);
+ void setActiveVideoTrack(int index);
+ void setActiveSubtitleTrack(int index);
- void setVideoOutput(QVideoWidget *);
- void setVideoOutput(QGraphicsVideoItem *);
- void setVideoOutput(QAbstractVideoSurface *surface);
- void setVideoOutput(const QList<QAbstractVideoSurface *> &surfaces);
+ void setAudioBufferOutput(QAudioBufferOutput *output);
+ QAudioBufferOutput *audioBufferOutput() const;
- QMediaContent media() const;
- const QIODevice *mediaStream() const;
- QMediaPlaylist *playlist() const;
- QMediaContent currentMedia() const;
+ void setAudioOutput(QAudioOutput *output);
+ QAudioOutput *audioOutput() const;
- State state() const;
+ void setVideoOutput(QObject *);
+ QObject *videoOutput() const;
+
+ void setVideoSink(QVideoSink *sink);
+ QVideoSink *videoSink() const;
+
+ QUrl source() const;
+ const QIODevice *sourceDevice() const;
+
+ PlaybackState playbackState() const;
MediaStatus mediaStatus() const;
qint64 duration() const;
qint64 position() const;
- int volume() const;
- bool isMuted() const;
- bool isAudioAvailable() const;
- bool isVideoAvailable() const;
+ bool hasAudio() const;
+ bool hasVideo() const;
- int bufferStatus() const;
+ float bufferProgress() const;
+ QMediaTimeRange bufferedTimeRange() const;
bool isSeekable() const;
qreal playbackRate() const;
+ bool isPlaying() const;
+
+ int loops() const;
+ void setLoops(int loops);
+
Error error() const;
QString errorString() const;
- QMultimedia::AvailabilityStatus availability() const override;
-
- QAudio::Role audioRole() const;
- void setAudioRole(QAudio::Role audioRole);
- QList<QAudio::Role> supportedAudioRoles() const;
- QString customAudioRole() const;
- void setCustomAudioRole(const QString &audioRole);
- QStringList supportedCustomAudioRoles() const;
+ bool isAvailable() const;
+ QMediaMetaData metaData() const;
public Q_SLOTS:
void play();
@@ -171,63 +154,50 @@ public Q_SLOTS:
void stop();
void setPosition(qint64 position);
- void setVolume(int volume);
- void setMuted(bool muted);
void setPlaybackRate(qreal rate);
- void setMedia(const QMediaContent &media, QIODevice *stream = nullptr);
- void setPlaylist(QMediaPlaylist *playlist);
+ void setSource(const QUrl &source);
+ void setSourceDevice(QIODevice *device, const QUrl &sourceUrl = QUrl());
Q_SIGNALS:
- void mediaChanged(const QMediaContent &media);
- void currentMediaChanged(const QMediaContent &media);
-
- void stateChanged(QMediaPlayer::State newState);
+ void sourceChanged(const QUrl &media);
+ void playbackStateChanged(QMediaPlayer::PlaybackState newState);
void mediaStatusChanged(QMediaPlayer::MediaStatus status);
void durationChanged(qint64 duration);
void positionChanged(qint64 position);
- void volumeChanged(int volume);
- void mutedChanged(bool muted);
- void audioAvailableChanged(bool available);
- void videoAvailableChanged(bool videoAvailable);
+ void hasAudioChanged(bool available);
+ void hasVideoChanged(bool videoAvailable);
- void bufferStatusChanged(int percentFilled);
+ void bufferProgressChanged(float progress);
void seekableChanged(bool seekable);
+ void playingChanged(bool playing);
void playbackRateChanged(qreal rate);
+ void loopsChanged();
- void audioRoleChanged(QAudio::Role role);
- void customAudioRoleChanged(const QString &role);
+ void metaDataChanged();
+ void videoOutputChanged();
+ void audioOutputChanged();
+ void audioBufferOutputChanged();
- void error(QMediaPlayer::Error error);
+ void tracksChanged();
+ void activeTracksChanged();
-public:
- bool bind(QObject *) override;
- void unbind(QObject *) override;
+ void errorChanged();
+ void errorOccurred(QMediaPlayer::Error error, const QString &errorString);
private:
Q_DISABLE_COPY(QMediaPlayer)
Q_DECLARE_PRIVATE(QMediaPlayer)
- Q_PRIVATE_SLOT(d_func(), void _q_stateChanged(QMediaPlayer::State))
- Q_PRIVATE_SLOT(d_func(), void _q_mediaStatusChanged(QMediaPlayer::MediaStatus))
- Q_PRIVATE_SLOT(d_func(), void _q_error(int, const QString &))
- Q_PRIVATE_SLOT(d_func(), void _q_updateMedia(const QMediaContent&))
- Q_PRIVATE_SLOT(d_func(), void _q_playlistDestroyed())
- Q_PRIVATE_SLOT(d_func(), void _q_handleMediaChanged(const QMediaContent&))
- Q_PRIVATE_SLOT(d_func(), void _q_handlePlaylistLoaded())
- Q_PRIVATE_SLOT(d_func(), void _q_handlePlaylistLoadFailed())
+ friend class QPlatformMediaPlayer;
};
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QMediaPlayer::State)
-Q_DECLARE_METATYPE(QMediaPlayer::MediaStatus)
-Q_DECLARE_METATYPE(QMediaPlayer::Error)
-
-Q_MEDIA_ENUM_DEBUG(QMediaPlayer, State)
+Q_MEDIA_ENUM_DEBUG(QMediaPlayer, PlaybackState)
Q_MEDIA_ENUM_DEBUG(QMediaPlayer, MediaStatus)
Q_MEDIA_ENUM_DEBUG(QMediaPlayer, Error)
diff --git a/src/multimedia/playback/qmediaplayer_p.h b/src/multimedia/playback/qmediaplayer_p.h
new file mode 100644
index 000000000..3d32d4e68
--- /dev/null
+++ b/src/multimedia/playback/qmediaplayer_p.h
@@ -0,0 +1,90 @@
+// 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
+
+//
+// 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 "qmediaplayer.h"
+#include "qmediametadata.h"
+#include "qvideosink.h"
+#include "qaudiooutput.h"
+#include "qaudiobufferoutput.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/qurl.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qtimer.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+class QPlatformMediaPlayer;
+
+class QMediaPlayerPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QMediaPlayer)
+
+public:
+ static QMediaPlayerPrivate *get(QMediaPlayer *session)
+ {
+ return reinterpret_cast<QMediaPlayerPrivate *>(QObjectPrivate::get(session));
+ }
+
+ QMediaPlayerPrivate() = default;
+ QPlatformMediaPlayer *control = nullptr;
+
+ QPointer<QAudioBufferOutput> audioBufferOutput;
+ QPointer<QAudioOutput> audioOutput;
+ QPointer<QVideoSink> videoSink;
+ QPointer<QObject> videoOutput;
+ QUrl qrcMedia;
+ std::unique_ptr<QFile> qrcFile;
+ QUrl source;
+ QIODevice *stream = nullptr;
+
+ QMediaPlayer::PlaybackState state = QMediaPlayer::StoppedState;
+ QErrorInfo<QMediaPlayer::Error> error;
+
+ void setMedia(const QUrl &media, QIODevice *stream = nullptr);
+
+ QList<QMediaMetaData> trackMetaData(QPlatformMediaPlayer::TrackType s) const;
+
+ void setState(QMediaPlayer::PlaybackState state);
+ void setStatus(QMediaPlayer::MediaStatus status);
+ void setError(QMediaPlayer::Error error, const QString &errorString);
+
+ void setVideoSink(QVideoSink *sink)
+ {
+ Q_Q(QMediaPlayer);
+ if (sink == videoSink)
+ return;
+ if (videoSink)
+ videoSink->setSource(nullptr);
+ videoSink = sink;
+ if (sink)
+ sink->setSource(q);
+ if (control)
+ control->setVideoSink(sink);
+ emit q->videoOutputChanged();
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/playback/qmediaplaylist.cpp b/src/multimedia/playback/qmediaplaylist.cpp
deleted file mode 100644
index 9539a1809..000000000
--- a/src/multimedia/playback/qmediaplaylist.cpp
+++ /dev/null
@@ -1,824 +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 "qmediaplaylist.h"
-#include "qmediaplaylist_p.h"
-#include "qmediaplaylistprovider_p.h"
-#include "qmediaplaylistioplugin_p.h"
-#include "qmedianetworkplaylistprovider_p.h"
-#include "qmediaservice.h"
-#include "qmediaplaylistcontrol_p.h"
-#include "qmediaplayercontrol.h"
-
-#include <QtCore/qlist.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qurl.h>
-#include <QtCore/qcoreevent.h>
-#include <QtCore/qcoreapplication.h>
-
-#include "qmediapluginloader_p.h"
-
-QT_BEGIN_NAMESPACE
-
-Q_GLOBAL_STATIC_WITH_ARGS(QMediaPluginLoader, playlistIOLoader,
- (QMediaPlaylistIOInterface_iid, QLatin1String("playlistformats"), Qt::CaseInsensitive))
-
-static void qRegisterMediaPlaylistMetaTypes()
-{
- qRegisterMetaType<QMediaPlaylist::Error>();
- qRegisterMetaType<QMediaPlaylist::PlaybackMode>();
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterMediaPlaylistMetaTypes)
-
-
-/*!
- \class QMediaPlaylist
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_playback
-
-
- \brief The QMediaPlaylist class provides a list of media content to play.
-
- QMediaPlaylist is intended to be used with other media objects,
- like QMediaPlayer.
-
- QMediaPlaylist allows to access the service intrinsic playlist functionality
- if available, otherwise it provides the local memory playlist implementation.
-
- \snippet multimedia-snippets/media.cpp Movie playlist
-
- Depending on playlist source implementation, most of the playlist mutating
- operations can be asynchronous.
-
- \sa QMediaContent
-*/
-
-
-/*!
- \enum QMediaPlaylist::PlaybackMode
-
- The QMediaPlaylist::PlaybackMode describes the order items in playlist are played.
-
- \value CurrentItemOnce The current item is played only once.
-
- \value CurrentItemInLoop The current item is played repeatedly in a loop.
-
- \value Sequential Playback starts from the current and moves through each successive item until the last is reached and then stops.
- The next item is a null item when the last one is currently playing.
-
- \value Loop Playback restarts at the first item after the last has finished playing.
-
- \value Random Play items in random order.
-*/
-
-
-
-/*!
- Create a new playlist object with the given \a parent.
-*/
-
-QMediaPlaylist::QMediaPlaylist(QObject *parent)
- : QObject(parent)
- , d_ptr(new QMediaPlaylistPrivate)
-{
- Q_D(QMediaPlaylist);
-
- d->q_ptr = this;
- d->networkPlaylistControl = new QMediaNetworkPlaylistControl(this);
-
- setMediaObject(nullptr);
-}
-
-/*!
- Destroys the playlist.
- */
-
-QMediaPlaylist::~QMediaPlaylist()
-{
- Q_D(QMediaPlaylist);
-
- if (d->mediaObject)
- d->mediaObject->unbind(this);
-
- delete d_ptr;
-}
-
-/*!
- Returns the QMediaObject instance that this QMediaPlaylist is bound too,
- or 0 otherwise.
-*/
-QMediaObject *QMediaPlaylist::mediaObject() const
-{
- return d_func()->mediaObject;
-}
-
-/*!
- \internal
- If \a mediaObject is null or doesn't have an intrinsic playlist,
- internal local memory playlist source will be created.
-*/
-bool QMediaPlaylist::setMediaObject(QMediaObject *mediaObject)
-{
- Q_D(QMediaPlaylist);
-
- if (mediaObject && mediaObject == d->mediaObject)
- return true;
-
- QMediaService *service = mediaObject
- ? mediaObject->service() : nullptr;
-
- QMediaPlaylistControl *newControl = nullptr;
-
- if (service)
- newControl = qobject_cast<QMediaPlaylistControl*>(service->requestControl(QMediaPlaylistControl_iid));
-
- if (!newControl)
- newControl = d->networkPlaylistControl;
-
- if (d->control != newControl) {
- int removedStart = -1;
- int removedEnd = -1;
- int insertedStart = -1;
- int insertedEnd = -1;
-
- if (d->control) {
- QMediaPlaylistProvider *playlist = d->control->playlistProvider();
- disconnect(playlist, SIGNAL(loadFailed(QMediaPlaylist::Error,QString)),
- this, SLOT(_q_loadFailed(QMediaPlaylist::Error,QString)));
-
- disconnect(playlist, &QMediaPlaylistProvider::mediaChanged, this, &QMediaPlaylist::mediaChanged);
- disconnect(playlist, &QMediaPlaylistProvider::mediaAboutToBeInserted, this, &QMediaPlaylist::mediaAboutToBeInserted);
- disconnect(playlist, &QMediaPlaylistProvider::mediaInserted, this, &QMediaPlaylist::mediaInserted);
- disconnect(playlist, &QMediaPlaylistProvider::mediaAboutToBeRemoved, this, &QMediaPlaylist::mediaAboutToBeRemoved);
- disconnect(playlist, &QMediaPlaylistProvider::mediaRemoved, this, &QMediaPlaylist::mediaRemoved);
-
- disconnect(playlist, &QMediaPlaylistProvider::loaded, this, &QMediaPlaylist::loaded);
-
- disconnect(d->control, &QMediaPlaylistControl::playbackModeChanged,
- this, &QMediaPlaylist::playbackModeChanged);
- disconnect(d->control, &QMediaPlaylistControl::currentIndexChanged,
- this, &QMediaPlaylist::currentIndexChanged);
- disconnect(d->control, &QMediaPlaylistControl::currentMediaChanged,
- this, &QMediaPlaylist::currentMediaChanged);
-
- // Copy playlist items, sync playback mode and sync current index between
- // old control and new control
- d->syncControls(d->control, newControl,
- &removedStart, &removedEnd,
- &insertedStart, &insertedEnd);
-
- if (d->mediaObject)
- d->mediaObject->service()->releaseControl(d->control);
- }
-
- d->control = newControl;
- QMediaPlaylistProvider *playlist = d->control->playlistProvider();
- connect(playlist, SIGNAL(loadFailed(QMediaPlaylist::Error,QString)),
- this, SLOT(_q_loadFailed(QMediaPlaylist::Error,QString)));
-
- connect(playlist, &QMediaPlaylistProvider::mediaChanged, this, &QMediaPlaylist::mediaChanged);
- connect(playlist, &QMediaPlaylistProvider::mediaAboutToBeInserted, this, &QMediaPlaylist::mediaAboutToBeInserted);
- connect(playlist, &QMediaPlaylistProvider::mediaInserted, this, &QMediaPlaylist::mediaInserted);
- connect(playlist, &QMediaPlaylistProvider::mediaAboutToBeRemoved, this, &QMediaPlaylist::mediaAboutToBeRemoved);
- connect(playlist, &QMediaPlaylistProvider::mediaRemoved, this, &QMediaPlaylist::mediaRemoved);
-
- connect(playlist, &QMediaPlaylistProvider::loaded, this, &QMediaPlaylist::loaded);
-
- connect(d->control, &QMediaPlaylistControl::playbackModeChanged,
- this, &QMediaPlaylist::playbackModeChanged);
- connect(d->control, &QMediaPlaylistControl::currentIndexChanged,
- this, &QMediaPlaylist::currentIndexChanged);
- connect(d->control, &QMediaPlaylistControl::currentMediaChanged,
- this, &QMediaPlaylist::currentMediaChanged);
-
- if (removedStart != -1 && removedEnd != -1) {
- emit mediaAboutToBeRemoved(removedStart, removedEnd);
- emit mediaRemoved(removedStart, removedEnd);
- }
-
- if (insertedStart != -1 && insertedEnd != -1) {
- emit mediaAboutToBeInserted(insertedStart, insertedEnd);
- emit mediaInserted(insertedStart, insertedEnd);
- }
- }
-
- d->mediaObject = mediaObject;
-
- return true;
-}
-
-/*!
- \property QMediaPlaylist::playbackMode
-
- This property defines the order that items in the playlist are played.
-
- \sa QMediaPlaylist::PlaybackMode
-*/
-
-QMediaPlaylist::PlaybackMode QMediaPlaylist::playbackMode() const
-{
- return d_func()->control->playbackMode();
-}
-
-void QMediaPlaylist::setPlaybackMode(QMediaPlaylist::PlaybackMode mode)
-{
- Q_D(QMediaPlaylist);
- d->control->setPlaybackMode(mode);
-}
-
-/*!
- Returns position of the current media content in the playlist.
-*/
-int QMediaPlaylist::currentIndex() const
-{
- return d_func()->control->currentIndex();
-}
-
-/*!
- Returns the current media content.
-*/
-
-QMediaContent QMediaPlaylist::currentMedia() const
-{
- return d_func()->playlist()->media(currentIndex());
-}
-
-/*!
- Returns the index of the item, which would be current after calling next()
- \a steps times.
-
- Returned value depends on the size of playlist, current position
- and playback mode.
-
- \sa QMediaPlaylist::playbackMode(), previousIndex()
-*/
-int QMediaPlaylist::nextIndex(int steps) const
-{
- return d_func()->control->nextIndex(steps);
-}
-
-/*!
- Returns the index of the item, which would be current after calling previous()
- \a steps times.
-
- \sa QMediaPlaylist::playbackMode(), nextIndex()
-*/
-
-int QMediaPlaylist::previousIndex(int steps) const
-{
- return d_func()->control->previousIndex(steps);
-}
-
-
-/*!
- Returns the number of items in the playlist.
-
- \sa isEmpty()
- */
-int QMediaPlaylist::mediaCount() const
-{
- return d_func()->playlist()->mediaCount();
-}
-
-/*!
- Returns true if the playlist contains no items, otherwise returns false.
-
- \sa mediaCount()
- */
-bool QMediaPlaylist::isEmpty() const
-{
- return mediaCount() == 0;
-}
-
-/*!
- Returns true if the playlist can be modified, otherwise returns false.
-
- \sa mediaCount()
- */
-bool QMediaPlaylist::isReadOnly() const
-{
- return d_func()->playlist()->isReadOnly();
-}
-
-/*!
- Returns the media content at \a index in the playlist.
-*/
-
-QMediaContent QMediaPlaylist::media(int index) const
-{
- return d_func()->playlist()->media(index);
-}
-
-/*!
- Append the media \a content to the playlist.
-
- Returns true if the operation is successful, otherwise returns false.
- */
-bool QMediaPlaylist::addMedia(const QMediaContent &content)
-{
- return d_func()->control->playlistProvider()->addMedia(content);
-}
-
-/*!
- Append multiple media content \a items to the playlist.
-
- Returns true if the operation is successful, otherwise returns false.
- */
-bool QMediaPlaylist::addMedia(const QList<QMediaContent> &items)
-{
- return d_func()->control->playlistProvider()->addMedia(items);
-}
-
-/*!
- Insert the media \a content to the playlist at position \a pos.
-
- Returns true if the operation is successful, otherwise returns false.
-*/
-
-bool QMediaPlaylist::insertMedia(int pos, const QMediaContent &content)
-{
- QMediaPlaylistProvider *playlist = d_func()->playlist();
- return playlist->insertMedia(qBound(0, pos, playlist->mediaCount()), content);
-}
-
-/*!
- Insert multiple media content \a items to the playlist at position \a pos.
-
- Returns true if the operation is successful, otherwise returns false.
-*/
-
-bool QMediaPlaylist::insertMedia(int pos, const QList<QMediaContent> &items)
-{
- QMediaPlaylistProvider *playlist = d_func()->playlist();
- return playlist->insertMedia(qBound(0, pos, playlist->mediaCount()), items);
-}
-
-/*!
- Move the item from position \a from to position \a to.
-
- Returns true if the operation is successful, otherwise false.
-
- \since 5.7
-*/
-bool QMediaPlaylist::moveMedia(int from, int to)
-{
- QMediaPlaylistProvider *playlist = d_func()->playlist();
- return playlist->moveMedia(qBound(0, from, playlist->mediaCount()),
- qBound(0, to, playlist->mediaCount()));
-}
-
-/*!
- Remove the item from the playlist at position \a pos.
-
- Returns true if the operation is successful, otherwise return false.
- */
-bool QMediaPlaylist::removeMedia(int pos)
-{
- QMediaPlaylistProvider *playlist = d_func()->playlist();
- if (pos >= 0 && pos < playlist->mediaCount())
- return playlist->removeMedia(pos);
- else
- return false;
-}
-
-/*!
- Remove items in the playlist from \a start to \a end inclusive.
-
- Returns true if the operation is successful, otherwise return false.
- */
-bool QMediaPlaylist::removeMedia(int start, int end)
-{
- QMediaPlaylistProvider *playlist = d_func()->playlist();
- start = qMax(0, start);
- end = qMin(end, playlist->mediaCount() - 1);
- if (start <= end)
- return playlist->removeMedia(start, end);
- else
- return false;
-}
-
-/*!
- Remove all the items from the playlist.
-
- Returns true if the operation is successful, otherwise return false.
- */
-bool QMediaPlaylist::clear()
-{
- Q_D(QMediaPlaylist);
- return d->playlist()->clear();
-}
-
-bool QMediaPlaylistPrivate::readItems(QMediaPlaylistReader *reader)
-{
- QList<QMediaContent> items;
-
- while (!reader->atEnd())
- items.append(reader->readItem());
-
- return playlist()->addMedia(items);
-}
-
-bool QMediaPlaylistPrivate::writeItems(QMediaPlaylistWriter *writer)
-{
- for (int i=0; i<playlist()->mediaCount(); i++) {
- if (!writer->writeItem(playlist()->media(i)))
- return false;
- }
- writer->close();
- return true;
-}
-
-/*!
- * \internal
- * Copy playlist items, sync playback mode and sync current index between old control and new control
-*/
-void QMediaPlaylistPrivate::syncControls(QMediaPlaylistControl *oldControl, QMediaPlaylistControl *newControl,
- int *removedStart, int *removedEnd,
- int *insertedStart, int *insertedEnd)
-{
- Q_ASSERT(oldControl != NULL && newControl != NULL);
- Q_ASSERT(removedStart != NULL && removedEnd != NULL
- && insertedStart != NULL && insertedEnd != NULL);
-
- QMediaPlaylistProvider *oldPlaylist = oldControl->playlistProvider();
- QMediaPlaylistProvider *newPlaylist = newControl->playlistProvider();
-
- Q_ASSERT(oldPlaylist != NULL && newPlaylist != NULL);
-
- *removedStart = -1;
- *removedEnd = -1;
- *insertedStart = -1;
- *insertedEnd = -1;
-
- if (newPlaylist->isReadOnly()) {
- // we can't transfer the items from the old control.
- // Report these items as removed.
- if (oldPlaylist->mediaCount() > 0) {
- *removedStart = 0;
- *removedEnd = oldPlaylist->mediaCount() - 1;
- }
- // The new control might have some items that can't be cleared.
- // Report these as inserted.
- if (newPlaylist->mediaCount() > 0) {
- *insertedStart = 0;
- *insertedEnd = newPlaylist->mediaCount() - 1;
- }
- } else {
- const int oldPlaylistSize = oldPlaylist->mediaCount();
-
- newPlaylist->clear();
- for (int i = 0; i < oldPlaylistSize; ++i)
- newPlaylist->addMedia(oldPlaylist->media(i));
- }
-
- newControl->setPlaybackMode(oldControl->playbackMode());
- newControl->setCurrentIndex(oldControl->currentIndex());
-}
-
-/*!
- Load playlist using network \a request. If \a format is specified, it is used,
- otherwise format is guessed from playlist name and data.
-
- New items are appended to playlist.
-
- QMediaPlaylist::loaded() signal is emitted if playlist was loaded successfully,
- otherwise the playlist emits loadFailed().
-*/
-void QMediaPlaylist::load(const QNetworkRequest &request, const char *format)
-{
- Q_D(QMediaPlaylist);
-
- d->error = NoError;
- d->errorString.clear();
-
- if (d->playlist()->load(request,format))
- return;
-
- if (isReadOnly()) {
- d->error = AccessDeniedError;
- d->errorString = tr("Could not add items to read only playlist.");
- emit loadFailed();
- return;
- }
-
- const auto keys = playlistIOLoader()->keys();
- for (QString const& key : keys) {
- QMediaPlaylistIOInterface* plugin = qobject_cast<QMediaPlaylistIOInterface*>(playlistIOLoader()->instance(key));
- if (plugin && plugin->canRead(request.url(), format)) {
- QMediaPlaylistReader *reader = plugin->createReader(request.url(), QByteArray(format));
- if (reader && d->readItems(reader)) {
- delete reader;
- emit loaded();
- return;
- }
- delete reader;
- }
- }
-
- d->error = FormatNotSupportedError;
- d->errorString = tr("Playlist format is not supported");
- emit loadFailed();
-
- return;
-}
-
-/*!
- Load playlist from \a location. If \a format is specified, it is used,
- otherwise format is guessed from location name and data.
-
- New items are appended to playlist.
-
- QMediaPlaylist::loaded() signal is emitted if playlist was loaded successfully,
- otherwise the playlist emits loadFailed().
-*/
-
-void QMediaPlaylist::load(const QUrl &location, const char *format)
-{
- load(QNetworkRequest(location), format);
-}
-
-/*!
- Load playlist from QIODevice \a device. If \a format is specified, it is used,
- otherwise format is guessed from device data.
-
- New items are appended to playlist.
-
- QMediaPlaylist::loaded() signal is emitted if playlist was loaded successfully,
- otherwise the playlist emits loadFailed().
-*/
-void QMediaPlaylist::load(QIODevice * device, const char *format)
-{
- Q_D(QMediaPlaylist);
-
- d->error = NoError;
- d->errorString.clear();
-
- if (d->playlist()->load(device,format))
- return;
-
- if (isReadOnly()) {
- d->error = AccessDeniedError;
- d->errorString = tr("Could not add items to read only playlist.");
- emit loadFailed();
- return;
- }
-
- const auto keys = playlistIOLoader()->keys();
- for (QString const& key : keys) {
- QMediaPlaylistIOInterface* plugin = qobject_cast<QMediaPlaylistIOInterface*>(playlistIOLoader()->instance(key));
- if (plugin && plugin->canRead(device,format)) {
- QMediaPlaylistReader *reader = plugin->createReader(device,QByteArray(format));
- if (reader && d->readItems(reader)) {
- delete reader;
- emit loaded();
- return;
- }
- delete reader;
- }
- }
-
- d->error = FormatNotSupportedError;
- d->errorString = tr("Playlist format is not supported");
- emit loadFailed();
-
- return;
-}
-
-/*!
- Save playlist to \a location. If \a format is specified, it is used,
- otherwise format is guessed from location name.
-
- Returns true if playlist was saved successfully, otherwise returns false.
- */
-bool QMediaPlaylist::save(const QUrl &location, const char *format)
-{
- Q_D(QMediaPlaylist);
-
- d->error = NoError;
- d->errorString.clear();
-
- if (d->playlist()->save(location,format))
- return true;
-
- QFile file(location.toLocalFile());
-
- if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
- d->error = AccessDeniedError;
- d->errorString = tr("The file could not be accessed.");
- return false;
- }
-
- return save(&file, format);
-}
-
-/*!
- Save playlist to QIODevice \a device using format \a format.
-
- Returns true if playlist was saved successfully, otherwise returns false.
-*/
-bool QMediaPlaylist::save(QIODevice * device, const char *format)
-{
- Q_D(QMediaPlaylist);
-
- d->error = NoError;
- d->errorString.clear();
-
- if (d->playlist()->save(device,format))
- return true;
-
- const auto keys = playlistIOLoader()->keys();
- for (QString const& key : keys) {
- QMediaPlaylistIOInterface* plugin = qobject_cast<QMediaPlaylistIOInterface*>(playlistIOLoader()->instance(key));
- if (plugin && plugin->canWrite(device,format)) {
- QMediaPlaylistWriter *writer = plugin->createWriter(device,QByteArray(format));
- if (writer && d->writeItems(writer)) {
- delete writer;
- return true;
- }
- delete writer;
- }
- }
-
- d->error = FormatNotSupportedError;
- d->errorString = tr("Playlist format is not supported.");
-
- return false;
-}
-
-/*!
- Returns the last error condition.
-*/
-QMediaPlaylist::Error QMediaPlaylist::error() const
-{
- return d_func()->error;
-}
-
-/*!
- Returns the string describing the last error condition.
-*/
-QString QMediaPlaylist::errorString() const
-{
- return d_func()->errorString;
-}
-
-/*!
- Shuffle items in the playlist.
-*/
-void QMediaPlaylist::shuffle()
-{
- d_func()->playlist()->shuffle();
-}
-
-
-/*!
- Advance to the next media content in playlist.
-*/
-void QMediaPlaylist::next()
-{
- d_func()->control->next();
-}
-
-/*!
- Return to the previous media content in playlist.
-*/
-void QMediaPlaylist::previous()
-{
- d_func()->control->previous();
-}
-
-/*!
- Activate media content from playlist at position \a playlistPosition.
-*/
-
-void QMediaPlaylist::setCurrentIndex(int playlistPosition)
-{
- d_func()->control->setCurrentIndex(playlistPosition);
-}
-
-/*!
- \fn void QMediaPlaylist::mediaInserted(int start, int end)
-
- This signal is emitted after media has been inserted into the playlist.
- The new items are those between \a start and \a end inclusive.
- */
-
-/*!
- \fn void QMediaPlaylist::mediaRemoved(int start, int end)
-
- This signal is emitted after media has been removed from the playlist.
- The removed items are those between \a start and \a end inclusive.
- */
-
-/*!
- \fn void QMediaPlaylist::mediaChanged(int start, int end)
-
- This signal is emitted after media has been changed in the playlist
- between \a start and \a end positions inclusive.
- */
-
-/*!
- \fn void QMediaPlaylist::currentIndexChanged(int position)
-
- Signal emitted when playlist position changed to \a position.
-*/
-
-/*!
- \fn void QMediaPlaylist::playbackModeChanged(QMediaPlaylist::PlaybackMode mode)
-
- Signal emitted when playback mode changed to \a mode.
-*/
-
-/*!
- \fn void QMediaPlaylist::mediaAboutToBeInserted(int start, int end)
-
- Signal emitted when items are to be inserted at \a start and ending at \a end.
-*/
-
-/*!
- \fn void QMediaPlaylist::mediaAboutToBeRemoved(int start, int end)
-
- Signal emitted when item are to be deleted at \a start and ending at \a end.
-*/
-
-/*!
- \fn void QMediaPlaylist::currentMediaChanged(const QMediaContent &content)
-
- Signal emitted when current media changes to \a content.
-*/
-
-/*!
- \property QMediaPlaylist::currentIndex
- \brief Current position.
-*/
-
-/*!
- \property QMediaPlaylist::currentMedia
- \brief Current media content.
-*/
-
-/*!
- \fn QMediaPlaylist::loaded()
-
- Signal emitted when playlist finished loading.
-*/
-
-/*!
- \fn QMediaPlaylist::loadFailed()
-
- Signal emitted if failed to load playlist.
-*/
-
-/*!
- \enum QMediaPlaylist::Error
-
- This enum describes the QMediaPlaylist error codes.
-
- \value NoError No errors.
- \value FormatError Format error.
- \value FormatNotSupportedError Format not supported.
- \value NetworkError Network error.
- \value AccessDeniedError Access denied error.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qmediaplaylist.cpp"
-#include "moc_qmediaplaylist_p.cpp"
diff --git a/src/multimedia/playback/qmediaplaylist.h b/src/multimedia/playback/qmediaplaylist.h
deleted file mode 100644
index 4eb93bd02..000000000
--- a/src/multimedia/playback/qmediaplaylist.h
+++ /dev/null
@@ -1,148 +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 QMEDIAPLAYLIST_H
-#define QMEDIAPLAYLIST_H
-
-#include <QtCore/qobject.h>
-
-#include <QtMultimedia/qmediacontent.h>
-#include <QtMultimedia/qmediaobject.h>
-#include <QtMultimedia/qmediabindableinterface.h>
-#include <QtMultimedia/qmediaenumdebug.h>
-
-
-QT_BEGIN_NAMESPACE
-
-
-class QMediaPlaylistProvider;
-
-class QMediaPlaylistPrivate;
-class Q_MULTIMEDIA_EXPORT QMediaPlaylist : public QObject, public QMediaBindableInterface
-{
- Q_OBJECT
- Q_INTERFACES(QMediaBindableInterface)
- Q_PROPERTY(QMediaPlaylist::PlaybackMode playbackMode READ playbackMode WRITE setPlaybackMode NOTIFY playbackModeChanged)
- Q_PROPERTY(QMediaContent currentMedia READ currentMedia NOTIFY currentMediaChanged)
- Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
- Q_ENUMS(PlaybackMode Error)
-
-public:
- enum PlaybackMode { CurrentItemOnce, CurrentItemInLoop, Sequential, Loop, Random };
- enum Error { NoError, FormatError, FormatNotSupportedError, NetworkError, AccessDeniedError };
-
- explicit QMediaPlaylist(QObject *parent = nullptr);
- virtual ~QMediaPlaylist();
-
- QMediaObject *mediaObject() const override;
-
- PlaybackMode playbackMode() const;
- void setPlaybackMode(PlaybackMode mode);
-
- int currentIndex() const;
- QMediaContent currentMedia() const;
-
- int nextIndex(int steps = 1) const;
- int previousIndex(int steps = 1) const;
-
- QMediaContent media(int index) const;
-
- int mediaCount() const;
- bool isEmpty() const;
- bool isReadOnly() const;
-
- bool addMedia(const QMediaContent &content);
- bool addMedia(const QList<QMediaContent> &items);
- bool insertMedia(int index, const QMediaContent &content);
- bool insertMedia(int index, const QList<QMediaContent> &items);
- bool moveMedia(int from, int to);
- bool removeMedia(int pos);
- bool removeMedia(int start, int end);
- bool clear();
-
- void load(const QNetworkRequest &request, const char *format = nullptr);
- void load(const QUrl &location, const char *format = nullptr);
- void load(QIODevice *device, const char *format = nullptr);
-
- bool save(const QUrl &location, const char *format = nullptr);
- bool save(QIODevice * device, const char *format);
-
- Error error() const;
- QString errorString() const;
-
-public Q_SLOTS:
- void shuffle();
-
- void next();
- void previous();
-
- void setCurrentIndex(int index);
-
-Q_SIGNALS:
- void currentIndexChanged(int index);
- void playbackModeChanged(QMediaPlaylist::PlaybackMode mode);
- void currentMediaChanged(const QMediaContent&);
-
- void mediaAboutToBeInserted(int start, int end);
- void mediaInserted(int start, int end);
- void mediaAboutToBeRemoved(int start, int end);
- void mediaRemoved(int start, int end);
- void mediaChanged(int start, int end);
-
- void loaded();
- void loadFailed();
-
-protected:
- bool setMediaObject(QMediaObject *object) override;
- QMediaPlaylistPrivate *d_ptr;
-
-private:
- Q_DECLARE_PRIVATE(QMediaPlaylist)
- Q_PRIVATE_SLOT(d_func(), void _q_loadFailed(QMediaPlaylist::Error, const QString &))
-};
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QMediaPlaylist::PlaybackMode)
-Q_DECLARE_METATYPE(QMediaPlaylist::Error)
-
-Q_MEDIA_ENUM_DEBUG(QMediaPlaylist, PlaybackMode)
-Q_MEDIA_ENUM_DEBUG(QMediaPlaylist, Error)
-
-#endif // QMEDIAPLAYLIST_H
diff --git a/src/multimedia/playback/qmediaplaylist_p.h b/src/multimedia/playback/qmediaplaylist_p.h
deleted file mode 100644
index 16fce00a9..000000000
--- a/src/multimedia/playback/qmediaplaylist_p.h
+++ /dev/null
@@ -1,173 +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 QMEDIAPLAYLIST_P_H
-#define QMEDIAPLAYLIST_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 "qmediaplaylist.h"
-#include "qmediaplaylistcontrol_p.h"
-#include "qmediaplayer.h"
-#include "qmediaplayercontrol.h"
-#include "qmedianetworkplaylistprovider_p.h"
-#include "qmediaobject_p.h"
-
-#include <QtCore/qdebug.h>
-
-#ifdef Q_MOC_RUN
-# pragma Q_MOC_EXPAND_MACROS
-#endif
-
-QT_BEGIN_NAMESPACE
-
-
-class QMediaPlaylistControl;
-class QMediaPlaylistProvider;
-class QMediaPlaylistReader;
-class QMediaPlaylistWriter;
-class QMediaPlayerControl;
-
-class QMediaPlaylistPrivate
-{
- Q_DECLARE_PUBLIC(QMediaPlaylist)
-public:
- QMediaPlaylistPrivate()
- :mediaObject(nullptr),
- control(nullptr),
- networkPlaylistControl(nullptr),
- error(QMediaPlaylist::NoError)
- {
- }
-
- virtual ~QMediaPlaylistPrivate() {}
-
- void _q_loadFailed(QMediaPlaylist::Error error, const QString &errorString)
- {
- this->error = error;
- this->errorString = errorString;
-
- emit q_ptr->loadFailed();
- }
-
- void _q_mediaObjectDeleted()
- {
- Q_Q(QMediaPlaylist);
- mediaObject = nullptr;
- if (control != networkPlaylistControl)
- control = nullptr;
- q->setMediaObject(nullptr);
- }
-
- QMediaObject *mediaObject;
-
- QMediaPlaylistControl *control;
- QMediaPlaylistProvider *playlist() const { return control->playlistProvider(); }
-
- QMediaPlaylistControl *networkPlaylistControl;
-
- bool readItems(QMediaPlaylistReader *reader);
- bool writeItems(QMediaPlaylistWriter *writer);
-
- void syncControls(QMediaPlaylistControl *oldControl, QMediaPlaylistControl *newControl,
- int *removedStart, int *removedEnd,
- int *insertedStart, int *insertedEnd);
-
- QMediaPlaylist::Error error;
- QString errorString;
-
- QMediaPlaylist *q_ptr;
-};
-
-
-class QMediaNetworkPlaylistControl : public QMediaPlaylistControl
-{
- Q_OBJECT
-public:
- QMediaNetworkPlaylistControl(QObject *parent)
- :QMediaPlaylistControl(parent)
- {
- QMediaPlaylistProvider *playlist = new QMediaNetworkPlaylistProvider(this);
- m_navigator = new QMediaPlaylistNavigator(playlist,this);
- m_navigator->setPlaybackMode(QMediaPlaylist::Sequential);
-
- connect(m_navigator, SIGNAL(currentIndexChanged(int)), SIGNAL(currentIndexChanged(int)));
- connect(m_navigator, SIGNAL(activated(QMediaContent)), SIGNAL(currentMediaChanged(QMediaContent)));
- connect(m_navigator, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)), SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)));
- }
-
- ~QMediaNetworkPlaylistControl() {}
-
- QMediaPlaylistProvider* playlistProvider() const override { return m_navigator->playlist(); }
- bool setPlaylistProvider(QMediaPlaylistProvider *mediaPlaylist) override
- {
- m_navigator->setPlaylist(mediaPlaylist);
- emit playlistProviderChanged();
- return true;
- }
-
- int currentIndex() const override { return m_navigator->currentIndex(); }
- void setCurrentIndex(int position) override { m_navigator->jump(position); }
- int nextIndex(int steps) const override { return m_navigator->nextIndex(steps); }
- int previousIndex(int steps) const override { return m_navigator->previousIndex(steps); }
-
- void next() override { m_navigator->next(); }
- void previous() override { m_navigator->previous(); }
-
- QMediaPlaylist::PlaybackMode playbackMode() const override { return m_navigator->playbackMode(); }
- void setPlaybackMode(QMediaPlaylist::PlaybackMode mode) override { m_navigator->setPlaybackMode(mode); }
-
-private:
- QMediaPlaylistNavigator *m_navigator;
-};
-
-
-QT_END_NAMESPACE
-
-
-#endif // QMEDIAPLAYLIST_P_H
diff --git a/src/multimedia/playback/qmediaplaylistioplugin.cpp b/src/multimedia/playback/qmediaplaylistioplugin.cpp
deleted file mode 100644
index 957c7c79d..000000000
--- a/src/multimedia/playback/qmediaplaylistioplugin.cpp
+++ /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$
-**
-****************************************************************************/
-
-#include "qmediaplaylistioplugin_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QMediaPlaylistReader
- \internal
-
- \brief The QMediaPlaylistReader class provides an interface for reading a playlist file.
- \inmodule QtMultimedia
-
- \ingroup multimedia
- \ingroup multimedia_playback
-
- \sa QMediaPlaylistIOPlugin
-*/
-
-/*!
- Destroys a media playlist reader.
-*/
-QMediaPlaylistReader::~QMediaPlaylistReader()
-{
-}
-
-/*!
- \fn QMediaPlaylistReader::atEnd() const
-
- Identifies if a playlist reader has reached the end of its input.
-
- Returns true if the reader has reached the end; and false otherwise.
-*/
-
-/*!
- \fn QMediaPlaylistReader::readItem()
-
- Reads an item of media from a playlist file.
-
- Returns the read media, or a null QMediaContent if no more media is available.
-*/
-
-/*!
- \fn QMediaPlaylistReader::close()
-
- Closes a playlist reader's input device.
-*/
-
-/*!
- \class QMediaPlaylistWriter
- \internal
-
- \brief The QMediaPlaylistWriter class provides an interface for writing a playlist file.
-
- \sa QMediaPlaylistIOPlugin
-*/
-
-/*!
- Destroys a media playlist writer.
-*/
-QMediaPlaylistWriter::~QMediaPlaylistWriter()
-{
-}
-
-/*!
- \fn QMediaPlaylistWriter::writeItem(const QMediaContent &media)
-
- Writes an item of \a media to a playlist file.
-
- Returns true if the media was written successfully; and false otherwise.
-*/
-
-/*!
- \fn QMediaPlaylistWriter::close()
-
- Finalizes the writing of a playlist and closes the output device.
-*/
-
-/*!
- \class QMediaPlaylistIOPlugin
- \internal
-
- \brief The QMediaPlaylistIOPlugin class provides an interface for media playlist I/O plug-ins.
-*/
-
-/*!
- Constructs a media playlist I/O plug-in with the given \a parent.
-*/
-QMediaPlaylistIOPlugin::QMediaPlaylistIOPlugin(QObject *parent)
- :QObject(parent)
-{
-}
-
-/*!
- Destroys a media playlist I/O plug-in.
-*/
-QMediaPlaylistIOPlugin::~QMediaPlaylistIOPlugin()
-{
-}
-
-/*!
- \fn QMediaPlaylistIOPlugin::canRead(QIODevice *device, const QByteArray &format) const
-
- Identifies if plug-in can read \a format data from an I/O \a device.
-
- Returns true if the data can be read; and false otherwise.
-*/
-
-/*!
- \fn QMediaPlaylistIOPlugin::canRead(const QUrl& location, const QByteArray &format) const
-
- Identifies if a plug-in can read \a format data from a URL \a location.
-
- Returns true if the data can be read; and false otherwise.
-*/
-
-/*!
- \fn QMediaPlaylistIOPlugin::canWrite(QIODevice *device, const QByteArray &format) const
-
- Identifies if a plug-in can write \a format data to an I/O \a device.
-
- Returns true if the data can be written; and false otherwise.
-*/
-
-/*!
- \fn QMediaPlaylistIOPlugin::createReader(QIODevice *device, const QByteArray &format)
-
- Returns a new QMediaPlaylistReader which reads \a format data from an I/O \a device.
-
- If the device is invalid or the format is unsupported this will return a null pointer.
-*/
-
-/*!
- \fn QMediaPlaylistIOPlugin::createReader(const QUrl& location, const QByteArray &format)
-
- Returns a new QMediaPlaylistReader which reads \a format data from a URL \a location.
-
- If the location or the format is unsupported this will return a null pointer.
-*/
-
-/*!
- \fn QMediaPlaylistIOPlugin::createWriter(QIODevice *device, const QByteArray &format)
-
- Returns a new QMediaPlaylistWriter which writes \a format data to an I/O \a device.
-
- If the device is invalid or the format is unsupported this will return a null pointer.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qmediaplaylistioplugin_p.cpp"
diff --git a/src/multimedia/playback/qmediaplaylistioplugin_p.h b/src/multimedia/playback/qmediaplaylistioplugin_p.h
deleted file mode 100644
index 153679958..000000000
--- a/src/multimedia/playback/qmediaplaylistioplugin_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 QMEDIAPLAYLISTIOPLUGIN_P_H
-#define QMEDIAPLAYLISTIOPLUGIN_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 <QtCore/qplugin.h>
-
-#include <qtmultimediaglobal.h>
-
-#include "qmediacontent.h"
-
-QT_BEGIN_NAMESPACE
-
-class QString;
-class QUrl;
-class QByteArray;
-class QIODevice;
-
-class Q_MULTIMEDIA_EXPORT QMediaPlaylistReader
-{
-public:
- virtual ~QMediaPlaylistReader();
-
- virtual bool atEnd() const = 0;
- virtual QMediaContent readItem() = 0;
- virtual void close() = 0;
-};
-
-class Q_MULTIMEDIA_EXPORT QMediaPlaylistWriter
-{
-public:
- virtual ~QMediaPlaylistWriter();
-
- virtual bool writeItem(const QMediaContent &content) = 0;
- virtual void close() = 0;
-};
-
-struct Q_MULTIMEDIA_EXPORT QMediaPlaylistIOInterface
-{
- virtual bool canRead(QIODevice *device, const QByteArray &format = QByteArray() ) const = 0;
- virtual bool canRead(const QUrl& location, const QByteArray &format = QByteArray()) const = 0;
-
- virtual bool canWrite(QIODevice *device, const QByteArray &format) const = 0;
-
- virtual QMediaPlaylistReader *createReader(QIODevice *device, const QByteArray &format = QByteArray()) = 0;
- virtual QMediaPlaylistReader *createReader(const QUrl& location, const QByteArray &format = QByteArray()) = 0;
-
- virtual QMediaPlaylistWriter *createWriter(QIODevice *device, const QByteArray &format) = 0;
-};
-
-#define QMediaPlaylistIOInterface_iid "org.qt-project.qt.mediaplaylistio/5.0"
-Q_DECLARE_INTERFACE(QMediaPlaylistIOInterface, QMediaPlaylistIOInterface_iid);
-
-class Q_MULTIMEDIA_EXPORT QMediaPlaylistIOPlugin : public QObject, public QMediaPlaylistIOInterface
-{
-Q_OBJECT
-Q_INTERFACES(QMediaPlaylistIOInterface)
-public:
- explicit QMediaPlaylistIOPlugin(QObject *parent = nullptr);
- ~QMediaPlaylistIOPlugin();
-
- bool canRead(QIODevice *device, const QByteArray &format = QByteArray() ) const override = 0;
- bool canRead(const QUrl& location, const QByteArray &format = QByteArray()) const override = 0;
-
- bool canWrite(QIODevice *device, const QByteArray &format) const override = 0;
-
- QMediaPlaylistReader *createReader(QIODevice *device, const QByteArray &format = QByteArray()) override = 0;
- QMediaPlaylistReader *createReader(const QUrl& location, const QByteArray &format = QByteArray()) override = 0;
-
- QMediaPlaylistWriter *createWriter(QIODevice *device, const QByteArray &format) override = 0;
-};
-
-QT_END_NAMESPACE
-
-
-#endif // QMEDIAPLAYLISTIOPLUGIN_P_H
diff --git a/src/multimedia/playback/qmediaplaylistnavigator.cpp b/src/multimedia/playback/qmediaplaylistnavigator.cpp
deleted file mode 100644
index 9b25f968a..000000000
--- a/src/multimedia/playback/qmediaplaylistnavigator.cpp
+++ /dev/null
@@ -1,544 +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 "qmediaplaylistnavigator_p.h"
-#include "qmediaplaylistprovider_p.h"
-#include "qmediaplaylist.h"
-#include "qmediaobject_p.h"
-
-#include <QtCore/qdebug.h>
-#include <QtCore/qrandom.h>
-
-QT_BEGIN_NAMESPACE
-
-class QMediaPlaylistNullProvider : public QMediaPlaylistProvider
-{
-public:
- QMediaPlaylistNullProvider() :QMediaPlaylistProvider() {}
- ~QMediaPlaylistNullProvider() {}
- int mediaCount() const override {return 0;}
- QMediaContent media(int) const override { return QMediaContent(); }
-};
-
-Q_GLOBAL_STATIC(QMediaPlaylistNullProvider, _q_nullMediaPlaylist)
-
-class QMediaPlaylistNavigatorPrivate
-{
- Q_DECLARE_NON_CONST_PUBLIC(QMediaPlaylistNavigator)
-public:
- QMediaPlaylistNavigatorPrivate()
- :playlist(nullptr),
- currentPos(-1),
- lastValidPos(-1),
- playbackMode(QMediaPlaylist::Sequential),
- randomPositionsOffset(-1)
- {
- }
-
- QMediaPlaylistProvider *playlist;
- int currentPos;
- int lastValidPos; //to be used with CurrentItemOnce playback mode
- QMediaPlaylist::PlaybackMode playbackMode;
- QMediaContent currentItem;
-
- mutable QList<int> randomModePositions;
- mutable int randomPositionsOffset;
-
- int nextItemPos(int steps = 1) const;
- int previousItemPos(int steps = 1) const;
-
- void _q_mediaInserted(int start, int end);
- void _q_mediaRemoved(int start, int end);
- void _q_mediaChanged(int start, int end);
-
- QMediaPlaylistNavigator *q_ptr;
-};
-
-
-int QMediaPlaylistNavigatorPrivate::nextItemPos(int steps) const
-{
- if (playlist->mediaCount() == 0)
- return -1;
-
- if (steps == 0)
- return currentPos;
-
- switch (playbackMode) {
- case QMediaPlaylist::CurrentItemOnce:
- return /*currentPos == -1 ? lastValidPos :*/ -1;
- case QMediaPlaylist::CurrentItemInLoop:
- return currentPos;
- case QMediaPlaylist::Sequential:
- {
- int nextPos = currentPos+steps;
- return nextPos < playlist->mediaCount() ? nextPos : -1;
- }
- case QMediaPlaylist::Loop:
- return (currentPos+steps) % playlist->mediaCount();
- case QMediaPlaylist::Random:
- {
- //TODO: limit the history size
-
- if (randomPositionsOffset == -1) {
- randomModePositions.clear();
- randomModePositions.append(currentPos);
- randomPositionsOffset = 0;
- }
-
- while (randomModePositions.size() < randomPositionsOffset+steps+1)
- randomModePositions.append(-1);
- int res = randomModePositions[randomPositionsOffset+steps];
- if (res<0 || res >= playlist->mediaCount()) {
- res = QRandomGenerator::global()->bounded(playlist->mediaCount());
- randomModePositions[randomPositionsOffset+steps] = res;
- }
-
- return res;
- }
- }
-
- return -1;
-}
-
-int QMediaPlaylistNavigatorPrivate::previousItemPos(int steps) const
-{
- if (playlist->mediaCount() == 0)
- return -1;
-
- if (steps == 0)
- return currentPos;
-
- switch (playbackMode) {
- case QMediaPlaylist::CurrentItemOnce:
- return /*currentPos == -1 ? lastValidPos :*/ -1;
- case QMediaPlaylist::CurrentItemInLoop:
- return currentPos;
- case QMediaPlaylist::Sequential:
- {
- int prevPos = currentPos == -1 ? playlist->mediaCount() - steps : currentPos - steps;
- return prevPos>=0 ? prevPos : -1;
- }
- case QMediaPlaylist::Loop:
- {
- int prevPos = currentPos - steps;
- while (prevPos<0)
- prevPos += playlist->mediaCount();
- return prevPos;
- }
- case QMediaPlaylist::Random:
- {
- //TODO: limit the history size
-
- if (randomPositionsOffset == -1) {
- randomModePositions.clear();
- randomModePositions.append(currentPos);
- randomPositionsOffset = 0;
- }
-
- while (randomPositionsOffset-steps < 0) {
- randomModePositions.prepend(-1);
- randomPositionsOffset++;
- }
-
- int res = randomModePositions[randomPositionsOffset-steps];
- if (res<0 || res >= playlist->mediaCount()) {
- res = QRandomGenerator::global()->bounded(playlist->mediaCount());
- randomModePositions[randomPositionsOffset-steps] = res;
- }
-
- return res;
- }
- }
-
- return -1;
-}
-
-/*!
- \class QMediaPlaylistNavigator
- \internal
-
- \brief The QMediaPlaylistNavigator class provides navigation for a media playlist.
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_playback
-
- \sa QMediaPlaylist, QMediaPlaylistProvider
-*/
-
-
-/*!
- Constructs a media playlist navigator for a \a playlist.
-
- The \a parent is passed to QObject.
- */
-QMediaPlaylistNavigator::QMediaPlaylistNavigator(QMediaPlaylistProvider *playlist, QObject *parent)
- : QObject(parent)
- , d_ptr(new QMediaPlaylistNavigatorPrivate)
-{
- d_ptr->q_ptr = this;
-
- setPlaylist(playlist ? playlist : _q_nullMediaPlaylist());
-}
-
-/*!
- Destroys a media playlist navigator.
- */
-
-QMediaPlaylistNavigator::~QMediaPlaylistNavigator()
-{
- delete d_ptr;
-}
-
-
-/*! \property QMediaPlaylistNavigator::playbackMode
- Contains the playback mode.
- */
-QMediaPlaylist::PlaybackMode QMediaPlaylistNavigator::playbackMode() const
-{
- return d_func()->playbackMode;
-}
-
-/*!
- Sets the playback \a mode.
- */
-void QMediaPlaylistNavigator::setPlaybackMode(QMediaPlaylist::PlaybackMode mode)
-{
- Q_D(QMediaPlaylistNavigator);
- if (d->playbackMode == mode)
- return;
-
- if (mode == QMediaPlaylist::Random) {
- d->randomPositionsOffset = 0;
- d->randomModePositions.append(d->currentPos);
- } else if (d->playbackMode == QMediaPlaylist::Random) {
- d->randomPositionsOffset = -1;
- d->randomModePositions.clear();
- }
-
- d->playbackMode = mode;
-
- emit playbackModeChanged(mode);
- emit surroundingItemsChanged();
-}
-
-/*!
- Returns the playlist being navigated.
-*/
-
-QMediaPlaylistProvider *QMediaPlaylistNavigator::playlist() const
-{
- return d_func()->playlist;
-}
-
-/*!
- Sets the \a playlist to navigate.
-*/
-void QMediaPlaylistNavigator::setPlaylist(QMediaPlaylistProvider *playlist)
-{
- Q_D(QMediaPlaylistNavigator);
-
- if (d->playlist == playlist)
- return;
-
- if (d->playlist) {
- d->playlist->disconnect(this);
- }
-
- if (playlist) {
- d->playlist = playlist;
- } else {
- //assign to shared readonly null playlist
- d->playlist = _q_nullMediaPlaylist();
- }
-
- connect(d->playlist, SIGNAL(mediaInserted(int,int)), SLOT(_q_mediaInserted(int,int)));
- connect(d->playlist, SIGNAL(mediaRemoved(int,int)), SLOT(_q_mediaRemoved(int,int)));
- connect(d->playlist, SIGNAL(mediaChanged(int,int)), SLOT(_q_mediaChanged(int,int)));
-
- d->randomPositionsOffset = -1;
- d->randomModePositions.clear();
-
- if (d->currentPos != -1) {
- d->currentPos = -1;
- emit currentIndexChanged(-1);
- }
-
- if (!d->currentItem.isNull()) {
- d->currentItem = QMediaContent();
- emit activated(d->currentItem); //stop playback
- }
-}
-
-/*! \property QMediaPlaylistNavigator::currentItem
-
- Contains the media at the current position in the playlist.
-
- \sa currentIndex()
-*/
-
-QMediaContent QMediaPlaylistNavigator::currentItem() const
-{
- return itemAt(d_func()->currentPos);
-}
-
-/*! \fn QMediaContent QMediaPlaylistNavigator::nextItem(int steps) const
-
- Returns the media that is \a steps positions ahead of the current
- position in the playlist.
-
- \sa nextIndex()
-*/
-QMediaContent QMediaPlaylistNavigator::nextItem(int steps) const
-{
- return itemAt(nextIndex(steps));
-}
-
-/*!
- Returns the media that is \a steps positions behind the current
- position in the playlist.
-
- \sa previousIndex()
- */
-QMediaContent QMediaPlaylistNavigator::previousItem(int steps) const
-{
- return itemAt(previousIndex(steps));
-}
-
-/*!
- Returns the media at a \a position in the playlist.
- */
-QMediaContent QMediaPlaylistNavigator::itemAt(int position) const
-{
- return d_func()->playlist->media(position);
-}
-
-/*! \property QMediaPlaylistNavigator::currentIndex
-
- Contains the position of the current media.
-
- If no media is current, the property contains -1.
-
- \sa nextIndex(), previousIndex()
-*/
-
-int QMediaPlaylistNavigator::currentIndex() const
-{
- return d_func()->currentPos;
-}
-
-/*!
- Returns a position \a steps ahead of the current position
- accounting for the playbackMode().
-
- If the position is beyond the end of the playlist, this value
- returned is -1.
-
- \sa currentIndex(), previousIndex(), playbackMode()
-*/
-
-int QMediaPlaylistNavigator::nextIndex(int steps) const
-{
- return d_func()->nextItemPos(steps);
-}
-
-/*!
-
- Returns a position \a steps behind the current position accounting
- for the playbackMode().
-
- If the position is prior to the beginning of the playlist this will
- return -1.
-
- \sa currentIndex(), nextIndex(), playbackMode()
-*/
-int QMediaPlaylistNavigator::previousIndex(int steps) const
-{
- return d_func()->previousItemPos(steps);
-}
-
-/*!
- Advances to the next item in the playlist.
-
- \sa previous(), jump(), playbackMode()
- */
-void QMediaPlaylistNavigator::next()
-{
- Q_D(QMediaPlaylistNavigator);
-
- int nextPos = d->nextItemPos();
-
- if ( playbackMode() == QMediaPlaylist::Random )
- d->randomPositionsOffset++;
-
- jump(nextPos);
-}
-
-/*!
- Returns to the previous item in the playlist,
-
- \sa next(), jump(), playbackMode()
- */
-void QMediaPlaylistNavigator::previous()
-{
- Q_D(QMediaPlaylistNavigator);
-
- int prevPos = d->previousItemPos();
- if ( playbackMode() == QMediaPlaylist::Random )
- d->randomPositionsOffset--;
-
- jump(prevPos);
-}
-
-/*!
- Jumps to a new \a position in the playlist.
- */
-void QMediaPlaylistNavigator::jump(int position)
-{
- Q_D(QMediaPlaylistNavigator);
-
- if (position < -1 || position >= d->playlist->mediaCount())
- position = -1;
-
- if (position != -1)
- d->lastValidPos = position;
-
- if (playbackMode() == QMediaPlaylist::Random) {
- if (d->randomModePositions[d->randomPositionsOffset] != position) {
- d->randomModePositions.clear();
- d->randomModePositions.append(position);
- d->randomPositionsOffset = 0;
- }
- }
-
- if (position != -1)
- d->currentItem = d->playlist->media(position);
- else
- d->currentItem = QMediaContent();
-
- if (position != d->currentPos) {
- d->currentPos = position;
- emit currentIndexChanged(d->currentPos);
- emit surroundingItemsChanged();
- }
-
- emit activated(d->currentItem);
-}
-
-/*!
- \internal
-*/
-void QMediaPlaylistNavigatorPrivate::_q_mediaInserted(int start, int end)
-{
- Q_Q(QMediaPlaylistNavigator);
-
- if (currentPos >= start) {
- currentPos = end-start+1;
- q->jump(currentPos);
- }
-
- //TODO: check if they really changed
- emit q->surroundingItemsChanged();
-}
-
-/*!
- \internal
-*/
-void QMediaPlaylistNavigatorPrivate::_q_mediaRemoved(int start, int end)
-{
- Q_Q(QMediaPlaylistNavigator);
-
- if (currentPos > end) {
- currentPos = currentPos - end-start+1;
- q->jump(currentPos);
- } else if (currentPos >= start) {
- //current item was removed
- currentPos = qMin(start, playlist->mediaCount()-1);
- q->jump(currentPos);
- }
-
- //TODO: check if they really changed
- emit q->surroundingItemsChanged();
-}
-
-/*!
- \internal
-*/
-void QMediaPlaylistNavigatorPrivate::_q_mediaChanged(int start, int end)
-{
- Q_Q(QMediaPlaylistNavigator);
-
- if (currentPos >= start && currentPos<=end) {
- QMediaContent src = playlist->media(currentPos);
- if (src != currentItem) {
- currentItem = src;
- emit q->activated(src);
- }
- }
-
- //TODO: check if they really changed
- emit q->surroundingItemsChanged();
-}
-
-/*!
- \fn QMediaPlaylistNavigator::activated(const QMediaContent &media)
-
- Signals that the current \a media has changed.
-*/
-
-/*!
- \fn QMediaPlaylistNavigator::currentIndexChanged(int position)
-
- Signals the \a position of the current media has changed.
-*/
-
-/*!
- \fn QMediaPlaylistNavigator::playbackModeChanged(QMediaPlaylist::PlaybackMode mode)
-
- Signals that the playback \a mode has changed.
-*/
-
-/*!
- \fn QMediaPlaylistNavigator::surroundingItemsChanged()
-
- Signals that media immediately surrounding the current position has changed.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qmediaplaylistnavigator_p.cpp"
diff --git a/src/multimedia/playback/qmediaplaylistnavigator_p.h b/src/multimedia/playback/qmediaplaylistnavigator_p.h
deleted file mode 100644
index 2ac03a62c..000000000
--- a/src/multimedia/playback/qmediaplaylistnavigator_p.h
+++ /dev/null
@@ -1,118 +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 QMEDIAPLAYLISTNAVIGATOR_P_H
-#define QMEDIAPLAYLISTNAVIGATOR_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 "qmediaplaylistprovider_p.h"
-#include "qmediaplaylist.h"
-#include <QtCore/qobject.h>
-
-QT_BEGIN_NAMESPACE
-
-
-class QMediaPlaylistNavigatorPrivate;
-class Q_MULTIMEDIA_EXPORT QMediaPlaylistNavigator : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(QMediaPlaylist::PlaybackMode playbackMode READ playbackMode WRITE setPlaybackMode NOTIFY playbackModeChanged)
- Q_PROPERTY(int currentIndex READ currentIndex WRITE jump NOTIFY currentIndexChanged)
- Q_PROPERTY(QMediaContent currentItem READ currentItem)
-
-public:
- QMediaPlaylistNavigator(QMediaPlaylistProvider *playlist, QObject *parent = nullptr);
- virtual ~QMediaPlaylistNavigator();
-
- QMediaPlaylistProvider *playlist() const;
- void setPlaylist(QMediaPlaylistProvider *playlist);
-
- QMediaPlaylist::PlaybackMode playbackMode() const;
-
- QMediaContent currentItem() const;
- QMediaContent nextItem(int steps = 1) const;
- QMediaContent previousItem(int steps = 1) const;
-
- QMediaContent itemAt(int position) const;
-
- int currentIndex() const;
- int nextIndex(int steps = 1) const;
- int previousIndex(int steps = 1) const;
-
-public Q_SLOTS:
- void next();
- void previous();
-
- void jump(int);
-
- void setPlaybackMode(QMediaPlaylist::PlaybackMode mode);
-
-Q_SIGNALS:
- void activated(const QMediaContent &content);
- void currentIndexChanged(int);
- void playbackModeChanged(QMediaPlaylist::PlaybackMode mode);
-
- void surroundingItemsChanged();
-
-protected:
- QMediaPlaylistNavigatorPrivate *d_ptr;
-
-private:
- Q_DISABLE_COPY(QMediaPlaylistNavigator)
- Q_DECLARE_PRIVATE(QMediaPlaylistNavigator)
-
- Q_PRIVATE_SLOT(d_func(), void _q_mediaInserted(int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_mediaRemoved(int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_mediaChanged(int start, int end))
-};
-
-QT_END_NAMESPACE
-
-
-#endif // QMEDIAPLAYLISTNAVIGATOR_P_H
diff --git a/src/multimedia/playback/qmediaplaylistprovider.cpp b/src/multimedia/playback/qmediaplaylistprovider.cpp
deleted file mode 100644
index 8089a9320..000000000
--- a/src/multimedia/playback/qmediaplaylistprovider.cpp
+++ /dev/null
@@ -1,321 +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 "qmediaplaylistprovider_p.h"
-
-#include <QtCore/qurl.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QMediaPlaylistProvider
- \internal
-
- \brief The QMediaPlaylistProvider class provides an abstract list of media.
- \inmodule QtMultimedia
-
- \ingroup multimedia
- \ingroup multimedia_playback
-
- \sa QMediaPlaylist
-*/
-
-/*!
- Constructs a playlist provider with the given \a parent.
-*/
-QMediaPlaylistProvider::QMediaPlaylistProvider(QObject *parent)
- :QObject(parent), d_ptr(new QMediaPlaylistProviderPrivate)
-{
-}
-
-/*!
- \internal
-*/
-QMediaPlaylistProvider::QMediaPlaylistProvider(QMediaPlaylistProviderPrivate &dd, QObject *parent)
- :QObject(parent), d_ptr(&dd)
-{
-}
-
-/*!
- Destroys a playlist provider.
-*/
-QMediaPlaylistProvider::~QMediaPlaylistProvider()
-{
- delete d_ptr;
-}
-
-/*!
- \fn QMediaPlaylistProvider::mediaCount() const;
-
- Returns the size of playlist.
-*/
-
-/*!
- \fn QMediaPlaylistProvider::media(int index) const;
-
- Returns the media at \a index in the playlist.
-
- If the index is invalid this will return a null media content.
-*/
-
-
-/*!
- Loads a playlist using network \a request. If no playlist \a format is specified the loader
- will inspect the URL or probe the headers to guess the format.
-
- New items are appended to playlist.
-
- Returns true if the provider supports the format and loading from the locations URL protocol,
- otherwise this will return false.
-*/
-bool QMediaPlaylistProvider::load(const QNetworkRequest &request, const char *format)
-{
- Q_UNUSED(request);
- Q_UNUSED(format);
- return false;
-}
-
-/*!
- Loads a playlist from from an I/O \a device. If no playlist \a format is specified the loader
- will probe the headers to guess the format.
-
- New items are appended to playlist.
-
- Returns true if the provider supports the format and loading from an I/O device, otherwise this
- will return false.
-*/
-bool QMediaPlaylistProvider::load(QIODevice * device, const char *format)
-{
- Q_UNUSED(device);
- Q_UNUSED(format);
- return false;
-}
-
-/*!
- Saves the contents of a playlist to a URL \a location. If no playlist \a format is specified
- the writer will inspect the URL to guess the format.
-
- Returns true if the playlist was saved successfully; and false otherwise.
- */
-bool QMediaPlaylistProvider::save(const QUrl &location, const char *format)
-{
- Q_UNUSED(location);
- Q_UNUSED(format);
- return false;
-}
-
-/*!
- Saves the contents of a playlist to an I/O \a device in the specified \a format.
-
- Returns true if the playlist was saved successfully; and false otherwise.
-*/
-bool QMediaPlaylistProvider::save(QIODevice * device, const char *format)
-{
- Q_UNUSED(device);
- Q_UNUSED(format);
- return false;
-}
-
-/*!
- Returns true if a playlist is read-only; otherwise returns false.
-*/
-bool QMediaPlaylistProvider::isReadOnly() const
-{
- return true;
-}
-
-/*!
- Append \a media to a playlist.
-
- Returns true if the media was appended; and false otherwise.
-*/
-bool QMediaPlaylistProvider::addMedia(const QMediaContent &media)
-{
- Q_UNUSED(media);
- return false;
-}
-
-/*!
- Append multiple media \a items to a playlist.
-
- Returns true if the media items were appended; and false otherwise.
-*/
-bool QMediaPlaylistProvider::addMedia(const QList<QMediaContent> &items)
-{
- for (const QMediaContent &item : items) {
- if (!addMedia(item))
- return false;
- }
-
- return true;
-}
-
-/*!
- Inserts \a media into a playlist at \a position.
-
- Returns true if the media was inserted; and false otherwise.
-*/
-bool QMediaPlaylistProvider::insertMedia(int position, const QMediaContent &media)
-{
- Q_UNUSED(position);
- Q_UNUSED(media);
- return false;
-}
-
-/*!
- Inserts multiple media \a items into a playlist at \a position.
-
- Returns true if the media \a items were inserted; and false otherwise.
-*/
-bool QMediaPlaylistProvider::insertMedia(int position, const QList<QMediaContent> &items)
-{
- for (int i=0; i<items.count(); i++) {
- if (!insertMedia(position+i,items.at(i)))
- return false;
- }
-
- return true;
-}
-
-/*!
- Move the media from position \a from to position \a to.
-
- Returns true if the operation is successful, otherwise false.
-
- \since 5.7
-*/
-bool QMediaPlaylistProvider::moveMedia(int from, int to)
-{
- Q_UNUSED(from);
- Q_UNUSED(to);
-
- return false;
-}
-
-/*!
- Removes the media at \a position from a playlist.
-
- Returns true if the media was removed; and false otherwise.
-*/
-bool QMediaPlaylistProvider::removeMedia(int position)
-{
- Q_UNUSED(position);
- return false;
-}
-
-/*!
- Removes the media between the given \a start and \a end positions from a playlist.
-
- Returns true if the media was removed; and false otherwise.
- */
-bool QMediaPlaylistProvider::removeMedia(int start, int end)
-{
- for (int pos=end; pos>=start; pos--) {
- if (!removeMedia(pos))
- return false;
- }
-
- return true;
-}
-
-/*!
- Removes all media from a playlist.
-
- Returns true if the media was removed; and false otherwise.
-*/
-bool QMediaPlaylistProvider::clear()
-{
- return removeMedia(0, mediaCount()-1);
-}
-
-/*!
- Shuffles the contents of a playlist.
-*/
-void QMediaPlaylistProvider::shuffle()
-{
-}
-
-/*!
- \fn void QMediaPlaylistProvider::mediaAboutToBeInserted(int start, int end);
-
- Signals that new media is about to be inserted into a playlist between the \a start and \a end
- positions.
-*/
-
-/*!
- \fn void QMediaPlaylistProvider::mediaInserted(int start, int end);
-
- Signals that new media has been inserted into a playlist between the \a start and \a end
- positions.
-*/
-
-/*!
- \fn void QMediaPlaylistProvider::mediaAboutToBeRemoved(int start, int end);
-
- Signals that media is about to be removed from a playlist between the \a start and \a end
- positions.
-*/
-
-/*!
- \fn void QMediaPlaylistProvider::mediaRemoved(int start, int end);
-
- Signals that media has been removed from a playlist between the \a start and \a end positions.
-*/
-
-/*!
- \fn void QMediaPlaylistProvider::mediaChanged(int start, int end);
-
- Signals that media in playlist between the \a start and \a end positions inclusive has changed.
-*/
-
-/*!
- \fn void QMediaPlaylistProvider::loaded()
-
- Signals that a load() finished successfully.
-*/
-
-/*!
- \fn void QMediaPlaylistProvider::loadFailed(QMediaPlaylist::Error error, const QString& errorMessage)
-
- Signals that a load failed() due to an \a error. The \a errorMessage provides more information.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qmediaplaylistprovider_p.cpp"
diff --git a/src/multimedia/playback/qmediaplaylistprovider_p.h b/src/multimedia/playback/qmediaplaylistprovider_p.h
deleted file mode 100644
index ed27612b9..000000000
--- a/src/multimedia/playback/qmediaplaylistprovider_p.h
+++ /dev/null
@@ -1,122 +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 QMEDIAPLAYLISTPROVIDER_P_H
-#define QMEDIAPLAYLISTPROVIDER_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 "qmediacontent.h"
-#include "qmediaplaylist.h"
-
-QT_BEGIN_NAMESPACE
-
-
-class QMediaPlaylistProviderPrivate
-{
-public:
- QMediaPlaylistProviderPrivate()
- {}
- virtual ~QMediaPlaylistProviderPrivate()
- {}
-};
-
-class Q_MULTIMEDIA_EXPORT QMediaPlaylistProvider : public QObject
-{
-Q_OBJECT
-public:
- QMediaPlaylistProvider(QObject *parent = nullptr);
- virtual ~QMediaPlaylistProvider();
-
- virtual bool load(const QNetworkRequest &request, const char *format = nullptr);
- virtual bool load(QIODevice *device, const char *format = nullptr);
- virtual bool save(const QUrl &location, const char *format = nullptr);
- virtual bool save(QIODevice * device, const char *format);
-
- virtual int mediaCount() const = 0;
- virtual QMediaContent media(int index) const = 0;
-
- virtual bool isReadOnly() const;
-
- virtual bool addMedia(const QMediaContent &content);
- virtual bool addMedia(const QList<QMediaContent> &contentList);
- virtual bool insertMedia(int index, const QMediaContent &content);
- virtual bool insertMedia(int index, const QList<QMediaContent> &content);
- virtual bool moveMedia(int from, int to);
- virtual bool removeMedia(int pos);
- virtual bool removeMedia(int start, int end);
- virtual bool clear();
-
-public Q_SLOTS:
- virtual void shuffle();
-
-Q_SIGNALS:
- void mediaAboutToBeInserted(int start, int end);
- void mediaInserted(int start, int end);
-
- void mediaAboutToBeRemoved(int start, int end);
- void mediaRemoved(int start, int end);
-
- void mediaChanged(int start, int end);
-
- void loaded();
- void loadFailed(QMediaPlaylist::Error, const QString& errorMessage);
-
-protected:
- QMediaPlaylistProviderPrivate *d_ptr;
- QMediaPlaylistProvider(QMediaPlaylistProviderPrivate &dd, QObject *parent);
-
-private:
- Q_DECLARE_PRIVATE(QMediaPlaylistProvider)
-};
-
-QT_END_NAMESPACE
-
-
-
-#endif // QMEDIAPLAYLISTSOURCE_P_H
diff --git a/src/multimedia/playback/qplaylistfileparser.cpp b/src/multimedia/playback/qplaylistfileparser.cpp
deleted file mode 100644
index c1a423308..000000000
--- a/src/multimedia/playback/qplaylistfileparser.cpp
+++ /dev/null
@@ -1,632 +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 "qplaylistfileparser_p.h"
-#include <qfileinfo.h>
-#include <QtCore/QDebug>
-#include <QtCore/qiodevice.h>
-#include <QtNetwork/QNetworkReply>
-#include <QtNetwork/QNetworkRequest>
-#include "qmediaplayer.h"
-#include "qmediaobject_p.h"
-#include "qmediametadata.h"
-#include "qmediacontent.h"
-
-QT_BEGIN_NAMESPACE
-
-namespace {
-
-class ParserBase
-{
-public:
- explicit ParserBase(QPlaylistFileParser *parent)
- : m_parent(parent)
- , m_aborted(false)
- {
- Q_ASSERT(m_parent);
- }
-
- bool parseLine(int lineIndex, const QString& line, const QUrl& root)
- {
- if (m_aborted)
- return false;
-
- const bool ok = parseLineImpl(lineIndex, line, root);
- return ok && !m_aborted;
- }
-
- virtual void abort() { m_aborted = true; }
- virtual ~ParserBase() { }
-
-protected:
- virtual bool parseLineImpl(int lineIndex, const QString& line, const QUrl& root) = 0;
-
- static QUrl expandToFullPath(const QUrl &root, const QString &line)
- {
- // On Linux, backslashes are not converted to forward slashes :/
- if (line.startsWith(QLatin1String("//")) || line.startsWith(QLatin1String("\\\\"))) {
- // Network share paths are not resolved
- return QUrl::fromLocalFile(line);
- }
-
- QUrl url(line);
- if (url.scheme().isEmpty()) {
- // Resolve it relative to root
- if (root.isLocalFile())
- return QUrl::fromUserInput(line, root.adjusted(QUrl::RemoveFilename).toLocalFile(), QUrl::AssumeLocalFile);
- else
- return root.resolved(url);
- } else if (url.scheme().length() == 1) {
- // Assume it's a drive letter for a Windows path
- url = QUrl::fromLocalFile(line);
- }
-
- return url;
- }
-
- void newItemFound(const QVariant& content) { Q_EMIT m_parent->newItem(content); }
-
-private:
- QPlaylistFileParser *m_parent;
- bool m_aborted;
-};
-
-class M3UParser : public ParserBase
-{
-public:
- explicit M3UParser(QPlaylistFileParser *q)
- : ParserBase(q)
- , m_extendedFormat(false)
- {
- }
-
- /*
- *
- Extended M3U directives
-
- #EXTM3U - header - must be first line of file
- #EXTINF - extra info - length (seconds), title
- #EXTINF - extra info - length (seconds), artist '-' title
-
- Example
-
- #EXTM3U
- #EXTINF:123, Sample artist - Sample title
- C:\Documents and Settings\I\My Music\Sample.mp3
- #EXTINF:321,Example Artist - Example title
- C:\Documents and Settings\I\My Music\Greatest Hits\Example.ogg
-
- */
- bool parseLineImpl(int lineIndex, const QString& line, const QUrl& root) override
- {
- if (line[0] == u'#' ) {
- if (m_extendedFormat) {
- if (line.startsWith(QLatin1String("#EXTINF:"))) {
- m_extraInfo.clear();
- int artistStart = line.indexOf(QLatin1String(","), 8);
- bool ok = false;
- QStringView lineView { line };
- int length = lineView.mid(8, artistStart < 8 ? -1 : artistStart - 8).trimmed().toInt(&ok);
- if (ok && length > 0) {
- //convert from second to milisecond
- m_extraInfo[QMediaMetaData::Duration] = QVariant(length * 1000);
- }
- if (artistStart > 0) {
- int titleStart = getSplitIndex(line, artistStart);
- if (titleStart > artistStart) {
- m_extraInfo[QMediaMetaData::Author] = lineView.mid(artistStart + 1,
- titleStart - artistStart - 1).trimmed().toString().
- replace(QLatin1String("--"), QLatin1String("-"));
- m_extraInfo[QMediaMetaData::Title] = lineView.mid(titleStart + 1).trimmed().toString().
- replace(QLatin1String("--"), QLatin1String("-"));
- } else {
- m_extraInfo[QMediaMetaData::Title] = lineView.mid(artistStart + 1).trimmed().toString().
- replace(QLatin1String("--"), QLatin1String("-"));
- }
- }
- }
- } else if (lineIndex == 0 && line.startsWith(QLatin1String("#EXTM3U"))) {
- m_extendedFormat = true;
- }
- } else {
- m_extraInfo[QLatin1String("url")] = expandToFullPath(root, line);
- newItemFound(QVariant(m_extraInfo));
- m_extraInfo.clear();
- }
-
- return true;
- }
-
- int getSplitIndex(const QString& line, int startPos)
- {
- if (startPos < 0)
- startPos = 0;
- const QChar* buf = line.data();
- for (int i = startPos; i < line.length(); ++i) {
- if (buf[i] == u'-') {
- if (i == line.length() - 1)
- return i;
- ++i;
- if (buf[i] != u'-')
- return i - 1;
- }
- }
- return -1;
- }
-
-private:
- QVariantMap m_extraInfo;
- bool m_extendedFormat;
-};
-
-class PLSParser : public ParserBase
-{
-public:
- explicit PLSParser(QPlaylistFileParser *q)
- : ParserBase(q)
- {
- }
-
-/*
- *
-The format is essentially that of an INI file structured as follows:
-
-Header
-
- * [playlist] : This tag indicates that it is a Playlist File
-
-Track Entry
-Assuming track entry #X
-
- * FileX : Variable defining location of stream.
- * TitleX : Defines track title.
- * LengthX : Length in seconds of track. Value of -1 indicates indefinite.
-
-Footer
-
- * NumberOfEntries : This variable indicates the number of tracks.
- * Version : Playlist version. Currently only a value of 2 is valid.
-
-[playlist]
-
-File1=Alternative\everclear - SMFTA.mp3
-
-Title1=Everclear - So Much For The Afterglow
-
-Length1=233
-
-File2=http://www.site.com:8000/listen.pls
-
-Title2=My Cool Stream
-
-Length5=-1
-
-NumberOfEntries=2
-
-Version=2
-*/
- bool parseLineImpl(int, const QString &line, const QUrl &root) override
- {
- // We ignore everything but 'File' entries, since that's the only thing we care about.
- if (!line.startsWith(QLatin1String("File")))
- return true;
-
- QString value = getValue(line);
- if (value.isEmpty())
- return true;
-
- newItemFound(expandToFullPath(root, value));
-
- return true;
- }
-
- QString getValue(QStringView line) {
- int start = line.indexOf(u'=');
- if (start < 0)
- return QString();
- return line.mid(start + 1).trimmed().toString();
- }
-};
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////////////
-
-class QPlaylistFileParserPrivate
-{
- Q_DECLARE_PUBLIC(QPlaylistFileParser)
-public:
- QPlaylistFileParserPrivate(QPlaylistFileParser *q)
- : q_ptr(q)
- , m_stream(nullptr)
- , m_type(QPlaylistFileParser::UNKNOWN)
- , m_scanIndex(0)
- , m_lineIndex(-1)
- , m_utf8(false)
- , m_aborted(false)
- {
- }
-
- void handleData();
- void handleParserFinished();
- void abort();
- void reset();
-
- QScopedPointer<QNetworkReply, QScopedPointerDeleteLater> m_source;
- QScopedPointer<ParserBase> m_currentParser;
- QByteArray m_buffer;
- QUrl m_root;
- QNetworkAccessManager m_mgr;
- QString m_mimeType;
- QPlaylistFileParser *q_ptr;
- QIODevice *m_stream;
- QPlaylistFileParser::FileType m_type;
- struct ParserJob
- {
- QIODevice *m_stream;
- QMediaContent m_media;
- QString m_mimeType;
- bool isValid() const { return m_stream || !m_media.isNull(); }
- void reset() { m_stream = nullptr; m_media = QMediaContent(); m_mimeType = QString(); }
- } m_pendingJob;
- int m_scanIndex;
- int m_lineIndex;
- bool m_utf8;
- bool m_aborted;
-
-private:
- bool processLine(int startIndex, int length);
-};
-
-#define LINE_LIMIT 4096
-#define READ_LIMIT 64
-
-bool QPlaylistFileParserPrivate::processLine(int startIndex, int length)
-{
- Q_Q(QPlaylistFileParser);
- m_lineIndex++;
-
- if (!m_currentParser) {
- const QString urlString = m_root.toString();
- const QString &suffix = !urlString.isEmpty() ? QFileInfo(urlString).suffix() : urlString;
- const QString &mimeType = m_source->header(QNetworkRequest::ContentTypeHeader).toString();
- m_type = QPlaylistFileParser::findPlaylistType(suffix, !mimeType.isEmpty() ? mimeType : m_mimeType, m_buffer.constData(), quint32(m_buffer.size()));
-
- switch (m_type) {
- case QPlaylistFileParser::UNKNOWN:
- emit q->error(QPlaylistFileParser::FormatError,
- QPlaylistFileParser::tr("%1 playlist type is unknown").arg(m_root.toString()));
- q->abort();
- return false;
- case QPlaylistFileParser::M3U:
- m_currentParser.reset(new M3UParser(q));
- break;
- case QPlaylistFileParser::M3U8:
- m_currentParser.reset(new M3UParser(q));
- m_utf8 = true;
- break;
- case QPlaylistFileParser::PLS:
- m_currentParser.reset(new PLSParser(q));
- break;
- }
-
- Q_ASSERT(!m_currentParser.isNull());
- }
-
- QString line;
-
- if (m_utf8) {
- line = QString::fromUtf8(m_buffer.constData() + startIndex, length).trimmed();
- } else {
- line = QString::fromLatin1(m_buffer.constData() + startIndex, length).trimmed();
- }
- if (line.isEmpty())
- return true;
-
- Q_ASSERT(m_currentParser);
- return m_currentParser->parseLine(m_lineIndex, line, m_root);
-}
-
-void QPlaylistFileParserPrivate::handleData()
-{
- Q_Q(QPlaylistFileParser);
- while (m_source->bytesAvailable() && !m_aborted) {
- int expectedBytes = qMin(READ_LIMIT, int(qMin(m_source->bytesAvailable(),
- qint64(LINE_LIMIT - m_buffer.size()))));
- m_buffer.push_back(m_source->read(expectedBytes));
- int processedBytes = 0;
- while (m_scanIndex < m_buffer.length() && !m_aborted) {
- char s = m_buffer[m_scanIndex];
- if (s == '\r' || s == '\n') {
- int l = m_scanIndex - processedBytes;
- if (l > 0) {
- if (!processLine(processedBytes, l))
- break;
- }
- processedBytes = m_scanIndex + 1;
- if (!m_source) {
- //some error happened, so exit parsing
- return;
- }
- }
- m_scanIndex++;
- }
-
- if (m_aborted)
- break;
-
- if (m_buffer.length() - processedBytes >= LINE_LIMIT) {
- emit q->error(QPlaylistFileParser::FormatError, QPlaylistFileParser::tr("invalid line in playlist file"));
- q->abort();
- break;
- }
-
- if (m_source->isFinished() && !m_source->bytesAvailable()) {
- //last line
- processLine(processedBytes, -1);
- break;
- }
-
- Q_ASSERT(m_buffer.length() == m_scanIndex);
- if (processedBytes == 0)
- continue;
-
- int copyLength = m_buffer.length() - processedBytes;
- if (copyLength > 0) {
- Q_ASSERT(copyLength <= READ_LIMIT);
- m_buffer = m_buffer.right(copyLength);
- } else {
- m_buffer.clear();
- }
- m_scanIndex = 0;
- }
-
- handleParserFinished();
-}
-
-QPlaylistFileParser::QPlaylistFileParser(QObject *parent)
- : QObject(parent)
- , d_ptr(new QPlaylistFileParserPrivate(this))
-{
-
-}
-
-QPlaylistFileParser::~QPlaylistFileParser()
-{
-
-}
-
-QPlaylistFileParser::FileType QPlaylistFileParser::findByMimeType(const QString &mime)
-{
- if (mime == QLatin1String("text/uri-list") || mime == QLatin1String("audio/x-mpegurl") || mime == QLatin1String("audio/mpegurl"))
- return QPlaylistFileParser::M3U;
-
- if (mime == QLatin1String("application/x-mpegURL") || mime == QLatin1String("application/vnd.apple.mpegurl"))
- return QPlaylistFileParser::M3U8;
-
- if (mime == QLatin1String("audio/x-scpls"))
- return QPlaylistFileParser::PLS;
-
- return QPlaylistFileParser::UNKNOWN;
-}
-
-QPlaylistFileParser::FileType QPlaylistFileParser::findBySuffixType(const QString &suffix)
-{
- const QString &s = suffix.toLower();
-
- if (s == QLatin1String("m3u"))
- return QPlaylistFileParser::M3U;
-
- if (s == QLatin1String("m3u8"))
- return QPlaylistFileParser::M3U8;
-
- if (s == QLatin1String("pls"))
- return QPlaylistFileParser::PLS;
-
- return QPlaylistFileParser::UNKNOWN;
-}
-
-QPlaylistFileParser::FileType QPlaylistFileParser::findByDataHeader(const char *data, quint32 size)
-{
- if (!data || size == 0)
- return QPlaylistFileParser::UNKNOWN;
-
- if (size >= 7 && strncmp(data, "#EXTM3U", 7) == 0)
- return QPlaylistFileParser::M3U;
-
- if (size >= 10 && strncmp(data, "[playlist]", 10) == 0)
- return QPlaylistFileParser::PLS;
-
- return QPlaylistFileParser::UNKNOWN;
-}
-
-QPlaylistFileParser::FileType QPlaylistFileParser::findPlaylistType(const QString& suffix,
- const QString& mime,
- const char *data,
- quint32 size)
-{
-
- FileType dataHeaderType = findByDataHeader(data, size);
- if (dataHeaderType != UNKNOWN)
- return dataHeaderType;
-
- FileType mimeType = findByMimeType(mime);
- if (mimeType != UNKNOWN)
- return mimeType;
-
- FileType suffixType = findBySuffixType(suffix);
- if (suffixType != UNKNOWN)
- return suffixType;
-
- return UNKNOWN;
-}
-
-/*
- * Delegating
- */
-void QPlaylistFileParser::start(const QMediaContent &media, QIODevice *stream, const QString &mimeType)
-{
- if (stream)
- start(stream, mimeType);
- else
- start(media.request(), mimeType);
-}
-
-void QPlaylistFileParser::start(QIODevice *stream, const QString &mimeType)
-{
- Q_D(QPlaylistFileParser);
- const bool validStream = stream ? (stream->isOpen() && stream->isReadable()) : false;
-
- if (!validStream) {
- Q_EMIT error(ResourceError, tr("Invalid stream"));
- return;
- }
-
- if (!d->m_currentParser.isNull()) {
- abort();
- d->m_pendingJob = { stream, QUrl(), mimeType };
- return;
- }
-
- d->reset();
- d->m_mimeType = mimeType;
- d->m_stream = stream;
- connect(d->m_stream, SIGNAL(readyRead()), this, SLOT(_q_handleData()));
- d->handleData();
-}
-
-void QPlaylistFileParser::start(const QNetworkRequest& request, const QString &mimeType)
-{
- Q_D(QPlaylistFileParser);
- const QUrl &url = request.url();
-
- if (url.isLocalFile() && !QFile::exists(url.toLocalFile())) {
- emit error(ResourceError, QString(tr("%1 does not exist")).arg(url.toString()));
- return;
- }
-
- if (!d->m_currentParser.isNull()) {
- abort();
- d->m_pendingJob = { nullptr, request, mimeType };
- return;
- }
-
- d->reset();
- d->m_root = url;
- d->m_mimeType = mimeType;
- d->m_source.reset(d->m_mgr.get(request));
- connect(d->m_source.data(), SIGNAL(readyRead()), this, SLOT(handleData()));
- connect(d->m_source.data(), SIGNAL(finished()), this, SLOT(handleData()));
- connect(d->m_source.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(handleError()));
-
- if (url.isLocalFile())
- d->handleData();
-}
-
-void QPlaylistFileParser::abort()
-{
- Q_D(QPlaylistFileParser);
- d->abort();
-
- if (d->m_source)
- d->m_source->disconnect();
-
- if (d->m_stream)
- disconnect(d->m_stream, SIGNAL(readyRead()), this, SLOT(handleData()));
-}
-
-void QPlaylistFileParser::handleData()
-{
- Q_D(QPlaylistFileParser);
- d->handleData();
-}
-
-void QPlaylistFileParserPrivate::handleParserFinished()
-{
- Q_Q(QPlaylistFileParser);
- const bool isParserValid = !m_currentParser.isNull();
- if (!isParserValid && !m_aborted)
- emit q->error(QPlaylistFileParser::FormatNotSupportedError, QPlaylistFileParser::tr("Empty file provided"));
-
- if (isParserValid && !m_aborted) {
- m_currentParser.reset();
- emit q->finished();
- }
-
- if (!m_aborted)
- q->abort();
-
- if (!m_source.isNull())
- m_source.reset();
-
- if (m_pendingJob.isValid())
- q->start(m_pendingJob.m_media, m_pendingJob.m_stream, m_pendingJob.m_mimeType);
-}
-
-void QPlaylistFileParserPrivate::abort()
-{
- m_aborted = true;
- if (!m_currentParser.isNull())
- m_currentParser->abort();
-}
-
-void QPlaylistFileParserPrivate::reset()
-{
- Q_ASSERT(m_currentParser.isNull());
- Q_ASSERT(m_source.isNull());
- m_buffer.clear();
- m_root.clear();
- m_mimeType.clear();
- m_stream = 0;
- m_type = QPlaylistFileParser::UNKNOWN;
- m_scanIndex = 0;
- m_lineIndex = -1;
- m_utf8 = false;
- m_aborted = false;
- m_pendingJob.reset();
-}
-
-void QPlaylistFileParser::handleError()
-{
- Q_D(QPlaylistFileParser);
- const QString &errorString = d->m_source->errorString();
- Q_EMIT error(QPlaylistFileParser::NetworkError, errorString);
- abort();
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/playback/qplaylistfileparser_p.h b/src/multimedia/playback/qplaylistfileparser_p.h
deleted file mode 100644
index cf96ccdbf..000000000
--- a/src/multimedia/playback/qplaylistfileparser_p.h
+++ /dev/null
@@ -1,122 +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 PLAYLISTFILEPARSER_P_H
-#define PLAYLISTFILEPARSER_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 "qtmultimediaglobal.h"
-#include <QtCore/qobject.h>
-
-QT_BEGIN_NAMESPACE
-
-class QIODevice;
-class QMediaContent;
-class QNetworkRequest;
-
-class QPlaylistFileParserPrivate;
-
-class Q_MULTIMEDIA_EXPORT QPlaylistFileParser : public QObject
-{
- Q_OBJECT
-public:
- QPlaylistFileParser(QObject *parent = nullptr);
- ~QPlaylistFileParser();
-
- enum FileType
- {
- UNKNOWN,
- M3U,
- M3U8, // UTF-8 version of M3U
- PLS
- };
-
- enum ParserError
- {
- NoError,
- FormatError,
- FormatNotSupportedError,
- ResourceError,
- NetworkError
- };
-
- void start(const QMediaContent &media, QIODevice *stream = nullptr, const QString &mimeType = QString());
- void start(const QNetworkRequest &request, const QString &mimeType = QString());
- void abort();
-
-Q_SIGNALS:
- void newItem(const QVariant& content);
- void finished();
- void error(QPlaylistFileParser::ParserError err, const QString& errorMsg);
-
-private Q_SLOTS:
- void handleData();
- void handleError();
-
-private:
- void start(QIODevice *stream, const QString &mimeType = QString());
-
- static FileType findByMimeType(const QString &mime);
- static FileType findBySuffixType(const QString &suffix);
- static FileType findByDataHeader(const char *data, quint32 size);
- static FileType findPlaylistType(QIODevice *device,
- const QString& mime);
- static FileType findPlaylistType(const QString &suffix,
- const QString& mime,
- const char *data = nullptr,
- quint32 size = 0);
-
- Q_DISABLE_COPY(QPlaylistFileParser)
- Q_DECLARE_PRIVATE(QPlaylistFileParser)
- QScopedPointer<QPlaylistFileParserPrivate> d_ptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // PLAYLISTFILEPARSER_P_H
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..5fac7234a
--- /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, &QPulseAudioEngine::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/pulseaudio/qaudioengine_pulse_p.h b/src/multimedia/pulseaudio/qaudioengine_pulse_p.h
new file mode 100644
index 000000000..2ed1fa0b1
--- /dev/null
+++ b/src/multimedia/pulseaudio/qaudioengine_pulse_p.h
@@ -0,0 +1,93 @@
+// 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
+
+//
+// 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/qmap.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qreadwritelock.h>
+#include <pulse/pulseaudio.h>
+#include "qpulsehelpers_p.h"
+#include <qaudioformat.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPulseAudioEngine : public QObject
+{
+ Q_OBJECT
+
+public:
+ QPulseAudioEngine(QObject *parent = 0);
+ ~QPulseAudioEngine();
+
+ static QPulseAudioEngine *instance();
+ pa_threaded_mainloop *mainloop() { return m_mainLoop; }
+ pa_context *context() { return m_context; }
+
+ inline void lock()
+ {
+ if (m_mainLoop)
+ pa_threaded_mainloop_lock(m_mainLoop);
+ }
+
+ inline void unlock()
+ {
+ if (m_mainLoop)
+ pa_threaded_mainloop_unlock(m_mainLoop);
+ }
+
+ inline void wait(pa_operation *op)
+ {
+ while (m_mainLoop && pa_operation_get_state(op) == PA_OPERATION_RUNNING)
+ pa_threaded_mainloop_wait(m_mainLoop);
+ }
+
+ QList<QAudioDevice> availableDevices(QAudioDevice::Mode mode) const;
+ QByteArray defaultDevice(QAudioDevice::Mode mode) const;
+
+Q_SIGNALS:
+ void contextFailed();
+ void audioInputsChanged();
+ void audioOutputsChanged();
+
+private Q_SLOTS:
+ void prepare();
+ void onContextFailed();
+
+private:
+ void updateDevices();
+ void release();
+
+public:
+ QMap<int, QAudioDevice> m_sinks;
+ QMap<int, QAudioDevice> m_sources;
+
+ QByteArray m_defaultSink;
+ QByteArray m_defaultSource;
+
+ mutable QReadWriteLock m_sinkLock;
+ mutable QReadWriteLock m_sourceLock;
+ mutable QReadWriteLock m_serverLock;
+
+private:
+ pa_mainloop_api *m_mainLoopApi;
+ pa_threaded_mainloop *m_mainLoop;
+ pa_context *m_context;
+ bool m_prepared;
+ };
+
+QT_END_NAMESPACE
+
+#endif
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/pulseaudio/qpulseaudiosource_p.h b/src/multimedia/pulseaudio/qpulseaudiosource_p.h
new file mode 100644
index 000000000..d652f81a0
--- /dev/null
+++ b/src/multimedia/pulseaudio/qpulseaudiosource_p.h
@@ -0,0 +1,116 @@
+// 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 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 "qaudio.h"
+#include "qaudiodevice.h"
+#include <private/qaudiosystem_p.h>
+#include <private/qaudiostatemachine_p.h>
+
+#include <pulse/pulseaudio.h>
+
+QT_BEGIN_NAMESPACE
+
+class PulseInputPrivate;
+
+class QPulseAudioSource : public QPlatformAudioSource
+{
+ Q_OBJECT
+
+public:
+ QPulseAudioSource(const QByteArray &device, QObject *parent);
+ ~QPulseAudioSource();
+
+ qint64 read(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 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;
+
+ qint64 m_totalTimeValue;
+ QIODevice *m_audioSource;
+ QAudioFormat m_format;
+ qreal m_volume;
+
+protected:
+ void timerEvent(QTimerEvent *event) override;
+
+private slots:
+ void userFeed();
+ void onPulseContextFailed();
+
+private:
+ void applyVolume(const void *src, void *dest, int len);
+
+ bool open();
+ void close();
+
+ bool m_pullMode;
+ bool m_opened;
+ int m_bufferSize;
+ int m_periodSize;
+ unsigned int m_periodTime;
+ 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
+{
+ Q_OBJECT
+public:
+ PulseInputPrivate(QPulseAudioSource *audio);
+ ~PulseInputPrivate() override = default;
+
+ qint64 readData(char *data, qint64 len) override;
+ qint64 writeData(const char *data, qint64 len) override;
+
+ void trigger();
+
+private:
+ QPulseAudioSource *m_audioDevice;
+};
+
+QT_END_NAMESPACE
+
+#endif
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/qmediabindableinterface.cpp b/src/multimedia/qmediabindableinterface.cpp
deleted file mode 100644
index 8a6b9fadd..000000000
--- a/src/multimedia/qmediabindableinterface.cpp
+++ /dev/null
@@ -1,82 +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 <qmediabindableinterface.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QMediaBindableInterface
- \inmodule QtMultimedia
-
- \ingroup multimedia
- \ingroup multimedia_core
-
-
- \brief The QMediaBindableInterface class is the base class for objects extending media objects functionality.
-
- \sa
-*/
-
-/*!
- Destroys a media helper object.
-*/
-
-QMediaBindableInterface::~QMediaBindableInterface()
-{
-}
-
-/*!
- \fn QMediaBindableInterface::mediaObject() const;
-
- Return the currently attached media object.
-*/
-
-
-/*!
- \fn QMediaBindableInterface::setMediaObject(QMediaObject *object);
-
- Attaches to the media \a object.
- Returns true if attached successfully, otherwise returns false.
-*/
-
-
-
-QT_END_NAMESPACE
-
diff --git a/src/multimedia/qmediabindableinterface.h b/src/multimedia/qmediabindableinterface.h
deleted file mode 100644
index ce0d0822e..000000000
--- a/src/multimedia/qmediabindableinterface.h
+++ /dev/null
@@ -1,69 +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 QMEDIABINDABLEINTERFACE_H
-#define QMEDIABINDABLEINTERFACE_H
-
-#include <QtMultimedia/qmediaobject.h>
-
-QT_BEGIN_NAMESPACE
-
-
-class QMediaObject;
-
-class Q_MULTIMEDIA_EXPORT QMediaBindableInterface
-{
-public:
- virtual ~QMediaBindableInterface();
-
- virtual QMediaObject *mediaObject() const = 0;
-
-protected:
- friend class QMediaObject;
- virtual bool setMediaObject(QMediaObject *object) = 0;
-};
-
-#define QMediaBindableInterface_iid \
- "org.qt-project.qt.mediabindable/5.0"
-Q_DECLARE_INTERFACE(QMediaBindableInterface, QMediaBindableInterface_iid)
-
-QT_END_NAMESPACE
-
-
-#endif // QMEDIABINDABLEINTERFACE_H
diff --git a/src/multimedia/qmediacontrol.cpp b/src/multimedia/qmediacontrol.cpp
deleted file mode 100644
index 6f0a980a2..000000000
--- a/src/multimedia/qmediacontrol.cpp
+++ /dev/null
@@ -1,136 +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/qmetaobject.h>
-#include <QtCore/qtimer.h>
-
-#include "qmediacontrol.h"
-#include "qmediacontrol_p.h"
-
-
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QMediaControl
- \obsolete
- \inmodule QtMultimedia
-
- \ingroup multimedia
- \ingroup multimedia_control
- \ingroup multimedia_core
-
- \brief The QMediaControl class provides a base interface for media service controls.
-
- Media controls provide an interface to individual features provided by a
- media service. Most services implement a principal control which exposes
- the core functionality of the service and a number of optional controls which
- expose any additional functionality.
-
- A pointer to a control implemented by a media service can be obtained using
- the \l {QMediaService::requestControl()} member of QMediaService. If the
- service doesn't implement a control it will instead return a null pointer.
-
- \snippet multimedia-snippets/media.cpp Request control
-
- Alternatively if the IId of the control has been declared using
- Q_MEDIA_DECLARE_CONTROL the template version of
- QMediaService::requestControl() can be used to request the service without
- explicitly passing the IId or using qobject_cast().
-
- \snippet multimedia-snippets/media.cpp Request control templated
-
- Most application code will not interface directly with a media service's
- controls, instead the QMediaObject which owns the service acts as an
- intermediary between one or more controls and the application.
-
- \sa QMediaService, QMediaObject
-*/
-
-/*!
- \macro Q_MEDIA_DECLARE_CONTROL(Class, IId)
- \relates QMediaControl
-
- The Q_MEDIA_DECLARE_CONTROL macro declares an \a IId for a \a Class that
- inherits from QMediaControl.
-
- Declaring an IId for a QMediaControl allows an instance of that control to
- be requested from QMediaService::requestControl() without explicitly
- passing the IId.
-
- \snippet multimedia-snippets/media.cpp Request control templated
-
- \sa QMediaService::requestControl()
-*/
-
-/*!
- Destroys a media control.
-*/
-
-QMediaControl::~QMediaControl()
-{
- delete d_ptr;
-}
-
-/*!
- Constructs a media control with the given \a parent.
-*/
-
-QMediaControl::QMediaControl(QObject *parent)
- : QObject(parent)
- , d_ptr(new QMediaControlPrivate)
-{
- d_ptr->q_ptr = this;
-}
-
-/*!
- \internal
-*/
-
-QMediaControl::QMediaControl(QMediaControlPrivate &dd, QObject *parent)
- : QObject(parent)
- , d_ptr(&dd)
-
-{
- d_ptr->q_ptr = this;
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qmediacontrol.cpp"
diff --git a/src/multimedia/qmediacontrol.h b/src/multimedia/qmediacontrol.h
deleted file mode 100644
index 48ae44f8a..000000000
--- a/src/multimedia/qmediacontrol.h
+++ /dev/null
@@ -1,79 +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 QABSTRACTMEDIACONTROL_H
-#define QABSTRACTMEDIACONTROL_H
-
-#include <QtMultimedia/qtmultimediaglobal.h>
-
-#include <QtCore/qobject.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qvariant.h>
-
-
-QT_BEGIN_NAMESPACE
-
-
-class QMediaControlPrivate;
-class Q_MULTIMEDIA_EXPORT QMediaControl : public QObject
-{
- Q_OBJECT
-
-public:
- ~QMediaControl();
-
-protected:
- explicit QMediaControl(QObject *parent = nullptr);
- explicit QMediaControl(QMediaControlPrivate &dd, QObject *parent = nullptr);
-
- QMediaControlPrivate *d_ptr;
-
-private:
- Q_DECLARE_PRIVATE(QMediaControl)
-};
-
-template <typename T> const char *qmediacontrol_iid() { return nullptr; }
-
-#define Q_MEDIA_DECLARE_CONTROL(Class, IId) \
- template <> inline const char *qmediacontrol_iid<Class *>() { return IId; }
-
-QT_END_NAMESPACE
-
-
-#endif // QABSTRACTMEDIACONTROL_H
diff --git a/src/multimedia/qmediacontrol_p.h b/src/multimedia/qmediacontrol_p.h
deleted file mode 100644
index e9827fd1e..000000000
--- a/src/multimedia/qmediacontrol_p.h
+++ /dev/null
@@ -1,72 +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 QABSTRACTMEDIACONTROL_P_H
-#define QABSTRACTMEDIACONTROL_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 <qtmultimediaglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-
-class QMediaControl;
-
-class QMediaControlPrivate
-{
-public:
- virtual ~QMediaControlPrivate() {}
-
- QMediaControl *q_ptr;
-};
-
-QT_END_NAMESPACE
-
-
-#endif
diff --git a/src/multimedia/qmediadevices.cpp b/src/multimedia/qmediadevices.cpp
new file mode 100644
index 000000000..1d77f4de8
--- /dev/null
+++ b/src/multimedia/qmediadevices.cpp
@@ -0,0 +1,288 @@
+// 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"
+#include "private/qplatformmediadevices_p.h"
+
+#include <qaudiodevice.h>
+#include <qcameradevice.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QMediaDevices
+ \brief The QMediaDevices class provides information about available
+ multimedia input and output devices.
+ \ingroup multimedia
+ \inmodule QtMultimedia
+
+ 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 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
+ select the device to be used.
+
+ QMediaDevices is a singleton object and all getters are thread-safe.
+*/
+
+/*!
+ \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 can be either built-in, or
+ connected through for example USB or Bluetooth.
+*/
+QList<QAudioDevice> QMediaDevices::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 can be either
+ built-in, or connected through for example USB or Bluetooth.
+*/
+QList<QAudioDevice> QMediaDevices::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()
+{
+ 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.
+ The audioInputsChanged() signal is emitted in this case.
+*/
+QAudioDevice QMediaDevices::defaultAudioInput()
+{
+ const auto inputs = audioInputs();
+ if (inputs.isEmpty())
+ return {};
+ for (const auto &info : inputs)
+ if (info.isDefault())
+ return info;
+ return inputs.value(0);
+}
+
+/*!
+ \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
+ audioOutputsChanged() signal is emitted in this case.
+*/
+QAudioDevice QMediaDevices::defaultAudioOutput()
+{
+ const auto outputs = audioOutputs();
+ if (outputs.isEmpty())
+ return {};
+ for (const auto &info : outputs)
+ if (info.isDefault())
+ return info;
+ return outputs.value(0);
+}
+
+/*!
+ \qmlproperty cameraDevice QtMultimedia::MediaDevices::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 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
+ videoInputsChanged() signal is emitted in that case.
+
+ \sa videoInputs()
+*/
+QCameraDevice QMediaDevices::defaultVideoInput()
+{
+ const auto inputs = videoInputs();
+ if (inputs.isEmpty())
+ return {};
+ for (const auto &info : inputs)
+ if (info.isDefault())
+ return info;
+ return inputs.value(0);
+}
+
+/*!
+ \internal
+*/
+QMediaDevices::QMediaDevices(QObject *parent)
+ : QObject(parent)
+{
+ 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() = default;
+
+void QMediaDevices::connectNotify(const QMetaMethod &signal)
+{
+ if (signal == QMetaMethod::fromSignal(&QMediaDevices::videoInputsChanged))
+ QPlatformMediaIntegration::instance()->mediaDevices()->initVideoDevicesConnection();
+
+ QObject::connectNotify(signal);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qmediadevices.cpp"
diff --git a/src/multimedia/qmediadevices.h b/src/multimedia/qmediadevices.h
new file mode 100644
index 000000000..832799095
--- /dev/null
+++ b/src/multimedia/qmediadevices.h
@@ -0,0 +1,56 @@
+// 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
+
+#include <QtMultimedia/qtmultimediaglobal.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qstringlist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAudioDevice;
+class QCameraDevice;
+
+class QMediaDevicesPrivate;
+
+class Q_MULTIMEDIA_EXPORT QMediaDevices : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QList<QAudioDevice> audioInputs READ audioInputs NOTIFY audioInputsChanged)
+ Q_PROPERTY(QList<QAudioDevice> audioOutputs READ audioOutputs NOTIFY audioOutputsChanged)
+ Q_PROPERTY(QList<QCameraDevice> videoInputs READ videoInputs NOTIFY videoInputsChanged)
+ Q_PROPERTY(QAudioDevice defaultAudioInput READ defaultAudioInput NOTIFY audioInputsChanged)
+ Q_PROPERTY(QAudioDevice defaultAudioOutput READ defaultAudioOutput NOTIFY audioOutputsChanged)
+ Q_PROPERTY(QCameraDevice defaultVideoInput READ defaultVideoInput NOTIFY videoInputsChanged)
+
+public:
+ QMediaDevices(QObject *parent = nullptr);
+ ~QMediaDevices();
+
+ static QList<QAudioDevice> audioInputs();
+ static QList<QAudioDevice> audioOutputs();
+ static QList<QCameraDevice> videoInputs();
+
+ static QAudioDevice defaultAudioInput();
+ static QAudioDevice defaultAudioOutput();
+ static QCameraDevice defaultVideoInput();
+
+Q_SIGNALS:
+ void audioInputsChanged();
+ void audioOutputsChanged();
+ void videoInputsChanged();
+
+protected:
+ void connectNotify(const QMetaMethod &signal) override;
+
+private:
+ friend class QMediaDevicesPrivate;
+};
+
+QT_END_NAMESPACE
+
+
+#endif // QABSTRACTMEDIASERVICE_H
+
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
new file mode 100644
index 000000000..a05648636
--- /dev/null
+++ b/src/multimedia/qmediaformat.cpp
@@ -0,0 +1,883 @@
+// 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"
+#include "private/qplatformmediaformatinfo_p.h"
+#include <QtCore/qmimedatabase.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QMediaFormat
+ \ingroup multimedia
+ \inmodule QtMultimedia
+ \brief Describes an encoding format for a multimedia file or stream.
+ \since 6.2
+
+ QMediaFormat describes an encoding format for a multimedia file or stream.
+
+ 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] =
+{
+ "",
+ "video/x-ms-wmv",
+ "video/x-msvideo",
+ "video/x-matroska",
+ "video/mp4",
+ "video/ogg",
+ "video/quicktime",
+ "video/webm",
+ // Audio Formats
+ "audio/mp4",
+ "audio/aac",
+ "audio/x-ms-wma",
+ "audio/mpeg",
+ "audio/flac",
+ "audio/wav"
+};
+
+constexpr QMediaFormat::FileFormat videoFormatPriorityList[] =
+{
+ QMediaFormat::MPEG4,
+ QMediaFormat::QuickTime,
+ QMediaFormat::AVI,
+ QMediaFormat::WebM,
+ QMediaFormat::WMV,
+ QMediaFormat::Matroska,
+ QMediaFormat::Ogg,
+ QMediaFormat::UnspecifiedFormat
+};
+
+constexpr QMediaFormat::FileFormat audioFormatPriorityList[] =
+{
+ QMediaFormat::Mpeg4Audio,
+ QMediaFormat::MP3,
+ QMediaFormat::WMA,
+ QMediaFormat::FLAC,
+ QMediaFormat::Wave,
+ QMediaFormat::UnspecifiedFormat
+};
+
+constexpr QMediaFormat::AudioCodec audioPriorityList[] =
+{
+ QMediaFormat::AudioCodec::AAC,
+ QMediaFormat::AudioCodec::MP3,
+ QMediaFormat::AudioCodec::AC3,
+ QMediaFormat::AudioCodec::Opus,
+ QMediaFormat::AudioCodec::EAC3,
+ QMediaFormat::AudioCodec::DolbyTrueHD,
+ QMediaFormat::AudioCodec::WMA,
+ QMediaFormat::AudioCodec::FLAC,
+ QMediaFormat::AudioCodec::Vorbis,
+ QMediaFormat::AudioCodec::Wave,
+ QMediaFormat::AudioCodec::Unspecified
+};
+
+constexpr QMediaFormat::VideoCodec videoPriorityList[] =
+{
+ QMediaFormat::VideoCodec::H265,
+ QMediaFormat::VideoCodec::VP9,
+ QMediaFormat::VideoCodec::H264,
+ QMediaFormat::VideoCodec::AV1,
+ QMediaFormat::VideoCodec::VP8,
+ QMediaFormat::VideoCodec::WMV,
+ QMediaFormat::VideoCodec::Theora,
+ QMediaFormat::VideoCodec::MPEG4,
+ QMediaFormat::VideoCodec::MPEG2,
+ QMediaFormat::VideoCodec::MPEG1,
+ QMediaFormat::VideoCodec::MotionJPEG,
+};
+
+}
+
+class QMediaFormatPrivate : public QSharedData
+{};
+
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QMediaFormatPrivate);
+
+/*! \enum QMediaFormat::FileFormat
+
+ Describes the container format used in a multimedia file or stream.
+
+ \value WMA
+ \l {Windows Media Audio}
+ \value AAC
+ \l{Advanced Audio Coding}
+ \value Matroska
+ \l{Matroska (MKV)}
+ \value WMV
+ \l{Windows Media Video}
+ \value MP3
+ \l{MPEG-1 Audio Layer III or MPEG-2 Audio Layer III}
+ \value Wave
+ \l{Waveform Audio File Format}
+ \value Ogg
+ \l{Ogg}
+ \value MPEG4
+ \l{MPEG-4}
+ \value AVI
+ \l{Audio Video Interleave}
+ \value QuickTime
+ \l{QuickTime}
+ \value WebM
+ \l{WebM}
+ \value Mpeg4Audio
+ \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.
+
+ \value WMA
+ \l {Windows Media Audio}
+ \value AC3
+ \l {Dolby Digital}
+ \value AAC
+ \l{Advanced Audio Coding}
+ \value ALAC
+ \l{Apple Lossless Audio Codec}
+ \value DolbyTrueHD
+ \l{Dolby TrueHD}
+ \value EAC3
+ \l {Dolby Digital Plus (EAC3)}
+ \value MP3
+ \l{MPEG-1 Audio Layer III or MPEG-2 Audio Layer III}
+ \value Wave
+ \l{Waveform Audio File Format}
+ \value Vorbis
+ \l{Ogg Vorbis}
+ \value FLAC
+ \l{Free Lossless Audio Codec}
+ \value Opus
+ \l{Opus Audio Format}
+ \value Unspecified
+ Unspecified codec
+
+ \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.
+
+ \value VP8
+ \l{VP8}
+ \value MPEG2
+ \l{MPEG-2}
+ \value MPEG1
+ \l{MPEG-1}
+ \value WMV
+ \l{Windows Media Video}
+ \value H265
+ \l{High Efficiency Video Coding (HEVC)}
+ \value H264
+ \l{Advanced Video Coding}
+ \value MPEG4
+ \l{MPEG-4}
+ \value AV1
+ \l{AOMedia Video 1}
+ \value MotionJPEG
+ \l{MotionJPEG}
+ \value VP9
+ \l{VP9}
+ \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
+
+/*!
+ Constructs a QMediaFormat object for \a format.
+*/
+QMediaFormat::QMediaFormat(FileFormat format)
+ : fmt(format)
+{
+}
+
+/*!
+ Destroys the QMediaFormat object.
+*/
+QMediaFormat::~QMediaFormat() = default;
+
+/*!
+ Constructs a QMediaFormat object by copying from \a other.
+*/
+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;
+
+/*! \fn QMediaFormat::QMediaFormat(QMediaFormat &&other)
+
+ Constructs a QMediaFormat objects by moving from \a other.
+*/
+
+/*! \fn QMediaFormat &QMediaFormat::operator=(QMediaFormat &&other)
+
+ Moves \a other into this QMediaFormat objects.
+*/
+
+// Properties
+/*! \property QMediaFormat::fileFormat
+
+ \brief The file (container) format of the media.
+
+ \sa QMediaFormat::FileFormat
+*/
+
+/*! \property QMediaFormat::audioCodec
+
+ \brief The audio codec of the media.
+
+ \sa QMediaFormat::AudioCodec
+*/
+
+/*! \property QMediaFormat::videoCodec
+
+ \brief The video codec of the media.
+
+ \sa QMediaFormat::VideoCodec
+*/
+
+/*! \fn void QMediaFormat::setVideoCodec(VideoCodec codec)
+
+ Sets the video codec to \a codec.
+
+ \sa videoCodec(), QMediaFormat::VideoCodec
+*/
+
+/*! \fn QMediaFormat::VideoCodec QMediaFormat::videoCodec() const
+
+ Returns the video codec used in this format.
+
+ \sa setVideoCodec(), QMediaFormat::VideoCodec
+*/
+
+/*! \fn void QMediaFormat::setAudioCodec(AudioCodec codec)
+
+ Sets the audio codec to \a codec.
+
+ \sa audioCodec(), QMediaFormat::AudioCodec
+*/
+
+/*! \fn QMediaFormat::AudioCodec QMediaFormat::audioCodec() const
+
+ Returns the audio codec used in this format.
+
+ \sa setAudioCodec(), QMediaFormat::AudioCodec
+*/
+
+/*!
+ Returns \c true if Qt Multimedia can encode or decode this format,
+ depending on \a mode.
+*/
+
+bool QMediaFormat::isSupported(ConversionMode mode) const
+{
+ return QPlatformMediaIntegration::instance()->formatInfo()->isSupported(*this, mode);
+}
+
+/*!
+ Returns the \l{MIME type} for the file format used in this media format.
+*/
+
+QMimeType QMediaFormat::mimeType() const
+{
+ return QMimeDatabase().mimeTypeForName(QString::fromLatin1(mimeTypeForFormat[fmt + 1]));
+}
+
+/*!
+ \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
+ codec indicated by \a{m}.
+
+ 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)
+{
+ 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
+ MediaFormat.
+
+ \sa QMediaFormat::ConversionMode
+*/
+QList<QMediaFormat::VideoCodec> QMediaFormat::supportedVideoCodecs(QMediaFormat::ConversionMode m)
+{
+ 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)
+{
+ return QPlatformMediaIntegration::instance()->formatInfo()->supportedAudioCodecs(*this, m);
+}
+
+/*!
+ \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",
+ "WMV",
+ "AVI",
+ "Matroska",
+ "MPEG-4",
+ "Ogg",
+ "QuickTime",
+ "WebM",
+ // Audio Formats
+ "MPEG-4 Audio",
+ "AAC",
+ "WMA",
+ "MP3",
+ "FLAC",
+ "Wave"
+ };
+ return QString::fromUtf8(descriptions[int(fileFormat) + 1]);
+}
+
+/*!
+ \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",
+ "MP3",
+ "AAC",
+ "AC3",
+ "EAC3",
+ "FLAC",
+ "DolbyTrueHD",
+ "Opus",
+ "Vorbis",
+ "Wave",
+ "WMA",
+ "ALAC",
+ };
+ return QString::fromUtf8(descriptions[int(codec) + 1]);
+}
+
+/*!
+ \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",
+ "MPEG1",
+ "MPEG2",
+ "MPEG4",
+ "H264",
+ "H265",
+ "VP8",
+ "VP9",
+ "AV1",
+ "Theora",
+ "WMV",
+ "MotionJPEG"
+ };
+ return QString::fromUtf8(descriptions[int(codec) + 1]);
+}
+
+/*!
+ \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",
+ "Windows Media Video",
+ "Audio Video Interleave",
+ "Matroska Multimedia Container",
+ "MPEG-4 Video Container",
+ "Ogg",
+ "QuickTime Container",
+ "WebM",
+ // Audio Formats
+ "MPEG-4 Audio",
+ "AAC",
+ "Windows Media Audio",
+ "MP3",
+ "Free Lossless Audio Codec (FLAC)",
+ "Wave File"
+ };
+ return QString::fromUtf8(descriptions[int(fileFormat) + 1]);
+}
+
+/*!
+ \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",
+ "MP3",
+ "Advanced Audio Codec (AAC)",
+ "Dolby Digital (AC3)",
+ "Dolby Digital Plus (E-AC3)",
+ "Free Lossless Audio Codec (FLAC)",
+ "Dolby True HD",
+ "Opus",
+ "Vorbis",
+ "Wave",
+ "Windows Media Audio",
+ "Apple Lossless Audio Codec (ALAC)",
+ };
+ return QString::fromUtf8(descriptions[int(codec) + 1]);
+}
+
+/*!
+ \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",
+ "MPEG-1 Video",
+ "MPEG-2 Video",
+ "MPEG-4 Video",
+ "H.264",
+ "H.265",
+ "VP8",
+ "VP9",
+ "AV1",
+ "Theora",
+ "Windows Media Video",
+ "MotionJPEG"
+ };
+ 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);
+ return fmt == other.fmt &&
+ audio == other.audio &&
+ video == other.video;
+}
+
+/*!
+ \enum QMediaFormat::ResolveFlags
+
+ Describes the requirements for resolving a suitable format for
+ QMediaRecorder.
+
+ \value NoFlags
+ No requirements
+ \value RequiresVideo
+ A video codec is required
+
+ \sa resolveForEncoding()
+*/
+
+/*!
+ Resolves the format, based on \a flags, to a format that is supported by
+ QMediaRecorder.
+
+ This method tries to find the best possible match for unspecified settings.
+ Settings that are not supported by the recorder will be modified to the closest
+ match that is supported.
+
+ When resolving, priority is given in the following order:
+ \list 1
+ \li File format
+ \li Video codec
+ \li Audio codec
+ \endlist
+*/
+void QMediaFormat::resolveForEncoding(ResolveFlags flags)
+{
+ const bool requiresVideo = (flags & ResolveFlags::RequiresVideo) != 0;
+
+ if (!requiresVideo)
+ video = VideoCodec::Unspecified;
+
+ // need to adjust the format. Priority is given first to file format, then video codec, then audio codec
+
+ QMediaFormat nullFormat;
+ auto supportedFormats = nullFormat.supportedFileFormats(QMediaFormat::Encode);
+ auto supportedAudioCodecs = nullFormat.supportedAudioCodecs(QMediaFormat::Encode);
+ auto supportedVideoCodecs = nullFormat.supportedVideoCodecs(QMediaFormat::Encode);
+
+ auto bestSupportedFileFormat = [&](QMediaFormat::AudioCodec audio = QMediaFormat::AudioCodec::Unspecified,
+ QMediaFormat::VideoCodec video = QMediaFormat::VideoCodec::Unspecified)
+ {
+ QMediaFormat f;
+ f.setAudioCodec(audio);
+ f.setVideoCodec(video);
+ auto supportedFormats = f.supportedFileFormats(QMediaFormat::Encode);
+ auto *list = (flags == NoFlags) ? audioFormatPriorityList : videoFormatPriorityList;
+ while (*list != QMediaFormat::UnspecifiedFormat) {
+ if (supportedFormats.contains(*list))
+ break;
+ ++list;
+ }
+ return *list;
+ };
+
+ // reset format if it does not support video when video is required
+ if (requiresVideo && this->supportedVideoCodecs(QMediaFormat::Encode).isEmpty())
+ fmt = QMediaFormat::UnspecifiedFormat;
+
+ // reset non supported formats and codecs
+ if (!supportedFormats.contains(fmt))
+ fmt = QMediaFormat::UnspecifiedFormat;
+ if (!supportedAudioCodecs.contains(audio))
+ audio = QMediaFormat::AudioCodec::Unspecified;
+ if (!requiresVideo || !supportedVideoCodecs.contains(video))
+ video = QMediaFormat::VideoCodec::Unspecified;
+
+ if (requiresVideo) {
+ // try finding a file format that is supported
+ if (fmt == QMediaFormat::UnspecifiedFormat)
+ fmt = bestSupportedFileFormat(audio, video);
+ // try without the audio codec
+ if (fmt == QMediaFormat::UnspecifiedFormat)
+ fmt = bestSupportedFileFormat(QMediaFormat::AudioCodec::Unspecified, video);
+ }
+ // try without the video codec
+ if (fmt == QMediaFormat::UnspecifiedFormat)
+ fmt = bestSupportedFileFormat(audio);
+ // give me a format that's supported
+ if (fmt == QMediaFormat::UnspecifiedFormat)
+ fmt = bestSupportedFileFormat();
+ // still nothing? Give up
+ if (fmt == QMediaFormat::UnspecifiedFormat) {
+ *this = {};
+ return;
+ }
+
+ // find a working video codec
+ if (requiresVideo) {
+ // reset the audio codec, so that we won't throw away the video codec
+ // if it is supported (choosing the specified video codec has higher
+ // priority than the specified audio codec)
+ auto a = audio;
+ audio = QMediaFormat::AudioCodec::Unspecified;
+ auto videoCodecs = this->supportedVideoCodecs(QMediaFormat::Encode);
+ if (!videoCodecs.contains(video)) {
+ // not supported, try to find a replacement
+ auto *list = videoPriorityList;
+ while (*list != QMediaFormat::VideoCodec::Unspecified) {
+ if (videoCodecs.contains(*list))
+ break;
+ ++list;
+ }
+ video = *list;
+ }
+ audio = a;
+ } else {
+ video = QMediaFormat::VideoCodec::Unspecified;
+ }
+
+ // and a working audio codec
+ auto audioCodecs = this->supportedAudioCodecs(QMediaFormat::Encode);
+ if (!audioCodecs.contains(audio)) {
+ auto *list = audioPriorityList;
+ while (*list != QMediaFormat::AudioCodec::Unspecified) {
+ if (audioCodecs.contains(*list))
+ break;
+ ++list;
+ }
+ audio = *list;
+ }
+}
+
+/*!
+ \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
new file mode 100644
index 000000000..225d21896
--- /dev/null
+++ b/src/multimedia/qmediaformat.h
@@ -0,0 +1,149 @@
+// 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
+
+#include <QtCore/qsharedpointer.h>
+#include <QtMultimedia/qtmultimediaglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMimeType;
+class QMediaFormat;
+class QMediaFormatPrivate;
+
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QMediaFormatPrivate, Q_MULTIMEDIA_EXPORT)
+
+class Q_MULTIMEDIA_EXPORT QMediaFormat
+{
+ Q_GADGET
+ Q_PROPERTY(FileFormat fileFormat READ fileFormat WRITE setFileFormat)
+ Q_PROPERTY(AudioCodec audioCodec READ audioCodec WRITE setAudioCodec)
+ Q_PROPERTY(VideoCodec videoCodec READ videoCodec WRITE setVideoCodec)
+ Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
+public:
+ enum FileFormat {
+ UnspecifiedFormat = -1,
+ // Video Formats
+ WMV,
+ AVI,
+ Matroska,
+ MPEG4,
+ Ogg,
+ QuickTime,
+ WebM,
+ // Audio Only Formats
+ Mpeg4Audio,
+ AAC,
+ WMA,
+ MP3,
+ FLAC,
+ Wave,
+ LastFileFormat = Wave
+ };
+ Q_ENUM(FileFormat)
+
+ enum class AudioCodec {
+ Unspecified = -1,
+ MP3,
+ AAC,
+ AC3,
+ EAC3,
+ FLAC,
+ DolbyTrueHD,
+ Opus,
+ Vorbis,
+ Wave,
+ WMA,
+ ALAC,
+ LastAudioCodec = ALAC
+ };
+ Q_ENUM(AudioCodec)
+
+ enum class VideoCodec {
+ Unspecified = -1,
+ MPEG1,
+ MPEG2,
+ MPEG4,
+ H264,
+ H265,
+ VP8,
+ VP9,
+ AV1,
+ Theora,
+ WMV,
+ MotionJPEG,
+ LastVideoCodec = MotionJPEG
+ };
+ Q_ENUM(VideoCodec)
+
+ enum ConversionMode {
+ Encode,
+ Decode
+ };
+ Q_ENUM(ConversionMode)
+
+ enum ResolveFlags
+ {
+ NoFlags,
+ RequiresVideo
+ };
+
+ QMediaFormat(FileFormat format = UnspecifiedFormat);
+ ~QMediaFormat();
+ QMediaFormat(const QMediaFormat &other) noexcept;
+ QMediaFormat &operator=(const QMediaFormat &other) noexcept;
+
+ QMediaFormat(QMediaFormat &&other) noexcept = default;
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QMediaFormat)
+ void swap(QMediaFormat &other) noexcept
+ {
+ std::swap(fmt, other.fmt);
+ std::swap(audio, other.audio);
+ std::swap(video, other.video);
+ d.swap(other.d);
+ }
+
+ FileFormat fileFormat() const { return fmt; }
+ void setFileFormat(FileFormat f) { fmt = f; }
+
+ void setVideoCodec(VideoCodec codec) { video = codec; }
+ VideoCodec videoCodec() const { return video; }
+
+ void setAudioCodec(AudioCodec codec) { audio = codec; }
+ AudioCodec audioCodec() const { return audio; }
+
+ Q_INVOKABLE bool isSupported(ConversionMode mode) const;
+
+ QMimeType mimeType() const;
+
+ Q_INVOKABLE QList<FileFormat> supportedFileFormats(ConversionMode m);
+ Q_INVOKABLE QList<VideoCodec> supportedVideoCodecs(ConversionMode m);
+ Q_INVOKABLE QList<AudioCodec> supportedAudioCodecs(ConversionMode m);
+
+ Q_INVOKABLE static QString fileFormatName(FileFormat fileFormat);
+ Q_INVOKABLE static QString audioCodecName(AudioCodec codec);
+ Q_INVOKABLE static QString videoCodecName(VideoCodec codec);
+
+ 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
+ { return !operator==(other); }
+
+ void resolveForEncoding(ResolveFlags flags);
+
+protected:
+ friend class QMediaFormatPrivate;
+ FileFormat fmt;
+ AudioCodec audio = AudioCodec::Unspecified;
+ VideoCodec video = VideoCodec::Unspecified;
+ QExplicitlySharedDataPointer<QMediaFormatPrivate> d;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/qmediaframeinput.cpp b/src/multimedia/qmediaframeinput.cpp
new file mode 100644
index 000000000..4bb90d3ee
--- /dev/null
+++ b/src/multimedia/qmediaframeinput.cpp
@@ -0,0 +1,43 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qmediaframeinput_p.h"
+
+QT_BEGIN_NAMESPACE
+
+void QMediaFrameInputPrivate::setCaptureSession(QMediaCaptureSession *session)
+{
+ if (session == m_captureSession)
+ return;
+
+ auto prevSession = std::exchange(m_captureSession, session);
+ updateCaptureSessionConnections(prevSession, session);
+ updateCanSendMediaFrame();
+}
+
+void QMediaFrameInputPrivate::updateCanSendMediaFrame()
+{
+ const bool canSendMediaFrame = m_captureSession && checkIfCanSendMediaFrame();
+ if (m_canSendMediaFrame != canSendMediaFrame) {
+ m_canSendMediaFrame = canSendMediaFrame;
+ if (m_canSendMediaFrame)
+ emitReadyToSendMediaFrame();
+ }
+}
+
+void QMediaFrameInputPrivate::postponeCheckReadyToSend()
+{
+ if (m_canSendMediaFrame && !m_postponeReadyToSendCheckRun) {
+ m_postponeReadyToSendCheckRun = true;
+ QMetaObject::invokeMethod(
+ q_ptr,
+ [this]() {
+ m_postponeReadyToSendCheckRun = false;
+ if (m_canSendMediaFrame)
+ emitReadyToSendMediaFrame();
+ },
+ Qt::QueuedConnection);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/qmediaframeinput_p.h b/src/multimedia/qmediaframeinput_p.h
new file mode 100644
index 000000000..22277865d
--- /dev/null
+++ b/src/multimedia/qmediaframeinput_p.h
@@ -0,0 +1,74 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QMEDIAFRAMEINPUT_P_H
+#define QMEDIAFRAMEINPUT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qmediacapturesession.h"
+#include <QtCore/private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMediaFrameInputPrivate : public QObjectPrivate
+{
+public:
+ void setCaptureSession(QMediaCaptureSession *session);
+
+ QMediaCaptureSession *captureSession() const { return m_captureSession; }
+
+protected:
+ template <typename Sender>
+ bool sendMediaFrame(Sender &&sender)
+ {
+ if (!m_canSendMediaFrame)
+ return false;
+
+ sender();
+ postponeCheckReadyToSend();
+ return true;
+ }
+
+ template <typename Sender, typename Signal>
+ void addUpdateSignal(Sender sender, Signal signal)
+ {
+ connect(sender, signal, this, &QMediaFrameInputPrivate::updateCanSendMediaFrame);
+ }
+
+ template <typename Sender, typename Signal>
+ void removeUpdateSignal(Sender sender, Signal signal)
+ {
+ disconnect(sender, signal, this, &QMediaFrameInputPrivate::updateCanSendMediaFrame);
+ }
+
+ void updateCanSendMediaFrame();
+
+private:
+ void postponeCheckReadyToSend();
+
+ virtual bool checkIfCanSendMediaFrame() const = 0;
+
+ virtual void emitReadyToSendMediaFrame() = 0;
+
+ virtual void updateCaptureSessionConnections(QMediaCaptureSession *prevSession,
+ QMediaCaptureSession *currentSession) = 0;
+
+private:
+ QMediaCaptureSession *m_captureSession = nullptr;
+ bool m_canSendMediaFrame = false;
+ bool m_postponeReadyToSendCheckRun = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QMEDIAFRAMEINPUT_P_H
diff --git a/src/multimedia/qmediainputencoderinterface_p.h b/src/multimedia/qmediainputencoderinterface_p.h
new file mode 100644
index 000000000..c199e59b4
--- /dev/null
+++ b/src/multimedia/qmediainputencoderinterface_p.h
@@ -0,0 +1,31 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QMEDIAINPUTENCODERINTERFACE_P_H
+#define QMEDIAINPUTENCODERINTERFACE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtMultimedia/qtmultimediaglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMediaInputEncoderInterface
+{
+public:
+ virtual ~QMediaInputEncoderInterface() = default;
+ virtual bool canPushFrame() const = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QMEDIAINPUTENCODERINTERFACE_P_H
diff --git a/src/multimedia/qmediametadata.cpp b/src/multimedia/qmediametadata.cpp
index 0b2343443..29b2a0a8d 100644
--- a/src/multimedia/qmediametadata.cpp
+++ b/src/multimedia/qmediametadata.cpp
@@ -1,261 +1,163 @@
-/****************************************************************************
-**
-** 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"
-QT_BEGIN_NAMESPACE
-
-/*
- When these conditions are satisfied, QStringLiteral is implemented by
- gcc's statement-expression extension. However, in this file it will
- not work, because "statement-expressions are not allowed outside functions
- nor in template-argument lists".
- MSVC 2012 produces an internal compiler error on encountering
- QStringLiteral in this context.
-
- Fall back to the less-performant QLatin1String in this case.
-*/
-#if defined(Q_CC_GNU) && defined(Q_COMPILER_LAMBDA)
-# define Q_DEFINE_METADATA(key) const QString QMediaMetaData::key(QStringLiteral(#key))
-#else
-# define Q_DEFINE_METADATA(key) const QString QMediaMetaData::key(QLatin1String(#key))
-#endif
-
-// Common
-Q_DEFINE_METADATA(Title);
-Q_DEFINE_METADATA(SubTitle);
-Q_DEFINE_METADATA(Author);
-Q_DEFINE_METADATA(Comment);
-Q_DEFINE_METADATA(Description);
-Q_DEFINE_METADATA(Category);
-Q_DEFINE_METADATA(Genre);
-Q_DEFINE_METADATA(Year);
-Q_DEFINE_METADATA(Date);
-Q_DEFINE_METADATA(UserRating);
-Q_DEFINE_METADATA(Keywords);
-Q_DEFINE_METADATA(Language);
-Q_DEFINE_METADATA(Publisher);
-Q_DEFINE_METADATA(Copyright);
-Q_DEFINE_METADATA(ParentalRating);
-Q_DEFINE_METADATA(RatingOrganization);
-
-// Media
-Q_DEFINE_METADATA(Size);
-Q_DEFINE_METADATA(MediaType);
-Q_DEFINE_METADATA(Duration);
-
-// Audio
-Q_DEFINE_METADATA(AudioBitRate);
-Q_DEFINE_METADATA(AudioCodec);
-Q_DEFINE_METADATA(AverageLevel);
-Q_DEFINE_METADATA(ChannelCount);
-Q_DEFINE_METADATA(PeakValue);
-Q_DEFINE_METADATA(SampleRate);
-
-// Music
-Q_DEFINE_METADATA(AlbumTitle);
-Q_DEFINE_METADATA(AlbumArtist);
-Q_DEFINE_METADATA(ContributingArtist);
-Q_DEFINE_METADATA(Composer);
-Q_DEFINE_METADATA(Conductor);
-Q_DEFINE_METADATA(Lyrics);
-Q_DEFINE_METADATA(Mood);
-Q_DEFINE_METADATA(TrackNumber);
-Q_DEFINE_METADATA(TrackCount);
-
-Q_DEFINE_METADATA(CoverArtUrlSmall);
-Q_DEFINE_METADATA(CoverArtUrlLarge);
-
-// Image/Video
-Q_DEFINE_METADATA(Resolution);
-Q_DEFINE_METADATA(PixelAspectRatio);
-Q_DEFINE_METADATA(Orientation);
-
-// Video
-Q_DEFINE_METADATA(VideoFrameRate);
-Q_DEFINE_METADATA(VideoBitRate);
-Q_DEFINE_METADATA(VideoCodec);
-
-Q_DEFINE_METADATA(PosterUrl);
-
-// Movie
-Q_DEFINE_METADATA(ChapterNumber);
-Q_DEFINE_METADATA(Director);
-Q_DEFINE_METADATA(LeadPerformer);
-Q_DEFINE_METADATA(Writer);
-
-// Photos
-Q_DEFINE_METADATA(CameraManufacturer);
-Q_DEFINE_METADATA(CameraModel);
-Q_DEFINE_METADATA(Event);
-Q_DEFINE_METADATA(Subject);
-Q_DEFINE_METADATA(ExposureTime);
-Q_DEFINE_METADATA(FNumber);
-Q_DEFINE_METADATA(ExposureProgram);
-Q_DEFINE_METADATA(ISOSpeedRatings);
-Q_DEFINE_METADATA(ExposureBiasValue);
-Q_DEFINE_METADATA(DateTimeOriginal);
-Q_DEFINE_METADATA(DateTimeDigitized);
-Q_DEFINE_METADATA(SubjectDistance);
-Q_DEFINE_METADATA(MeteringMode);
-Q_DEFINE_METADATA(LightSource);
-Q_DEFINE_METADATA(Flash);
-Q_DEFINE_METADATA(FocalLength);
-Q_DEFINE_METADATA(ExposureMode);
-Q_DEFINE_METADATA(WhiteBalance);
-Q_DEFINE_METADATA(DigitalZoomRatio);
-Q_DEFINE_METADATA(FocalLengthIn35mmFilm);
-Q_DEFINE_METADATA(SceneCaptureType);
-Q_DEFINE_METADATA(GainControl);
-Q_DEFINE_METADATA(Contrast);
-Q_DEFINE_METADATA(Saturation);
-Q_DEFINE_METADATA(Sharpness);
-Q_DEFINE_METADATA(DeviceSettingDescription);
-
-// Location
-Q_DEFINE_METADATA(GPSLatitude);
-Q_DEFINE_METADATA(GPSLongitude);
-Q_DEFINE_METADATA(GPSAltitude);
-Q_DEFINE_METADATA(GPSTimeStamp);
-Q_DEFINE_METADATA(GPSSatellites);
-Q_DEFINE_METADATA(GPSStatus);
-Q_DEFINE_METADATA(GPSDOP);
-Q_DEFINE_METADATA(GPSSpeed);
-Q_DEFINE_METADATA(GPSTrack);
-Q_DEFINE_METADATA(GPSTrackRef);
-Q_DEFINE_METADATA(GPSImgDirection);
-Q_DEFINE_METADATA(GPSImgDirectionRef);
-Q_DEFINE_METADATA(GPSMapDatum);
-Q_DEFINE_METADATA(GPSProcessingMethod);
-Q_DEFINE_METADATA(GPSAreaInformation);
-
-Q_DEFINE_METADATA(PosterImage);
-Q_DEFINE_METADATA(CoverArtImage);
-Q_DEFINE_METADATA(ThumbnailImage);
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvariant.h>
+#include <QtGui/qimage.h>
+#include <QtMultimedia/qmediaformat.h>
+QT_BEGIN_NAMESPACE
/*!
- \namespace QMediaMetaData
- \ingroup multimedia-namespaces
- \ingroup multimedia
+ \class QMediaMetaData
\inmodule QtMultimedia
- \brief Provides identifiers for meta-data attributes.
+ \brief Provides meta-data for media files.
- \note Not all identifiers are supported on all platforms. Please consult vendor documentation for specific support
- on different platforms.
+ \note Not all identifiers are supported on all platforms.
\table 60%
\header \li {3,1}
Common attributes
\header \li Value \li Description \li Type
\row \li Title \li The title of the media. \li QString
- \row \li SubTitle \li The sub-title of the media. \li QString
\row \li Author \li The authors of the media. \li QStringList
\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 Category \li The category of the media. \li QStringList
\row \li Genre \li The genre of the media. \li QStringList
- \row \li Year \li The year of release of the media. \li int
- \row \li Date \li The date of the media. \li QDate.
- \row \li UserRating \li A user rating of the media. \li int [0..100]
- \row \li Keywords \li A list of keywords describing the media. \li QStringList
- \row \li Language \li The language of media, as an ISO 639-2 code. \li QString
+ \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
\row \li Copyright \li The media's copyright notice. \li QString
- \row \li ParentalRating \li The parental rating of the media. \li QString
- \row \li RatingOrganization \li The organization responsible for the parental rating of the media.
- \li QString
+ \row \li Url \li A Url pointing to the origin of the media. \li QUrl
\header \li {3,1}
Media attributes
- \row \li Size \li The size in bytes of the media. \li qint64
\row \li MediaType \li The type of the media (audio, video, etc). \li QString
- \row \li Duration \li The duration in millseconds of the media. \li qint64
+ \row \li FileFormat \li The file format of the media. \li QMediaFormat::FileFormat
+ \row \li Duration \li The duration in milliseconds of the media. \li qint64
\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 QString
- \row \li AverageLevel \li The average volume level of the media. \li int
- \row \li ChannelCount \li The number of channels in the media's audio stream. \li int
- \row \li PeakValue \li The peak volume of the media's audio stream. \li int
- \row \li SampleRate \li The sample rate of the media's audio stream in hertz. \li int
+ \row \li AudioCodec \li The codec of the media's audio stream. \li QMediaFormat::AudioCodec
+
+ \header \li {3,1}
+ Video attributes
+ \row \li VideoFrameRate \li The frame rate of the media's video stream. \li qreal
+ \row \li VideoBitRate \li The bit rate of the media's video stream in bits per second. \li int
+ \row \li VideoCodec \li The codec of the media's video stream. \li QMediaFormat::VideoCodec
+ \row \li HasHdrContent \li True if video is intended for HDR display (FFmpeg and Darwin media backends only). \li bool
\header \li {3,1}
Music attributes
\row \li AlbumTitle \li The title of the album the media belongs to. \li QString
\row \li AlbumArtist \li The principal artist of the album the media belongs to. \li QString
\row \li ContributingArtist \li The artists contributing to the media. \li QStringList
- \row \li Composer \li The composer of the media. \li QStringList
- \row \li Conductor \li The conductor of the media. \li QString
- \row \li Lyrics \li The lyrics to the media. \li QString
- \row \li Mood \li The mood of the media. \li QString
\row \li TrackNumber \li The track number of the media. \li int
- \row \li TrackCount \li The number of tracks on the album containing the media. \li int
+ \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 CoverArtUrlSmall \li The URL of a small cover art image. \li QUrl
- \row \li CoverArtUrlLarge \li The URL of a large cover art image. \li QUrl
+ \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
- \row \li PixelAspectRatio \li The pixel aspect ratio of an image or video. \li QSize
- \row \li Orientation \li Orientation of an image or video. \li int (degrees)
- \header \li {3,1}
- Video attributes
- \row \li VideoFrameRate \li The frame rate of the media's video stream. \li qreal
- \row \li VideoBitRate \li The bit rate of the media's video stream in bits per second. \li int
- \row \li VideoCodec \li The codec of the media's video stream. \li QString
+ \endtable
+*/
- \row \li PosterUrl \li The URL of a poster image. \li QUrl
- \row \li PosterImage \li An embedded poster image. \li QImage
- \header \li {3,1}
- Movie attributes
- \row \li ChapterNumber \li The chapter number of the media. \li int
- \row \li Director \li The director of the media. \li QString
- \row \li LeadPerformer \li The lead performer in the media. \li QStringList
- \row \li Writer \li The writer of the media. \li QStringList
+/*!
+ 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>();
+
+ case HasHdrContent:
+ return QMetaType::fromType<bool>();
+
+ default:
+ return QMetaType::fromType<void>();
+ }
+}
+
+/*!
+ \qmlvaluetype mediaMetaData
+ \ingroup qmlvaluetypes
+ \inqmlmodule QtMultimedia
+ \since 6.2
+ //! \instantiates QMediaMetaData
+ \brief Provides meta-data for media files.
+ \ingroup multimedia_qml
+ \ingroup multimedia_audio_qml
+ \ingroup multimedia_video_qml
+
+ Meta-data is supplementary data describing media.
+ See QMediaMetaData for available meta data attributes.
+*/
+
+/*
+ Some potential attributes to add if we can properly support them.
+ Might require that we add EXIF support to Qt Multimedia
\header \li {3,1}
Photo attributes.
@@ -275,17 +177,16 @@ Q_DEFINE_METADATA(ThumbnailImage);
\row \li DateTimeOriginal \li The date and time when the original image data was generated. \li QDateTime
\row \li DateTimeDigitized \li The date and time when the image was stored as digital data. \li QDateTime
\row \li SubjectDistance \li The distance to the subject, given in meters. \li qreal
- \row \li MeteringMode \li The metering mode. \li QCameraExposure::MeteringMode
\row \li LightSource
\li The kind of light source. \li QString
\row \li Flash
- \li Status of flash when the image was shot. \li QCameraExposure::FlashMode
+ \li Status of flash when the image was shot. \li QCamera::FlashMode
\row \li FocalLength
\li The actual focal length of the lens, in mm. \li qreal
\row \li ExposureMode
- \li Indicates the exposure mode set when the image was shot. \li QCameraExposure::ExposureMode
+ \li Indicates the exposure mode set when the image was shot. \li QCamera::ExposureMode
\row \li WhiteBalance
- \li Indicates the white balance mode set when the image was shot. \li QCameraImageProcessing::WhiteBalanceMode
+ \li Indicates the white balance mode set when the image was shot. \li QCamera::WhiteBalanceMode
\row \li DigitalZoomRatio
\li Indicates the digital zoom ratio when the image was shot. \li qreal
\row \li FocalLengthIn35mmFilm
@@ -345,8 +246,305 @@ Q_DEFINE_METADATA(ThumbnailImage);
\row \li GPSAreaInformation
\li The name of the GPS area. \li QString
- \row \li ThumbnailImage \li An embedded thumbnail image. \li QImage
\endtable
*/
+/*!
+ \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
+ \value [since 6.8] HasHdrContent Video may have HDR content (read only, FFmpeg and Darwin media backends only)
+*/
+
+/*!
+ \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.
+*/
+
+/*!
+ \fn QVariant QMediaMetaData::value(QMediaMetaData::Key key) const
+
+ 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::mediaMetaData::isEmpty()
+ Returns \c true if the meta data contains no items: otherwise returns \c{false}.
+*/
+
+/*!
+ \fn bool QMediaMetaData::isEmpty() const
+ Returns \c true if the meta data contains no items: otherwise returns \c{false}.
+*/
+
+/*!
+ \qmlmethod void QtMultimedia::mediaMetaData::clear()
+ Removes all data from the MediaMetaData object.
+*/
+
+/*!
+ \fn void QMediaMetaData::clear()
+ Removes all data from the meta data object.
+*/
+
+/*!
+ \qmlmethod void QtMultimedia::mediaMetaData::insert(Key k, variant value)
+ Inserts a \a value into a Key: \a{k}.
+*/
+
+/*!
+ \fn void QMediaMetaData::insert(QMediaMetaData::Key k, const QVariant &value)
+ Inserts a \a value into a Key: \a{k}.
+*/
+/*!
+ \qmlmethod void QtMultimedia::mediaMetaData::remove(Key k)
+ Removes meta data from a Key: \a{k}.
+*/
+
+/*!
+ \fn void QMediaMetaData::remove(QMediaMetaData::Key k)
+ Removes meta data from a Key: \a{k}.
+*/
+
+/*!
+ \qmlmethod list<Key> QtMultimedia::mediaMetaData::keys()
+ Returns a list of MediaMetaData.Keys.
+*/
+
+/*!
+ \fn QMediaMetaData::keys() const
+ Returns a QList of QMediaMetaData::Keys.
+*/
+
+/*!
+ \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.
+*/
+/*!
+ Returns the meta data for key \a key as a QString.
+
+ This is mainly meant to simplify presenting the meta data to a user.
+*/
+QString QMediaMetaData::stringValue(QMediaMetaData::Key key) const
+{
+ QVariant value = data.value(key);
+ if (value.isNull())
+ return QString();
+
+ switch (key) {
+ // string based or convertible to string
+ case Title:
+ case Author:
+ case Comment:
+ case Description:
+ case Genre:
+ case Publisher:
+ case Copyright:
+ case Date:
+ case Url:
+ case MediaType:
+ case AudioBitRate:
+ case VideoBitRate:
+ case VideoFrameRate:
+ case AlbumTitle:
+ case AlbumArtist:
+ case ContributingArtist:
+ case TrackNumber:
+ case Composer:
+ case Orientation:
+ case LeadPerformer:
+ case HasHdrContent:
+ return value.toString();
+ case Language: {
+ auto l = value.value<QLocale::Language>();
+ return QLocale::languageToString(l);
+ }
+ case Duration: {
+ QTime time = QTime::fromMSecsSinceStartOfDay(value.toInt());
+ return time.toString();
+ }
+ case FileFormat:
+ return QMediaFormat::fileFormatName(value.value<QMediaFormat::FileFormat>());
+ case AudioCodec:
+ return QMediaFormat::audioCodecName(value.value<QMediaFormat::AudioCodec>());
+ case VideoCodec:
+ return QMediaFormat::videoCodecName(value.value<QMediaFormat::VideoCodec>());
+ case Resolution: {
+ QSize size = value.toSize();
+ return QStringLiteral("%1 x %2").arg(size.width()).arg(size.height());
+ }
+ case ThumbnailImage:
+ case CoverArtImage:
+ break;
+ }
+ return QString();
+}
+/*!
+ \qmlmethod string QtMultimedia::mediaMetaData::metaDataKeyToString(Key key)
+ returns a string representation of \a key that can be used when presenting
+ meta data to users.
+*/
+
+/*!
+ returns a string representation of \a key that can be used when presenting
+ meta data to users.
+*/
+QString QMediaMetaData::metaDataKeyToString(QMediaMetaData::Key key)
+{
+ switch (key) {
+ case QMediaMetaData::Title:
+ return (QCoreApplication::translate("QMediaMetaData", "Title"));
+ case QMediaMetaData::Author:
+ return (QCoreApplication::translate("QMediaMetaData", "Author"));
+ case QMediaMetaData::Comment:
+ return (QCoreApplication::translate("QMediaMetaData", "Comment"));
+ case QMediaMetaData::Description:
+ return (QCoreApplication::translate("QMediaMetaData", "Description"));
+ case QMediaMetaData::Genre:
+ return (QCoreApplication::translate("QMediaMetaData", "Genre"));
+ case QMediaMetaData::Date:
+ return (QCoreApplication::translate("QMediaMetaData", "Date"));
+ case QMediaMetaData::Language:
+ return (QCoreApplication::translate("QMediaMetaData", "Language"));
+ case QMediaMetaData::Publisher:
+ return (QCoreApplication::translate("QMediaMetaData", "Publisher"));
+ case QMediaMetaData::Copyright:
+ return (QCoreApplication::translate("QMediaMetaData", "Copyright"));
+ case QMediaMetaData::Url:
+ return (QCoreApplication::translate("QMediaMetaData", "Url"));
+ case QMediaMetaData::Duration:
+ return (QCoreApplication::translate("QMediaMetaData", "Duration"));
+ case QMediaMetaData::MediaType:
+ return (QCoreApplication::translate("QMediaMetaData", "Media type"));
+ case QMediaMetaData::FileFormat:
+ return (QCoreApplication::translate("QMediaMetaData", "Container Format"));
+ case QMediaMetaData::AudioBitRate:
+ return (QCoreApplication::translate("QMediaMetaData", "Audio bit rate"));
+ case QMediaMetaData::AudioCodec:
+ return (QCoreApplication::translate("QMediaMetaData", "Audio codec"));
+ case QMediaMetaData::VideoBitRate:
+ return (QCoreApplication::translate("QMediaMetaData", "Video bit rate"));
+ case QMediaMetaData::VideoCodec:
+ return (QCoreApplication::translate("QMediaMetaData", "Video codec"));
+ case QMediaMetaData::VideoFrameRate:
+ return (QCoreApplication::translate("QMediaMetaData", "Video frame rate"));
+ case QMediaMetaData::AlbumTitle:
+ return (QCoreApplication::translate("QMediaMetaData", "Album title"));
+ case QMediaMetaData::AlbumArtist:
+ return (QCoreApplication::translate("QMediaMetaData", "Album artist"));
+ case QMediaMetaData::ContributingArtist:
+ return (QCoreApplication::translate("QMediaMetaData", "Contributing artist"));
+ case QMediaMetaData::TrackNumber:
+ return (QCoreApplication::translate("QMediaMetaData", "Track number"));
+ case QMediaMetaData::Composer:
+ return (QCoreApplication::translate("QMediaMetaData", "Composer"));
+ case QMediaMetaData::ThumbnailImage:
+ return (QCoreApplication::translate("QMediaMetaData", "Thumbnail image"));
+ case QMediaMetaData::CoverArtImage:
+ return (QCoreApplication::translate("QMediaMetaData", "Cover art image"));
+ case QMediaMetaData::Orientation:
+ return (QCoreApplication::translate("QMediaMetaData", "Orientation"));
+ case QMediaMetaData::Resolution:
+ return (QCoreApplication::translate("QMediaMetaData", "Resolution"));
+ case QMediaMetaData::LeadPerformer:
+ return (QCoreApplication::translate("QMediaMetaData", "Lead performer"));
+ case QMediaMetaData::HasHdrContent:
+ return (QCoreApplication::translate("QMediaMetaData", "Has HDR content"));
+ }
+ return QString();
+}
+
+QDebug operator<<(QDebug dbg, const QMediaMetaData &metaData)
+{
+ QDebugStateSaver sv(dbg);
+ dbg.nospace();
+
+ dbg << "QMediaMetaData{";
+ auto range = metaData.asKeyValueRange();
+ auto begin = std::begin(range);
+
+ for (auto it = begin; it != std::end(range); ++it) {
+ if (it != begin)
+ dbg << ", ";
+ dbg << it->first << ": " << it->second;
+ }
+
+ dbg << "}";
+ return dbg;
+}
+
+// operator documentation
+/*!
+\fn QVariant &QMediaMetaData ::operator[](QMediaMetaData::Key k)
+ Returns data stored at the Key \a{k}.
+ \code
+ QMediaMetaData rockBallad1;
+ rockBalad[QMediaMetaData::Genre]="Rock"
+ \endcode
+*/
+
+/*!
+\fn bool QMediaMetaData::operator==(const QMediaMetaData &a, const QMediaMetaData &b)
+ Compares two meta data objects \a a and \a b, and returns
+ \c true if they are identical or \c false if they differ.
+*/
+
+/*!
+\fn bool QMediaMetaData::operator!=(const QMediaMetaData &a, const QMediaMetaData &b)
+ Compares two meta data objects \a a and \a b, and returns
+ \c false if they are identical or \c true if they differ.
+*/
+
+/*!
+ \variable QMediaMetaData::data
+ \brief the meta data.
+ \note this is a \c protected member of its class.
+*/
+
+/*!
+ \fn auto QMediaMetaData::asKeyValueRange() const
+ \internal
+*/
+
QT_END_NAMESPACE
+
+#include "moc_qmediametadata.cpp"
diff --git a/src/multimedia/qmediametadata.h b/src/multimedia/qmediametadata.h
index 8d8744490..e8c028dd2 100644
--- a/src/multimedia/qmediametadata.h
+++ b/src/multimedia/qmediametadata.h
@@ -1,49 +1,17 @@
-/****************************************************************************
-**
-** 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/qmetatype.h>
+#include <QtCore/qvariant.h>
#include <QtCore/qstring.h>
-
+#include <QtCore/qhash.h>
#include <QtMultimedia/qtmultimediaglobal.h>
QT_BEGIN_NAMESPACE
@@ -51,238 +19,83 @@ QT_BEGIN_NAMESPACE
// Class forward declaration required for QDoc bug
class QString;
-#define Q_DECLARE_METADATA(key) Q_MULTIMEDIA_EXPORT extern const QString key
-
-namespace QMediaMetaData {
-#ifdef Q_QDOC
- // QDoc does not like macros, so try to keep this in sync :)
- QString Title;
- QString SubTitle;
- QString Author;
- QString Comment;
- QString Description;
- QString Category;
- QString Genre;
- QString Year;
- QString Date;
- QString UserRating;
- QString Keywords;
- QString Language;
- QString Publisher;
- QString Copyright;
- QString ParentalRating;
- QString RatingOrganization;
-
- // Media
- QString Size;
- QString MediaType;
- QString Duration;
-
- // Audio
- QString AudioBitRate;
- QString AudioCodec;
- QString AverageLevel;
- QString ChannelCount;
- QString PeakValue;
- QString SampleRate;
+class Q_MULTIMEDIA_EXPORT QMediaMetaData
+{
+ Q_GADGET
+public:
+ enum Key {
+ Title,
+ Author,
+ Comment,
+ Description,
+ Genre,
+ Date,
- // Music
- QString AlbumTitle;
- QString AlbumArtist;
- QString ContributingArtist;
- QString Composer;
- QString Conductor;
- QString Lyrics;
- QString Mood;
- QString TrackNumber;
- QString TrackCount;
+ Language,
+ Publisher,
+ Copyright,
+ Url,
- QString CoverArtUrlSmall;
- QString CoverArtUrlLarge;
+ Duration,
+ MediaType,
+ FileFormat,
- // Image/Video
- QString Resolution;
- QString PixelAspectRatio;
+ AudioBitRate,
+ AudioCodec,
+ VideoBitRate,
+ VideoCodec,
+ VideoFrameRate,
- // Video
- QString VideoFrameRate;
- QString VideoBitRate;
- QString VideoCodec;
+ AlbumTitle,
+ AlbumArtist,
+ ContributingArtist,
+ TrackNumber,
+ Composer,
+ LeadPerformer,
- QString PosterUrl;
+ ThumbnailImage,
+ CoverArtImage,
- // Movie
- QString ChapterNumber;
- QString Director;
- QString LeadPerformer;
- QString Writer;
+ Orientation,
+ Resolution,
- // Photos
- QString CameraManufacturer;
- QString CameraModel;
- QString Event;
- QString Subject;
- QString Orientation;
- QString ExposureTime;
- QString FNumber;
- QString ExposureProgram;
- QString ISOSpeedRatings;
- QString ExposureBiasValue;
- QString DateTimeOriginal;
- QString DateTimeDigitized;
- QString SubjectDistance;
- QString MeteringMode;
- QString LightSource;
- QString Flash;
- QString FocalLength;
- QString ExposureMode;
- QString WhiteBalance;
- QString DigitalZoomRatio;
- QString FocalLengthIn35mmFilm;
- QString SceneCaptureType;
- QString GainControl;
- QString Contrast;
- QString Saturation;
- QString Sharpness;
- QString DeviceSettingDescription;
+ HasHdrContent,
+ };
+ Q_ENUM(Key)
- // Location
- QString GPSLatitude;
- QString GPSLongitude;
- QString GPSAltitude;
- QString GPSTimeStamp;
- QString GPSSatellites;
- QString GPSStatus;
- QString GPSDOP;
- QString GPSSpeed;
- QString GPSTrack;
- QString GPSTrackRef;
- QString GPSImgDirection;
- QString GPSImgDirectionRef;
- QString GPSMapDatum;
- QString GPSProcessingMethod;
- QString GPSAreaInformation;
+ static constexpr int NumMetaData = HasHdrContent + 1;
- QString PosterImage;
- QString CoverArtImage;
- QString ThumbnailImage;
-#else
- // Common
- Q_DECLARE_METADATA(Title);
- Q_DECLARE_METADATA(SubTitle);
- Q_DECLARE_METADATA(Author);
- Q_DECLARE_METADATA(Comment);
- Q_DECLARE_METADATA(Description);
- Q_DECLARE_METADATA(Category);
- Q_DECLARE_METADATA(Genre);
- Q_DECLARE_METADATA(Year);
- Q_DECLARE_METADATA(Date);
- Q_DECLARE_METADATA(UserRating);
- Q_DECLARE_METADATA(Keywords);
- Q_DECLARE_METADATA(Language);
- Q_DECLARE_METADATA(Publisher);
- Q_DECLARE_METADATA(Copyright);
- Q_DECLARE_METADATA(ParentalRating);
- Q_DECLARE_METADATA(RatingOrganization);
+// QMetaType typeForKey(Key k);
+ Q_INVOKABLE QVariant value(Key k) const { return data.value(k); }
+ Q_INVOKABLE void insert(Key k, const QVariant &value) { data.insert(k, value); }
+ Q_INVOKABLE void remove(Key k) { data.remove(k); }
+ Q_INVOKABLE QList<Key> keys() const { return data.keys(); }
- // Media
- Q_DECLARE_METADATA(Size);
- Q_DECLARE_METADATA(MediaType);
- Q_DECLARE_METADATA(Duration);
+ QVariant &operator[](Key k) { return data[k]; }
+ Q_INVOKABLE void clear() { data.clear(); }
- // Audio
- Q_DECLARE_METADATA(AudioBitRate);
- Q_DECLARE_METADATA(AudioCodec);
- Q_DECLARE_METADATA(AverageLevel);
- Q_DECLARE_METADATA(ChannelCount);
- Q_DECLARE_METADATA(PeakValue);
- Q_DECLARE_METADATA(SampleRate);
+ Q_INVOKABLE bool isEmpty() const { return data.isEmpty(); }
+ Q_INVOKABLE QString stringValue(Key k) const;
- // Music
- Q_DECLARE_METADATA(AlbumTitle);
- Q_DECLARE_METADATA(AlbumArtist);
- Q_DECLARE_METADATA(ContributingArtist);
- Q_DECLARE_METADATA(Composer);
- Q_DECLARE_METADATA(Conductor);
- Q_DECLARE_METADATA(Lyrics);
- Q_DECLARE_METADATA(Mood);
- Q_DECLARE_METADATA(TrackNumber);
- Q_DECLARE_METADATA(TrackCount);
+ Q_INVOKABLE static QString metaDataKeyToString(Key k);
- Q_DECLARE_METADATA(CoverArtUrlSmall);
- Q_DECLARE_METADATA(CoverArtUrlLarge);
+ QT_TECH_PREVIEW_API auto asKeyValueRange() const { return data.asKeyValueRange(); }
- // Image/Video
- Q_DECLARE_METADATA(Resolution);
- Q_DECLARE_METADATA(PixelAspectRatio);
+protected:
+ Q_MULTIMEDIA_EXPORT friend QDebug operator<<(QDebug, const QMediaMetaData &);
- // Video
- Q_DECLARE_METADATA(VideoFrameRate);
- Q_DECLARE_METADATA(VideoBitRate);
- Q_DECLARE_METADATA(VideoCodec);
+ friend bool operator==(const QMediaMetaData &a, const QMediaMetaData &b)
+ { return a.data == b.data; }
+ friend bool operator!=(const QMediaMetaData &a, const QMediaMetaData &b)
+ { return a.data != b.data; }
- Q_DECLARE_METADATA(PosterUrl);
+ static QMetaType keyType(Key key);
- // Movie
- Q_DECLARE_METADATA(ChapterNumber);
- Q_DECLARE_METADATA(Director);
- Q_DECLARE_METADATA(LeadPerformer);
- Q_DECLARE_METADATA(Writer);
-
- // Photos
- Q_DECLARE_METADATA(CameraManufacturer);
- Q_DECLARE_METADATA(CameraModel);
- Q_DECLARE_METADATA(Event);
- Q_DECLARE_METADATA(Subject);
- Q_DECLARE_METADATA(Orientation);
- Q_DECLARE_METADATA(ExposureTime);
- Q_DECLARE_METADATA(FNumber);
- Q_DECLARE_METADATA(ExposureProgram);
- Q_DECLARE_METADATA(ISOSpeedRatings);
- Q_DECLARE_METADATA(ExposureBiasValue);
- Q_DECLARE_METADATA(DateTimeOriginal);
- Q_DECLARE_METADATA(DateTimeDigitized);
- Q_DECLARE_METADATA(SubjectDistance);
- Q_DECLARE_METADATA(MeteringMode);
- Q_DECLARE_METADATA(LightSource);
- Q_DECLARE_METADATA(Flash);
- Q_DECLARE_METADATA(FocalLength);
- Q_DECLARE_METADATA(ExposureMode);
- Q_DECLARE_METADATA(WhiteBalance);
- Q_DECLARE_METADATA(DigitalZoomRatio);
- Q_DECLARE_METADATA(FocalLengthIn35mmFilm);
- Q_DECLARE_METADATA(SceneCaptureType);
- Q_DECLARE_METADATA(GainControl);
- Q_DECLARE_METADATA(Contrast);
- Q_DECLARE_METADATA(Saturation);
- Q_DECLARE_METADATA(Sharpness);
- Q_DECLARE_METADATA(DeviceSettingDescription);
-
- // Location
- Q_DECLARE_METADATA(GPSLatitude);
- Q_DECLARE_METADATA(GPSLongitude);
- Q_DECLARE_METADATA(GPSAltitude);
- Q_DECLARE_METADATA(GPSTimeStamp);
- Q_DECLARE_METADATA(GPSSatellites);
- Q_DECLARE_METADATA(GPSStatus);
- Q_DECLARE_METADATA(GPSDOP);
- Q_DECLARE_METADATA(GPSSpeed);
- Q_DECLARE_METADATA(GPSTrack);
- Q_DECLARE_METADATA(GPSTrackRef);
- Q_DECLARE_METADATA(GPSImgDirection);
- Q_DECLARE_METADATA(GPSImgDirectionRef);
- Q_DECLARE_METADATA(GPSMapDatum);
- Q_DECLARE_METADATA(GPSProcessingMethod);
- Q_DECLARE_METADATA(GPSAreaInformation);
-
- Q_DECLARE_METADATA(PosterImage);
- Q_DECLARE_METADATA(CoverArtImage);
- Q_DECLARE_METADATA(ThumbnailImage);
-#endif
-}
-
-#undef Q_DECLARE_METADATA
+ QHash<Key, QVariant> data;
+};
QT_END_NAMESPACE
+Q_DECLARE_METATYPE(QMediaMetaData)
+
#endif // QMEDIAMETADATA_H
diff --git a/src/multimedia/qmediaobject.cpp b/src/multimedia/qmediaobject.cpp
deleted file mode 100644
index 26a8580f5..000000000
--- a/src/multimedia/qmediaobject.cpp
+++ /dev/null
@@ -1,427 +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/qmetaobject.h>
-#include <QtCore/qdebug.h>
-
-#include "qmediaobject_p.h"
-
-#include <qmediaservice.h>
-#include <qmetadatareadercontrol.h>
-#include <qmediabindableinterface.h>
-#include <qmediaavailabilitycontrol.h>
-
-QT_BEGIN_NAMESPACE
-
-void QMediaObjectPrivate::_q_notify()
-{
- Q_Q(QMediaObject);
-
- const QMetaObject* m = q->metaObject();
-
- // QTBUG-57045
- // we create a copy of notifyProperties container to ensure that if a property is removed
- // from the original container as a result of invoking propertyChanged signal, the iterator
- // won't become invalidated
- QSet<int> properties = notifyProperties;
-
- for (int pi : qAsConst(properties)) {
- QMetaProperty p = m->property(pi);
- p.notifySignal().invoke(
- q, QGenericArgument(p.metaType().name(), p.read(q).data()));
- }
-}
-
-void QMediaObjectPrivate::_q_availabilityChanged()
-{
- Q_Q(QMediaObject);
-
- // Really this should not always emit, but
- // we can't really tell from here (isAvailable
- // may not have changed, or the mediaobject's overridden
- // availability() may not have changed).
- q->availabilityChanged(q->availability());
- q->availabilityChanged(q->isAvailable());
-}
-
-/*!
- \class QMediaObject
-
- \brief The QMediaObject class provides a common base for multimedia objects.
- \inmodule QtMultimedia
-
- \ingroup multimedia
- \ingroup multimedia_core
-
- It provides some basic functionality that is common to other high level classes
- like \l QMediaPlayer, \l QAudioDecoder and \l QCamera, including availability
- and meta-data functionality, as well as functionality to connect media objects
- with support classes like QMediaPlaylist.
-
- The higher level QMediaObject derived classes provide the actual multimedia
- functionality, by internally using a QMediaService. Each media object
- hosts a QMediaService and uses the QMediaControl interfaces implemented by the service to implement its
- API. These controls can be accessed from the media object if necessary, but in general
- the useful functionality can be accessed from the higher level classes.
-
- Most media objects when constructed will request a new
- QMediaService instance, but some like
- QMediaRecorder and QAudioRecorder will share a service with another object.
-
- \sa QMediaService, QMediaControl
-*/
-
-/*!
- Destroys this media object.
-*/
-
-QMediaObject::~QMediaObject()
-{
-}
-
-/*!
- Returns the availability of the functionality offered by this object.
-
- In some cases the functionality may not be available (for example, if
- the current operating system or platform does not provide the required
- functionality), or it may be temporarily unavailable (for example,
- audio playback during a phone call or similar).
-*/
-
-QMultimedia::AvailabilityStatus QMediaObject::availability() const
-{
- if (d_func()->service == nullptr)
- return QMultimedia::ServiceMissing;
-
- if (d_func()->availabilityControl)
- return d_func()->availabilityControl->availability();
-
- return QMultimedia::Available;
-}
-
-/*!
- Returns true if the service is available for use.
-*/
-
-bool QMediaObject::isAvailable() const
-{
- return availability() == QMultimedia::Available;
-}
-
-/*!
- Returns the media service that provides the functionality of this multimedia object.
-*/
-
-QMediaService* QMediaObject::service() const
-{
- return d_func()->service;
-}
-
-int QMediaObject::notifyInterval() const
-{
- return d_func()->notifyTimer->interval();
-}
-
-void QMediaObject::setNotifyInterval(int milliSeconds)
-{
- Q_D(QMediaObject);
-
- if (d->notifyTimer->interval() != milliSeconds) {
- d->notifyTimer->setInterval(milliSeconds);
-
- emit notifyIntervalChanged(milliSeconds);
- }
-}
-
-/*!
- Bind \a object to this QMediaObject instance.
-
- This method establishes a relationship between this media object and a
- helper object. The nature of the relationship depends on both parties. This
- methods returns true if the helper was successfully bound, false otherwise.
-
- Most subclasses of QMediaObject provide more convenient functions
- that wrap this functionality, so this function rarely needs to be
- called directly.
-
- The object passed must implement the QMediaBindableInterface interface.
-
- \sa QMediaBindableInterface
-*/
-bool QMediaObject::bind(QObject *object)
-{
- QMediaBindableInterface *helper = qobject_cast<QMediaBindableInterface*>(object);
- if (!helper)
- return false;
-
- QMediaObject *currentObject = helper->mediaObject();
-
- if (currentObject == this)
- return true;
-
- if (currentObject)
- currentObject->unbind(object);
-
- return helper->setMediaObject(this);
-}
-
-/*!
- Detach \a object from the QMediaObject instance.
-
- Unbind the helper object from this media object. A warning
- will be generated if the object was not previously bound to this
- object.
-
- \sa QMediaBindableInterface
-*/
-void QMediaObject::unbind(QObject *object)
-{
- QMediaBindableInterface *helper = qobject_cast<QMediaBindableInterface*>(object);
-
- if (helper && helper->mediaObject() == this)
- helper->setMediaObject(nullptr);
- else
- qWarning() << "QMediaObject: Trying to unbind not connected helper object";
-}
-
-/*!
- Constructs a media object which uses the functionality provided by a media \a service.
-
- The \a parent is passed to QObject.
-
- This class is meant as a base class for multimedia objects so this
- constructor is protected.
-*/
-
-QMediaObject::QMediaObject(QObject *parent, QMediaService *service)
- : QObject(*new QMediaObjectPrivate, parent)
-{
- Q_D(QMediaObject);
-
- d->notifyTimer = new QTimer(this);
- d->notifyTimer->setInterval(1000);
- connect(d->notifyTimer, SIGNAL(timeout()), SLOT(_q_notify()));
-
- d->service = service;
-
- setupControls();
-}
-
-/*!
- \internal
-*/
-
-QMediaObject::QMediaObject(QMediaObjectPrivate &dd, QObject *parent, QMediaService *service)
- : QObject(dd, parent)
-{
- Q_D(QMediaObject);
-
- d->notifyTimer = new QTimer(this);
- d->notifyTimer->setInterval(1000);
- connect(d->notifyTimer, SIGNAL(timeout()), SLOT(_q_notify()));
-
- d->service = service;
-
- setupControls();
-}
-
-/*!
- Watch the property \a name. The property's notify signal will be emitted
- once every \c notifyInterval milliseconds.
-
- \sa notifyInterval
-*/
-
-void QMediaObject::addPropertyWatch(QByteArray const &name)
-{
- Q_D(QMediaObject);
-
- const QMetaObject* m = metaObject();
-
- int index = m->indexOfProperty(name.constData());
-
- if (index != -1 && m->property(index).hasNotifySignal()) {
- d->notifyProperties.insert(index);
-
- if (!d->notifyTimer->isActive())
- d->notifyTimer->start();
- }
-}
-
-/*!
- Remove property \a name from the list of properties whose changes are
- regularly signaled.
-
- \sa notifyInterval
-*/
-
-void QMediaObject::removePropertyWatch(QByteArray const &name)
-{
- Q_D(QMediaObject);
-
- int index = metaObject()->indexOfProperty(name.constData());
-
- if (index != -1) {
- d->notifyProperties.remove(index);
-
- if (d->notifyProperties.isEmpty())
- d->notifyTimer->stop();
- }
-}
-
-/*!
- \property QMediaObject::notifyInterval
-
- The interval at which notifiable properties will update.
-
- The interval is expressed in milliseconds, the default value is 1000.
-
- \sa addPropertyWatch(), removePropertyWatch()
-*/
-
-/*!
- \fn void QMediaObject::notifyIntervalChanged(int milliseconds)
-
- Signal a change in the notify interval period to \a milliseconds.
-*/
-
-/*!
- Returns true if there is meta-data associated with this media object, else false.
-*/
-
-bool QMediaObject::isMetaDataAvailable() const
-{
- Q_D(const QMediaObject);
-
- return d->metaDataControl
- ? d->metaDataControl->isMetaDataAvailable()
- : false;
-}
-
-/*!
- \fn QMediaObject::metaDataAvailableChanged(bool available)
-
- Signals that the \a available state of a media object's meta-data has changed.
-*/
-
-/*!
- Returns the value associated with a meta-data \a key.
-
- See the list of predefined \l {QMediaMetaData}{meta-data keys}.
-*/
-QVariant QMediaObject::metaData(const QString &key) const
-{
- Q_D(const QMediaObject);
-
- return d->metaDataControl
- ? d->metaDataControl->metaData(key)
- : QVariant();
-}
-
-/*!
- Returns a list of keys there is meta-data available for.
-*/
-QStringList QMediaObject::availableMetaData() const
-{
- Q_D(const QMediaObject);
-
- return d->metaDataControl
- ? d->metaDataControl->availableMetaData()
- : QStringList();
-}
-
-/*!
- \fn QMediaObject::metaDataChanged()
-
- Signals that this media object's meta-data has changed.
-
- If multiple meta-data elements are changed,
- metaDataChanged(const QString &key, const QVariant &value) signal is emitted
- for each of them with metaDataChanged() changed emitted once.
-*/
-
-/*!
- \fn QMediaObject::metaDataChanged(const QString &key, const QVariant &value)
-
- Signal the changes of one meta-data element \a value with the given \a key.
-*/
-
-
-void QMediaObject::setupControls()
-{
- Q_D(QMediaObject);
-
- if (d->service != nullptr) {
- d->metaDataControl = qobject_cast<QMetaDataReaderControl*>(
- d->service->requestControl(QMetaDataReaderControl_iid));
-
- if (d->metaDataControl) {
- connect(d->metaDataControl, SIGNAL(metaDataChanged()), SIGNAL(metaDataChanged()));
- connect(d->metaDataControl,
- SIGNAL(metaDataChanged(QString,QVariant)),
- SIGNAL(metaDataChanged(QString,QVariant)));
- connect(d->metaDataControl,
- SIGNAL(metaDataAvailableChanged(bool)),
- SIGNAL(metaDataAvailableChanged(bool)));
- }
-
- d->availabilityControl = d->service->requestControl<QMediaAvailabilityControl*>();
- if (d->availabilityControl) {
- connect(d->availabilityControl,
- SIGNAL(availabilityChanged(QMultimedia::AvailabilityStatus)),
- SLOT(_q_availabilityChanged()));
- }
- }
-}
-
-/*!
- \fn QMediaObject::availabilityChanged(bool available)
-
- Signal emitted when the availability state has changed to \a available.
-*/
-
-/*!
- \fn QMediaObject::availabilityChanged(QMultimedia::AvailabilityStatus availability)
-
- Signal emitted when the availability of the service has changed to \a availability.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qmediaobject.cpp"
diff --git a/src/multimedia/qmediaobject.h b/src/multimedia/qmediaobject.h
deleted file mode 100644
index 7c8da9555..000000000
--- a/src/multimedia/qmediaobject.h
+++ /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$
-**
-****************************************************************************/
-
-#ifndef QABSTRACTMEDIAOBJECT_H
-#define QABSTRACTMEDIAOBJECT_H
-
-#include <QtCore/qobject.h>
-#include <QtCore/qstringlist.h>
-
-#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qmultimedia.h>
-
-QT_BEGIN_NAMESPACE
-
-
-class QMediaService;
-class QMediaBindableInterface;
-
-class QMediaObjectPrivate;
-class Q_MULTIMEDIA_EXPORT QMediaObject : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(int notifyInterval READ notifyInterval WRITE setNotifyInterval NOTIFY notifyIntervalChanged)
-public:
- ~QMediaObject();
-
- virtual bool isAvailable() const;
- virtual QMultimedia::AvailabilityStatus availability() const;
-
- virtual QMediaService* service() const;
-
- int notifyInterval() const;
- void setNotifyInterval(int milliSeconds);
-
- virtual bool bind(QObject *);
- virtual void unbind(QObject *);
-
- bool isMetaDataAvailable() const;
-
- QVariant metaData(const QString &key) const;
- QStringList availableMetaData() const;
-
-Q_SIGNALS:
- void notifyIntervalChanged(int milliSeconds);
-
- void metaDataAvailableChanged(bool available);
- void metaDataChanged();
- void metaDataChanged(const QString &key, const QVariant &value);
-
- void availabilityChanged(bool available);
- void availabilityChanged(QMultimedia::AvailabilityStatus availability);
-
-protected:
- QMediaObject(QObject *parent, QMediaService *service);
- QMediaObject(QMediaObjectPrivate &dd, QObject *parent, QMediaService *service);
-
- void addPropertyWatch(QByteArray const &name);
- void removePropertyWatch(QByteArray const &name);
-
-private:
- void setupControls();
-
- Q_DECLARE_PRIVATE(QMediaObject)
- Q_PRIVATE_SLOT(d_func(), void _q_notify())
- Q_PRIVATE_SLOT(d_func(), void _q_availabilityChanged())
-};
-
-
-QT_END_NAMESPACE
-
-
-#endif // QABSTRACTMEDIAOBJECT_H
diff --git a/src/multimedia/qmediaobject_p.h b/src/multimedia/qmediaobject_p.h
deleted file mode 100644
index 5067fa6d1..000000000
--- a/src/multimedia/qmediaobject_p.h
+++ /dev/null
@@ -1,94 +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 QABSTRACTMEDIAOBJECT_P_H
-#define QABSTRACTMEDIAOBJECT_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/qbytearray.h>
-#include <QtCore/qset.h>
-#include <QtCore/qtimer.h>
-
-#include "qmediaobject.h"
-#include "private/qobject_p.h"
-
-QT_BEGIN_NAMESPACE
-
-
-class QMetaDataReaderControl;
-class QMediaAvailabilityControl;
-
-#define Q_DECLARE_NON_CONST_PUBLIC(Class) \
- inline Class* q_func() { return static_cast<Class *>(q_ptr); } \
- friend class Class;
-
-
-class QMediaObjectPrivate : public QObjectPrivate
-{
- Q_DECLARE_PUBLIC(QMediaObject)
-
-public:
- QMediaObjectPrivate() : service(nullptr), metaDataControl(nullptr), availabilityControl(nullptr), notifyTimer(nullptr) {}
- virtual ~QMediaObjectPrivate() {}
-
- void _q_notify();
- void _q_availabilityChanged();
-
- QMediaService *service;
- QMetaDataReaderControl *metaDataControl;
- QMediaAvailabilityControl *availabilityControl;
-
- QTimer* notifyTimer;
- QSet<int> notifyProperties;
-};
-
-QT_END_NAMESPACE
-
-
-#endif
diff --git a/src/multimedia/qmediapluginloader.cpp b/src/multimedia/qmediapluginloader.cpp
deleted file mode 100644
index 3e9e6cc21..000000000
--- a/src/multimedia/qmediapluginloader.cpp
+++ /dev/null
@@ -1,186 +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 "qmediapluginloader_p.h"
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qjsonarray.h>
-#include <private/qfactoryloader_p.h>
-
-#include "qmediaserviceproviderplugin.h"
-
-QT_BEGIN_NAMESPACE
-
-QMediaPluginLoader::QMediaPluginLoader(const char *iid, const QString &location, Qt::CaseSensitivity caseSensitivity):
- m_iid(iid)
-{
-#if defined(Q_OS_ANDROID)
- m_location = QString(location).replace(QLatin1Char('/'), QLatin1Char('_'));
-#else
- m_location = QString::fromLatin1("/%1").arg(location);
-#endif
- m_factoryLoader = new QFactoryLoader(m_iid, m_location, caseSensitivity);
- loadMetadata();
-}
-
-QMediaPluginLoader::~QMediaPluginLoader()
-{
- delete m_factoryLoader;
-}
-
-QStringList QMediaPluginLoader::keys() const
-{
- return m_metadata.keys();
-}
-
-QObject* QMediaPluginLoader::instance(QString const &key)
-{
- if (!m_metadata.contains(key))
- return nullptr;
-
- int idx = m_metadata.value(key).first().value(QStringLiteral("index")).toDouble();
- if (idx < 0)
- return nullptr;
-
- return m_factoryLoader->instance(idx);
-}
-
-QList<QObject*> QMediaPluginLoader::instances(QString const &key)
-{
- if (!m_metadata.contains(key))
- return QList<QObject*>();
-
- QList<QString> keys;
- QList<QObject *> objects;
- const auto list = m_metadata.value(key);
- for (const QJsonObject &jsonobj : list) {
- int idx = jsonobj.value(QStringLiteral("index")).toDouble();
- if (idx < 0)
- continue;
-
- QObject *object = m_factoryLoader->instance(idx);
- if (!objects.contains(object)) {
- QJsonArray arr = jsonobj.value(QStringLiteral("Keys")).toArray();
- keys.append(!arr.isEmpty() ? arr.at(0).toString() : QStringLiteral(""));
- objects.append(object);
- }
- }
-
- static const bool showDebug = qEnvironmentVariableIntValue("QT_DEBUG_PLUGINS");
- static const QStringList preferredPlugins =
- qEnvironmentVariable("QT_MULTIMEDIA_PREFERRED_PLUGINS").split(QLatin1Char(','), Qt::SkipEmptyParts);
- for (int i = preferredPlugins.size() - 1; i >= 0; --i) {
- auto name = preferredPlugins[i];
- bool found = false;
- for (int j = 0; j < keys.size(); ++j) {
- if (!keys[j].startsWith(name))
- continue;
-
- auto obj = objects[j];
- objects.removeAt(j);
- objects.prepend(obj);
- auto k = keys[j];
- keys.removeAt(j);
- keys.prepend(k);
- found = true;
- break;
- }
-
- if (showDebug && !found)
- qWarning() << "QMediaPluginLoader: pattern" << name << "did not match any loaded plugin";
- }
-
- if (showDebug)
- qDebug() << "QMediaPluginLoader: loaded plugins for key" << key << ":" << keys;
-
- return objects;
-}
-
-void QMediaPluginLoader::loadMetadata()
-{
-#if !defined QT_NO_DEBUG
- const bool showDebug = qgetenv("QT_DEBUG_PLUGINS").toInt() > 0;
-#endif
-
-#if !defined QT_NO_DEBUG
- if (showDebug)
- qDebug() << "QMediaPluginLoader: loading metadata for iid " << m_iid << " at location " << m_location;
-#endif
-
- if (!m_metadata.isEmpty()) {
-#if !defined QT_NO_DEBUG
- if (showDebug)
- qDebug() << "QMediaPluginLoader: already loaded metadata, returning";
-#endif
- return;
- }
-
- QList<QJsonObject> meta = m_factoryLoader->metaData();
- for (int i = 0; i < meta.size(); i++) {
- QJsonObject jsonobj = meta.at(i).value(QStringLiteral("MetaData")).toObject();
- jsonobj.insert(QStringLiteral("index"), i);
-#if !defined QT_NO_DEBUG
- if (showDebug)
- qDebug() << "QMediaPluginLoader: Inserted index " << i << " into metadata: " << jsonobj;
-#endif
-
- QJsonArray arr = jsonobj.value(QStringLiteral("Services")).toArray();
- // Preserve compatibility with older plugins (made before 5.1) in which
- // services were declared in the 'Keys' property
- if (arr.isEmpty())
- arr = jsonobj.value(QStringLiteral("Keys")).toArray();
-
- for (const QJsonValue &value : qAsConst(arr)) {
- QString key = value.toString();
-
- if (!m_metadata.contains(key)) {
-#if !defined QT_NO_DEBUG
- if (showDebug)
- qDebug() << "QMediaPluginLoader: Inserting new list for key: " << key;
-#endif
- m_metadata.insert(key, QList<QJsonObject>());
- }
-
- m_metadata[key].append(jsonobj);
- }
- }
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/multimedia/qmediapluginloader_p.h b/src/multimedia/qmediapluginloader_p.h
deleted file mode 100644
index a4e726544..000000000
--- a/src/multimedia/qmediapluginloader_p.h
+++ /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$
-**
-****************************************************************************/
-
-#ifndef QMEDIAPLUGINLOADER_H
-#define QMEDIAPLUGINLOADER_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/qobject.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qmap.h>
-#include <QtCore/qjsonobject.h>
-
-
-QT_BEGIN_NAMESPACE
-
-class QFactoryLoader;
-class QMediaServiceProviderPlugin;
-
-class Q_MULTIMEDIA_EXPORT QMediaPluginLoader
-{
-public:
- QMediaPluginLoader(const char *iid,
- const QString &suffix = QString(),
- Qt::CaseSensitivity = Qt::CaseSensitive);
- ~QMediaPluginLoader();
-
- QStringList keys() const;
- QObject* instance(QString const &key);
- QList<QObject*> instances(QString const &key);
-
-private:
- void loadMetadata();
-
- QByteArray m_iid;
- QString m_location;
- QMap<QString, QList<QJsonObject> > m_metadata;
-
- QFactoryLoader *m_factoryLoader;
-};
-
-QT_END_NAMESPACE
-
-
-#endif // QMEDIAPLUGINLOADER_H
diff --git a/src/multimedia/qmediaresourcepolicy_p.cpp b/src/multimedia/qmediaresourcepolicy_p.cpp
deleted file mode 100644
index 14dc15968..000000000
--- a/src/multimedia/qmediaresourcepolicy_p.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 "qmediaresourcepolicy_p.h"
-#include "qmediapluginloader_p.h"
-#include "qmediaresourcepolicyplugin_p.h"
-#include "qmediaresourceset_p.h"
-
-namespace {
- class QDummyMediaPlayerResourceSet : public QMediaPlayerResourceSetInterface
- {
- public:
- QDummyMediaPlayerResourceSet(QObject *parent)
- : QMediaPlayerResourceSetInterface(parent)
- {
- }
-
- bool isVideoEnabled() const override
- {
- return true;
- }
-
- bool isGranted() const override
- {
- return true;
- }
-
- bool isAvailable() const override
- {
- return true;
- }
-
- void acquire() override {}
- void release() override {}
- void setVideoEnabled(bool) override {}
- };
-}
-
-QT_BEGIN_NAMESPACE
-
-Q_GLOBAL_STATIC_WITH_ARGS(QMediaPluginLoader, resourcePolicyLoader,
- (QMediaResourceSetFactoryInterface_iid, QLatin1String("resourcepolicy"), Qt::CaseInsensitive))
-
-Q_GLOBAL_STATIC(QObject, dummyRoot)
-
-QObject* QMediaResourcePolicy::createResourceSet(const QString& interfaceId)
-{
- QMediaResourceSetFactoryInterface *factory =
- qobject_cast<QMediaResourceSetFactoryInterface*>(resourcePolicyLoader()
- ->instance(QLatin1String("default")));
- QObject *obj = nullptr;
- if (factory)
- obj = factory->create(interfaceId);
-
- if (!obj) {
- if (interfaceId == QLatin1String(QMediaPlayerResourceSetInterface_iid)) {
- obj = new QDummyMediaPlayerResourceSet(dummyRoot());
- }
- }
- Q_ASSERT(obj);
- return obj;
-}
-
-void QMediaResourcePolicy::destroyResourceSet(QObject* resourceSet)
-{
- if (resourceSet->parent() == dummyRoot()) {
- delete resourceSet;
- return;
- }
- QMediaResourceSetFactoryInterface *factory =
- qobject_cast<QMediaResourceSetFactoryInterface*>(resourcePolicyLoader()
- ->instance(QLatin1String("default")));
- Q_ASSERT(factory);
- if (!factory)
- return;
- return factory->destroy(resourceSet);
-}
-QT_END_NAMESPACE
diff --git a/src/multimedia/qmediaresourcepolicy_p.h b/src/multimedia/qmediaresourcepolicy_p.h
deleted file mode 100644
index 13e3f4913..000000000
--- a/src/multimedia/qmediaresourcepolicy_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 QMEDIARESOURCEPOLICY_H
-#define QMEDIARESOURCEPOLICY_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 "qtmultimediaglobal.h"
-
-QT_BEGIN_NAMESPACE
-
-class Q_MULTIMEDIA_EXPORT QMediaResourcePolicy
-{
-public:
- //a dummy object will always be provided if the interfaceId is not supported
- template<typename T>
- static T* createResourceSet();
- static void destroyResourceSet(QObject* resourceSet);
-private:
- static QObject* createResourceSet(const QString& interfaceId);
-};
-
-template<typename T>
-T* QMediaResourcePolicy::createResourceSet()
-{
- return qobject_cast<T*>(QMediaResourcePolicy::createResourceSet(T::iid()));
-}
-
-QT_END_NAMESPACE
-
-#endif // QMEDIARESOURCEPOLICY_H
diff --git a/src/multimedia/qmediaresourcepolicyplugin_p.cpp b/src/multimedia/qmediaresourcepolicyplugin_p.cpp
deleted file mode 100644
index 051eeb9db..000000000
--- a/src/multimedia/qmediaresourcepolicyplugin_p.cpp
+++ /dev/null
@@ -1,53 +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 "qmediaresourcepolicyplugin_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QMediaResourcePolicyPlugin::QMediaResourcePolicyPlugin(QObject *parent)
- : QObject(parent)
-{
-}
-
-QMediaResourcePolicyPlugin::~QMediaResourcePolicyPlugin()
-{
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/qmediaresourcepolicyplugin_p.h b/src/multimedia/qmediaresourcepolicyplugin_p.h
deleted file mode 100644
index e37551390..000000000
--- a/src/multimedia/qmediaresourcepolicyplugin_p.h
+++ /dev/null
@@ -1,81 +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 QRESOURCEPOLICYPLUGIN_P_H
-#define QRESOURCEPOLICYPLUGIN_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QObject>
-#include <qtmultimediaglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-struct Q_MULTIMEDIA_EXPORT QMediaResourceSetFactoryInterface
-{
- virtual QObject* create(const QString& interfaceId) = 0;
- virtual void destroy(QObject *resourceSet) = 0;
-};
-
-#define QMediaResourceSetFactoryInterface_iid \
- "org.qt-project.qt.mediaresourcesetfactory/5.0"
-Q_DECLARE_INTERFACE(QMediaResourceSetFactoryInterface, QMediaResourceSetFactoryInterface_iid)
-
-class Q_MULTIMEDIA_EXPORT QMediaResourcePolicyPlugin : public QObject, public QMediaResourceSetFactoryInterface
-{
- Q_OBJECT
- Q_INTERFACES(QMediaResourceSetFactoryInterface)
-
-public:
- QMediaResourcePolicyPlugin(QObject *parent = nullptr);
- ~QMediaResourcePolicyPlugin();
-};
-
-QT_END_NAMESPACE
-
-#endif // QRESOURCEPOLICYPLUGIN_P_H
diff --git a/src/multimedia/qmediaresourceset_p.cpp b/src/multimedia/qmediaresourceset_p.cpp
deleted file mode 100644
index 6f6d89d73..000000000
--- a/src/multimedia/qmediaresourceset_p.cpp
+++ /dev/null
@@ -1,54 +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 "qmediaresourceset_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QMediaPlayerResourceSetInterface::QMediaPlayerResourceSetInterface(QObject *parent)
- : QObject(parent)
-{
-}
-
-QString QMediaPlayerResourceSetInterface::iid()
-{
- return QLatin1String(QMediaPlayerResourceSetInterface_iid);
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/qmediaresourceset_p.h b/src/multimedia/qmediaresourceset_p.h
deleted file mode 100644
index 5ad4ca7aa..000000000
--- a/src/multimedia/qmediaresourceset_p.h
+++ /dev/null
@@ -1,88 +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 QMEDIARESOURCESET_P_H
-#define QMEDIARESOURCESET_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-#include <QObject>
-#include <qtmultimediaglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-#define QMediaPlayerResourceSetInterface_iid \
- "org.qt-project.qt.mediaplayerresourceset/5.0"
-
-class Q_MULTIMEDIA_EXPORT QMediaPlayerResourceSetInterface : public QObject
-{
- Q_OBJECT
-public:
- virtual bool isVideoEnabled() const = 0;
- virtual bool isGranted() const = 0;
- virtual bool isAvailable() const = 0;
-
- virtual void acquire() = 0;
- virtual void release() = 0;
- virtual void setVideoEnabled(bool enabled) = 0;
-
- static QString iid();
-
-Q_SIGNALS:
- void resourcesGranted();
- void resourcesLost();
- void resourcesDenied();
- void resourcesReleased();
- void availabilityChanged(bool available);
-
-protected:
- QMediaPlayerResourceSetInterface(QObject *parent = nullptr);
-};
-
-QT_END_NAMESPACE
-
-#endif // QMEDIARESOURCESET_P_H
diff --git a/src/multimedia/qmediaservice.cpp b/src/multimedia/qmediaservice.cpp
deleted file mode 100644
index ad543acae..000000000
--- a/src/multimedia/qmediaservice.cpp
+++ /dev/null
@@ -1,143 +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 "qmediaservice.h"
-#include "qmediaservice_p.h"
-
-#include <QtCore/qtimer.h>
-
-
-
-QT_BEGIN_NAMESPACE
-
-
-/*!
- \class QMediaService
- \obsolete
- \brief The QMediaService class provides a common base class for media
- service implementations.
- \ingroup multimedia
- \ingroup multimedia_control
- \ingroup multimedia_core
- \inmodule QtMultimedia
-
- Media services provide implementations of the functionality promised
- by media objects, and allow multiple providers to implement a QMediaObject.
-
- To provide the functionality of a QMediaObject media services implement
- QMediaControl interfaces. Services typically implement one core media
- control which provides the core feature of a media object, and some
- number of additional controls which provide either optional features of
- the media object, or features of a secondary media object or peripheral
- object.
-
- A pointer to media service's QMediaControl implementation can be obtained
- by passing the control's interface name to the requestControl() function.
-
- \snippet multimedia-snippets/media.cpp Request control
-
- Media objects can use services loaded dynamically from plug-ins or
- implemented statically within an applications. Plug-in based services
- should also implement the QMediaServiceProviderPlugin interface. Static
- services should implement the QMediaServiceProvider interface. In general,
- implementing a QMediaService is outside of the scope of this documentation
- and support on the relevant mailing lists or IRC channels should be sought.
-
- \sa QMediaObject, QMediaControl
-*/
-
-/*!
- Construct a media service with the given \a parent. This class is meant as a
- base class for Multimedia services so this constructor is protected.
-*/
-
-QMediaService::QMediaService(QObject *parent)
- : QObject(*new QMediaServicePrivate, parent)
-{
-}
-
-/*!
- \internal
-*/
-QMediaService::QMediaService(QMediaServicePrivate &dd, QObject *parent)
- : QObject(dd, parent)
-{
-}
-
-/*!
- Destroys a media service.
-*/
-
-QMediaService::~QMediaService()
-{
-}
-
-/*!
- \fn QMediaControl* QMediaService::requestControl(const char *interface)
-
- Returns a pointer to the media control implementing \a interface.
-
- If the service does not implement the control, or if it is unavailable a
- null pointer is returned instead.
-
- Controls must be returned to the service when no longer needed using the
- releaseControl() function.
-*/
-
-/*!
- \fn T QMediaService::requestControl()
-
- Returns a pointer to the media control of type T implemented by a media service.
-
- If the service does not implement the control, or if it is unavailable a
- null pointer is returned instead.
-
- Controls must be returned to the service when no longer needed using the
- releaseControl() function.
-*/
-
-/*!
- \fn void QMediaService::releaseControl(QMediaControl *control);
-
- Releases a \a control back to the service.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qmediaservice.cpp"
diff --git a/src/multimedia/qmediaservice.h b/src/multimedia/qmediaservice.h
deleted file mode 100644
index f3e38630c..000000000
--- a/src/multimedia/qmediaservice.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 QABSTRACTMEDIASERVICE_H
-#define QABSTRACTMEDIASERVICE_H
-
-#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtCore/qobject.h>
-#include <QtCore/qstringlist.h>
-
-#include <QtMultimedia/qmediacontrol.h>
-
-QT_BEGIN_NAMESPACE
-
-
-class QMediaServicePrivate;
-class Q_MULTIMEDIA_EXPORT QMediaService : public QObject
-{
- Q_OBJECT
-
-public:
- ~QMediaService();
-
- virtual QMediaControl* requestControl(const char *name) = 0;
-
- template <typename T> inline T requestControl() {
- if (QMediaControl *control = requestControl(qmediacontrol_iid<T>())) {
- if (T typedControl = qobject_cast<T>(control))
- return typedControl;
- releaseControl(control);
- }
- return 0;
- }
-
- virtual void releaseControl(QMediaControl *control) = 0;
-
-protected:
- QMediaService(QObject* parent);
- QMediaService(QMediaServicePrivate &dd, QObject *parent);
-
-private:
- Q_DECLARE_PRIVATE(QMediaService)
-};
-
-QT_END_NAMESPACE
-
-
-#endif // QABSTRACTMEDIASERVICE_H
-
diff --git a/src/multimedia/qmediaservice_p.h b/src/multimedia/qmediaservice_p.h
deleted file mode 100644
index a9dbd5d29..000000000
--- a/src/multimedia/qmediaservice_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 QABSTRACTMEDIASERVICE_P_H
-#define QABSTRACTMEDIASERVICE_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/qobject_p.h"
-
-QT_BEGIN_NAMESPACE
-
-
-class QAudioDeviceControl;
-
-class QMediaServicePrivate : public QObjectPrivate
-{
- Q_DECLARE_PUBLIC(QMediaService)
-public:
- QMediaServicePrivate() {}
- virtual ~QMediaServicePrivate() {}
-};
-
-QT_END_NAMESPACE
-
-
-
-#endif
diff --git a/src/multimedia/qmediaserviceprovider.cpp b/src/multimedia/qmediaserviceprovider.cpp
deleted file mode 100644
index 93b560d8c..000000000
--- a/src/multimedia/qmediaserviceprovider.cpp
+++ /dev/null
@@ -1,1004 +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 <QtCore/qmap.h>
-
-#include "qmediaservice.h"
-#include "qmediaserviceprovider_p.h"
-#include "qmediaserviceproviderplugin.h"
-#include "qmediapluginloader_p.h"
-#include "qmediaplayer.h"
-
-QT_BEGIN_NAMESPACE
-
-QMediaServiceProviderFactoryInterface::~QMediaServiceProviderFactoryInterface()
-{
-}
-
-class QMediaServiceProviderHintPrivate : public QSharedData
-{
-public:
- QMediaServiceProviderHintPrivate(QMediaServiceProviderHint::Type type)
- : type(type)
- {
- }
-
- QMediaServiceProviderHintPrivate(const QMediaServiceProviderHintPrivate &other)
- :QSharedData(other),
- type(other.type),
- device(other.device),
- cameraPosition(other.cameraPosition),
- mimeType(other.mimeType),
- codecs(other.codecs),
- features(other.features)
- {
- }
-
- ~QMediaServiceProviderHintPrivate()
- {
- }
-
- QMediaServiceProviderHint::Type type;
- QByteArray device;
- QCamera::Position cameraPosition = QCamera::UnspecifiedPosition;
- QString mimeType;
- QStringList codecs;
- QMediaServiceProviderHint::Features features;
-};
-
-/*!
- \class QMediaServiceProviderHint
- \obsolete
-
- \brief The QMediaServiceProviderHint class describes what is required of a QMediaService.
-
- \inmodule QtMultimedia
-
- \ingroup multimedia
- \ingroup multimedia_control
- \ingroup multimedia_core
-
- \internal
-
- The QMediaServiceProvider class uses hints to select an appropriate media service.
-*/
-
-/*!
- \enum QMediaServiceProviderHint::Feature
-
- Enumerates features a media service may provide.
-
- \value LowLatencyPlayback
- The service is expected to play simple audio formats,
- but playback should start without significant delay.
- Such playback service can be used for beeps, ringtones, etc.
-
- \value RecordingSupport
- The service provides audio or video recording functions.
-
- \value StreamPlayback
- The service is capable of playing QIODevice based streams.
-
- \value VideoSurface
- The service is capable of renderering to a QAbstractVideoSurface
- output.
-*/
-
-/*!
- \enum QMediaServiceProviderHint::Type
-
- Enumerates the possible types of media service provider hint.
-
- \value Null En empty hint, use the default service.
- \value ContentType Select media service most suitable for certain content type.
- \value Device Select media service which supports certain device.
- \value SupportedFeatures Select media service supporting the set of optional features.
- \value CameraPosition Select media service having a camera at a specified position.
-*/
-
-
-/*!
- Constructs an empty media service provider hint.
-*/
-QMediaServiceProviderHint::QMediaServiceProviderHint()
- :d(new QMediaServiceProviderHintPrivate(Null))
-{
-}
-
-/*!
- Constructs a ContentType media service provider hint.
-
- This type of hint describes a service that is able to play content of a specific MIME \a type
- encoded with one or more of the listed \a codecs.
-*/
-QMediaServiceProviderHint::QMediaServiceProviderHint(const QString &type, const QStringList& codecs)
- :d(new QMediaServiceProviderHintPrivate(ContentType))
-{
- d->mimeType = type;
- d->codecs = codecs;
-}
-
-/*!
- Constructs a Device media service provider hint.
-
- This type of hint describes a media service that utilizes a specific \a device.
-*/
-QMediaServiceProviderHint::QMediaServiceProviderHint(const QByteArray &device)
- :d(new QMediaServiceProviderHintPrivate(Device))
-{
- d->device = device;
-}
-
-/*!
- \since 5.3
-
- Constructs a CameraPosition media service provider hint.
-
- This type of hint describes a media service that has a camera in the specific \a position.
-*/
-QMediaServiceProviderHint::QMediaServiceProviderHint(QCamera::Position position)
- :d(new QMediaServiceProviderHintPrivate(CameraPosition))
-{
- d->cameraPosition = position;
-}
-
-/*!
- Constructs a SupportedFeatures media service provider hint.
-
- This type of hint describes a service which supports a specific set of \a features.
-*/
-QMediaServiceProviderHint::QMediaServiceProviderHint(QMediaServiceProviderHint::Features features)
- :d(new QMediaServiceProviderHintPrivate(SupportedFeatures))
-{
- d->features = features;
-}
-
-/*!
- Constructs a copy of the media service provider hint \a other.
-*/
-QMediaServiceProviderHint::QMediaServiceProviderHint(const QMediaServiceProviderHint &other)
- :d(other.d)
-{
-}
-
-/*!
- Destroys a media service provider hint.
-*/
-QMediaServiceProviderHint::~QMediaServiceProviderHint()
-{
-}
-
-/*!
- Assigns the value \a other to a media service provider hint.
-*/
-QMediaServiceProviderHint& QMediaServiceProviderHint::operator=(const QMediaServiceProviderHint &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Identifies if \a other is of equal value to a media service provider hint.
-
- Returns true if the hints are equal, and false if they are not.
-*/
-bool QMediaServiceProviderHint::operator == (const QMediaServiceProviderHint &other) const
-{
- return (d == other.d) ||
- (d->type == other.d->type &&
- d->device == other.d->device &&
- d->cameraPosition == other.d->cameraPosition &&
- d->mimeType == other.d->mimeType &&
- d->codecs == other.d->codecs &&
- d->features == other.d->features);
-}
-
-/*!
- Identifies if \a other is not of equal value to a media service provider hint.
-
- Returns true if the hints are not equal, and false if they are.
-*/
-bool QMediaServiceProviderHint::operator != (const QMediaServiceProviderHint &other) const
-{
- return !(*this == other);
-}
-
-/*!
- Returns true if a media service provider is null.
-*/
-bool QMediaServiceProviderHint::isNull() const
-{
- return d->type == Null;
-}
-
-/*!
- Returns the type of a media service provider hint.
-*/
-QMediaServiceProviderHint::Type QMediaServiceProviderHint::type() const
-{
- return d->type;
-}
-
-/*!
- Returns the mime type of the media a service is expected to be able play.
-*/
-QString QMediaServiceProviderHint::mimeType() const
-{
- return d->mimeType;
-}
-
-/*!
- Returns a list of codes a media service is expected to be able to decode.
-*/
-QStringList QMediaServiceProviderHint::codecs() const
-{
- return d->codecs;
-}
-
-/*!
- Returns the name of a device a media service is expected to utilize.
-*/
-QByteArray QMediaServiceProviderHint::device() const
-{
- return d->device;
-}
-
-/*!
- \since 5.3
-
- Returns the camera's position a media service is expected to utilize.
-*/
-QCamera::Position QMediaServiceProviderHint::cameraPosition() const
-{
- return d->cameraPosition;
-}
-
-
-/*!
- Returns a set of features a media service is expected to provide.
-*/
-QMediaServiceProviderHint::Features QMediaServiceProviderHint::features() const
-{
- return d->features;
-}
-
-
-Q_GLOBAL_STATIC_WITH_ARGS(QMediaPluginLoader, loader,
- (QMediaServiceProviderFactoryInterface_iid, QLatin1String("mediaservice"), Qt::CaseInsensitive))
-
-
-class QPluginServiceProvider : public QMediaServiceProvider
-{
- struct MediaServiceData {
- QByteArray type;
- QMediaServiceProviderPlugin *plugin;
-
- MediaServiceData() : plugin(nullptr) { }
- };
-
- QMap<const QMediaService*, MediaServiceData> mediaServiceData;
-
-public:
- QMediaService* requestService(const QByteArray &type, const QMediaServiceProviderHint &hint) override
- {
- QString key(QLatin1String(type.constData()));
-
- QList<QMediaServiceProviderPlugin *>plugins;
- const auto instances = loader()->instances(key);
- for (QObject *obj : instances) {
- QMediaServiceProviderPlugin *plugin =
- qobject_cast<QMediaServiceProviderPlugin*>(obj);
- if (plugin)
- plugins << plugin;
- }
-
- if (!plugins.isEmpty()) {
- QMediaServiceProviderPlugin *plugin = nullptr;
-
- switch (hint.type()) {
- case QMediaServiceProviderHint::Null:
- plugin = plugins[0];
- //special case for media player, if low latency was not asked,
- //prefer services not offering it, since they are likely to support
- //more formats
- if (type == QByteArray(Q_MEDIASERVICE_MEDIAPLAYER)) {
- for (QMediaServiceProviderPlugin *currentPlugin : qAsConst(plugins)) {
- QMediaServiceFeaturesInterface *iface =
- qobject_cast<QMediaServiceFeaturesInterface*>(currentPlugin);
-
- if (!iface || !(iface->supportedFeatures(type) &
- QMediaServiceProviderHint::LowLatencyPlayback)) {
- plugin = currentPlugin;
- break;
- }
-
- }
- }
- break;
- case QMediaServiceProviderHint::SupportedFeatures:
- plugin = plugins[0];
- for (QMediaServiceProviderPlugin *currentPlugin : qAsConst(plugins)) {
- QMediaServiceFeaturesInterface *iface =
- qobject_cast<QMediaServiceFeaturesInterface*>(currentPlugin);
-
- if (iface) {
- if ((iface->supportedFeatures(type) & hint.features()) == hint.features()) {
- plugin = currentPlugin;
- break;
- }
- }
- }
- break;
- case QMediaServiceProviderHint::Device: {
- plugin = plugins[0];
- for (QMediaServiceProviderPlugin *currentPlugin : qAsConst(plugins)) {
- QMediaServiceSupportedDevicesInterface *iface =
- qobject_cast<QMediaServiceSupportedDevicesInterface*>(currentPlugin);
-
- if (iface && iface->devices(type).contains(hint.device())) {
- plugin = currentPlugin;
- break;
- }
- }
- }
- break;
- case QMediaServiceProviderHint::CameraPosition: {
- plugin = plugins[0];
- if (type == QByteArray(Q_MEDIASERVICE_CAMERA)
- && hint.cameraPosition() != QCamera::UnspecifiedPosition) {
- for (QMediaServiceProviderPlugin *currentPlugin : qAsConst(plugins)) {
- const QMediaServiceSupportedDevicesInterface *deviceIface =
- qobject_cast<QMediaServiceSupportedDevicesInterface*>(currentPlugin);
- const QMediaServiceCameraInfoInterface *cameraIface =
- qobject_cast<QMediaServiceCameraInfoInterface*>(currentPlugin);
-
- if (deviceIface && cameraIface) {
- const QList<QByteArray> cameras = deviceIface->devices(type);
- for (const QByteArray &camera : cameras) {
- if (cameraIface->cameraPosition(camera) == hint.cameraPosition()) {
- plugin = currentPlugin;
- break;
- }
- }
- }
- }
- }
- }
- break;
- case QMediaServiceProviderHint::ContentType: {
- QMultimedia::SupportEstimate estimate = QMultimedia::NotSupported;
- for (QMediaServiceProviderPlugin *currentPlugin : qAsConst(plugins)) {
- QMultimedia::SupportEstimate currentEstimate = QMultimedia::MaybeSupported;
- QMediaServiceSupportedFormatsInterface *iface =
- qobject_cast<QMediaServiceSupportedFormatsInterface*>(currentPlugin);
-
- if (iface)
- currentEstimate = iface->hasSupport(hint.mimeType(), hint.codecs());
-
- if (currentEstimate > estimate) {
- estimate = currentEstimate;
- plugin = currentPlugin;
-
- if (currentEstimate == QMultimedia::PreferredService)
- break;
- }
- }
- }
- break;
- }
-
- if (plugin != nullptr) {
- QMediaService *service = plugin->create(key);
- if (service != nullptr) {
- MediaServiceData d;
- d.type = type;
- d.plugin = plugin;
- mediaServiceData.insert(service, d);
- }
-
- return service;
- }
- }
-
- qWarning() << "defaultServiceProvider::requestService(): no service found for -" << key;
- return nullptr;
- }
-
- void releaseService(QMediaService *service) override
- {
- if (service != nullptr) {
- MediaServiceData d = mediaServiceData.take(service);
-
- if (d.plugin != nullptr)
- d.plugin->release(service);
- }
- }
-
- QMediaServiceProviderHint::Features supportedFeatures(const QMediaService *service) const override
- {
- if (service) {
- MediaServiceData d = mediaServiceData.value(service);
-
- if (d.plugin) {
- QMediaServiceFeaturesInterface *iface =
- qobject_cast<QMediaServiceFeaturesInterface*>(d.plugin);
-
- if (iface)
- return iface->supportedFeatures(d.type);
- }
- }
-
- return QMediaServiceProviderHint::Features();
- }
-
- QMultimedia::SupportEstimate hasSupport(const QByteArray &serviceType,
- const QString &mimeType,
- const QStringList& codecs,
- int flags) const override
- {
- const QList<QObject*> instances = loader()->instances(QLatin1String(serviceType));
-
- if (instances.isEmpty())
- return QMultimedia::NotSupported;
-
- bool allServicesProvideInterface = true;
- QMultimedia::SupportEstimate supportEstimate = QMultimedia::NotSupported;
-
- for (QObject *obj : instances) {
- QMediaServiceSupportedFormatsInterface *iface =
- qobject_cast<QMediaServiceSupportedFormatsInterface*>(obj);
-
-
- if (flags) {
- QMediaServiceFeaturesInterface *iface =
- qobject_cast<QMediaServiceFeaturesInterface*>(obj);
-
- if (iface) {
- QMediaServiceProviderHint::Features features = iface->supportedFeatures(serviceType);
-
- //if low latency playback was asked, skip services known
- //not to provide low latency playback
- if ((flags & QMediaPlayer::LowLatency) &&
- !(features & QMediaServiceProviderHint::LowLatencyPlayback))
- continue;
-
- //the same for QIODevice based streams support
- if ((flags & QMediaPlayer::StreamPlayback) &&
- !(features & QMediaServiceProviderHint::StreamPlayback))
- continue;
- }
- }
-
- if (iface)
- supportEstimate = qMax(supportEstimate, iface->hasSupport(mimeType, codecs));
- else
- allServicesProvideInterface = false;
- }
-
- //don't return PreferredService
- supportEstimate = qMin(supportEstimate, QMultimedia::ProbablySupported);
-
- //Return NotSupported only if no services are available of serviceType
- //or all the services returned NotSupported, otherwise return at least MaybeSupported
- if (!allServicesProvideInterface)
- supportEstimate = qMax(QMultimedia::MaybeSupported, supportEstimate);
-
- return supportEstimate;
- }
-
- QStringList supportedMimeTypes(const QByteArray &serviceType, int flags) const override
- {
- const QList<QObject*> instances = loader()->instances(QLatin1String(serviceType));
-
- QStringList supportedTypes;
-
- for (QObject *obj : instances) {
- QMediaServiceSupportedFormatsInterface *iface =
- qobject_cast<QMediaServiceSupportedFormatsInterface*>(obj);
-
-
- if (flags) {
- QMediaServiceFeaturesInterface *iface =
- qobject_cast<QMediaServiceFeaturesInterface*>(obj);
-
- if (iface) {
- QMediaServiceProviderHint::Features features = iface->supportedFeatures(serviceType);
-
- // If low latency playback was asked for, skip MIME types from services known
- // not to provide low latency playback
- if ((flags & QMediaPlayer::LowLatency) &&
- !(features & QMediaServiceProviderHint::LowLatencyPlayback))
- continue;
-
- //the same for QIODevice based streams support
- if ((flags & QMediaPlayer::StreamPlayback) &&
- !(features & QMediaServiceProviderHint::StreamPlayback))
- continue;
-
- //the same for QAbstractVideoSurface support
- if ((flags & QMediaPlayer::VideoSurface) &&
- !(features & QMediaServiceProviderHint::VideoSurface))
- continue;
- }
- }
-
- if (iface) {
- supportedTypes << iface->supportedMimeTypes();
- }
- }
-
- // Multiple services may support the same MIME type
- supportedTypes.removeDuplicates();
-
- return supportedTypes;
- }
-
- QByteArray defaultDevice(const QByteArray &serviceType) const override
- {
- const auto instances = loader()->instances(QLatin1String(serviceType));
- for (QObject *obj : instances) {
- const QMediaServiceDefaultDeviceInterface *iface =
- qobject_cast<QMediaServiceDefaultDeviceInterface*>(obj);
-
- if (iface) {
- QByteArray name = iface->defaultDevice(serviceType);
- if (!name.isEmpty())
- return name;
- }
- }
-
- // if QMediaServiceDefaultDeviceInterface is not implemented, return the
- // first available device.
- QList<QByteArray> devs = devices(serviceType);
- if (!devs.isEmpty())
- return devs.first();
-
- return QByteArray();
- }
-
- QList<QByteArray> devices(const QByteArray &serviceType) const override
- {
- QList<QByteArray> res;
-
- const auto instances = loader()->instances(QLatin1String(serviceType));
- for (QObject *obj : instances) {
- QMediaServiceSupportedDevicesInterface *iface =
- qobject_cast<QMediaServiceSupportedDevicesInterface*>(obj);
-
- if (iface) {
- res.append(iface->devices(serviceType));
- }
- }
-
- return res;
- }
-
- QString deviceDescription(const QByteArray &serviceType, const QByteArray &device) override
- {
- const auto instances = loader()->instances(QLatin1String(serviceType));
- for (QObject *obj : instances) {
- QMediaServiceSupportedDevicesInterface *iface =
- qobject_cast<QMediaServiceSupportedDevicesInterface*>(obj);
-
- if (iface) {
- if (iface->devices(serviceType).contains(device))
- return iface->deviceDescription(serviceType, device);
- }
- }
-
- return QString();
- }
-
- QCamera::Position cameraPosition(const QByteArray &device) const override
- {
- const QByteArray serviceType(Q_MEDIASERVICE_CAMERA);
- const auto instances = loader()->instances(QString::fromLatin1(serviceType));
- for (QObject *obj : instances) {
- const QMediaServiceSupportedDevicesInterface *deviceIface =
- qobject_cast<QMediaServiceSupportedDevicesInterface*>(obj);
- const QMediaServiceCameraInfoInterface *cameraIface =
- qobject_cast<QMediaServiceCameraInfoInterface*>(obj);
-
- if (cameraIface) {
- if (deviceIface && !deviceIface->devices(serviceType).contains(device))
- continue;
- return cameraIface->cameraPosition(device);
- }
- }
-
- return QCamera::UnspecifiedPosition;
- }
-
- int cameraOrientation(const QByteArray &device) const override
- {
- const QByteArray serviceType(Q_MEDIASERVICE_CAMERA);
- const auto instances = loader()->instances(QString::fromLatin1(serviceType));
- for (QObject *obj : instances) {
- const QMediaServiceSupportedDevicesInterface *deviceIface =
- qobject_cast<QMediaServiceSupportedDevicesInterface*>(obj);
- const QMediaServiceCameraInfoInterface *cameraIface =
- qobject_cast<QMediaServiceCameraInfoInterface*>(obj);
-
- if (cameraIface) {
- if (deviceIface && !deviceIface->devices(serviceType).contains(device))
- continue;
- return cameraIface->cameraOrientation(device);
- }
- }
-
- return 0;
- }
-};
-
-Q_GLOBAL_STATIC(QPluginServiceProvider, pluginProvider);
-
-/*!
- \class QMediaServiceProvider
- \obsolete
- \ingroup multimedia
- \ingroup multimedia_control
- \ingroup multimedia_core
-
- \internal
-
- \brief The QMediaServiceProvider class provides an abstract allocator for media services.
-*/
-
-/*!
- \internal
- \fn QMediaServiceProvider::requestService(const QByteArray &type, const QMediaServiceProviderHint &hint)
-
- Requests an instance of a \a type service which best matches the given \a
- hint.
-
- Returns a pointer to the requested service, or a null pointer if there is
- no suitable service.
-
- The returned service must be released with releaseService when it is
- finished with.
-*/
-
-/*!
- \internal
- \fn QMediaServiceProvider::releaseService(QMediaService *service)
-
- Releases a media \a service requested with requestService().
-*/
-
-/*!
- \internal
- \fn QMediaServiceProvider::supportedFeatures(const QMediaService *service) const
-
- Returns the features supported by a given \a service.
-*/
-QMediaServiceProviderHint::Features QMediaServiceProvider::supportedFeatures(const QMediaService *service) const
-{
- Q_UNUSED(service);
-
- return {};
-}
-
-/*!
- \internal
- Returns how confident a media service provider is that is can provide a \a
- serviceType service that is able to play media of a specific \a mimeType
- that is encoded using the listed \a codecs while adhering to constraints
- identified in \a flags.
-*/
-QMultimedia::SupportEstimate QMediaServiceProvider::hasSupport(const QByteArray &serviceType,
- const QString &mimeType,
- const QStringList& codecs,
- int flags) const
-{
- Q_UNUSED(serviceType);
- Q_UNUSED(mimeType);
- Q_UNUSED(codecs);
- Q_UNUSED(flags);
-
- return QMultimedia::MaybeSupported;
-}
-
-/*!
- \internal
- \fn QStringList QMediaServiceProvider::supportedMimeTypes(const QByteArray &serviceType, int flags) const
-
- Returns a list of MIME types supported by the service provider for the
- specified \a serviceType.
-
- The resultant list is restricted to MIME types which can be supported given
- the constraints in \a flags.
-*/
-QStringList QMediaServiceProvider::supportedMimeTypes(const QByteArray &serviceType, int flags) const
-{
- Q_UNUSED(serviceType);
- Q_UNUSED(flags);
-
- return QStringList();
-}
-
-/*!
- \internal
- \since 5.3
-
- Returns the default device for a \a service type.
-*/
-QByteArray QMediaServiceProvider::defaultDevice(const QByteArray &serviceType) const
-{
- Q_UNUSED(serviceType);
- return QByteArray();
-}
-
-/*!
- \internal
- Returns the list of devices related to \a service type.
-*/
-QList<QByteArray> QMediaServiceProvider::devices(const QByteArray &service) const
-{
- Q_UNUSED(service);
- return QList<QByteArray>();
-}
-
-/*!
- \internal
- Returns the description of \a device related to \a serviceType, suitable for use by
- an application for display.
-*/
-QString QMediaServiceProvider::deviceDescription(const QByteArray &serviceType, const QByteArray &device)
-{
- Q_UNUSED(serviceType);
- Q_UNUSED(device);
- return QString();
-}
-
-/*!
- \internal
- \since 5.3
-
- Returns the physical position of a camera \a device on the system hardware.
-*/
-QCamera::Position QMediaServiceProvider::cameraPosition(const QByteArray &device) const
-{
- Q_UNUSED(device);
- return QCamera::UnspecifiedPosition;
-}
-
-/*!
- \internal
- \since 5.3
-
- Returns the physical orientation of the camera \a device. The value is the angle by which the
- camera image should be rotated anti-clockwise (in steps of 90 degrees) so it shows correctly on
- the display in its natural orientation.
-*/
-int QMediaServiceProvider::cameraOrientation(const QByteArray &device) const
-{
- Q_UNUSED(device);
- return 0;
-}
-
-static QMediaServiceProvider *qt_defaultMediaServiceProvider = nullptr;
-
-/*!
- Sets a media service \a provider as the default.
- It's useful for unit tests to provide mock service.
-
- \internal
-*/
-void QMediaServiceProvider::setDefaultServiceProvider(QMediaServiceProvider *provider)
-{
- qt_defaultMediaServiceProvider = provider;
-}
-
-
-/*!
- \internal
- Returns a default provider of media services.
-*/
-QMediaServiceProvider *QMediaServiceProvider::defaultServiceProvider()
-{
- return qt_defaultMediaServiceProvider != nullptr
- ? qt_defaultMediaServiceProvider
- : static_cast<QMediaServiceProvider *>(pluginProvider());
-}
-
-/*!
- \class QMediaServiceProviderPlugin
- \obsolete
- \inmodule QtMultimedia
- \brief The QMediaServiceProviderPlugin class interface provides an interface for QMediaService
- plug-ins.
-
- A media service provider plug-in may implement one or more of
- QMediaServiceSupportedFormatsInterface,
- QMediaServiceSupportedDevicesInterface, and QMediaServiceFeaturesInterface
- to identify the features it supports.
-*/
-
-/*!
- \fn QMediaServiceProviderPlugin::create(const QString &key)
-
- Constructs a new instance of the QMediaService identified by \a key.
-
- The QMediaService returned must be destroyed with release().
-*/
-
-/*!
- \fn QMediaServiceProviderPlugin::release(QMediaService *service)
-
- Destroys a media \a service constructed with create().
-*/
-
-
-/*!
- \class QMediaServiceSupportedFormatsInterface
- \obsolete
- \inmodule QtMultimedia
- \brief The QMediaServiceSupportedFormatsInterface class interface
- identifies if a media service plug-in supports a media format.
-
- A QMediaServiceProviderPlugin may implement this interface.
-*/
-
-/*!
- \fn QMediaServiceSupportedFormatsInterface::~QMediaServiceSupportedFormatsInterface()
-
- Destroys a media service supported formats interface.
-*/
-
-/*!
- \fn QMediaServiceSupportedFormatsInterface::hasSupport(const QString &mimeType, const QStringList& codecs) const
-
- Returns the level of support a media service plug-in has for a \a mimeType
- and set of \a codecs.
-*/
-
-/*!
- \fn QMediaServiceSupportedFormatsInterface::supportedMimeTypes() const
-
- Returns a list of MIME types supported by the media service plug-in.
-*/
-
-/*!
- \class QMediaServiceSupportedDevicesInterface
- \obsolete
- \inmodule QtMultimedia
- \brief The QMediaServiceSupportedDevicesInterface class interface
- identifies the devices supported by a media service plug-in.
-
- A QMediaServiceProviderPlugin may implement this interface.
-*/
-
-/*!
- \fn QMediaServiceSupportedDevicesInterface::~QMediaServiceSupportedDevicesInterface()
-
- Destroys a media service supported devices interface.
-*/
-
-/*!
- \fn QList<QByteArray> QMediaServiceSupportedDevicesInterface::devices(const QByteArray &service) const
-
- Returns a list of devices available for a \a service type.
-*/
-
-/*!
- \fn QString QMediaServiceSupportedDevicesInterface::deviceDescription(const QByteArray &service, const QByteArray &device)
-
- Returns the description of a \a device available for a \a service type.
-*/
-
-/*!
- \class QMediaServiceDefaultDeviceInterface
- \obsolete
- \inmodule QtMultimedia
- \brief The QMediaServiceDefaultDeviceInterface class interface
- identifies the default device used by a media service plug-in.
-
- A QMediaServiceProviderPlugin may implement this interface.
-
- \since 5.3
-*/
-
-/*!
- \fn QMediaServiceDefaultDeviceInterface::~QMediaServiceDefaultDeviceInterface()
-
- Destroys a media service default device interface.
-*/
-
-/*!
- \fn QByteArray QMediaServiceDefaultDeviceInterface::defaultDevice(const QByteArray &service) const
-
- Returns the default device for a \a service type.
-*/
-
-/*!
- \class QMediaServiceCameraInfoInterface
- \obsolete
- \inmodule QtMultimedia
- \since 5.3
- \brief The QMediaServiceCameraInfoInterface class interface
- provides camera-specific information about devices supported by a camera service plug-in.
-
- A QMediaServiceProviderPlugin may implement this interface, in that case it also needs to
- implement the QMediaServiceSupportedDevicesInterface.
-*/
-
-/*!
- \fn QMediaServiceCameraInfoInterface::~QMediaServiceCameraInfoInterface()
-
- Destroys a media service camera info interface.
-*/
-
-/*!
- \fn QMediaServiceCameraInfoInterface::cameraPosition(const QByteArray &device) const
-
- Returns the physical position of a camera \a device supported by a camera service plug-in.
-*/
-
-/*!
- \fn QMediaServiceCameraInfoInterface::cameraOrientation(const QByteArray &device) const
-
- Returns the physical orientation of a camera \a device supported by a camera service plug-in.
-*/
-
-/*!
- \class QMediaServiceFeaturesInterface
- \obsolete
- \inmodule QtMultimedia
- \brief The QMediaServiceFeaturesInterface class interface identifies
- features supported by a media service plug-in.
-
- A QMediaServiceProviderPlugin may implement this interface.
-*/
-
-/*!
- \fn QMediaServiceFeaturesInterface::~QMediaServiceFeaturesInterface()
-
- Destroys a media service features interface.
-*/
-/*!
- \fn QMediaServiceFeaturesInterface::supportedFeatures(const QByteArray &service) const
-
- Returns a set of features supported by a plug-in \a service.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qmediaserviceprovider_p.cpp"
-#include "moc_qmediaserviceproviderplugin.cpp"
diff --git a/src/multimedia/qmediaserviceprovider_p.h b/src/multimedia/qmediaserviceprovider_p.h
deleted file mode 100644
index 4ca9c9e8f..000000000
--- a/src/multimedia/qmediaserviceprovider_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 Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** 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 QMEDIASERVICEPROVIDER_H
-#define QMEDIASERVICEPROVIDER_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/qshareddata.h>
-#include <qtmultimediaglobal.h>
-#include "qmultimedia.h"
-#include "qmediaserviceproviderplugin.h"
-
-QT_BEGIN_NAMESPACE
-
-
-class QMediaService;
-
-class Q_MULTIMEDIA_EXPORT QMediaServiceProvider : public QObject
-{
- Q_OBJECT
-
-public:
- virtual QMediaService* requestService(const QByteArray &type, const QMediaServiceProviderHint &hint = QMediaServiceProviderHint()) = 0;
- virtual void releaseService(QMediaService *service) = 0;
-
- virtual QMediaServiceProviderHint::Features supportedFeatures(const QMediaService *service) const;
-
- virtual QMultimedia::SupportEstimate hasSupport(const QByteArray &serviceType,
- const QString &mimeType,
- const QStringList& codecs,
- int flags = 0) const;
- virtual QStringList supportedMimeTypes(const QByteArray &serviceType, int flags = 0) const;
-
- virtual QByteArray defaultDevice(const QByteArray &serviceType) const;
- virtual QList<QByteArray> devices(const QByteArray &serviceType) const;
- virtual QString deviceDescription(const QByteArray &serviceType, const QByteArray &device);
-
- virtual QCamera::Position cameraPosition(const QByteArray &device) const;
- virtual int cameraOrientation(const QByteArray &device) const;
-
- static QMediaServiceProvider* defaultServiceProvider();
- static void setDefaultServiceProvider(QMediaServiceProvider *provider);
-};
-
-QT_END_NAMESPACE
-
-
-#endif // QMEDIASERVICEPROVIDER_H
diff --git a/src/multimedia/qmediaserviceproviderplugin.h b/src/multimedia/qmediaserviceproviderplugin.h
deleted file mode 100644
index 3337b2e72..000000000
--- a/src/multimedia/qmediaserviceproviderplugin.h
+++ /dev/null
@@ -1,245 +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 QMEDIASERVICEPROVIDERPLUGIN_H
-#define QMEDIASERVICEPROVIDERPLUGIN_H
-
-#include <QtCore/qstringlist.h>
-#include <QtCore/qplugin.h>
-#include <QtMultimedia/qmultimedia.h>
-#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qcamera.h>
-
-#ifdef Q_MOC_RUN
-# pragma Q_MOC_EXPAND_MACROS
-#endif
-
-QT_BEGIN_NAMESPACE
-
-// Required for QDoc workaround
-class QString;
-
-class QMediaService;
-
-class QMediaServiceProviderHintPrivate;
-class Q_MULTIMEDIA_EXPORT QMediaServiceProviderHint
-{
-public:
- enum Type { Null, ContentType, Device, SupportedFeatures, CameraPosition };
-
- enum Feature {
- LowLatencyPlayback = 0x01,
- RecordingSupport = 0x02,
- StreamPlayback = 0x04,
- VideoSurface = 0x08
- };
- Q_DECLARE_FLAGS(Features, Feature)
-
- QMediaServiceProviderHint();
- QMediaServiceProviderHint(const QString &mimeType, const QStringList& codecs);
- QMediaServiceProviderHint(const QByteArray &device);
- QMediaServiceProviderHint(QCamera::Position position);
- QMediaServiceProviderHint(Features features);
- QMediaServiceProviderHint(const QMediaServiceProviderHint &other);
- ~QMediaServiceProviderHint();
-
- QMediaServiceProviderHint& operator=(const QMediaServiceProviderHint &other);
-
- bool operator == (const QMediaServiceProviderHint &other) const;
- bool operator != (const QMediaServiceProviderHint &other) const;
-
- bool isNull() const;
-
- Type type() const;
-
- QString mimeType() const;
- QStringList codecs() const;
-
- QByteArray device() const;
- QCamera::Position cameraPosition() const;
-
- Features features() const;
-
- //to be extended, if necessary
-
-private:
- QSharedDataPointer<QMediaServiceProviderHintPrivate> d;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QMediaServiceProviderHint::Features)
-
-// Required for QDoc workaround
-class QString;
-
-struct Q_MULTIMEDIA_EXPORT QMediaServiceProviderFactoryInterface
-{
- virtual QMediaService* create(QString const& key) = 0;
- virtual void release(QMediaService *service) = 0;
- virtual ~QMediaServiceProviderFactoryInterface();
-};
-
-#define QMediaServiceProviderFactoryInterface_iid \
- "org.qt-project.qt.mediaserviceproviderfactory/5.0"
-Q_DECLARE_INTERFACE(QMediaServiceProviderFactoryInterface, QMediaServiceProviderFactoryInterface_iid)
-
-// Required for QDoc workaround
-class QString;
-
-struct Q_MULTIMEDIA_EXPORT QMediaServiceSupportedFormatsInterface
-{
- virtual ~QMediaServiceSupportedFormatsInterface() {}
- virtual QMultimedia::SupportEstimate hasSupport(const QString &mimeType, const QStringList& codecs) const = 0;
- virtual QStringList supportedMimeTypes() const = 0;
-};
-
-#define QMediaServiceSupportedFormatsInterface_iid \
- "org.qt-project.qt.mediaservicesupportedformats/5.0"
-Q_DECLARE_INTERFACE(QMediaServiceSupportedFormatsInterface, QMediaServiceSupportedFormatsInterface_iid)
-
-// Required for QDoc workaround
-class QString;
-
-struct Q_MULTIMEDIA_EXPORT QMediaServiceSupportedDevicesInterface
-{
- virtual ~QMediaServiceSupportedDevicesInterface() {}
- virtual QList<QByteArray> devices(const QByteArray &service) const = 0;
- virtual QString deviceDescription(const QByteArray &service, const QByteArray &device) = 0;
-};
-
-#define QMediaServiceSupportedDevicesInterface_iid \
- "org.qt-project.qt.mediaservicesupporteddevices/5.0"
-Q_DECLARE_INTERFACE(QMediaServiceSupportedDevicesInterface, QMediaServiceSupportedDevicesInterface_iid)
-
-// This should be part of QMediaServiceSupportedDevicesInterface but it can't in order
-// to preserve binary compatibility with 5.2 and earlier.
-// The whole media service plugin API shouldn't even be public in the first place. It should
-// be made private in Qt 6.0 and QMediaServiceDefaultDeviceInterface should be merged with
-// QMediaServiceSupportedDevicesInterface
-struct Q_MULTIMEDIA_EXPORT QMediaServiceDefaultDeviceInterface
-{
- virtual ~QMediaServiceDefaultDeviceInterface() {}
- virtual QByteArray defaultDevice(const QByteArray &service) const = 0;
-};
-
-#define QMediaServiceDefaultDeviceInterface_iid \
- "org.qt-project.qt.mediaservicedefaultdevice/5.3"
-Q_DECLARE_INTERFACE(QMediaServiceDefaultDeviceInterface, QMediaServiceDefaultDeviceInterface_iid)
-
-struct Q_MULTIMEDIA_EXPORT QMediaServiceCameraInfoInterface
-{
- virtual ~QMediaServiceCameraInfoInterface() {}
- virtual QCamera::Position cameraPosition(const QByteArray &device) const = 0;
- virtual int cameraOrientation(const QByteArray &device) const = 0;
-};
-
-#define QMediaServiceCameraInfoInterface_iid \
- "org.qt-project.qt.mediaservicecamerainfo/5.3"
-Q_DECLARE_INTERFACE(QMediaServiceCameraInfoInterface, QMediaServiceCameraInfoInterface_iid)
-
-// Required for QDoc workaround
-class QString;
-
-struct Q_MULTIMEDIA_EXPORT QMediaServiceFeaturesInterface
-{
- virtual ~QMediaServiceFeaturesInterface() {}
- virtual QMediaServiceProviderHint::Features supportedFeatures(const QByteArray &service) const = 0;
-};
-
-
-#define QMediaServiceFeaturesInterface_iid \
- "org.qt-project.qt.mediaservicefeatures/5.0"
-Q_DECLARE_INTERFACE(QMediaServiceFeaturesInterface, QMediaServiceFeaturesInterface_iid)
-
-// Required for QDoc workaround
-class QString;
-
-class Q_MULTIMEDIA_EXPORT QMediaServiceProviderPlugin : public QObject, public QMediaServiceProviderFactoryInterface
-{
- Q_OBJECT
- Q_INTERFACES(QMediaServiceProviderFactoryInterface)
-
-public:
- QMediaService* create(const QString& key) override = 0;
- void release(QMediaService *service) override = 0;
-};
-
-/*!
- Service with support for media playback
- Required Controls: QMediaPlayerControl
- Optional Controls: QMediaPlaylistControl, QAudioDeviceControl
- Video Output Controls (used by QWideoWidget and QGraphicsVideoItem):
- Required: QVideoOutputControl
- Optional: QVideoWindowControl, QVideoRendererControl, QVideoWidgetControl
-*/
-#define Q_MEDIASERVICE_MEDIAPLAYER "org.qt-project.qt.mediaplayer"
-
-/*!
- Service with support for recording from audio sources
- Required Controls: QAudioDeviceControl
- Recording Controls (QMediaRecorder):
- Required: QMediaRecorderControl
- Recommended: QAudioEncoderSettingsControl
- Optional: QMediaContainerControl
-*/
-#define Q_MEDIASERVICE_AUDIOSOURCE "org.qt-project.qt.audiosource"
-
-/*!
- Service with support for camera use.
- Required Controls: QCameraControl
- Optional Controls: QCameraExposureControl, QCameraFocusControl, QCameraImageProcessingControl
- Still Capture Controls: QCameraImageCaptureControl
- Video Capture Controls (QMediaRecorder):
- Required: QMediaRecorderControl
- Recommended: QAudioEncoderSettingsControl, QVideoEncoderSettingsControl, QMediaContainerControl
- Viewfinder Video Output Controls (used by QCameraViewfinder and QGraphicsVideoItem):
- Required: QVideoOutputControl
- Optional: QVideoWindowControl, QVideoRendererControl, QVideoWidgetControl
-*/
-#define Q_MEDIASERVICE_CAMERA "org.qt-project.qt.camera"
-
-/*!
- Service with support for decoding audio.
- Required Controls: QAudioDecoderControl
- Optional: that streams control
-*/
-#define Q_MEDIASERVICE_AUDIODECODER "org.qt-project.qt.audiodecode"
-
-QT_END_NAMESPACE
-
-#endif // QMEDIASERVICEPROVIDERPLUGIN_H
diff --git a/src/multimedia/qmediastoragelocation.cpp b/src/multimedia/qmediastoragelocation.cpp
index c77ad5dba..61c4061f4 100644
--- a/src/multimedia/qmediastoragelocation.cpp
+++ b/src/multimedia/qmediastoragelocation.cpp
@@ -1,145 +1,86 @@
-/****************************************************************************
-**
-** 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 "qmediastoragelocation_p.h"
#include <QStandardPaths>
+#include <QUrl>
QT_BEGIN_NAMESPACE
-QMediaStorageLocation::QMediaStorageLocation()
-{
-}
-
-void QMediaStorageLocation::addStorageLocation(MediaType type, const QString &location)
-{
- m_customLocations[type].append(location);
-}
-
-QDir QMediaStorageLocation::defaultLocation(MediaType type) const
+QDir QMediaStorageLocation::defaultDirectory(QStandardPaths::StandardLocation type)
{
QStringList dirCandidates;
- dirCandidates << m_customLocations.value(type);
-
- switch (type) {
- case Movies:
- dirCandidates << QStandardPaths::writableLocation(QStandardPaths::MoviesLocation);
- break;
- case Music:
- dirCandidates << QStandardPaths::writableLocation(QStandardPaths::MusicLocation);
- break;
- case Pictures:
- dirCandidates << QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
- default:
- break;
- }
+#if QT_CONFIG(mmrenderer)
+ dirCandidates << QLatin1String("shared/camera");
+#endif
+ dirCandidates << QStandardPaths::writableLocation(type);
+ dirCandidates << QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
dirCandidates << QDir::homePath();
dirCandidates << QDir::currentPath();
dirCandidates << QDir::tempPath();
- for (const QString &path : qAsConst(dirCandidates)) {
- if (QFileInfo(path).isWritable())
- return QDir(path);
+ for (const QString &path : std::as_const(dirCandidates)) {
+ QDir dir(path);
+ if (dir.exists() && QFileInfo(path).isWritable())
+ return dir;
}
return QDir();
}
-QString QMediaStorageLocation::generateFileName(const QString &requestedName,
- MediaType type,
- const QString &prefix,
- const QString &extension) const
+static QString generateFileName(const QDir &dir, const QString &prefix, const QString &extension)
{
- if (requestedName.isEmpty())
- return generateFileName(prefix, defaultLocation(type), extension);
+ auto lastMediaIndex = 0;
+ const auto list = dir.entryList({ QStringLiteral("%1*.%2").arg(prefix, extension) });
+ for (const QString &fileName : list) {
+ auto mediaIndex = QStringView{fileName}.mid(prefix.size(), fileName.size() - prefix.size() - extension.size() - 1).toInt();
+ lastMediaIndex = qMax(lastMediaIndex, mediaIndex);
+ }
- QString path = requestedName;
+ const QString name = QStringLiteral("%1%2.%3")
+ .arg(prefix)
+ .arg(lastMediaIndex + 1, 4, 10, QLatin1Char('0'))
+ .arg(extension);
- if (QFileInfo(path).isRelative())
- path = defaultLocation(type).absoluteFilePath(path);
+ return dir.absoluteFilePath(name);
+}
- if (QFileInfo(path).isDir())
- return generateFileName(prefix, QDir(path), extension);
- if (!path.endsWith(extension))
- path.append(QString(QLatin1String(".%1")).arg(extension));
+QString QMediaStorageLocation::generateFileName(const QString &requestedName,
+ QStandardPaths::StandardLocation type,
+ const QString &extension)
+{
+ using namespace Qt::StringLiterals;
- return path;
-}
+ if (QUrl(requestedName).scheme() == "content"_L1)
+ return requestedName;
-QString QMediaStorageLocation::generateFileName(const QString &prefix,
- const QDir &dir,
- const QString &extension) const
-{
- QMutexLocker lock(&m_mutex);
-
- const QString lastMediaKey = dir.absolutePath() + QLatin1Char(' ') + prefix + QLatin1Char(' ') + extension;
- qint64 lastMediaIndex = m_lastUsedIndex.value(lastMediaKey, 0);
-
- if (lastMediaIndex == 0) {
- // first run, find the maximum media number during the fist capture
- const auto list = dir.entryList(QStringList() << QString(QLatin1String("%1*.%2")).arg(prefix).arg(extension));
- for (const QString &fileName : list) {
- const qint64 mediaIndex = QStringView{fileName}.mid(prefix.length(), fileName.size() - prefix.length() - extension.length() - 1).toInt();
- lastMediaIndex = qMax(lastMediaIndex, mediaIndex);
- }
+ auto prefix = "clip_"_L1;
+ switch (type) {
+ case QStandardPaths::PicturesLocation: prefix = "image_"_L1; break;
+ case QStandardPaths::MoviesLocation: prefix = "video_"_L1; break;
+ case QStandardPaths::MusicLocation: prefix = "record_"_L1; break;
+ default: break;
}
- // don't just rely on cached lastMediaIndex value,
- // someone else may create a file after camera started
- while (true) {
- const QString name = QString(QLatin1String("%1%2.%3")).arg(prefix)
- .arg(lastMediaIndex + 1, 8, 10, QLatin1Char('0'))
- .arg(extension);
+ if (requestedName.isEmpty())
+ return generateFileName(defaultDirectory(type), prefix, extension);
- const QString path = dir.absoluteFilePath(name);
- if (!QFileInfo::exists(path)) {
- m_lastUsedIndex[lastMediaKey] = lastMediaIndex + 1;
- return path;
- }
+ QString path = requestedName;
- lastMediaIndex++;
- }
+ if (QFileInfo(path).isRelative() && QUrl(path).isRelative())
+ path = defaultDirectory(type).absoluteFilePath(path);
+
+ if (QFileInfo(path).isDir())
+ return generateFileName(QDir(path), prefix, extension);
- return QString();
+ if (!path.endsWith(extension))
+ path.append(QStringLiteral(".%1").arg(extension));
+
+ return path;
}
QT_END_NAMESPACE
diff --git a/src/multimedia/qmediastoragelocation_p.h b/src/multimedia/qmediastoragelocation_p.h
index 13399b54d..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
@@ -52,36 +16,16 @@
//
#include <qtmultimediaglobal.h>
+#include <QStandardPaths>
#include <QDir>
-#include <QMap>
-#include <QHash>
-#include <QMutex>
+#include <private/qglobal_p.h>
QT_BEGIN_NAMESPACE
-class Q_MULTIMEDIA_EXPORT QMediaStorageLocation
+namespace QMediaStorageLocation
{
-public:
- enum MediaType {
- Movies,
- Music,
- Pictures,
- Sounds
- };
-
- QMediaStorageLocation();
-
- void addStorageLocation(MediaType type, const QString &location);
-
- QDir defaultLocation(MediaType type) const;
-
- QString generateFileName(const QString &requestedName, MediaType type, const QString &prefix, const QString &extension) const;
- QString generateFileName(const QString &prefix, const QDir &dir, const QString &extension) const;
-
-private:
- mutable QMutex m_mutex;
- mutable QHash<QString, qint64> m_lastUsedIndex;
- QMap<MediaType, QStringList> m_customLocations;
+ 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 913790a0e..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>
@@ -44,8 +8,9 @@
QT_BEGIN_NAMESPACE
/*!
- \class QMediaTimeInterval
- \brief The QMediaTimeInterval class represents a time interval with integer precision.
+ \class QMediaTimeRange::Interval
+ \brief The QMediaTimeRange::Interval class represents a time interval with
+ integer precision.
\inmodule QtMultimedia
\ingroup multimedia
@@ -71,169 +36,101 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn QMediaTimeInterval::QMediaTimeInterval()
-
- Constructs an empty interval.
-*/
-QMediaTimeInterval::QMediaTimeInterval()
- : s(0)
- , e(0)
-{
-
-}
-
-/*!
- \fn QMediaTimeInterval::QMediaTimeInterval(qint64 start, qint64 end)
+ \fn QMediaTimeRange::Interval::Interval(qint64 start, qint64 end)
Constructs an interval with the specified \a start and \a end times.
*/
-QMediaTimeInterval::QMediaTimeInterval(qint64 start, qint64 end)
- : s(start)
- , e(end)
-{
-
-}
/*!
- \fn QMediaTimeInterval::start() const
+ \fn QMediaTimeRange::Interval::start() const
Returns the start time of the interval.
\sa end()
*/
-qint64 QMediaTimeInterval::start() const
-{
- return s;
-}
/*!
- \fn QMediaTimeInterval::end() const
+ \fn QMediaTimeRange::Interval::end() const
Returns the end time of the interval.
\sa start()
*/
-qint64 QMediaTimeInterval::end() const
-{
- return e;
-}
/*!
- \fn QMediaTimeInterval::contains(qint64 time) const
+ \fn QMediaTimeRange::Interval::contains(qint64 time) const
Returns true if the time interval contains the specified \a time.
That is, start() <= time <= end().
*/
-bool QMediaTimeInterval::contains(qint64 time) const
-{
- return isNormal() ? (s <= time && time <= e)
- : (e <= time && time <= s);
-}
/*!
- \fn QMediaTimeInterval::isNormal() const
+ \fn QMediaTimeRange::Interval::isNormal() const
Returns true if this time interval is normal.
A normal time interval has start() <= end().
\sa normalized()
*/
-bool QMediaTimeInterval::isNormal() const
-{
- return s <= e;
-}
/*!
- \fn QMediaTimeInterval::normalized() const
+ \fn QMediaTimeRange::Interval::normalized() const
Returns a normalized version of this interval.
If the start() time of the interval is greater than the end() time,
then the returned interval has the start and end times swapped.
*/
-QMediaTimeInterval QMediaTimeInterval::normalized() const
-{
- if(s > e)
- return QMediaTimeInterval(e, s);
-
- return *this;
-}
/*!
- \fn QMediaTimeInterval::translated(qint64 offset) const
+ \fn QMediaTimeRange::Interval::translated(qint64 offset) const
Returns a copy of this time interval, translated by a value of \a offset.
An interval can be moved forward through time with a positive offset, or backward
through time with a negative offset.
*/
-QMediaTimeInterval QMediaTimeInterval::translated(qint64 offset) const
-{
- return QMediaTimeInterval(s + offset, e + offset);
-}
/*!
- \relates QMediaTimeRange
+ \fn bool QMediaTimeRange::Interval::operator==(QMediaTimeRange::Interval lhs, QMediaTimeRange::Interval rhs)
- Returns true if \a a is exactly equal to \a b.
+ Returns true if \a lhs is exactly equal to \a rhs.
*/
-bool operator==(const QMediaTimeInterval &a, const QMediaTimeInterval &b)
-{
- return a.start() == b.start() && a.end() == b.end();
-}
/*!
- \relates QMediaTimeRange
+ \fn bool QMediaTimeRange::Interval::operator!=(QMediaTimeRange::Interval lhs, QMediaTimeRange::Interval rhs)
- Returns true if \a a is not exactly equal to \a b.
+ Returns true if \a lhs is not exactly equal to \a rhs.
*/
-bool operator!=(const QMediaTimeInterval &a, const QMediaTimeInterval &b)
-{
- return a.start() != b.start() || a.end() != b.end();
-}
class QMediaTimeRangePrivate : public QSharedData
{
public:
+ QMediaTimeRangePrivate() = default;
+ QMediaTimeRangePrivate(const QMediaTimeRange::Interval &interval);
- QMediaTimeRangePrivate();
- QMediaTimeRangePrivate(const QMediaTimeRangePrivate &other);
- QMediaTimeRangePrivate(const QMediaTimeInterval &interval);
-
- QList<QMediaTimeInterval> intervals;
+ QList<QMediaTimeRange::Interval> intervals;
- void addInterval(const QMediaTimeInterval &interval);
- void removeInterval(const QMediaTimeInterval &interval);
+ void addInterval(const QMediaTimeRange::Interval &interval);
+ void removeInterval(const QMediaTimeRange::Interval &interval);
};
-QMediaTimeRangePrivate::QMediaTimeRangePrivate()
- : QSharedData()
-{
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QMediaTimeRangePrivate);
-}
-
-QMediaTimeRangePrivate::QMediaTimeRangePrivate(const QMediaTimeRangePrivate &other)
- : QSharedData()
- , intervals(other.intervals)
-{
-
-}
-
-QMediaTimeRangePrivate::QMediaTimeRangePrivate(const QMediaTimeInterval &interval)
- : QSharedData()
+QMediaTimeRangePrivate::QMediaTimeRangePrivate(const QMediaTimeRange::Interval &interval)
{
- if(interval.isNormal())
+ if (interval.isNormal())
intervals << interval;
}
-void QMediaTimeRangePrivate::addInterval(const QMediaTimeInterval &interval)
+void QMediaTimeRangePrivate::addInterval(const QMediaTimeRange::Interval &interval)
{
// Handle normalized intervals only
- if(!interval.isNormal())
+ if (!interval.isNormal())
return;
// 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);
@@ -242,29 +139,29 @@ void QMediaTimeRangePrivate::addInterval(const QMediaTimeInterval &interval)
}
// 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?
- if(i > 0 && intervals[i - 1].e >= interval.s - 1)
+ if (i > 0 && intervals[i - 1].e >= interval.s - 1)
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);
}
}
-void QMediaTimeRangePrivate::removeInterval(const QMediaTimeInterval &interval)
+void QMediaTimeRangePrivate::removeInterval(const QMediaTimeRange::Interval &interval)
{
// Handle normalized intervals only
- if(!interval.isNormal())
+ if (!interval.isNormal())
return;
- for (int i = 0; i < intervals.count(); i++) {
- QMediaTimeInterval r = intervals[i];
+ for (int i = 0; i < intervals.size(); i++) {
+ const QMediaTimeRange::Interval r = intervals.at(i);
if (r.e < interval.s) {
// Before the removal interval
@@ -275,7 +172,7 @@ void QMediaTimeRangePrivate::removeInterval(const QMediaTimeInterval &interval)
} else if (r.s < interval.s && interval.e < r.e) {
// Split case - a single range has a chunk removed
intervals[i].e = interval.s -1;
- addInterval(QMediaTimeInterval(interval.e + 1, r.e));
+ addInterval(QMediaTimeRange::Interval(interval.e + 1, r.e));
break;
} else if (r.s < interval.s) {
// Trimming Tail Case
@@ -311,14 +208,12 @@ void QMediaTimeRangePrivate::removeInterval(const QMediaTimeInterval &interval)
within the range may be expanded, trimmed, deleted, merged or split to ensure
that all intervals within the time range remain distinct and disjoint. As a
consequence, all intervals added or removed from a time range must be
- \l{QMediaTimeInterval::isNormal()}{normal}.
+ \l{QMediaTimeRange::Interval::isNormal()}{normal}.
- \sa QMediaTimeInterval
+ \sa QMediaTimeRange::Interval
*/
/*!
- \fn QMediaTimeRange::QMediaTimeRange()
-
Constructs an empty time range.
*/
QMediaTimeRange::QMediaTimeRange()
@@ -328,80 +223,76 @@ QMediaTimeRange::QMediaTimeRange()
}
/*!
- \fn QMediaTimeRange::QMediaTimeRange(qint64 start, qint64 end)
-
Constructs a time range that contains an initial interval from
\a start to \a end inclusive.
- If the interval is not \l{QMediaTimeInterval::isNormal()}{normal},
+ If the interval is not \l{QMediaTimeRange::Interval::isNormal()}{normal},
the resulting time range will be empty.
\sa addInterval()
*/
QMediaTimeRange::QMediaTimeRange(qint64 start, qint64 end)
- : d(new QMediaTimeRangePrivate(QMediaTimeInterval(start, end)))
+ : QMediaTimeRange(Interval(start, end))
{
-
}
/*!
- \fn QMediaTimeRange::QMediaTimeRange(const QMediaTimeInterval &interval)
-
Constructs a time range that contains an initial interval, \a interval.
- If \a interval is not \l{QMediaTimeInterval::isNormal()}{normal},
+ If \a interval is not \l{QMediaTimeRange::Interval::isNormal()}{normal},
the resulting time range will be empty.
\sa addInterval()
*/
-QMediaTimeRange::QMediaTimeRange(const QMediaTimeInterval &interval)
+QMediaTimeRange::QMediaTimeRange(const QMediaTimeRange::Interval &interval)
: d(new QMediaTimeRangePrivate(interval))
{
-
}
/*!
- \fn QMediaTimeRange::QMediaTimeRange(const QMediaTimeRange &range)
-
Constructs a time range by copying another time \a range.
*/
-QMediaTimeRange::QMediaTimeRange(const QMediaTimeRange &range)
- : d(range.d)
-{
+QMediaTimeRange::QMediaTimeRange(const QMediaTimeRange &range) noexcept = default;
-}
+/*! \fn QMediaTimeRange::QMediaTimeRange(QMediaTimeRange &&other)
+
+ Constructs a time range by moving from \a other.
+*/
+
+/*!
+ \fn void QMediaTimeRange::swap(QMediaTimeRange &other) noexcept
+
+ Swaps the current instance with the \a other.
+*/
/*!
\fn QMediaTimeRange::~QMediaTimeRange()
Destructor.
*/
-QMediaTimeRange::~QMediaTimeRange()
-{
-
-}
+QMediaTimeRange::~QMediaTimeRange() = default;
/*!
Takes a copy of the \a other time range and returns itself.
*/
-QMediaTimeRange &QMediaTimeRange::operator=(const QMediaTimeRange &other)
-{
- d = other.d;
- return *this;
-}
+QMediaTimeRange &QMediaTimeRange::operator=(const QMediaTimeRange &other) noexcept = default;
+
+/*!
+ \fn QMediaTimeRange &QMediaTimeRange::operator=(QMediaTimeRange &&other)
+
+ Moves \a other into this time range.
+*/
/*!
Sets the time range to a single continuous interval, \a interval.
*/
-QMediaTimeRange &QMediaTimeRange::operator=(const QMediaTimeInterval &interval)
+QMediaTimeRange &QMediaTimeRange::operator=(const QMediaTimeRange::Interval &interval)
{
d = new QMediaTimeRangePrivate(interval);
return *this;
}
/*!
- \fn QMediaTimeRange::earliestTime() const
-
Returns the earliest time within the time range.
For empty time ranges, this value is equal to zero.
@@ -411,14 +302,12 @@ QMediaTimeRange &QMediaTimeRange::operator=(const QMediaTimeInterval &interval)
qint64 QMediaTimeRange::earliestTime() const
{
if (!d->intervals.isEmpty())
- return d->intervals[0].s;
+ return d->intervals[0].start();
return 0;
}
/*!
- \fn QMediaTimeRange::latestTime() const
-
Returns the latest time within the time range.
For empty time ranges, this value is equal to zero.
@@ -428,13 +317,12 @@ qint64 QMediaTimeRange::earliestTime() const
qint64 QMediaTimeRange::latestTime() const
{
if (!d->intervals.isEmpty())
- return d->intervals[d->intervals.count() - 1].e;
+ return d->intervals[d->intervals.size() - 1].end();
return 0;
}
/*!
- \fn QMediaTimeRange::addInterval(qint64 start, qint64 end)
\overload
Adds the interval specified by \a start and \a end
@@ -444,15 +332,14 @@ qint64 QMediaTimeRange::latestTime() const
*/
void QMediaTimeRange::addInterval(qint64 start, qint64 end)
{
- d->addInterval(QMediaTimeInterval(start, end));
+ detach();
+ d->addInterval(Interval(start, end));
}
/*!
- \fn QMediaTimeRange::addInterval(const QMediaTimeInterval &interval)
-
Adds the specified \a interval to the time range.
- Adding intervals which are not \l{QMediaTimeInterval::isNormal()}{normal}
+ Adding intervals which are not \l{QMediaTimeRange::Interval::isNormal()}{normal}
is invalid, and will be ignored.
If the specified interval is adjacent to, or overlaps existing
@@ -462,8 +349,9 @@ void QMediaTimeRange::addInterval(qint64 start, qint64 end)
\sa removeInterval()
*/
-void QMediaTimeRange::addInterval(const QMediaTimeInterval &interval)
+void QMediaTimeRange::addInterval(const QMediaTimeRange::Interval &interval)
{
+ detach();
d->addInterval(interval);
}
@@ -474,14 +362,14 @@ void QMediaTimeRange::addInterval(const QMediaTimeInterval &interval)
*/
void QMediaTimeRange::addTimeRange(const QMediaTimeRange &range)
{
+ detach();
const auto intervals = range.intervals();
- for (const QMediaTimeInterval &i : intervals) {
+ for (const Interval &i : intervals) {
d->addInterval(i);
}
}
/*!
- \fn QMediaTimeRange::removeInterval(qint64 start, qint64 end)
\overload
Removes the interval specified by \a start and \a end
@@ -491,15 +379,16 @@ void QMediaTimeRange::addTimeRange(const QMediaTimeRange &range)
*/
void QMediaTimeRange::removeInterval(qint64 start, qint64 end)
{
- d->removeInterval(QMediaTimeInterval(start, end));
+ detach();
+ d->removeInterval(Interval(start, end));
}
/*!
- \fn QMediaTimeRange::removeInterval(const QMediaTimeInterval &interval)
+ \fn QMediaTimeRange::removeInterval(const QMediaTimeRange::Interval &interval)
Removes the specified \a interval from the time range.
- Removing intervals which are not \l{QMediaTimeInterval::isNormal()}{normal}
+ Removing intervals which are not \l{QMediaTimeRange::Interval::isNormal()}{normal}
is invalid, and will be ignored.
Intervals within the time range will be trimmed, split or deleted
@@ -510,8 +399,9 @@ void QMediaTimeRange::removeInterval(qint64 start, qint64 end)
\sa addInterval()
*/
-void QMediaTimeRange::removeInterval(const QMediaTimeInterval &interval)
+void QMediaTimeRange::removeInterval(const QMediaTimeRange::Interval &interval)
{
+ detach();
d->removeInterval(interval);
}
@@ -522,8 +412,9 @@ void QMediaTimeRange::removeInterval(const QMediaTimeInterval &interval)
*/
void QMediaTimeRange::removeTimeRange(const QMediaTimeRange &range)
{
+ detach();
const auto intervals = range.intervals();
- for (const QMediaTimeInterval &i : intervals) {
+ for (const Interval &i : intervals) {
d->removeInterval(i);
}
}
@@ -540,7 +431,7 @@ QMediaTimeRange& QMediaTimeRange::operator+=(const QMediaTimeRange &other)
/*!
Adds the specified \a interval to the time range and returns the result.
*/
-QMediaTimeRange& QMediaTimeRange::operator+=(const QMediaTimeInterval &interval)
+QMediaTimeRange& QMediaTimeRange::operator+=(const QMediaTimeRange::Interval &interval)
{
addInterval(interval);
return *this;
@@ -558,7 +449,7 @@ QMediaTimeRange& QMediaTimeRange::operator-=(const QMediaTimeRange &other)
/*!
Removes the specified \a interval from the time range and returns the result.
*/
-QMediaTimeRange& QMediaTimeRange::operator-=(const QMediaTimeInterval &interval)
+QMediaTimeRange& QMediaTimeRange::operator-=(const QMediaTimeRange::Interval &interval)
{
removeInterval(interval);
return *this;
@@ -573,15 +464,24 @@ QMediaTimeRange& QMediaTimeRange::operator-=(const QMediaTimeInterval &interval)
*/
void QMediaTimeRange::clear()
{
+ detach();
d->intervals.clear();
}
/*!
+ \internal
+*/
+void QMediaTimeRange::detach()
+{
+ d.detach();
+}
+
+/*!
\fn QMediaTimeRange::intervals() const
Returns the list of intervals covered by this time range.
*/
-QList<QMediaTimeInterval> QMediaTimeRange::intervals() const
+QList<QMediaTimeRange::Interval> QMediaTimeRange::intervals() const
{
return d->intervals;
}
@@ -606,7 +506,7 @@ bool QMediaTimeRange::isEmpty() const
*/
bool QMediaTimeRange::isContinuous() const
{
- return (d->intervals.count() <= 1);
+ return (d->intervals.size() <= 1);
}
/*!
@@ -616,11 +516,11 @@ 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;
- if (time < d->intervals[i].s)
+ if (time < d->intervals[i].start())
break;
}
@@ -628,53 +528,47 @@ bool QMediaTimeRange::contains(qint64 time) const
}
/*!
- \relates QMediaTimeRange
+ \fn bool QMediaTimeRange::operator==(const QMediaTimeRange &lhs, const QMediaTimeRange &rhs)
- Returns true if all intervals in \a a are present in \a b.
+ Returns true if all intervals in \a lhs are present in \a rhs.
*/
-bool operator==(const QMediaTimeRange &a, const QMediaTimeRange &b)
-{
- return a.intervals() == b.intervals();
-}
/*!
- \relates QMediaTimeRange
+ \fn bool QMediaTimeRange::operator!=(const QMediaTimeRange &lhs, const QMediaTimeRange &rhs)
- Returns true if one or more intervals in \a a are not present in \a b.
+ Returns true if one or more intervals in \a lhs are not present in \a rhs.
*/
-bool operator!=(const QMediaTimeRange &a, const QMediaTimeRange &b)
-{
- return !(a == b);
-}
/*!
+ \fn QMediaTimeRange operator+(const QMediaTimeRange &r1, const QMediaTimeRange &r2)
\relates QMediaTimeRange
Returns a time range containing the union between \a r1 and \a r2.
*/
-QMediaTimeRange operator+(const QMediaTimeRange &r1, const QMediaTimeRange &r2)
-{
- return (QMediaTimeRange(r1) += r2);
-}
/*!
+ \fn QMediaTimeRange operator-(const QMediaTimeRange &r1, const QMediaTimeRange &r2)
\relates QMediaTimeRange
Returns a time range containing \a r2 subtracted from \a r1.
*/
-QMediaTimeRange operator-(const QMediaTimeRange &r1, const QMediaTimeRange &r2)
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QMediaTimeRange::Interval &interval)
{
- return (QMediaTimeRange(r1) -= r2);
+ QDebugStateSaver saver(dbg);
+ dbg.nospace();
+ dbg << "QMediaTimeRange::Interval( " << interval.start() << ", " << interval.end() << " )";
+ return dbg;
}
-#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QMediaTimeRange &range)
{
QDebugStateSaver saver(dbg);
dbg.nospace();
dbg << "QMediaTimeRange( ";
const auto intervals = range.intervals();
- for (const QMediaTimeInterval &interval : intervals)
+ for (const auto &interval : intervals)
dbg << '(' << interval.start() << ", " << interval.end() << ") ";
dbg.space();
dbg << ')';
@@ -683,4 +577,3 @@ QDebug operator<<(QDebug dbg, const QMediaTimeRange &range)
#endif
QT_END_NAMESPACE
-
diff --git a/src/multimedia/qmediatimerange.h b/src/multimedia/qmediatimerange.h
index 97524f24a..7245a845a 100644
--- a/src/multimedia/qmediatimerange.h
+++ b/src/multimedia/qmediatimerange.h
@@ -1,131 +1,129 @@
-/****************************************************************************
-**
-** 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
#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qmultimedia.h>
#include <QtCore/qshareddata.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qmetatype.h>
QT_BEGIN_NAMESPACE
class QMediaTimeRangePrivate;
-class Q_MULTIMEDIA_EXPORT QMediaTimeInterval
-{
-public:
- QMediaTimeInterval();
- QMediaTimeInterval(qint64 start, qint64 end);
-
- qint64 start() const;
- qint64 end() const;
-
- bool contains(qint64 time) const;
-
- bool isNormal() const;
- QMediaTimeInterval normalized() const;
- QMediaTimeInterval translated(qint64 offset) const;
-
-private:
- friend class QMediaTimeRangePrivate;
- friend class QMediaTimeRange;
-
- qint64 s;
- qint64 e;
-};
-
-Q_MULTIMEDIA_EXPORT bool operator==(const QMediaTimeInterval&, const QMediaTimeInterval&);
-Q_MULTIMEDIA_EXPORT bool operator!=(const QMediaTimeInterval&, const QMediaTimeInterval&);
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QMediaTimeRangePrivate, Q_MULTIMEDIA_EXPORT)
class Q_MULTIMEDIA_EXPORT QMediaTimeRange
{
public:
+ struct Interval
+ {
+ constexpr Interval() noexcept = default;
+ explicit constexpr Interval(qint64 start, qint64 end) noexcept
+ : s(start), e(end)
+ {}
+
+ constexpr qint64 start() const noexcept { return s; }
+ constexpr qint64 end() const noexcept { return e; }
+
+ constexpr bool contains(qint64 time) const noexcept
+ {
+ return isNormal() ? (s <= time && time <= e)
+ : (e <= time && time <= s);
+ }
+
+ constexpr bool isNormal() const noexcept { return s <= e; }
+ constexpr Interval normalized() const
+ {
+ return s > e ? Interval(e, s) : *this;
+ }
+ constexpr Interval translated(qint64 offset) const
+ {
+ return Interval(s + offset, e + offset);
+ }
+
+ friend constexpr bool operator==(Interval lhs, Interval rhs) noexcept
+ {
+ return lhs.start() == rhs.start() && lhs.end() == rhs.end();
+ }
+ friend constexpr bool operator!=(Interval lhs, Interval rhs) noexcept
+ {
+ return lhs.start() != rhs.start() || lhs.end() != rhs.end();
+ }
+
+ private:
+ friend class QMediaTimeRangePrivate;
+ qint64 s = 0;
+ qint64 e = 0;
+ };
QMediaTimeRange();
- QMediaTimeRange(qint64 start, qint64 end);
- QMediaTimeRange(const QMediaTimeInterval&);
- QMediaTimeRange(const QMediaTimeRange &range);
+ explicit QMediaTimeRange(qint64 start, qint64 end);
+ QMediaTimeRange(const Interval&);
+ QMediaTimeRange(const QMediaTimeRange &range) noexcept;
~QMediaTimeRange();
- QMediaTimeRange &operator=(const QMediaTimeRange&);
- QMediaTimeRange &operator=(const QMediaTimeInterval&);
+ QMediaTimeRange &operator=(const QMediaTimeRange&) noexcept;
+
+ QMediaTimeRange(QMediaTimeRange &&other) noexcept = default;
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QMediaTimeRange)
+ void swap(QMediaTimeRange &other) noexcept
+ { d.swap(other.d); }
+ void detach();
+
+ QMediaTimeRange &operator=(const Interval&);
qint64 earliestTime() const;
qint64 latestTime() const;
- QList<QMediaTimeInterval> intervals() const;
+ QList<QMediaTimeRange::Interval> intervals() const;
bool isEmpty() const;
bool isContinuous() const;
bool contains(qint64 time) const;
void addInterval(qint64 start, qint64 end);
- void addInterval(const QMediaTimeInterval &interval);
+ void addInterval(const Interval &interval);
void addTimeRange(const QMediaTimeRange&);
void removeInterval(qint64 start, qint64 end);
- void removeInterval(const QMediaTimeInterval &interval);
+ void removeInterval(const Interval &interval);
void removeTimeRange(const QMediaTimeRange&);
QMediaTimeRange& operator+=(const QMediaTimeRange&);
- QMediaTimeRange& operator+=(const QMediaTimeInterval&);
+ QMediaTimeRange& operator+=(const Interval&);
QMediaTimeRange& operator-=(const QMediaTimeRange&);
- QMediaTimeRange& operator-=(const QMediaTimeInterval&);
+ QMediaTimeRange& operator-=(const Interval&);
void clear();
+ friend inline bool operator==(const QMediaTimeRange &lhs, const QMediaTimeRange &rhs)
+ { return lhs.intervals() == rhs.intervals(); }
+ friend inline bool operator!=(const QMediaTimeRange &lhs, const QMediaTimeRange &rhs)
+ { return lhs.intervals() != rhs.intervals(); }
+
private:
- QSharedDataPointer<QMediaTimeRangePrivate> d;
+ QExplicitlySharedDataPointer<QMediaTimeRangePrivate> d;
};
-Q_MULTIMEDIA_EXPORT bool operator==(const QMediaTimeRange&, const QMediaTimeRange&);
-Q_MULTIMEDIA_EXPORT bool operator!=(const QMediaTimeRange&, const QMediaTimeRange&);
-Q_MULTIMEDIA_EXPORT QMediaTimeRange operator+(const QMediaTimeRange&, const QMediaTimeRange&);
-Q_MULTIMEDIA_EXPORT QMediaTimeRange operator-(const QMediaTimeRange&, const QMediaTimeRange&);
-
#ifndef QT_NO_DEBUG_STREAM
+Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, const QMediaTimeRange::Interval &);
Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, const QMediaTimeRange &);
#endif
+inline QMediaTimeRange operator+(const QMediaTimeRange &r1, const QMediaTimeRange &r2)
+{ return (QMediaTimeRange(r1) += r2); }
+inline QMediaTimeRange operator-(const QMediaTimeRange &r1, const QMediaTimeRange &r2)
+{ return (QMediaTimeRange(r1) -= r2); }
+
+Q_DECLARE_SHARED(QMediaTimeRange)
+
QT_END_NAMESPACE
+Q_DECLARE_METATYPE(QMediaTimeRange)
+Q_DECLARE_METATYPE(QMediaTimeRange::Interval)
#endif // QMEDIATIMERANGE_H
diff --git a/src/multimedia/qmultimedia.cpp b/src/multimedia/qmultimedia.cpp
deleted file mode 100644
index 34d7cbe5a..000000000
--- a/src/multimedia/qmultimedia.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include "qmultimedia.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \namespace QMultimedia
- \ingroup multimedia-namespaces
- \ingroup multimedia
- \inmodule QtMultimedia
-
- \ingroup multimedia
- \ingroup multimedia_core
-
- \brief The QMultimedia namespace contains miscellaneous identifiers used throughout the Qt Multimedia library.
-
-*/
-
-static void qRegisterMultimediaMetaTypes()
-{
- qRegisterMetaType<QMultimedia::AvailabilityStatus>();
- qRegisterMetaType<QMultimedia::SupportEstimate>();
- qRegisterMetaType<QMultimedia::EncodingMode>();
- qRegisterMetaType<QMultimedia::EncodingQuality>();
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterMultimediaMetaTypes)
-
-
-/*!
- \enum QMultimedia::SupportEstimate
-
- Enumerates the levels of support a media service provider may have for a feature.
-
- \value NotSupported The feature is not supported.
- \value MaybeSupported The feature may be supported.
- \value ProbablySupported The feature is probably supported.
- \value PreferredService The service is the preferred provider of a service.
-*/
-
-/*!
- \enum QMultimedia::EncodingQuality
-
- Enumerates quality encoding levels.
-
- \value VeryLowQuality
- \value LowQuality
- \value NormalQuality
- \value HighQuality
- \value VeryHighQuality
-*/
-
-/*!
- \enum QMultimedia::EncodingMode
-
- Enumerates encoding modes.
-
- \value ConstantQualityEncoding Encoding will aim to have a constant quality, adjusting bitrate to fit.
- \value ConstantBitRateEncoding Encoding will use a constant bit rate, adjust quality to fit.
- \value AverageBitRateEncoding Encoding will try to keep an average bitrate setting, but will use
- more or less as needed.
- \value TwoPassEncoding The media will first be processed to determine the characteristics,
- and then processed a second time allocating more bits to the areas
- that need it.
-*/
-
-/*!
- \enum QMultimedia::AvailabilityStatus
-
- Enumerates Service status errors.
-
- \value Available The service is operating correctly.
- \value ServiceMissing There is no service available to provide the requested functionality.
- \value ResourceError The service could not allocate resources required to function correctly.
- \value Busy The service must wait for access to necessary resources.
-*/
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/qmultimedia.h b/src/multimedia/qmultimedia.h
deleted file mode 100644
index a3dbc5e3e..000000000
--- a/src/multimedia/qmultimedia.h
+++ /dev/null
@@ -1,96 +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 QMULTIMEDIA_H
-#define QMULTIMEDIA_H
-
-#include <QtCore/qpair.h>
-#include <QtCore/qmetatype.h>
-#include <QtCore/qstring.h>
-
-#include <QtMultimedia/qtmultimediaglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QMultimedia
-{
- enum SupportEstimate
- {
- NotSupported,
- MaybeSupported,
- ProbablySupported,
- PreferredService
- };
-
- enum EncodingQuality
- {
- VeryLowQuality,
- LowQuality,
- NormalQuality,
- HighQuality,
- VeryHighQuality
- };
-
- enum EncodingMode
- {
- ConstantQualityEncoding,
- ConstantBitRateEncoding,
- AverageBitRateEncoding,
- TwoPassEncoding
- };
-
- enum AvailabilityStatus
- {
- Available,
- ServiceMissing,
- Busy,
- ResourceError
- };
-
-}
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QMultimedia::AvailabilityStatus)
-Q_DECLARE_METATYPE(QMultimedia::SupportEstimate)
-Q_DECLARE_METATYPE(QMultimedia::EncodingMode)
-Q_DECLARE_METATYPE(QMultimedia::EncodingQuality)
-
-
-#endif
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 771502bdd..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
@@ -51,11 +15,49 @@
// We mean it.
//
-#include <QtMultimedia/qmultimedia.h>
+#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/qnx/qqnxaudiosink.cpp b/src/multimedia/qnx/qqnxaudiosink.cpp
new file mode 100644
index 000000000..fa4b97ab6
--- /dev/null
+++ b/src/multimedia/qnx/qqnxaudiosink.cpp
@@ -0,0 +1,516 @@
+// 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 <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(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_bytesWritten(0)
+ , m_requestedBufferSize(0)
+ , m_deviceInfo(deviceInfo)
+ , m_pcmNotifier(0)
+{
+ 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()
+{
+ stop();
+}
+
+void QQnxAudioSink::start(QIODevice *source)
+{
+ if (m_state != QAudio::StoppedState)
+ stop();
+
+ m_source = source;
+ m_pushSource = false;
+
+ if (open()) {
+ changeState(QAudio::ActiveState, QAudio::NoError);
+ m_timer->start();
+ } else {
+ changeState(QAudio::StoppedState, QAudio::OpenError);
+ }
+}
+
+QIODevice *QQnxAudioSink::start()
+{
+ if (m_state != QAudio::StoppedState)
+ stop();
+
+ m_source = new QnxPushIODevice(this);
+ m_source->open(QIODevice::WriteOnly|QIODevice::Unbuffered);
+ m_pushSource = true;
+
+ if (open()) {
+ changeState(QAudio::IdleState, QAudio::NoError);
+ } else {
+ changeState(QAudio::StoppedState, QAudio::OpenError);
+ }
+
+ return m_source;
+}
+
+void QQnxAudioSink::stop()
+{
+ if (m_state == QAudio::StoppedState)
+ return;
+
+ changeState(QAudio::StoppedState, QAudio::NoError);
+
+ close();
+}
+
+void QQnxAudioSink::reset()
+{
+ if (m_pcmHandle)
+#if SND_PCM_VERSION < SND_PROTOCOL_VERSION('P',3,0,2)
+ snd_pcm_playback_drain(m_pcmHandle.get());
+#else
+ snd_pcm_channel_drain(m_pcmHandle.get(), SND_PCM_CHANNEL_PLAYBACK);
+#endif
+ stop();
+}
+
+void QQnxAudioSink::suspend()
+{
+ if (!m_pcmHandle)
+ return;
+
+ snd_pcm_playback_pause(m_pcmHandle.get());
+ suspendInternal(QAudio::SuspendedState);
+}
+
+void QQnxAudioSink::resume()
+{
+ 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;
+
+ const std::optional<snd_pcm_channel_status_t> status = QnxAudioUtils::pcmChannelStatus(
+ m_pcmHandle.get(), QAudioDevice::Output);
+
+ return status ? status->free : 0;
+}
+
+qint64 QQnxAudioSink::processedUSecs() const
+{
+ return qint64(1000000) * m_format.framesForBytes(m_bytesWritten) / m_format.sampleRate();
+}
+
+QAudio::Error QQnxAudioSink::error() const
+{
+ return m_error;
+}
+
+QAudio::State QQnxAudioSink::state() const
+{
+ return m_state;
+}
+
+void QQnxAudioSink::setFormat(const QAudioFormat &format)
+{
+ if (m_state == QAudio::StoppedState)
+ m_format = format;
+}
+
+QAudioFormat QQnxAudioSink::format() const
+{
+ return m_format;
+}
+
+void QQnxAudioSink::setVolume(qreal volume)
+{
+ m_volume = qBound(qreal(0.0), volume, qreal(1.0));
+}
+
+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
+ || m_state == QAudio::SuspendedState)
+ return;
+
+ const int bytesAvailable = bytesFree();
+
+ // 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);
+ const int bytesRequested = m_format.bytesForFrames(qMin(frames, maxFrames));
+
+ char buffer[bytesRequested];
+ const int bytesRead = m_source->read(buffer, bytesRequested);
+
+ // reading can take a while and stream may have been stopped
+ if (!m_pcmHandle)
+ return;
+
+ if (bytesRead > 0) {
+ const qint64 bytesWritten = write(buffer, bytesRead);
+
+ 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
+ if (bytesRead == 0)
+ changeState(QAudio::IdleState, QAudio::NoError);
+ else
+ changeState(QAudio::IdleState, QAudio::IOError);
+ }
+}
+
+bool QQnxAudioSink::open()
+{
+ if (!m_format.isValid() || m_format.sampleRate() <= 0) {
+ if (!m_format.isValid())
+ qWarning("QQnxAudioSink: open error, invalid format.");
+ else
+ qWarning("QQnxAudioSink: open error, invalid sample rate (%d).", m_format.sampleRate());
+
+ return false;
+ }
+
+
+ m_pcmHandle = QnxAudioUtils::openPcmDevice(m_deviceInfo.id(), QAudioDevice::Output);
+
+ if (!m_pcmHandle)
+ return false;
+
+ 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;
+ }
+
+ addPcmEventFilter();
+
+ // Necessary so that bytesFree() which uses the "free" member of the status struct works
+ 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);
+
+ if (!info) {
+ close();
+ return false;
+ }
+
+ const int fragmentSize = std::clamp(m_requestedBufferSize,
+ info->min_fragment_size, info->max_fragment_size);
+
+ 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.get(), SND_PCM_CHANNEL_PLAYBACK)) < 0) {
+ qWarning("QQnxAudioSink: open error, couldn't prepare channel (0x%x)", -errorCode);
+ close();
+ return false;
+ }
+
+ 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_bytesWritten = 0;
+
+ createPcmNotifiers();
+
+ return true;
+}
+
+void QQnxAudioSink::close()
+{
+ 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.get(), SND_PCM_CHANNEL_PLAYBACK);
+#else
+ snd_pcm_plugin_drop(m_pcmHandle.get(), SND_PCM_CHANNEL_PLAYBACK);
+#endif
+ m_pcmHandle = nullptr;
+ }
+
+ if (m_pushSource) {
+ delete m_source;
+ m_source = 0;
+ }
+}
+
+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);
+ }
+}
+
+qint64 QQnxAudioSink::pushData(const char *data, qint64 len)
+{
+ 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)
+{
+ if (!m_pcmHandle)
+ return 0;
+
+ // Make sure we're writing (N * frame) worth of bytes
+ const int size = m_format.bytesForFrames(qBound(qint64(0), qint64(bytesFree()), len) / m_format.bytesPerFrame());
+
+ if (size == 0)
+ return 0;
+
+ int written = 0;
+
+ if (m_volume < 1.0f) {
+ char out[size];
+ QAudioHelperInternal::qMultiplySamples(m_volume, m_format, data, out, size);
+ written = snd_pcm_plugin_write(m_pcmHandle.get(), out, size);
+ } else {
+ written = snd_pcm_plugin_write(m_pcmHandle.get(), data, size);
+ }
+
+ if (written > 0) {
+ m_bytesWritten += written;
+ return written;
+ }
+
+ return 0;
+}
+
+void QQnxAudioSink::suspendInternal(QAudio::State suspendState)
+{
+ if (!m_pushSource)
+ m_timer->stop();
+
+ m_suspendedInState = m_state;
+ changeState(suspendState, QAudio::NoError);
+}
+
+void QQnxAudioSink::resumeInternal()
+{
+ changeState(m_suspendedInState, QAudio::NoError);
+
+ m_timer->start();
+}
+
+QAudio::State suspendState(const snd_pcm_event_t &event)
+{
+ Q_ASSERT(event.type == SND_PCM_EVENT_AUDIOMGMT_STATUS);
+ Q_ASSERT(event.data.audiomgmt_status.new_status == SND_PCM_STATUS_SUSPENDED);
+ return QAudio::SuspendedState;
+}
+
+void QQnxAudioSink::addPcmEventFilter()
+{
+ /* Enable PCM events */
+ snd_pcm_filter_t filter;
+ memset(&filter, 0, sizeof(filter));
+ filter.enable = (1<<SND_PCM_EVENT_AUDIOMGMT_STATUS) |
+ (1<<SND_PCM_EVENT_AUDIOMGMT_MUTE) |
+ (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.get(),
+ SND_PCM_CHANNEL_PLAYBACK),
+ QSocketNotifier::Read, this);
+ connect(m_pcmNotifier, &QSocketNotifier::activated,
+ this, &QQnxAudioSink::pcmNotifierActivated);
+}
+
+void QQnxAudioSink::destroyPcmNotifiers()
+{
+ if (m_pcmNotifier) {
+ delete m_pcmNotifier;
+ m_pcmNotifier = 0;
+ }
+}
+
+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.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));
+ else if (pcm_event.data.audiomgmt_status.new_status == SND_PCM_STATUS_RUNNING)
+ 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();
+ }
+ }
+}
+
+QnxPushIODevice::QnxPushIODevice(QQnxAudioSink *output)
+ : QIODevice(output),
+ m_output(output)
+{
+}
+
+QnxPushIODevice::~QnxPushIODevice()
+{
+}
+
+qint64 QnxPushIODevice::readData(char *data, qint64 len)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(len);
+ return 0;
+}
+
+qint64 QnxPushIODevice::writeData(const char *data, qint64 len)
+{
+ return m_output->pushData(data, len);
+}
+
+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/qnx/qqnxaudiosource.cpp b/src/multimedia/qnx/qqnxaudiosource.cpp
new file mode 100644
index 000000000..becbaa0c0
--- /dev/null
+++ b/src/multimedia/qnx/qqnxaudiosource.cpp
@@ -0,0 +1,376 @@
+// 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 <private/qaudiohelpers_p.h>
+
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+QQnxAudioSource::QQnxAudioSource(const QAudioDevice &deviceInfo, QObject *parent)
+ : QPlatformAudioSource(parent)
+ , m_audioSource(0)
+ , m_pcmNotifier(0)
+ , m_error(QAudio::NoError)
+ , m_state(QAudio::StoppedState)
+ , m_bytesRead(0)
+ , m_elapsedTimeOffset(0)
+ , m_totalTimeValue(0)
+ , m_volume(qreal(1.0f))
+ , m_bytesAvailable(0)
+ , m_bufferSize(0)
+ , m_periodSize(0)
+ , m_deviceInfo(deviceInfo)
+ , m_pullMode(true)
+{
+}
+
+QQnxAudioSource::~QQnxAudioSource()
+{
+ close();
+}
+
+void QQnxAudioSource::start(QIODevice *device)
+{
+ if (m_state != QAudio::StoppedState)
+ close();
+
+ if (!m_pullMode && m_audioSource)
+ delete m_audioSource;
+
+ m_pullMode = true;
+ m_audioSource = device;
+
+ if (open())
+ changeState(QAudio::ActiveState, QAudio::NoError);
+ else
+ changeState(QAudio::StoppedState, QAudio::OpenError);
+}
+
+QIODevice *QQnxAudioSource::start()
+{
+ if (m_state != QAudio::StoppedState)
+ close();
+
+ if (!m_pullMode && m_audioSource)
+ delete m_audioSource;
+
+ m_pullMode = false;
+ m_audioSource = new InputPrivate(this);
+ m_audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
+
+ if (open()) {
+ changeState(QAudio::IdleState, QAudio::NoError);
+ } else {
+ delete m_audioSource;
+ m_audioSource = 0;
+
+ changeState(QAudio::StoppedState, QAudio::OpenError);
+ }
+
+ return m_audioSource;
+}
+
+void QQnxAudioSource::stop()
+{
+ if (m_state == QAudio::StoppedState)
+ return;
+
+ changeState(QAudio::StoppedState, QAudio::NoError);
+ close();
+}
+
+void QQnxAudioSource::reset()
+{
+ stop();
+ m_bytesAvailable = 0;
+}
+
+void QQnxAudioSource::suspend()
+{
+ if (m_state == QAudio::StoppedState)
+ return;
+
+ snd_pcm_capture_pause(m_pcmHandle.get());
+
+ if (m_pcmNotifier)
+ m_pcmNotifier->setEnabled(false);
+
+ changeState(QAudio::SuspendedState, QAudio::NoError);
+}
+
+void QQnxAudioSource::resume()
+{
+ if (m_state == QAudio::StoppedState)
+ return;
+
+ snd_pcm_capture_resume(m_pcmHandle.get());
+
+ if (m_pcmNotifier)
+ m_pcmNotifier->setEnabled(true);
+
+ if (m_pullMode)
+ changeState(QAudio::ActiveState, QAudio::NoError);
+ else
+ changeState(QAudio::IdleState, QAudio::NoError);
+}
+
+qsizetype QQnxAudioSource::bytesReady() const
+{
+ return qMax(m_bytesAvailable, 0);
+}
+
+void QQnxAudioSource::setBufferSize(qsizetype bufferSize)
+{
+ m_bufferSize = bufferSize;
+}
+
+qsizetype QQnxAudioSource::bufferSize() const
+{
+ return m_bufferSize;
+}
+
+qint64 QQnxAudioSource::processedUSecs() const
+{
+ return qint64(1000000) * m_format.framesForBytes(m_bytesRead) / m_format.sampleRate();
+}
+
+QAudio::Error QQnxAudioSource::error() const
+{
+ return m_error;
+}
+
+QAudio::State QQnxAudioSource::state() const
+{
+ return m_state;
+}
+
+void QQnxAudioSource::setFormat(const QAudioFormat &format)
+{
+ if (m_state == QAudio::StoppedState)
+ m_format = format;
+}
+
+QAudioFormat QQnxAudioSource::format() const
+{
+ return m_format;
+}
+
+void QQnxAudioSource::setVolume(qreal volume)
+{
+ m_volume = qBound(qreal(0.0), volume, qreal(1.0));
+}
+
+qreal QQnxAudioSource::volume() const
+{
+ return m_volume;
+}
+
+void QQnxAudioSource::userFeed()
+{
+ if (m_state == QAudio::StoppedState || m_state == QAudio::SuspendedState)
+ return;
+
+ deviceReady();
+}
+
+bool QQnxAudioSource::deviceReady()
+{
+ if (m_pullMode) {
+ // reads some audio data and writes it to QIODevice
+ read(0, 0);
+ } else {
+ m_bytesAvailable = m_periodSize;
+
+ // emits readyRead() so user will call read() on QIODevice to get some audio data
+ if (m_audioSource != 0) {
+ InputPrivate *input = qobject_cast<InputPrivate*>(m_audioSource);
+ input->trigger();
+ }
+ }
+
+ if (m_state != QAudio::ActiveState)
+ return true;
+
+ return true;
+}
+
+bool QQnxAudioSource::open()
+{
+ if (!m_format.isValid() || m_format.sampleRate() <= 0) {
+ if (!m_format.isValid())
+ qWarning("QQnxAudioSource: open error, invalid format.");
+ else
+ qWarning("QQnxAudioSource: open error, invalid sample rate (%d).", m_format.sampleRate());
+
+ return false;
+ }
+
+ m_pcmHandle = QnxAudioUtils::openPcmDevice(m_deviceInfo.id(), QAudioDevice::Input);
+
+ 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.get(), PLUGIN_MMAP);
+
+ 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);
+
+ 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.get(), SND_PCM_CHANNEL_CAPTURE)) < 0) {
+ qWarning("QQnxAudioSource: open error, couldn't prepare channel (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_elapsedTimeOffset = 0;
+ m_totalTimeValue = 0;
+ m_bytesRead = 0;
+
+ m_pcmNotifier = new QSocketNotifier(snd_pcm_file_descriptor(m_pcmHandle.get(), SND_PCM_CHANNEL_CAPTURE),
+ QSocketNotifier::Read, this);
+ connect(m_pcmNotifier, SIGNAL(activated(QSocketDescriptor)), this, SLOT(userFeed()));
+
+ return true;
+}
+
+void QQnxAudioSource::close()
+{
+ if (m_pcmHandle) {
+#if SND_PCM_VERSION < SND_PROTOCOL_VERSION('P',3,0,2)
+ snd_pcm_plugin_flush(m_pcmHandle.get(), SND_PCM_CHANNEL_CAPTURE);
+#else
+ 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_pullMode && m_audioSource) {
+ delete m_audioSource;
+ m_audioSource = 0;
+ }
+}
+
+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.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.get(), &status)) < 0) {
+ qWarning("QQnxAudioSource: read error, couldn't get plugin status (0x%x)", -errorCode);
+ close();
+ 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.get(), SND_PCM_CHANNEL_CAPTURE)) < 0) {
+ qWarning("QQnxAudioSource: read error, couldn't prepare plugin (0x%x)", -errorCode);
+ close();
+ changeState(QAudio::StoppedState, QAudio::FatalError);
+ return -1;
+ }
+ }
+ } else {
+ changeState(QAudio::ActiveState, QAudio::NoError);
+ }
+
+ if (m_volume < 1.0f)
+ QAudioHelperInternal::qMultiplySamples(m_volume, m_format, tempBuffer.data(), tempBuffer.data(), actualRead);
+
+ m_bytesRead += actualRead;
+
+ if (m_pullMode) {
+ m_audioSource->write(tempBuffer.data(), actualRead);
+ } else {
+ memcpy(data, tempBuffer.data(), qMin(static_cast<qint64>(actualRead), len));
+ }
+
+ m_bytesAvailable = 0;
+
+ return actualRead;
+}
+
+void QQnxAudioSource::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);
+ }
+}
+
+InputPrivate::InputPrivate(QQnxAudioSource *audio)
+ : m_audioDevice(audio)
+{
+}
+
+qint64 InputPrivate::readData(char *data, qint64 len)
+{
+ return m_audioDevice->read(data, len);
+}
+
+qint64 InputPrivate::writeData(const char *data, qint64 len)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(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();
+}
+
+QT_END_NAMESPACE
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/qsymbolsresolveutils.cpp b/src/multimedia/qsymbolsresolveutils.cpp
new file mode 100644
index 000000000..81c7410d2
--- /dev/null
+++ b/src/multimedia/qsymbolsresolveutils.cpp
@@ -0,0 +1,79 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qsymbolsresolveutils_p.h"
+
+#include <qdebug.h>
+#include <algorithm>
+#include <qloggingcategory.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_STATIC_LOGGING_CATEGORY(qLcSymbolsResolver, "qt.multimedia.symbolsresolver");
+
+bool SymbolsResolver::isLazyLoadEnabled()
+{
+ static const bool lazyLoad =
+ !static_cast<bool>(qEnvironmentVariableIntValue("QT_INSTANT_LOAD_FFMPEG_STUBS"));
+ return lazyLoad;
+}
+
+SymbolsResolver::SymbolsResolver(const char *libLoggingName, LibraryLoader loader)
+ : m_libLoggingName(libLoggingName)
+{
+ Q_ASSERT(libLoggingName);
+ Q_ASSERT(loader);
+
+ auto library = loader();
+ if (library && library->isLoaded())
+ m_library = std::move(library);
+ else
+ qCWarning(qLcSymbolsResolver) << "Couldn't load" << m_libLoggingName << "library";
+}
+
+SymbolsResolver::SymbolsResolver(const char *libName, const char *version,
+ const char *libLoggingName)
+ : m_libLoggingName(libLoggingName ? libLoggingName : libName)
+{
+ Q_ASSERT(libName);
+ Q_ASSERT(version);
+
+ auto library = std::make_unique<QLibrary>(QString::fromLocal8Bit(libName),
+ QString::fromLocal8Bit(version));
+ if (library->load())
+ m_library = std::move(library);
+ else
+ qCWarning(qLcSymbolsResolver) << "Couldn't load" << m_libLoggingName << "library";
+}
+
+SymbolsResolver::~SymbolsResolver()
+{
+ if (m_library)
+ m_library->unload();
+}
+
+QFunctionPointer SymbolsResolver::initFunction(const char *funcName)
+{
+ if (!m_library)
+ return nullptr;
+ if (auto func = m_library->resolve(funcName))
+ return func;
+
+ qCWarning(qLcSymbolsResolver) << "Couldn't resolve" << m_libLoggingName << "symbol" << funcName;
+ m_library->unload();
+ m_library.reset();
+ return nullptr;
+}
+
+void SymbolsResolver::checkLibrariesLoaded(SymbolsMarker *begin, SymbolsMarker *end)
+{
+ if (m_library) {
+ qCDebug(qLcSymbolsResolver) << m_libLoggingName << "symbols resolved";
+ } else {
+ const auto size = reinterpret_cast<char *>(end) - reinterpret_cast<char *>(begin);
+ memset(begin, 0, size);
+ qCWarning(qLcSymbolsResolver) << "Couldn't resolve" << m_libLoggingName << "symbols";
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/qsymbolsresolveutils_p.h b/src/multimedia/qsymbolsresolveutils_p.h
new file mode 100644
index 000000000..98a552170
--- /dev/null
+++ b/src/multimedia/qsymbolsresolveutils_p.h
@@ -0,0 +1,178 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef Q_SYMBOLSRESOLVEUTILS
+#define Q_SYMBOLSRESOLVEUTILS
+
+#include <QtCore/qlibrary.h>
+#include <QtMultimedia/qtmultimediaexports.h>
+#include <tuple>
+#include <memory>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+constexpr bool areVersionsEqual(const char lhs[], const char rhs[])
+{
+ int i = 0;
+ for (; lhs[i] && rhs[i]; ++i)
+ if (lhs[i] != rhs[i])
+ return false;
+ return lhs[i] == rhs[i];
+}
+
+constexpr bool areVersionsEqual(const char lhs[], int rhsInt)
+{
+ int lhsInt = 0;
+ for (int i = 0; lhs[i]; ++i) {
+ if (lhs[i] < '0' || lhs[i] > '9')
+ return false;
+
+ lhsInt *= 10;
+ lhsInt += lhs[i] - '0';
+ }
+
+ return lhsInt == rhsInt;
+}
+
+
+template <typename T>
+struct DefaultReturn
+{
+ template <typename... Arg>
+ T operator()(Arg &&...) { return val; }
+ T val;
+};
+
+template <>
+struct DefaultReturn<void>
+{
+ template <typename... Arg>
+ void operator()(Arg &&...) { }
+};
+
+template <typename...>
+struct FuncInfo;
+
+template <typename R, typename... A>
+struct FuncInfo<R(A...)>
+{
+ using Return = R;
+ using Args = std::tuple<A...>;
+};
+
+class Q_MULTIMEDIA_EXPORT SymbolsResolver
+{
+public:
+ using LibraryLoader = std::unique_ptr<QLibrary> (*)();
+ static bool isLazyLoadEnabled();
+
+ ~SymbolsResolver();
+protected:
+ SymbolsResolver(const char *libLoggingName, LibraryLoader loader);
+
+ SymbolsResolver(const char *libName, const char *version = "",
+ const char *libLoggingName = nullptr);
+
+ QFunctionPointer initFunction(const char *name);
+
+ struct SymbolsMarker {};
+ void checkLibrariesLoaded(SymbolsMarker *begin, SymbolsMarker *end);
+
+private:
+ const char *m_libLoggingName;
+ std::unique_ptr<QLibrary> m_library;
+};
+
+
+QT_END_NAMESPACE
+
+// clang-format off
+
+#define CHECK_VERSIONS(Name, NeededSoversion, DetectedVersion) \
+ static_assert(areVersionsEqual(NeededSoversion, DetectedVersion), \
+ "Configuartion error: misleading " Name " versions!")
+
+#define BEGIN_INIT_FUNCS(...) \
+ QT_USE_NAMESPACE \
+ namespace { \
+ class SymbolsResolverImpl : SymbolsResolver { \
+ public: \
+ SymbolsResolverImpl() : SymbolsResolver(__VA_ARGS__) \
+ { checkLibrariesLoaded(&symbolsBegin, &symbolsEnd); } \
+ static const SymbolsResolverImpl& instance() \
+ { static const SymbolsResolverImpl instance; return instance; } \
+ SymbolsMarker symbolsBegin;
+
+#define INIT_FUNC(F) QFunctionPointer F = initFunction(#F);
+
+#define END_INIT_FUNCS() \
+ SymbolsMarker symbolsEnd; \
+ }; \
+ [[maybe_unused]] static const auto *instantResolver = \
+ SymbolsResolver::isLazyLoadEnabled() ? &SymbolsResolverImpl::instance() : nullptr; \
+ }
+
+
+#ifdef Q_EXPORT_STUB_SYMBOLS
+#define EXPORT_FUNC Q_MULTIMEDIA_EXPORT
+#else
+#define EXPORT_FUNC
+#endif
+
+#define DEFINE_FUNC_IMPL(F, Vars, TypesWithVars, ReturnFunc) \
+ using F##_ReturnType = FuncInfo<decltype(F)>::Return; \
+ extern "C" EXPORT_FUNC [[maybe_unused]] F##_ReturnType F(TypesWithVars(F)) { \
+ using F##_Type = F##_ReturnType (*)(TypesWithVars(F)); \
+ const auto f = SymbolsResolverImpl::instance().F; \
+ return f ? (reinterpret_cast<F##_Type>(f))(Vars()) : ReturnFunc(); \
+ }
+
+
+#define VAR(I) a##I
+#define VARS0()
+#define VARS1() VAR(0)
+#define VARS2() VARS1(), VAR(1)
+#define VARS3() VARS2(), VAR(2)
+#define VARS4() VARS3(), VAR(3)
+#define VARS5() VARS4(), VAR(4)
+#define VARS6() VARS5(), VAR(5)
+#define VARS7() VARS6(), VAR(6)
+#define VARS8() VARS7(), VAR(7)
+#define VARS9() VARS8(), VAR(8)
+#define VARS10() VARS9(), VAR(9)
+#define VARS11() VARS10(), VAR(10)
+
+#define TYPE_WITH_VAR(F, I) std::tuple_element_t<I, FuncInfo<decltype(F)>::Args> VAR(I)
+#define TYPES_WITH_VARS0(F)
+#define TYPES_WITH_VARS1(F) TYPE_WITH_VAR(F, 0)
+#define TYPES_WITH_VARS2(F) TYPES_WITH_VARS1(F), TYPE_WITH_VAR(F, 1)
+#define TYPES_WITH_VARS3(F) TYPES_WITH_VARS2(F), TYPE_WITH_VAR(F, 2)
+#define TYPES_WITH_VARS4(F) TYPES_WITH_VARS3(F), TYPE_WITH_VAR(F, 3)
+#define TYPES_WITH_VARS5(F) TYPES_WITH_VARS4(F), TYPE_WITH_VAR(F, 4)
+#define TYPES_WITH_VARS6(F) TYPES_WITH_VARS5(F), TYPE_WITH_VAR(F, 5)
+#define TYPES_WITH_VARS7(F) TYPES_WITH_VARS6(F), TYPE_WITH_VAR(F, 6)
+#define TYPES_WITH_VARS8(F) TYPES_WITH_VARS7(F), TYPE_WITH_VAR(F, 7)
+#define TYPES_WITH_VARS9(F) TYPES_WITH_VARS8(F), TYPE_WITH_VAR(F, 8)
+#define TYPES_WITH_VARS10(F) TYPES_WITH_VARS9(F), TYPE_WITH_VAR(F, 9)
+#define TYPES_WITH_VARS11(F) TYPES_WITH_VARS10(F), TYPE_WITH_VAR(F, 10)
+
+
+#define RET(F, ...) DefaultReturn<FuncInfo<decltype(F)>::Return>{__VA_ARGS__}
+
+#define DEFINE_FUNC(F, ArgsCount, /*Return value*/...) \
+ DEFINE_FUNC_IMPL(F, VARS##ArgsCount, TYPES_WITH_VARS##ArgsCount, RET(F, __VA_ARGS__));
+
+// clang-format on
+
+#endif // Q_SYMBOLSRESOLVEUTILS
diff --git a/src/multimedia/qt_cmdline.cmake b/src/multimedia/qt_cmdline.cmake
new file mode 100644
index 000000000..5aabbbcb7
--- /dev/null
+++ b/src/multimedia/qt_cmdline.cmake
@@ -0,0 +1,8 @@
+# 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)
+qt_commandline_option(gstreamer TYPE optionalString VALUES no yes)
+qt_commandline_option(pulseaudio 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/qaudiorecorder.cpp b/src/multimedia/recording/qaudiorecorder.cpp
deleted file mode 100644
index 1db5c54a2..000000000
--- a/src/multimedia/recording/qaudiorecorder.cpp
+++ /dev/null
@@ -1,248 +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 "qaudiorecorder.h"
-#include "qaudioinputselectorcontrol.h"
-#include "qmediaobject_p.h"
-#include "qmediarecorder_p.h"
-#include <qmediaservice.h>
-#include <qmediaserviceprovider_p.h>
-
-#include <QtCore/qdebug.h>
-#include <QtCore/qurl.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qmetaobject.h>
-
-#include <qaudioformat.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QAudioRecorder
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_recording
-
- \brief The QAudioRecorder class is used for the recording of audio.
-
- The QAudioRecorder class is a high level media recording class and contains
- the same functionality as \l QMediaRecorder.
-
- \snippet multimedia-snippets/media.cpp Audio recorder
-
- In addition QAudioRecorder provides functionality for selecting the audio input.
-
- \snippet multimedia-snippets/media.cpp Audio recorder inputs
-
- The \l {Audio Recorder Example} shows how to use this class in more detail.
-
- \sa QMediaRecorder, QAudioInputSelectorControl
-*/
-
-class QAudioRecorderObject : public QMediaObject
-{
-public:
- QAudioRecorderObject(QObject *parent, QMediaService *service)
- :QMediaObject(parent, service)
- {
- }
-
- ~QAudioRecorderObject()
- {
- }
-};
-
-class QAudioRecorderPrivate : public QMediaRecorderPrivate
-{
- Q_DECLARE_NON_CONST_PUBLIC(QAudioRecorder)
-
-public:
- void initControls()
- {
- Q_Q(QAudioRecorder);
- audioInputSelector = nullptr;
-
- QMediaService *service = mediaObject ? mediaObject->service() : nullptr;
-
- if (service != nullptr)
- audioInputSelector = qobject_cast<QAudioInputSelectorControl*>(service->requestControl(QAudioInputSelectorControl_iid));
-
- if (audioInputSelector) {
- q->connect(audioInputSelector, SIGNAL(activeInputChanged(QString)),
- SIGNAL(audioInputChanged(QString)));
- q->connect(audioInputSelector, SIGNAL(availableInputsChanged()),
- SIGNAL(availableAudioInputsChanged()));
- }
- }
-
- QAudioRecorderPrivate():
- QMediaRecorderPrivate(),
- provider(nullptr),
- audioInputSelector(nullptr) {}
-
- QMediaServiceProvider *provider;
- QAudioInputSelectorControl *audioInputSelector;
-};
-
-
-
-/*!
- Constructs an audio recorder.
- The \a parent is passed to QMediaObject.
-*/
-
-QAudioRecorder::QAudioRecorder(QObject *parent):
- QMediaRecorder(*new QAudioRecorderPrivate, nullptr, parent)
-{
- Q_D(QAudioRecorder);
- d->provider = QMediaServiceProvider::defaultServiceProvider();
-
- QMediaService *service = d->provider->requestService(Q_MEDIASERVICE_AUDIOSOURCE);
- setMediaObject(new QAudioRecorderObject(this, service));
- d->initControls();
-}
-
-/*!
- Destroys an audio recorder object.
-*/
-
-QAudioRecorder::~QAudioRecorder()
-{
- Q_D(QAudioRecorder);
- QMediaService *service = d->mediaObject ? d->mediaObject->service() : nullptr;
- QMediaObject *mediaObject = d->mediaObject;
- setMediaObject(nullptr);
-
- if (service && d->audioInputSelector)
- service->releaseControl(d->audioInputSelector);
-
- if (d->provider && service)
- d->provider->releaseService(service);
-
- delete mediaObject;
-}
-
-/*!
- Returns a list of available audio inputs
-*/
-
-QStringList QAudioRecorder::audioInputs() const
-{
- Q_D(const QAudioRecorder);
- if (d->audioInputSelector)
- return d->audioInputSelector->availableInputs();
- else
- return QStringList();
-}
-
-/*!
- Returns the readable translated description of the audio input device with \a name.
-*/
-
-QString QAudioRecorder::audioInputDescription(const QString& name) const
-{
- Q_D(const QAudioRecorder);
-
- if (d->audioInputSelector)
- return d->audioInputSelector->inputDescription(name);
- else
- return QString();
-}
-
-/*!
- Returns the default audio input name.
-*/
-
-QString QAudioRecorder::defaultAudioInput() const
-{
- Q_D(const QAudioRecorder);
-
- if (d->audioInputSelector)
- return d->audioInputSelector->defaultInput();
- else
- return QString();
-}
-
-/*!
- \property QAudioRecorder::audioInput
- \brief the active audio input name.
-
-*/
-
-/*!
- Returns the active audio input name.
-*/
-
-QString QAudioRecorder::audioInput() const
-{
- Q_D(const QAudioRecorder);
-
- if (d->audioInputSelector)
- return d->audioInputSelector->activeInput();
- else
- return QString();
-}
-
-/*!
- Set the active audio input to \a name.
-*/
-
-void QAudioRecorder::setAudioInput(const QString& name)
-{
- Q_D(const QAudioRecorder);
-
- if (d->audioInputSelector)
- return d->audioInputSelector->setActiveInput(name);
-}
-
-/*!
- \fn QAudioRecorder::audioInputChanged(const QString& name)
-
- Signal emitted when active audio input changes to \a name.
-*/
-
-/*!
- \fn QAudioRecorder::availableAudioInputsChanged()
-
- Signal is emitted when the available audio inputs change.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qaudiorecorder.cpp"
diff --git a/src/multimedia/recording/qaudiorecorder.h b/src/multimedia/recording/qaudiorecorder.h
deleted file mode 100644
index e57794b40..000000000
--- a/src/multimedia/recording/qaudiorecorder.h
+++ /dev/null
@@ -1,88 +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 QAUDIORECORDER_H
-#define QAUDIORECORDER_H
-
-#include <QtMultimedia/qmediarecorder.h>
-#include <QtMultimedia/qmediaobject.h>
-#include <QtMultimedia/qmediaencodersettings.h>
-#include <QtMultimedia/qmediaenumdebug.h>
-
-#include <QtCore/qpair.h>
-
-QT_BEGIN_NAMESPACE
-
-class QString;
-class QSize;
-class QAudioFormat;
-QT_END_NAMESPACE
-
-QT_BEGIN_NAMESPACE
-
-class QAudioRecorderPrivate;
-class Q_MULTIMEDIA_EXPORT QAudioRecorder : public QMediaRecorder
-{
- Q_OBJECT
- Q_PROPERTY(QString audioInput READ audioInput WRITE setAudioInput NOTIFY audioInputChanged)
-public:
- explicit QAudioRecorder(QObject *parent = nullptr);
- ~QAudioRecorder();
-
- QStringList audioInputs() const;
- QString defaultAudioInput() const;
- QString audioInputDescription(const QString& name) const;
-
- QString audioInput() const;
-
-public Q_SLOTS:
- void setAudioInput(const QString& name);
-
-Q_SIGNALS:
- void audioInputChanged(const QString& name);
- void availableAudioInputsChanged();
-
-private:
- Q_DISABLE_COPY(QAudioRecorder)
- Q_DECLARE_PRIVATE(QAudioRecorder)
-};
-
-QT_END_NAMESPACE
-
-#endif // QAUDIORECORDER_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
new file mode 100644
index 000000000..9df09acef
--- /dev/null
+++ b/src/multimedia/recording/qmediacapturesession.cpp
@@ -0,0 +1,688 @@
+// 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 "qmediacapturesession_p.h"
+#include "qaudiodevice.h"
+#include "qcamera.h"
+#include "qmediarecorder.h"
+#include "qimagecapture.h"
+#include "qvideosink.h"
+#include "qscreencapture.h"
+#include "qwindowcapture.h"
+#include "qvideoframeinput.h"
+
+#include "qplatformmediaintegration_p.h"
+#include "qplatformmediacapture_p.h"
+#include "qaudioinput.h"
+#include "qaudiobufferinput.h"
+#include "qaudiooutput.h"
+
+QT_BEGIN_NAMESPACE
+
+void QMediaCaptureSessionPrivate::setVideoSink(QVideoSink *sink)
+{
+ Q_Q(QMediaCaptureSession);
+
+ if (sink == videoSink)
+ return;
+ if (videoSink)
+ videoSink->setSource(nullptr);
+ videoSink = sink;
+ if (sink)
+ sink->setSource(q);
+ if (captureSession)
+ captureSession->setVideoPreview(sink);
+ emit q->videoOutputChanged();
+}
+
+/*!
+ \class QMediaCaptureSession
+
+ \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 video input to QMediaCaptureSession using setCamera(),
+ setScreenCapture(), setWindowCapture() or setVideoFrameInput().
+ A preview of the captured media can be seen by setting a QVideoWidget or QGraphicsVideoItem
+ using setVideoOutput().
+
+ You can connect a microphone to QMediaCaptureSession using setAudioInput(), or set your
+ custom audio input using setAudioBufferInput().
+ The captured sound can be heard by routing the audio to an output device using setAudioOutput().
+
+ You can capture still images from a camera by setting a QImageCapture object on the capture
+ session, and record audio/video using a QMediaRecorder.
+
+ \sa QCamera, QAudioDevice, QMediaRecorder, QImageCapture, QScreenCapture, QWindowCapture,
+ QVideoFrameInput, QMediaRecorder, QGraphicsVideoItem
+*/
+
+/*!
+ \qmltype CaptureSession
+ \since 6.2
+ \instantiates QMediaCaptureSession
+ \brief Allows capturing of audio and video content.
+
+ \inqmlmodule QtMultimedia
+ \ingroup multimedia_qml
+ \ingroup multimedia_audio_qml
+ \ingroup multimedia_video_qml
+
+ This is the central type that manages capturing of media on the local device.
+
+ 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.
+
+ Route audio to an output device by assigning an AudioOutput object
+ to the audioOutput property.
+
+ Capture still images from a camera by assigning an ImageCapture to the
+ imageCapture property.
+
+ Record audio/video by assigning a MediaRecorder to the recorder property.
+
+\qml
+ CaptureSession {
+ id: captureSession
+ camera: Camera {
+ id: camera
+ }
+ imageCapture: ImageCapture {
+ id: imageCapture
+ }
+
+ recorder: MediaRecorder {
+ id: recorder
+ }
+ videoOutput: preview
+ }
+\endqml
+
+ \sa Camera, MediaDevices, MediaRecorder, ImageCapture, ScreenCapture, WindowCapture, AudioInput, VideoOutput
+*/
+
+/*!
+ Creates a session for media capture from the \a parent object.
+ */
+QMediaCaptureSession::QMediaCaptureSession(QObject *parent)
+ : QObject{ *new QMediaCaptureSessionPrivate, parent }
+{
+ QT6_ONLY(Q_UNUSED(unused))
+
+ Q_D(QMediaCaptureSession);
+
+ auto maybeCaptureSession = QPlatformMediaIntegration::instance()->createCaptureSession();
+ if (maybeCaptureSession) {
+ d->captureSession.reset(maybeCaptureSession.value());
+ d->captureSession->setCaptureSession(this);
+ } else {
+ qWarning() << "Failed to initialize QMediaCaptureSession" << maybeCaptureSession.error();
+ }
+}
+
+/*!
+ Destroys the session.
+ */
+QMediaCaptureSession::~QMediaCaptureSession()
+{
+ Q_D(QMediaCaptureSession);
+
+ setCamera(nullptr);
+ setRecorder(nullptr);
+ setImageCapture(nullptr);
+ setScreenCapture(nullptr);
+ setWindowCapture(nullptr);
+ setVideoFrameInput(nullptr);
+ setAudioBufferInput(nullptr);
+ setAudioInput(nullptr);
+ setAudioOutput(nullptr);
+ d->setVideoSink(nullptr);
+ d->captureSession.reset();
+}
+/*!
+ \qmlproperty AudioInput QtMultimedia::CaptureSession::audioInput
+
+ 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
+{
+ Q_D(const QMediaCaptureSession);
+ return d->audioInput;
+}
+
+/*!
+ 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 *input)
+{
+ Q_D(QMediaCaptureSession);
+
+ QAudioInput *oldInput = d->audioInput;
+ if (oldInput == input)
+ return;
+
+ // To avoid double emit of audioInputChanged
+ // from recursive setAudioInput(nullptr) call.
+ d->audioInput = nullptr;
+
+ if (d->captureSession)
+ d->captureSession->setAudioInput(nullptr);
+ if (oldInput)
+ oldInput->setDisconnectFunction({});
+ if (input) {
+ input->setDisconnectFunction([this](){ setAudioInput(nullptr); });
+ if (d->captureSession)
+ d->captureSession->setAudioInput(input->handle());
+ }
+ d->audioInput = input;
+ emit audioInputChanged();
+}
+
+/*!
+ \property QMediaCaptureSession::audioBufferInput
+ \since 6.8
+
+ \brief The object used to send custom audio buffers to \l QMediaRecorder.
+*/
+QAudioBufferInput *QMediaCaptureSession::audioBufferInput() const
+{
+ Q_D(const QMediaCaptureSession);
+
+ return d->audioBufferInput;
+}
+
+void QMediaCaptureSession::setAudioBufferInput(QAudioBufferInput *input)
+{
+ Q_D(QMediaCaptureSession);
+
+ // TODO: come up with an unification of the captures setup
+ QAudioBufferInput *oldInput = d->audioBufferInput;
+ if (oldInput == input)
+ return;
+ d->audioBufferInput = input;
+ if (d->captureSession)
+ d->captureSession->setAudioBufferInput(nullptr);
+ if (oldInput) {
+ if (oldInput->captureSession() && oldInput->captureSession() != this)
+ oldInput->captureSession()->setAudioBufferInput(nullptr);
+ oldInput->setCaptureSession(nullptr);
+ }
+ if (input) {
+ if (input->captureSession())
+ input->captureSession()->setAudioBufferInput(nullptr);
+ if (d->captureSession)
+ d->captureSession->setAudioBufferInput(input->platformAudioBufferInput());
+ input->setCaptureSession(this);
+ }
+ emit audioBufferInputChanged();
+}
+
+/*!
+ \qmlproperty Camera QtMultimedia::CaptureSession::camera
+
+ \brief The camera used to capture video.
+
+ Record video or take images by adding a camera to the capture session using
+ this property.
+*/
+
+/*!
+ \property QMediaCaptureSession::camera
+
+ \brief The camera used to capture video.
+
+ Record video or take images by adding a camera to the capture session
+ using this property.
+*/
+QCamera *QMediaCaptureSession::camera() const
+{
+ Q_D(const QMediaCaptureSession);
+
+ return d->camera;
+}
+
+void QMediaCaptureSession::setCamera(QCamera *camera)
+{
+ Q_D(QMediaCaptureSession);
+
+ // TODO: come up with an unification of the captures setup
+ QCamera *oldCamera = d->camera;
+ if (oldCamera == camera)
+ return;
+ d->camera = camera;
+ if (d->captureSession)
+ d->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->captureSession)
+ d->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()
+{
+ Q_D(QMediaCaptureSession);
+
+ return d->screenCapture;
+}
+
+void QMediaCaptureSession::setScreenCapture(QScreenCapture *screenCapture)
+{
+ Q_D(QMediaCaptureSession);
+
+ // TODO: come up with an unification of the captures setup
+ QScreenCapture *oldScreenCapture = d->screenCapture;
+ if (oldScreenCapture == screenCapture)
+ return;
+ d->screenCapture = screenCapture;
+ if (d->captureSession)
+ d->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->captureSession)
+ d->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()
+{
+ Q_D(QMediaCaptureSession);
+ return d->windowCapture;
+}
+
+void QMediaCaptureSession::setWindowCapture(QWindowCapture *windowCapture)
+{
+ Q_D(QMediaCaptureSession);
+
+ // TODO: come up with an unification of the captures setup
+ QWindowCapture *oldCapture = d->windowCapture;
+ if (oldCapture == windowCapture)
+ return;
+ d->windowCapture = windowCapture;
+ if (d->captureSession)
+ d->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->captureSession)
+ d->captureSession->setWindowCapture(windowCapture->platformWindowCapture());
+ windowCapture->setCaptureSession(this);
+ }
+ emit windowCaptureChanged();
+}
+
+/*!
+ \property QMediaCaptureSession::videoFrameInput
+ \since 6.8
+
+ \brief The object used to send custom video frames to
+ \l QMediaRecorder or a video output.
+*/
+QVideoFrameInput *QMediaCaptureSession::videoFrameInput() const
+{
+ Q_D(const QMediaCaptureSession);
+ return d->videoFrameInput;
+}
+
+void QMediaCaptureSession::setVideoFrameInput(QVideoFrameInput *input)
+{
+ Q_D(QMediaCaptureSession);
+ // TODO: come up with an unification of the captures setup
+ QVideoFrameInput *oldInput = d->videoFrameInput;
+ if (oldInput == input)
+ return;
+ d->videoFrameInput = input;
+ if (d->captureSession)
+ d->captureSession->setVideoFrameInput(nullptr);
+ if (oldInput) {
+ if (oldInput->captureSession() && oldInput->captureSession() != this)
+ oldInput->captureSession()->setVideoFrameInput(nullptr);
+ oldInput->setCaptureSession(nullptr);
+ }
+ if (input) {
+ if (input->captureSession())
+ input->captureSession()->setVideoFrameInput(nullptr);
+ if (d->captureSession)
+ d->captureSession->setVideoFrameInput(input->platformVideoFrameInput());
+ input->setCaptureSession(this);
+ }
+ emit videoFrameInputChanged();
+}
+
+/*!
+ \qmlproperty ImageCapture QtMultimedia::CaptureSession::imageCapture
+
+ \brief The object used to capture still images.
+
+ Add an ImageCapture interface to the capture session to enable
+ capturing of still images from the camera.
+*/
+/*!
+ \property QMediaCaptureSession::imageCapture
+
+ \brief the object used to capture still images.
+
+ Add a QImageCapture object to the capture session to enable
+ capturing of still images from the camera.
+*/
+QImageCapture *QMediaCaptureSession::imageCapture()
+{
+ Q_D(QMediaCaptureSession);
+
+ return d->imageCapture;
+}
+
+void QMediaCaptureSession::setImageCapture(QImageCapture *imageCapture)
+{
+ Q_D(QMediaCaptureSession);
+
+ // TODO: come up with an unification of the captures setup
+ QImageCapture *oldImageCapture = d->imageCapture;
+ if (oldImageCapture == imageCapture)
+ return;
+ d->imageCapture = imageCapture;
+ if (d->captureSession)
+ d->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->captureSession)
+ d->captureSession->setImageCapture(imageCapture->platformImageCapture());
+ imageCapture->setCaptureSession(this);
+ }
+ emit imageCaptureChanged();
+}
+/*!
+ \qmlproperty MediaRecorder QtMultimedia::CaptureSession::recorder
+
+ \brief The recorder object used to capture audio/video.
+
+ Add a MediaRcorder object to the capture session to enable
+ recording of audio and/or video from the capture session.
+*/
+/*!
+ \property QMediaCaptureSession::recorder
+
+ \brief The recorder object used to capture audio/video.
+
+ Add a QMediaRecorder object to the capture session to enable
+ recording of audio and/or video from the capture session.
+*/
+
+QMediaRecorder *QMediaCaptureSession::recorder()
+{
+ Q_D(QMediaCaptureSession);
+ return d->recorder;
+}
+
+void QMediaCaptureSession::setRecorder(QMediaRecorder *recorder)
+{
+ Q_D(QMediaCaptureSession);
+ QMediaRecorder *oldRecorder = d->recorder;
+ if (oldRecorder == recorder)
+ return;
+ d->recorder = recorder;
+ if (d->captureSession)
+ d->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->captureSession)
+ d->captureSession->setMediaRecorder(recorder->platformRecoder());
+ recorder->setCaptureSession(this);
+ }
+ emit recorderChanged();
+}
+/*!
+ \qmlproperty VideoOutput QtMultimedia::CaptureSession::videoOutput
+
+ \brief The VideoOutput that is the video preview for the capture session.
+
+ A VideoOutput based preview is expected to have an invokable videoSink()
+ method that returns a QVideoSink.
+
+ The previously set preview is detached.
+
+*/
+/*!
+ \property QMediaCaptureSession::videoOutput
+
+ Returns the video output for the session.
+*/
+QObject *QMediaCaptureSession::videoOutput() const
+{
+ Q_D(const QMediaCaptureSession);
+ return d->videoOutput;
+}
+/*!
+ Sets a QObject, (\a output), to a video preview for the capture session.
+
+ A QObject based preview is expected to have an invokable videoSink()
+ method that returns a QVideoSink.
+
+ The previously set preview is detached.
+*/
+void QMediaCaptureSession::setVideoOutput(QObject *output)
+{
+ Q_D(QMediaCaptureSession);
+ if (d->videoOutput == output)
+ return;
+ QVideoSink *sink = qobject_cast<QVideoSink *>(output);
+ if (!sink && output) {
+ auto *mo = output->metaObject();
+ mo->invokeMethod(output, "videoSink", Q_RETURN_ARG(QVideoSink *, sink));
+ }
+ d->videoOutput = output;
+ d->setVideoSink(sink);
+}
+
+/*!
+ Sets a QVideoSink, (\a sink), to a video preview for the capture session.
+
+ A QObject based preview is expected to have an invokable videoSink()
+ method that returns a QVideoSink.
+
+ The previously set preview is detached.
+*/
+void QMediaCaptureSession::setVideoSink(QVideoSink *sink)
+{
+ Q_D(QMediaCaptureSession);
+ d->videoOutput = nullptr;
+ d->setVideoSink(sink);
+}
+
+/*!
+ Returns the QVideoSink for the session.
+*/
+QVideoSink *QMediaCaptureSession::videoSink() const
+{
+ Q_D(const QMediaCaptureSession);
+ return d->videoSink;
+}
+/*!
+ 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);
+
+ QAudioOutput *oldOutput = d->audioOutput;
+ if (oldOutput == output)
+ return;
+
+ // We don't want to end up with signal emitted
+ // twice (from recursive call setAudioInput(nullptr)
+ // from oldOutput->setDisconnectFunction():
+ d->audioOutput = nullptr;
+
+ if (d->captureSession)
+ d->captureSession->setAudioOutput(nullptr);
+ if (oldOutput)
+ oldOutput->setDisconnectFunction({});
+ if (output) {
+ output->setDisconnectFunction([this](){ setAudioOutput(nullptr); });
+ if (d->captureSession)
+ d->captureSession->setAudioOutput(output->handle());
+ }
+ d->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
+{
+ Q_D(const QMediaCaptureSession);
+ return d->audioOutput;
+}
+
+/*!
+ \internal
+*/
+QPlatformMediaCaptureSession *QMediaCaptureSession::platformSession() const
+{
+ Q_D(const QMediaCaptureSession);
+ return d->captureSession.get();
+}
+/*!
+ \qmlsignal QtMultimedia::CaptureSession::audioInputChanged()
+ This signal is emitted when an audio input has changed.
+ \sa CaptureSession::audioInput
+*/
+
+/*!
+ \qmlsignal QtMultimedia::CaptureSession::cameraChanged()
+ This signal is emitted when the selected camera has changed.
+ \sa CaptureSession::camera
+*/
+
+/*!
+ \qmlsignal QtMultimedia::CaptureSession::imageCaptureChanged()
+ This signal is emitted when the selected interface has changed.
+ \sa CaptureSession::camera
+*/
+
+/*!
+ \qmlsignal QtMultimedia::CaptureSession::recorderChanged()
+ This signal is emitted when the selected recorder has changed.
+ \sa CaptureSession::recorder
+*/
+
+/*!
+ \qmlsignal QtMultimedia::CaptureSession::videoOutputChanged()
+ This signal is emitted when the selected video output has changed.
+ \sa CaptureSession::videoOutput
+*/
+
+/*!
+ \qmlsignal QtMultimedia::CaptureSession::audioOutputChanged()
+ This signal is emitted when the selected audio output has changed.
+ \sa CaptureSession::audioOutput
+*/
+QT_END_NAMESPACE
+
+#include "moc_qmediacapturesession.cpp"
diff --git a/src/multimedia/recording/qmediacapturesession.h b/src/multimedia/recording/qmediacapturesession.h
new file mode 100644
index 000000000..219c382d1
--- /dev/null
+++ b/src/multimedia/recording/qmediacapturesession.h
@@ -0,0 +1,106 @@
+// 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
+
+#include <QtCore/qobject.h>
+#include <QtMultimedia/qtmultimediaglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QCamera;
+class QAudioInput;
+class QAudioBufferInput;
+class QAudioOutput;
+class QCameraDevice;
+class QImageCapture;
+class QMediaRecorder;
+class QPlatformMediaCaptureSession;
+class QVideoSink;
+class QScreenCapture;
+class QWindowCapture;
+class QVideoFrameInput;
+
+class QMediaCaptureSessionPrivate;
+class Q_MULTIMEDIA_EXPORT QMediaCaptureSession : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QAudioInput *audioInput READ audioInput WRITE setAudioInput NOTIFY audioInputChanged)
+ Q_PROPERTY(QAudioBufferInput *audioBufferInput READ audioBufferInput WRITE setAudioBufferInput
+ NOTIFY audioBufferInputChanged)
+ Q_PROPERTY(QAudioOutput *audioOutput READ audioOutput WRITE setAudioOutput NOTIFY audioOutputChanged)
+ Q_PROPERTY(QCamera *camera READ camera WRITE setCamera NOTIFY cameraChanged)
+ Q_PROPERTY(
+ QScreenCapture *screenCapture READ screenCapture WRITE setScreenCapture NOTIFY screenCaptureChanged)
+ Q_PROPERTY(
+ QWindowCapture *windowCapture READ windowCapture WRITE setWindowCapture NOTIFY windowCaptureChanged)
+ Q_PROPERTY(QVideoFrameInput *videoFrameInput READ videoFrameInput WRITE setVideoFrameInput
+ NOTIFY videoFrameInputChanged)
+ Q_PROPERTY(QImageCapture *imageCapture READ imageCapture WRITE setImageCapture NOTIFY imageCaptureChanged)
+ Q_PROPERTY(QMediaRecorder *recorder READ recorder WRITE setRecorder NOTIFY recorderChanged)
+ Q_PROPERTY(QObject *videoOutput READ videoOutput WRITE setVideoOutput NOTIFY videoOutputChanged)
+public:
+ explicit QMediaCaptureSession(QObject *parent = nullptr);
+ ~QMediaCaptureSession();
+
+ QAudioInput *audioInput() const;
+ void setAudioInput(QAudioInput *input);
+
+ QAudioBufferInput *audioBufferInput() const;
+ void setAudioBufferInput(QAudioBufferInput *input);
+
+ QCamera *camera() const;
+ void setCamera(QCamera *camera);
+
+ QImageCapture *imageCapture();
+ void setImageCapture(QImageCapture *imageCapture);
+
+ QScreenCapture *screenCapture();
+ void setScreenCapture(QScreenCapture *screenCapture);
+
+ QWindowCapture *windowCapture();
+ void setWindowCapture(QWindowCapture *windowCapture);
+
+ QVideoFrameInput *videoFrameInput() const;
+ void setVideoFrameInput(QVideoFrameInput *input);
+
+ QMediaRecorder *recorder();
+ void setRecorder(QMediaRecorder *recorder);
+
+ void setVideoOutput(QObject *output);
+ QObject *videoOutput() const;
+
+ void setVideoSink(QVideoSink *sink);
+ QVideoSink *videoSink() const;
+
+ void setAudioOutput(QAudioOutput *output);
+ QAudioOutput *audioOutput() const;
+
+ QPlatformMediaCaptureSession *platformSession() const;
+
+Q_SIGNALS:
+ void audioInputChanged();
+ void audioBufferInputChanged();
+ void cameraChanged();
+ void screenCaptureChanged();
+ void windowCaptureChanged();
+ void videoFrameInputChanged();
+ void imageCaptureChanged();
+ void recorderChanged();
+ void videoOutputChanged();
+ void audioOutputChanged();
+
+private:
+ friend class QPlatformMediaCaptureSession;
+
+ // ### Qt7: remove unused member
+ QT6_ONLY(void *unused = nullptr;) // for ABI compatibility
+
+ Q_DISABLE_COPY(QMediaCaptureSession)
+ Q_DECLARE_PRIVATE(QMediaCaptureSession)
+};
+
+QT_END_NAMESPACE
+
+#endif // QMEDIACAPTURESESSION_H
diff --git a/src/multimedia/recording/qmediacapturesession_p.h b/src/multimedia/recording/qmediacapturesession_p.h
new file mode 100644
index 000000000..cba222993
--- /dev/null
+++ b/src/multimedia/recording/qmediacapturesession_p.h
@@ -0,0 +1,53 @@
+// 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 QMEDIACAPTURESESSION_P_H
+#define QMEDIACAPTURESESSION_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/qmediacapturesession.h>
+
+#include <QtCore/qpointer.h>
+#include <QtCore/private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMediaCaptureSessionPrivate : public QObjectPrivate
+{
+public:
+ static QMediaCaptureSessionPrivate *get(QMediaCaptureSession *session)
+ {
+ return reinterpret_cast<QMediaCaptureSessionPrivate *>(QObjectPrivate::get(session));
+ }
+
+ Q_DECLARE_PUBLIC(QMediaCaptureSession)
+
+ std::unique_ptr<QPlatformMediaCaptureSession> captureSession;
+ QAudioInput *audioInput = nullptr;
+ QPointer<QAudioBufferInput> audioBufferInput;
+ QAudioOutput *audioOutput = nullptr;
+ QPointer<QCamera> camera;
+ QPointer<QScreenCapture> screenCapture;
+ QPointer<QWindowCapture> windowCapture;
+ QPointer<QVideoFrameInput> videoFrameInput;
+ QPointer<QImageCapture> imageCapture;
+ QPointer<QMediaRecorder> recorder;
+ QPointer<QVideoSink> videoSink;
+ QPointer<QObject> videoOutput;
+
+ void setVideoSink(QVideoSink *sink);
+};
+
+QT_END_NAMESPACE
+
+#endif // QMEDIACAPTURESESSION_P_H
diff --git a/src/multimedia/recording/qmediaencodersettings.cpp b/src/multimedia/recording/qmediaencodersettings.cpp
deleted file mode 100644
index 0e169c2b0..000000000
--- a/src/multimedia/recording/qmediaencodersettings.cpp
+++ /dev/null
@@ -1,952 +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 "qmediaencodersettings.h"
-
-QT_BEGIN_NAMESPACE
-
-static void qRegisterEncoderSettingsMetaTypes()
-{
- qRegisterMetaType<QAudioEncoderSettings>();
- qRegisterMetaType<QVideoEncoderSettings>();
- qRegisterMetaType<QImageEncoderSettings>();
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterEncoderSettingsMetaTypes)
-
-
-class QAudioEncoderSettingsPrivate : public QSharedData
-{
-public:
- QAudioEncoderSettingsPrivate() :
- isNull(true),
- encodingMode(QMultimedia::ConstantQualityEncoding),
- bitrate(-1),
- sampleRate(-1),
- channels(-1),
- quality(QMultimedia::NormalQuality)
- {
- }
-
- QAudioEncoderSettingsPrivate(const QAudioEncoderSettingsPrivate &other):
- QSharedData(other),
- isNull(other.isNull),
- encodingMode(other.encodingMode),
- codec(other.codec),
- bitrate(other.bitrate),
- sampleRate(other.sampleRate),
- channels(other.channels),
- quality(other.quality),
- encodingOptions(other.encodingOptions)
- {
- }
-
- bool isNull;
- QMultimedia::EncodingMode encodingMode;
- QString codec;
- int bitrate;
- int sampleRate;
- int channels;
- QMultimedia::EncodingQuality quality;
- QVariantMap encodingOptions;
-
-private:
- QAudioEncoderSettingsPrivate& operator=(const QAudioEncoderSettingsPrivate &other);
-};
-
-/*!
- \class QAudioEncoderSettings
-
- \brief The QAudioEncoderSettings class provides a set of audio encoder settings.
-
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_recording
-
- A audio encoder settings object is used to specify the audio encoder
- settings used by QMediaRecorder. Audio encoder settings are selected by
- constructing a QAudioEncoderSettings object, setting the desired properties
- and then passing it to a QMediaRecorder instance using the
- QMediaRecorder::setEncodingSettings() function.
-
- \snippet multimedia-snippets/media.cpp Audio encoder settings
-
- \sa QMediaRecorder, QAudioEncoderSettingsControl
-*/
-
-/*!
- Construct a null audio encoder settings object.
-*/
-QAudioEncoderSettings::QAudioEncoderSettings()
- :d(new QAudioEncoderSettingsPrivate)
-{
-}
-
-/*!
- Constructs a copy of the audio encoder settings object \a other.
-*/
-
-QAudioEncoderSettings::QAudioEncoderSettings(const QAudioEncoderSettings& other)
- :d(other.d)
-{
-}
-
-/*!
- Destroys an audio encoder settings object.
-*/
-
-QAudioEncoderSettings::~QAudioEncoderSettings()
-{
-}
-
-/*!
- Assigns the value of \a other to an audio encoder settings object.
-*/
-
-QAudioEncoderSettings& QAudioEncoderSettings::operator=(const QAudioEncoderSettings &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Determines if \a other is of equal value to an audio encoder settings
- object.
-
- Returns true if the settings objects are of equal value, and false if they
- are not of equal value.
-*/
-
-bool QAudioEncoderSettings::operator==(const QAudioEncoderSettings &other) const
-{
- return (d == other.d) ||
- (d->isNull == other.d->isNull &&
- d->encodingMode == other.d->encodingMode &&
- d->bitrate == other.d->bitrate &&
- d->sampleRate == other.d->sampleRate &&
- d->channels == other.d->channels &&
- d->quality == other.d->quality &&
- d->codec == other.d->codec &&
- d->encodingOptions == other.d->encodingOptions);
-}
-
-/*!
- Determines if \a other is of equal value to an audio encoder settings
- object.
-
- Returns true if the settings objects are not of equal value, and true if
- they are of equal value.
-*/
-
-bool QAudioEncoderSettings::operator!=(const QAudioEncoderSettings &other) const
-{
- return !(*this == other);
-}
-
-/*!
- Identifies if an audio settings object is initialized.
-
- Returns true if the settings object is null, and false if it is not.
-*/
-
-bool QAudioEncoderSettings::isNull() const
-{
- return d->isNull;
-}
-
-/*!
- Returns the audio encoding mode.
-
- \sa QMultimedia::EncodingMode
-*/
-QMultimedia::EncodingMode QAudioEncoderSettings::encodingMode() const
-{
- return d->encodingMode;
-}
-
-/*!
- Sets the audio encoding \a mode setting.
-
- If QMultimedia::ConstantQualityEncoding is set, the quality
- encoding parameter is used and bit rate is ignored,
- otherwise the bitrate is used.
-
- The audio codec, channels count and sample rate settings are used in all
- the encoding modes.
-
- \sa encodingMode(), QMultimedia::EncodingMode
-*/
-void QAudioEncoderSettings::setEncodingMode(QMultimedia::EncodingMode mode)
-{
- d->encodingMode = mode;
-}
-
-/*!
- Returns the audio codec.
-*/
-QString QAudioEncoderSettings::codec() const
-{
- return d->codec;
-}
-
-/*!
- Sets the audio \a codec.
-*/
-void QAudioEncoderSettings::setCodec(const QString& codec)
-{
- d->isNull = false;
- d->codec = codec;
-}
-
-/*!
- Returns the bit rate of the compressed audio stream in bits per second.
-*/
-int QAudioEncoderSettings::bitRate() const
-{
- return d->bitrate;
-}
-
-/*!
- Returns the number of audio channels.
-*/
-int QAudioEncoderSettings::channelCount() const
-{
- return d->channels;
-}
-
-/*!
- Sets the number of audio \a channels.
-
- A value of -1 indicates the encoder should make an optimal choice based on
- what is available from the audio source and the limitations of the codec.
-*/
-void QAudioEncoderSettings::setChannelCount(int channels)
-{
- d->isNull = false;
- d->channels = channels;
-}
-
-/*!
- Sets the audio bit \a rate in bits per second.
-*/
-void QAudioEncoderSettings::setBitRate(int rate)
-{
- d->isNull = false;
- d->bitrate = rate;
-}
-
-/*!
- Returns the audio sample rate in Hz.
-*/
-int QAudioEncoderSettings::sampleRate() const
-{
- return d->sampleRate;
-}
-
-/*!
- Sets the audio sample \a rate in Hz.
-
- A value of -1 indicates the encoder should make an optimal choice based on what is avaialbe
- from the audio source and the limitations of the codec.
- */
-void QAudioEncoderSettings::setSampleRate(int rate)
-{
- d->isNull = false;
- d->sampleRate = rate;
-}
-
-/*!
- Returns the audio encoding quality.
-*/
-
-QMultimedia::EncodingQuality QAudioEncoderSettings::quality() const
-{
- return d->quality;
-}
-
-/*!
- Set the audio encoding \a quality.
-
- Setting the audio quality parameter allows backend to choose the balanced
- set of encoding parameters to achieve the desired quality level.
-
- The \a quality settings parameter is only used in the
- \l {QMultimedia::ConstantQualityEncoding}{constant quality} \l{encodingMode()}{encoding mode}.
-*/
-void QAudioEncoderSettings::setQuality(QMultimedia::EncodingQuality quality)
-{
- d->isNull = false;
- d->quality = quality;
-}
-
-/*!
- Returns the value of encoding \a option.
-
- \sa setEncodingOption(), encodingOptions()
-*/
-QVariant QAudioEncoderSettings::encodingOption(const QString &option) const
-{
- return d->encodingOptions.value(option);
-}
-
-/*!
- Returns the all the encoding options as QVariantMap.
-
- \sa encodingOption(), setEncodingOptions()
-*/
-QVariantMap QAudioEncoderSettings::encodingOptions() const
-{
- return d->encodingOptions;
-}
-
-/*!
- Set the encoding \a option to \a value.
-
- The supported set and meaning of encoding options are
- system and selected codec specific.
-
- \sa encodingOption(), setEncodingOptions()
-*/
-void QAudioEncoderSettings::setEncodingOption(const QString &option, const QVariant &value)
-{
- d->isNull = false;
- if (value.isNull())
- d->encodingOptions.remove(option);
- else
- d->encodingOptions.insert(option, value);
-}
-
-/*!
- Replace all the encoding options with \a options.
-
- The supported set and meaning of encoding options are
- system and selected codec specific.
-
- \sa encodingOption(), setEncodingOption()
-*/
-void QAudioEncoderSettings::setEncodingOptions(const QVariantMap &options)
-{
- d->isNull = false;
- d->encodingOptions = options;
-}
-
-class QVideoEncoderSettingsPrivate : public QSharedData
-{
-public:
- QVideoEncoderSettingsPrivate() :
- isNull(true),
- encodingMode(QMultimedia::ConstantQualityEncoding),
- bitrate(-1),
- frameRate(0),
- quality(QMultimedia::NormalQuality)
- {
- }
-
- QVideoEncoderSettingsPrivate(const QVideoEncoderSettingsPrivate &other):
- QSharedData(other),
- isNull(other.isNull),
- encodingMode(other.encodingMode),
- codec(other.codec),
- bitrate(other.bitrate),
- resolution(other.resolution),
- frameRate(other.frameRate),
- quality(other.quality),
- encodingOptions(other.encodingOptions)
- {
- }
-
- bool isNull;
- QMultimedia::EncodingMode encodingMode;
- QString codec;
- int bitrate;
- QSize resolution;
- qreal frameRate;
- QMultimedia::EncodingQuality quality;
- QVariantMap encodingOptions;
-
-private:
- QVideoEncoderSettingsPrivate& operator=(const QVideoEncoderSettingsPrivate &other);
-};
-
-/*!
- \class QVideoEncoderSettings
-
- \brief The QVideoEncoderSettings class provides a set of video encoder settings.
-
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_recording
-
- A video encoder settings object is used to specify the video encoder
- settings used by QMediaRecorder. Video encoder settings are selected by
- constructing a QVideoEncoderSettings object, setting the desired properties
- and then passing it to a QMediaRecorder instance using the
- QMediaRecorder::setEncodingSettings() function.
-
- \snippet multimedia-snippets/media.cpp Video encoder settings
-
- \sa QMediaRecorder, QVideoEncoderSettingsControl
-*/
-
-/*!
- Constructs a null video encoder settings object.
-*/
-
-QVideoEncoderSettings::QVideoEncoderSettings()
- :d(new QVideoEncoderSettingsPrivate)
-{
-}
-
-/*!
- Constructs a copy of the video encoder settings object \a other.
-*/
-
-QVideoEncoderSettings::QVideoEncoderSettings(const QVideoEncoderSettings& other)
- :d(other.d)
-{
-}
-
-/*!
- Destroys a video encoder settings object.
-*/
-
-QVideoEncoderSettings::~QVideoEncoderSettings()
-{
-}
-
-/*!
- Assigns the value of \a other to a video encoder settings object.
-*/
-QVideoEncoderSettings &QVideoEncoderSettings::operator=(const QVideoEncoderSettings &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Determines if \a other is of equal value to a video encoder settings object.
-
- Returns true if the settings objects are of equal value, and false if they
- are not of equal value.
-*/
-bool QVideoEncoderSettings::operator==(const QVideoEncoderSettings &other) const
-{
- return (d == other.d) ||
- (d->isNull == other.d->isNull &&
- d->encodingMode == other.d->encodingMode &&
- d->bitrate == other.d->bitrate &&
- d->quality == other.d->quality &&
- d->codec == other.d->codec &&
- d->resolution == other.d->resolution &&
- qFuzzyCompare(d->frameRate, other.d->frameRate) &&
- d->encodingOptions == other.d->encodingOptions);
-}
-
-/*!
- Determines if \a other is of equal value to a video encoder settings object.
-
- Returns true if the settings objects are not of equal value, and false if
- they are of equal value.
-*/
-bool QVideoEncoderSettings::operator!=(const QVideoEncoderSettings &other) const
-{
- return !(*this == other);
-}
-
-/*!
- Identifies if a video encoder settings object is uninitalized.
-
- Returns true if the settings are null, and false if they are not.
-*/
-bool QVideoEncoderSettings::isNull() const
-{
- return d->isNull;
-}
-
-/*!
- Returns the video encoding mode.
-
- \sa QMultimedia::EncodingMode
-*/
-QMultimedia::EncodingMode QVideoEncoderSettings::encodingMode() const
-{
- return d->encodingMode;
-}
-
-/*!
- Sets the video encoding \a mode.
-
- If QMultimedia::ConstantQualityEncoding is set,
- the quality encoding parameter is used and bit rate is ignored,
- otherwise the bitrate is used.
-
- The rest of encoding settings are respected regardless of encoding mode.
-
- \sa QMultimedia::EncodingMode
-*/
-void QVideoEncoderSettings::setEncodingMode(QMultimedia::EncodingMode mode)
-{
- d->isNull = false;
- d->encodingMode = mode;
-}
-
-/*!
- Returns the video codec.
-*/
-
-QString QVideoEncoderSettings::codec() const
-{
- return d->codec;
-}
-
-/*!
- Sets the video \a codec.
-*/
-void QVideoEncoderSettings::setCodec(const QString& codec)
-{
- d->isNull = false;
- d->codec = codec;
-}
-
-/*!
- Returns bit rate of the encoded video stream in bits per second.
-*/
-int QVideoEncoderSettings::bitRate() const
-{
- return d->bitrate;
-}
-
-/*!
- Sets the bit rate of the encoded video stream to \a value.
-*/
-
-void QVideoEncoderSettings::setBitRate(int value)
-{
- d->isNull = false;
- d->bitrate = value;
-}
-
-/*!
- Returns the video frame rate.
-*/
-qreal QVideoEncoderSettings::frameRate() const
-{
- return d->frameRate;
-}
-
-/*!
- \fn QVideoEncoderSettings::setFrameRate(qreal rate)
-
- Sets the video frame \a rate.
-
- A value of 0 indicates the encoder should make an optimal choice based on what is available
- from the video source and the limitations of the codec.
-*/
-
-void QVideoEncoderSettings::setFrameRate(qreal rate)
-{
- d->isNull = false;
- d->frameRate = rate;
-}
-
-/*!
- Returns the resolution of the encoded video.
-*/
-
-QSize QVideoEncoderSettings::resolution() const
-{
- return d->resolution;
-}
-
-/*!
- Sets the \a resolution of the encoded video.
-
- An empty QSize indicates the encoder should make an optimal choice based on
- what is available from the video source and the limitations of the codec.
-*/
-
-void QVideoEncoderSettings::setResolution(const QSize &resolution)
-{
- d->isNull = false;
- d->resolution = resolution;
-}
-
-/*!
- Sets the \a width and \a height of the resolution of the encoded video.
-
- \overload
-*/
-
-void QVideoEncoderSettings::setResolution(int width, int height)
-{
- d->isNull = false;
- d->resolution = QSize(width, height);
-}
-
-/*!
- Returns the video encoding quality.
-*/
-
-QMultimedia::EncodingQuality QVideoEncoderSettings::quality() const
-{
- return d->quality;
-}
-
-/*!
- Sets the video encoding \a quality.
-
- Setting the video quality parameter allows backend to choose the balanced
- set of encoding parameters to achieve the desired quality level.
-
- The \a quality settings parameter is only used in the
- \l {QMultimedia::ConstantQualityEncoding}{constant quality} \l{encodingMode()}{encoding mode}.
- The \a quality settings parameter is only used in the \l
- {QMultimedia::ConstantQualityEncoding}{constant quality}
- \l{encodingMode()}{encoding mode}.
-*/
-
-void QVideoEncoderSettings::setQuality(QMultimedia::EncodingQuality quality)
-{
- d->isNull = false;
- d->quality = quality;
-}
-
-/*!
- Returns the value of encoding \a option.
-
- \sa setEncodingOption(), encodingOptions()
-*/
-QVariant QVideoEncoderSettings::encodingOption(const QString &option) const
-{
- return d->encodingOptions.value(option);
-}
-
-/*!
- Returns the all the encoding options as QVariantMap.
-
- \sa encodingOption(), setEncodingOptions()
-*/
-QVariantMap QVideoEncoderSettings::encodingOptions() const
-{
- return d->encodingOptions;
-}
-
-/*!
- Set the encoding \a option \a value.
-
- The supported set and meaning of encoding options are
- system and selected codec specific.
-
- \sa encodingOption(), setEncodingOptions()
-*/
-void QVideoEncoderSettings::setEncodingOption(const QString &option, const QVariant &value)
-{
- d->isNull = false;
- if (value.isNull())
- d->encodingOptions.remove(option);
- else
- d->encodingOptions.insert(option, value);
-}
-
-/*!
- Replace all the encoding options with \a options.
-
- The supported set and meaning of encoding options are
- system and selected codec specific.
-
- \sa encodingOption(), setEncodingOption()
-*/
-void QVideoEncoderSettings::setEncodingOptions(const QVariantMap &options)
-{
- d->isNull = false;
- d->encodingOptions = options;
-}
-
-
-class QImageEncoderSettingsPrivate : public QSharedData
-{
-public:
- QImageEncoderSettingsPrivate() :
- isNull(true),
- quality(QMultimedia::NormalQuality)
- {
- }
-
- QImageEncoderSettingsPrivate(const QImageEncoderSettingsPrivate &other):
- QSharedData(other),
- isNull(other.isNull),
- codec(other.codec),
- resolution(other.resolution),
- quality(other.quality),
- encodingOptions(other.encodingOptions)
- {
- }
-
- bool isNull;
- QString codec;
- QSize resolution;
- QMultimedia::EncodingQuality quality;
- QVariantMap encodingOptions;
-
-private:
- QImageEncoderSettingsPrivate& operator=(const QImageEncoderSettingsPrivate &other);
-};
-
-/*!
- \class QImageEncoderSettings
-
-
- \brief The QImageEncoderSettings class provides a set of image encoder
- settings.
-
- \inmodule QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_camera
-
- A image encoder settings object is used to specify the image encoder
- settings used by QCameraImageCapture. Image encoder settings are selected
- by constructing a QImageEncoderSettings object, setting the desired
- properties and then passing it to a QCameraImageCapture instance using the
- QCameraImageCapture::setImageSettings() function.
-
- \snippet multimedia-snippets/media.cpp Image encoder settings
-
- \sa QImageEncoderControl
-*/
-
-/*!
- Constructs a null image encoder settings object.
-*/
-
-QImageEncoderSettings::QImageEncoderSettings()
- :d(new QImageEncoderSettingsPrivate)
-{
-}
-
-/*!
- Constructs a copy of the image encoder settings object \a other.
-*/
-
-QImageEncoderSettings::QImageEncoderSettings(const QImageEncoderSettings& other)
- :d(other.d)
-{
-}
-
-/*!
- Destroys a image encoder settings object.
-*/
-
-QImageEncoderSettings::~QImageEncoderSettings()
-{
-}
-
-/*!
- Assigns the value of \a other to a image encoder settings object.
-*/
-QImageEncoderSettings &QImageEncoderSettings::operator=(const QImageEncoderSettings &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Determines if \a other is of equal value to a image encoder settings
- object.
-
- Returns true if the settings objects are of equal value, and false if they
- are not of equal value.
-*/
-bool QImageEncoderSettings::operator==(const QImageEncoderSettings &other) const
-{
- return (d == other.d) ||
- (d->isNull == other.d->isNull &&
- d->quality == other.d->quality &&
- d->codec == other.d->codec &&
- d->resolution == other.d->resolution &&
- d->encodingOptions == other.d->encodingOptions);
-
-}
-
-/*!
- Determines if \a other is of equal value to a image encoder settings
- object.
-
- Returns true if the settings objects are not of equal value, and false if
- they are of equal value.
-*/
-bool QImageEncoderSettings::operator!=(const QImageEncoderSettings &other) const
-{
- return !(*this == other);
-}
-
-/*!
- Identifies if a image encoder settings object is uninitalized.
-
- Returns true if the settings are null, and false if they are not.
-*/
-bool QImageEncoderSettings::isNull() const
-{
- return d->isNull;
-}
-
-/*!
- Returns the image codec.
-*/
-
-QString QImageEncoderSettings::codec() const
-{
- return d->codec;
-}
-
-/*!
- Sets the image \a codec.
-*/
-void QImageEncoderSettings::setCodec(const QString& codec)
-{
- d->isNull = false;
- d->codec = codec;
-}
-
-/*!
- Returns the resolution of the encoded image.
-*/
-
-QSize QImageEncoderSettings::resolution() const
-{
- return d->resolution;
-}
-
-/*!
- Sets the \a resolution of the encoded image.
-
- An empty QSize indicates the encoder should make an optimal choice based on
- what is available from the image source and the limitations of the codec.
-*/
-
-void QImageEncoderSettings::setResolution(const QSize &resolution)
-{
- d->isNull = false;
- d->resolution = resolution;
-}
-
-/*!
- Sets the \a width and \a height of the resolution of the encoded image.
-
- \overload
-*/
-
-void QImageEncoderSettings::setResolution(int width, int height)
-{
- d->isNull = false;
- d->resolution = QSize(width, height);
-}
-
-/*!
- Returns the image encoding quality.
-*/
-
-QMultimedia::EncodingQuality QImageEncoderSettings::quality() const
-{
- return d->quality;
-}
-
-/*!
- Sets the image encoding \a quality.
-*/
-
-void QImageEncoderSettings::setQuality(QMultimedia::EncodingQuality quality)
-{
- d->isNull = false;
- d->quality = quality;
-}
-
-/*!
- Returns the value of encoding \a option.
-
- \sa setEncodingOption(), encodingOptions()
-*/
-QVariant QImageEncoderSettings::encodingOption(const QString &option) const
-{
- return d->encodingOptions.value(option);
-}
-
-/*!
- Returns the all the encoding options as QVariantMap.
-
- \sa encodingOption(), setEncodingOptions()
-*/
-QVariantMap QImageEncoderSettings::encodingOptions() const
-{
- return d->encodingOptions;
-}
-
-/*!
- Set the encoding \a option \a value.
-
- The supported set and meaning of encoding options are
- system and selected codec specific.
-
- \sa encodingOption(), setEncodingOptions()
-*/
-void QImageEncoderSettings::setEncodingOption(const QString &option, const QVariant &value)
-{
- d->isNull = false;
- if (value.isNull())
- d->encodingOptions.remove(option);
- else
- d->encodingOptions.insert(option, value);
-}
-
-/*!
- Replace all the encoding options with \a options.
-
- The supported set and meaning of encoding options are
- system and selected codec specific.
-
- \sa encodingOption(), setEncodingOption()
-*/
-void QImageEncoderSettings::setEncodingOptions(const QVariantMap &options)
-{
- d->isNull = false;
- d->encodingOptions = options;
-}
-
-
-QT_END_NAMESPACE
-
diff --git a/src/multimedia/recording/qmediaencodersettings.h b/src/multimedia/recording/qmediaencodersettings.h
deleted file mode 100644
index 0d6a9eddf..000000000
--- a/src/multimedia/recording/qmediaencodersettings.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 QMEDIAENCODERSETTINGS_H
-#define QMEDIAENCODERSETTINGS_H
-
-#include <QtCore/qsharedpointer.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qsize.h>
-#include <QtCore/qvariant.h>
-#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qmultimedia.h>
-
-QT_BEGIN_NAMESPACE
-
-
-
-class QAudioEncoderSettingsPrivate;
-class Q_MULTIMEDIA_EXPORT QAudioEncoderSettings
-{
-public:
- QAudioEncoderSettings();
- QAudioEncoderSettings(const QAudioEncoderSettings& other);
-
- ~QAudioEncoderSettings();
-
- QAudioEncoderSettings& operator=(const QAudioEncoderSettings &other);
- bool operator==(const QAudioEncoderSettings &other) const;
- bool operator!=(const QAudioEncoderSettings &other) const;
-
- bool isNull() const;
-
- QMultimedia::EncodingMode encodingMode() const;
- void setEncodingMode(QMultimedia::EncodingMode);
-
- QString codec() const;
- void setCodec(const QString& codec);
-
- int bitRate() const;
- void setBitRate(int bitrate);
-
- int channelCount() const;
- void setChannelCount(int channels);
-
- int sampleRate() const;
- void setSampleRate(int rate);
-
- QMultimedia::EncodingQuality quality() const;
- void setQuality(QMultimedia::EncodingQuality quality);
-
- QVariant encodingOption(const QString &option) const;
- QVariantMap encodingOptions() const;
- void setEncodingOption(const QString &option, const QVariant &value);
- void setEncodingOptions(const QVariantMap &options);
-
-private:
- QSharedDataPointer<QAudioEncoderSettingsPrivate> d;
-};
-
-class QVideoEncoderSettingsPrivate;
-class Q_MULTIMEDIA_EXPORT QVideoEncoderSettings
-{
-public:
- QVideoEncoderSettings();
- QVideoEncoderSettings(const QVideoEncoderSettings& other);
-
- ~QVideoEncoderSettings();
-
- QVideoEncoderSettings& operator=(const QVideoEncoderSettings &other);
- bool operator==(const QVideoEncoderSettings &other) const;
- bool operator!=(const QVideoEncoderSettings &other) const;
-
- bool isNull() const;
-
- QMultimedia::EncodingMode encodingMode() const;
- void setEncodingMode(QMultimedia::EncodingMode);
-
- QString codec() const;
- void setCodec(const QString &);
-
- QSize resolution() const;
- void setResolution(const QSize &);
- void setResolution(int width, int height);
-
- qreal frameRate() const;
- void setFrameRate(qreal rate);
-
- int bitRate() const;
- void setBitRate(int bitrate);
-
- QMultimedia::EncodingQuality quality() const;
- void setQuality(QMultimedia::EncodingQuality quality);
-
- QVariant encodingOption(const QString &option) const;
- QVariantMap encodingOptions() const;
- void setEncodingOption(const QString &option, const QVariant &value);
- void setEncodingOptions(const QVariantMap &options);
-
-private:
- QSharedDataPointer<QVideoEncoderSettingsPrivate> d;
-};
-
-class QImageEncoderSettingsPrivate;
-class Q_MULTIMEDIA_EXPORT QImageEncoderSettings
-{
-public:
- QImageEncoderSettings();
- QImageEncoderSettings(const QImageEncoderSettings& other);
-
- ~QImageEncoderSettings();
-
- QImageEncoderSettings& operator=(const QImageEncoderSettings &other);
- bool operator==(const QImageEncoderSettings &other) const;
- bool operator!=(const QImageEncoderSettings &other) const;
-
- bool isNull() const;
-
- QString codec() const;
- void setCodec(const QString &);
-
- QSize resolution() const;
- void setResolution(const QSize &);
- void setResolution(int width, int height);
-
- QMultimedia::EncodingQuality quality() const;
- void setQuality(QMultimedia::EncodingQuality quality);
-
- QVariant encodingOption(const QString &option) const;
- QVariantMap encodingOptions() const;
- void setEncodingOption(const QString &option, const QVariant &value);
- void setEncodingOptions(const QVariantMap &options);
-
-private:
- QSharedDataPointer<QImageEncoderSettingsPrivate> d;
-};
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QAudioEncoderSettings)
-Q_DECLARE_METATYPE(QVideoEncoderSettings)
-Q_DECLARE_METATYPE(QImageEncoderSettings)
-
-
-#endif
diff --git a/src/multimedia/recording/qmediarecorder.cpp b/src/multimedia/recording/qmediarecorder.cpp
index 617627985..ea38b231a 100644
--- a/src/multimedia/recording/qmediarecorder.cpp
+++ b/src/multimedia/recording/qmediarecorder.cpp
@@ -1,61 +1,24 @@
-/****************************************************************************
-**
-** 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 "qmediarecorder.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 "qmediarecorder_p.h"
-#include <qmediarecordercontrol.h>
-#include "qmediaobject_p.h"
-#include <qmediaservice.h>
-#include <qmediaserviceprovider_p.h>
-#include <qmetadatawritercontrol.h>
-#include <qaudioencodersettingscontrol.h>
-#include <qvideoencodersettingscontrol.h>
-#include <qmediacontainercontrol.h>
-#include <qmediaavailabilitycontrol.h>
+#include <private/qplatformmediarecorder_p.h>
+#include <qaudiodevice.h>
#include <qcamera.h>
-#include <qcameracontrol.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>
#include <QtCore/qdebug.h>
#include <QtCore/qurl.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qmetaobject.h>
+#include <QtCore/qtimer.h>
#include <qaudioformat.h>
@@ -66,179 +29,103 @@ QT_BEGIN_NAMESPACE
\inmodule QtMultimedia
\ingroup multimedia
\ingroup multimedia_recording
+ \ingroup multimedia_video
+ \ingroup multimedia_audio
- \brief The QMediaRecorder class is used for the recording of media content.
+ \brief The QMediaRecorder class is used for encoding and recording a capture session.
- The QMediaRecorder class is a high level media recording class. It's not
- intended to be used alone but for accessing the media recording functions
- of other media objects, like QCamera.
+ The QMediaRecorder class is a class for encoding and recording media generated in a
+ QMediaCaptureSession.
\snippet multimedia-snippets/media.cpp Media recorder
-
- \sa QAudioRecorder
*/
+/*!
+ \qmltype MediaRecorder
+ \instantiates QMediaRecorder
+ \brief For encoding and recording media generated in a CaptureSession.
-static void qRegisterMediaRecorderMetaTypes()
-{
- qRegisterMetaType<QMediaRecorder::State>("QMediaRecorder::State");
- qRegisterMetaType<QMediaRecorder::Status>("QMediaRecorder::Status");
- qRegisterMetaType<QMediaRecorder::Error>("QMediaRecorder::Error");
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterMediaRecorderMetaTypes)
-
-
-QMediaRecorderPrivate::QMediaRecorderPrivate():
- mediaObject(nullptr),
- control(nullptr),
- formatControl(nullptr),
- audioControl(nullptr),
- videoControl(nullptr),
- metaDataControl(nullptr),
- availabilityControl(nullptr),
- settingsChanged(false),
- notifyTimer(nullptr),
- state(QMediaRecorder::StoppedState),
- error(QMediaRecorder::NoError)
-{
-}
-
-#define ENUM_NAME(c,e,v) (c::staticMetaObject.enumerator(c::staticMetaObject.indexOfEnumerator(e)).valueToKey((v)))
-
-void QMediaRecorderPrivate::_q_stateChanged(QMediaRecorder::State ps)
-{
- Q_Q(QMediaRecorder);
-
- if (ps == QMediaRecorder::RecordingState)
- notifyTimer->start();
- else
- notifyTimer->stop();
-
-// qDebug() << "Recorder state changed:" << ENUM_NAME(QMediaRecorder,"State",ps);
- if (state != ps) {
- emit q->stateChanged(ps);
- }
-
- state = ps;
-}
-
-
-void QMediaRecorderPrivate::_q_error(int error, const QString &errorString)
-{
- Q_Q(QMediaRecorder);
-
- this->error = QMediaRecorder::Error(error);
- this->errorString = errorString;
+ \inqmlmodule QtMultimedia
+ \ingroup multimedia_qml
+ \ingroup multimedia_audio_qml
+ \ingroup multimedia_video_qml
- emit q->error(this->error);
-}
+ The MediaRecorder element can be used within a CaptureSession to record and encode audio and
+ video captured from a microphone and camera
-void QMediaRecorderPrivate::_q_serviceDestroyed()
-{
- mediaObject = nullptr;
- control = nullptr;
- formatControl = nullptr;
- audioControl = nullptr;
- videoControl = nullptr;
- metaDataControl = nullptr;
- availabilityControl = nullptr;
- settingsChanged = true;
-}
+ \since 6.2
+ The code below shows a simple capture session containing a MediaRecorder using the default
+ camera and default audio input.
-void QMediaRecorderPrivate::_q_updateActualLocation(const QUrl &location)
-{
- if (actualLocation != location) {
- actualLocation = location;
- emit q_func()->actualLocationChanged(actualLocation);
+\qml
+ CaptureSession {
+ id: captureSession
+ camera: Camera {
+ id: camera
+ active: true
+ }
+ audioInput: AudioInput {}
+ recorder: MediaRecorder {
+ id: recorder
+ }
}
-}
-
-void QMediaRecorderPrivate::_q_notify()
-{
- emit q_func()->durationChanged(q_func()->duration());
-}
-
-void QMediaRecorderPrivate::_q_updateNotifyInterval(int ms)
-{
- notifyTimer->setInterval(ms);
-}
-
-void QMediaRecorderPrivate::applySettingsLater()
-{
- if (control && !settingsChanged) {
- settingsChanged = true;
- QMetaObject::invokeMethod(q_func(), "_q_applySettings", Qt::QueuedConnection);
+\endqml
+
+ The code below shows how the recording can be started and stopped.
+\qml
+ CameraButton {
+ text: "Record"
+ visible: recorder.recorderState !== MediaRecorder.RecordingState
+ onClicked: recorder.record()
}
-}
-void QMediaRecorderPrivate::_q_applySettings()
-{
- if (control && settingsChanged) {
- settingsChanged = false;
- control->applySettings();
+ CameraButton {
+ id: stopButton
+ text: "Stop"
+ visible: recorder.recorderState === MediaRecorder.RecordingState
+ onClicked: recorder.stop()
}
-}
+\endqml
-void QMediaRecorderPrivate::_q_availabilityChanged(QMultimedia::AvailabilityStatus availability)
+ \sa CaptureSession, Camera, AudioInput, ImageCapture
+*/
+QMediaRecorderPrivate::QMediaRecorderPrivate()
{
- Q_Q(QMediaRecorder);
- Q_UNUSED(error);
- Q_UNUSED(availability);
-
- // Really this should not always emit, but
- // we can't really tell from here (isAvailable
- // may not have changed, or the mediaobject's overridden
- // availability() may not have changed).
- q->availabilityChanged(q->availability());
- q->availabilityChanged(q->isAvailable());
+ // Force an early initialization of the mime database
+ // to avoid a delay when recording for the first time.
+ encoderSettings.mimeType();
}
-void QMediaRecorderPrivate::restartCamera()
+QString QMediaRecorderPrivate::msgFailedStartRecording()
{
- //restart camera if it can't apply new settings in the Active state
- QCamera *camera = qobject_cast<QCamera*>(mediaObject);
- if (camera && camera->captureMode() == QCamera::CaptureVideo) {
- QMetaObject::invokeMethod(camera,
- "_q_preparePropertyChange",
- Qt::DirectConnection,
- Q_ARG(int, QCameraControl::VideoEncodingSettings));
- }
+ return QMediaRecorder::tr("Failed to start recording");
}
-
/*!
- Constructs a media recorder which records the media produced by \a mediaObject.
-
- The \a parent is passed to QMediaObject.
+ Constructs a media recorder which records the media produced by a microphone and camera.
+ The media recorder is a child of \a{parent}.
*/
-QMediaRecorder::QMediaRecorder(QMediaObject *mediaObject, QObject *parent):
- QObject(parent),
- d_ptr(new QMediaRecorderPrivate)
+QMediaRecorder::QMediaRecorder(QObject *parent)
+ : QObject(parent),
+ d_ptr(new QMediaRecorderPrivate)
{
Q_D(QMediaRecorder);
- d->q_ptr = this;
- d->notifyTimer = new QTimer(this);
- connect(d->notifyTimer, SIGNAL(timeout()), SLOT(_q_notify()));
+ auto &mediaIntegration = *QPlatformMediaIntegration::instance();
- setMediaObject(mediaObject);
-}
-
-/*!
- \internal
-*/
-QMediaRecorder::QMediaRecorder(QMediaRecorderPrivate &dd, QMediaObject *mediaObject, QObject *parent):
- QObject(parent),
- d_ptr(&dd)
-{
- Q_D(QMediaRecorder);
d->q_ptr = this;
-
- d->notifyTimer = new QTimer(this);
- connect(d->notifyTimer, SIGNAL(timeout()), SLOT(_q_notify()));
-
- setMediaObject(mediaObject);
+ 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();
+ }
}
/*!
@@ -247,219 +134,76 @@ QMediaRecorder::QMediaRecorder(QMediaRecorderPrivate &dd, QMediaObject *mediaObj
QMediaRecorder::~QMediaRecorder()
{
+ if (d_ptr->captureSession)
+ d_ptr->captureSession->setRecorder(nullptr);
+ delete d_ptr->control;
delete d_ptr;
}
/*!
- Returns the QMediaObject instance that this QMediaRecorder is bound too,
- or 0 otherwise.
+ \internal
*/
-QMediaObject *QMediaRecorder::mediaObject() const
+QPlatformMediaRecorder *QMediaRecorder::platformRecoder() const
{
- return d_func()->mediaObject;
+ return d_ptr->control;
}
/*!
\internal
*/
-bool QMediaRecorder::setMediaObject(QMediaObject *object)
+void QMediaRecorder::setCaptureSession(QMediaCaptureSession *session)
{
Q_D(QMediaRecorder);
+ d->captureSession = session;
+}
+/*!
+ \qmlproperty QUrl QtMultimedia::MediaRecorder::outputLocation
+ \brief The destination location of media content.
- if (object == d->mediaObject)
- return true;
-
- if (d->mediaObject) {
- if (d->control) {
- disconnect(d->control, SIGNAL(stateChanged(QMediaRecorder::State)),
- this, SLOT(_q_stateChanged(QMediaRecorder::State)));
-
- disconnect(d->control, SIGNAL(statusChanged(QMediaRecorder::Status)),
- this, SIGNAL(statusChanged(QMediaRecorder::Status)));
-
- disconnect(d->control, SIGNAL(mutedChanged(bool)),
- this, SIGNAL(mutedChanged(bool)));
-
- disconnect(d->control, SIGNAL(volumeChanged(qreal)),
- this, SIGNAL(volumeChanged(qreal)));
-
- disconnect(d->control, SIGNAL(durationChanged(qint64)),
- this, SIGNAL(durationChanged(qint64)));
-
- disconnect(d->control, SIGNAL(actualLocationChanged(QUrl)),
- this, SLOT(_q_updateActualLocation(QUrl)));
-
- disconnect(d->control, SIGNAL(error(int,QString)),
- this, SLOT(_q_error(int,QString)));
- }
-
- disconnect(d->mediaObject, SIGNAL(notifyIntervalChanged(int)), this, SLOT(_q_updateNotifyInterval(int)));
-
- QMediaService *service = d->mediaObject->service();
-
- if (service) {
- disconnect(service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed()));
-
- if (d->control)
- service->releaseControl(d->control);
- if (d->formatControl)
- service->releaseControl(d->formatControl);
- if (d->audioControl)
- service->releaseControl(d->audioControl);
- if (d->videoControl)
- service->releaseControl(d->videoControl);
- if (d->metaDataControl) {
- disconnect(d->metaDataControl, SIGNAL(metaDataChanged()),
- this, SIGNAL(metaDataChanged()));
- disconnect(d->metaDataControl, SIGNAL(metaDataChanged(QString,QVariant)),
- this, SIGNAL(metaDataChanged(QString,QVariant)));
- disconnect(d->metaDataControl, SIGNAL(metaDataAvailableChanged(bool)),
- this, SIGNAL(metaDataAvailableChanged(bool)));
- disconnect(d->metaDataControl, SIGNAL(writableChanged(bool)),
- this, SIGNAL(metaDataWritableChanged(bool)));
-
- service->releaseControl(d->metaDataControl);
- }
- if (d->availabilityControl) {
- disconnect(d->availabilityControl, SIGNAL(availabilityChanged(QMultimedia::AvailabilityStatus)),
- this, SLOT(_q_availabilityChanged(QMultimedia::AvailabilityStatus)));
- service->releaseControl(d->availabilityControl);
- }
- }
- }
-
- d->control = nullptr;
- d->formatControl = nullptr;
- d->audioControl = nullptr;
- d->videoControl = nullptr;
- d->metaDataControl = nullptr;
- d->availabilityControl = nullptr;
-
- d->mediaObject = object;
-
- if (d->mediaObject) {
- QMediaService *service = d->mediaObject->service();
-
- d->notifyTimer->setInterval(d->mediaObject->notifyInterval());
- connect(d->mediaObject, SIGNAL(notifyIntervalChanged(int)), SLOT(_q_updateNotifyInterval(int)));
-
- if (service) {
- d->control = qobject_cast<QMediaRecorderControl*>(service->requestControl(QMediaRecorderControl_iid));
-
- if (d->control) {
- d->formatControl = qobject_cast<QMediaContainerControl *>(service->requestControl(QMediaContainerControl_iid));
- d->audioControl = qobject_cast<QAudioEncoderSettingsControl *>(service->requestControl(QAudioEncoderSettingsControl_iid));
- d->videoControl = qobject_cast<QVideoEncoderSettingsControl *>(service->requestControl(QVideoEncoderSettingsControl_iid));
-
- QMediaControl *control = service->requestControl(QMetaDataWriterControl_iid);
- if (control) {
- d->metaDataControl = qobject_cast<QMetaDataWriterControl *>(control);
- if (!d->metaDataControl) {
- service->releaseControl(control);
- } else {
- connect(d->metaDataControl,
- SIGNAL(metaDataChanged()),
- SIGNAL(metaDataChanged()));
- connect(d->metaDataControl, SIGNAL(metaDataChanged(QString,QVariant)),
- this, SIGNAL(metaDataChanged(QString,QVariant)));
- connect(d->metaDataControl,
- SIGNAL(metaDataAvailableChanged(bool)),
- SIGNAL(metaDataAvailableChanged(bool)));
- connect(d->metaDataControl,
- SIGNAL(writableChanged(bool)),
- SIGNAL(metaDataWritableChanged(bool)));
- }
- }
-
- d->availabilityControl = service->requestControl<QMediaAvailabilityControl*>();
- if (d->availabilityControl) {
- connect(d->availabilityControl, SIGNAL(availabilityChanged(QMultimedia::AvailabilityStatus)),
- this, SLOT(_q_availabilityChanged(QMultimedia::AvailabilityStatus)));
- }
-
- connect(d->control, SIGNAL(stateChanged(QMediaRecorder::State)),
- this, SLOT(_q_stateChanged(QMediaRecorder::State)));
-
- connect(d->control, SIGNAL(statusChanged(QMediaRecorder::Status)),
- this, SIGNAL(statusChanged(QMediaRecorder::Status)));
-
- connect(d->control, SIGNAL(mutedChanged(bool)),
- this, SIGNAL(mutedChanged(bool)));
-
- connect(d->control, SIGNAL(volumeChanged(qreal)),
- this, SIGNAL(volumeChanged(qreal)));
-
- connect(d->control, SIGNAL(durationChanged(qint64)),
- this, SIGNAL(durationChanged(qint64)));
-
- connect(d->control, SIGNAL(actualLocationChanged(QUrl)),
- this, SLOT(_q_updateActualLocation(QUrl)));
-
- connect(d->control, SIGNAL(error(int,QString)),
- this, SLOT(_q_error(int,QString)));
-
- connect(service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed()));
-
-
- d->applySettingsLater();
-
- return true;
- }
- }
+ Setting the location can fail, for example when the service supports only
+ local file system locations but a network URL was passed. If the operation
+ fails an errorOccured() signal is emitted.
- d->mediaObject = nullptr;
- return false;
- }
+ The location can be relative or empty. If empty the recorder uses the
+ system specific place and file naming scheme.
- return true;
-}
+ \sa errorOccurred()
+*/
/*!
\property QMediaRecorder::outputLocation
\brief the destination location of media content.
Setting the location can fail, for example when the service supports only
- local file system locations but a network URL was passed. If the service
- does not support media recording this setting the output location will
- always fail.
+ local file system locations but a network URL was passed. If the operation
+ fails an errorOccured() signal is emitted.
- The \a location can be relative or empty;
- in this case the recorder uses the system specific place and file naming scheme.
- After recording has stated, QMediaRecorder::outputLocation() returns the actual output location.
+ The output location can be relative or empty; in the latter case the recorder
+ uses the system specific place and file naming scheme.
*/
/*!
- \property QMediaRecorder::actualLocation
- \brief the actual location of the last media content.
+ \qmlproperty QUrl QtMultimedia::MediaRecorder::actualLocation
+ \brief The actual location of the last media content.
The actual location is usually available after recording starts,
and reset when new location is set or new recording starts.
*/
/*!
- Returns true if media recorder service ready to use.
+ \property QMediaRecorder::actualLocation
+ \brief The actual location of the last media content.
- \sa availabilityChanged()
+ The actual location is usually available after recording starts,
+ and reset when new location is set or new recording starts.
*/
-bool QMediaRecorder::isAvailable() const
-{
- return availability() == QMultimedia::Available;
-}
/*!
- Returns the availability of this functionality.
-
- \sa availabilityChanged()
+ Returns \c true if media recorder service ready to use.
*/
-QMultimedia::AvailabilityStatus QMediaRecorder::availability() const
+bool QMediaRecorder::isAvailable() const
{
- if (d_func()->control == nullptr)
- return QMultimedia::ServiceMissing;
-
- if (d_func()->availabilityControl)
- return d_func()->availabilityControl->availability();
-
- return QMultimedia::Available;
+ return d_func()->control && d_func()->captureSession;
}
QUrl QMediaRecorder::outputLocation() const
@@ -467,41 +211,68 @@ QUrl QMediaRecorder::outputLocation() const
return d_func()->control ? d_func()->control->outputLocation() : QUrl();
}
-bool QMediaRecorder::setOutputLocation(const QUrl &location)
+void QMediaRecorder::setOutputLocation(const QUrl &location)
{
Q_D(QMediaRecorder);
- d->actualLocation.clear();
- return d->control ? d->control->setOutputLocation(location) : false;
+ if (!d->control) {
+ emit errorOccurred(QMediaRecorder::ResourceError, d->initErrorMessage);
+ return;
+ }
+ d->control->setOutputLocation(location);
+ d->control->clearActualLocation();
+ if (!location.isEmpty() && !d->control->isLocationWritable(location))
+ emit errorOccurred(QMediaRecorder::LocationNotWritable, tr("Output location not writable"));
}
-QUrl QMediaRecorder::actualLocation() const
+/*!
+ Set the output IO device for media content.
+
+ The \a device must have been opened in the \l{QIODevice::WriteOnly}{WriteOnly} 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)
{
- return d_func()->actualLocation;
+ Q_D(QMediaRecorder);
+ d->control->setOutputDevice(device);
}
/*!
- Returns the current media recorder state.
+ Returns the output IO device for media content.
- \sa QMediaRecorder::State
+ \sa setOutputDevice()
*/
+QIODevice *QMediaRecorder::outputDevice() const
+{
+ Q_D(const QMediaRecorder);
+ return d->control->outputDevice();
+}
-QMediaRecorder::State QMediaRecorder::state() const
+QUrl QMediaRecorder::actualLocation() const
{
- return d_func()->control ? QMediaRecorder::State(d_func()->control->state()) : StoppedState;
+ Q_D(const QMediaRecorder);
+ return d->control ? d->control->actualLocation() : QUrl();
}
/*!
- Returns the current media recorder status.
+ Returns the current media recorder state.
- \sa QMediaRecorder::Status
+ \sa QMediaRecorder::RecorderState
*/
-QMediaRecorder::Status QMediaRecorder::status() const
+QMediaRecorder::RecorderState QMediaRecorder::recorderState() const
{
- return d_func()->control ? QMediaRecorder::Status(d_func()->control->status()) : UnavailableStatus;
+ return d_func()->control ? QMediaRecorder::RecorderState(d_func()->control->state()) : StoppedState;
}
/*!
+ \property QMediaRecorder::error
+
Returns the current error state.
\sa errorString()
@@ -509,10 +280,19 @@ QMediaRecorder::Status QMediaRecorder::status() const
QMediaRecorder::Error QMediaRecorder::error() const
{
- return d_func()->error;
+ Q_D(const QMediaRecorder);
+
+ return d->control ? d->control->error() : QMediaRecorder::ResourceError;
}
+/*!
+ \qmlproperty string QtMultimedia::MediaRecorder::errorString
+ \brief This property holds a string describing the current error state.
+ \sa error
+*/
/*!
+ \property QMediaRecorder::errorString
+
Returns a string describing the current error state.
\sa error()
@@ -520,8 +300,15 @@ QMediaRecorder::Error QMediaRecorder::error() const
QString QMediaRecorder::errorString() const
{
- return d_func()->errorString;
+ Q_D(const QMediaRecorder);
+
+ return d->control ? d->control->errorString() : d->initErrorMessage;
}
+/*!
+ \qmlproperty qint64 QtMultimedia::MediaRecorder::duration
+
+ \brief This property holds the recorded media duration in milliseconds.
+*/
/*!
\property QMediaRecorder::duration
@@ -533,577 +320,671 @@ qint64 QMediaRecorder::duration() const
{
return d_func()->control ? d_func()->control->duration() : 0;
}
-
/*!
- \property QMediaRecorder::muted
+ \fn void QMediaRecorder::encoderSettingsChanged()
- \brief whether a recording audio stream is muted.
+ Signals when the encoder settings change.
*/
+/*!
+ \qmlmethod QtMultimedia::MediaRecorder::record()
+ \brief Starts recording.
-bool QMediaRecorder::isMuted() const
-{
- return d_func()->control ? d_func()->control->isMuted() : 0;
-}
+ While the recorder state is changed immediately to
+ \c MediaRecorder.RecordingState, recording may start asynchronously.
-void QMediaRecorder::setMuted(bool muted)
-{
- Q_D(QMediaRecorder);
-
- if (d->control)
- d->control->setMuted(muted);
-}
+ If recording fails, the error() signal is emitted with recorder state being
+ reset back to \c{QMediaRecorder.StoppedState}.
+ \note On mobile devices, recording will happen in the orientation the
+ device had when calling record and is locked for the duration of the recording.
+ To avoid artifacts on the user interface, we recommend to keep the user interface
+ locked to the same orientation as long as the recording is ongoing using
+ the contentOrientation property of the Window and unlock it again once the recording
+ is finished.
+*/
/*!
- \property QMediaRecorder::volume
-
- \brief the current recording audio volume.
+ Start recording.
- The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this
- range will be clamped.
+ While the recorder state is changed immediately to
+ c\{QMediaRecorder::RecordingState}, recording may start asynchronously.
- The default volume is \c 1.0.
+ If recording fails error() signal is emitted with recorder state being
+ reset back to \c{QMediaRecorder::StoppedState}.
- UI volume controls should usually be scaled nonlinearly. 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.
+ \note On mobile devices, recording will happen in the orientation the
+ device had when calling record and is locked for the duration of the recording.
+ To avoid artifacts on the user interface, we recommend to keep the user interface
+ locked to the same orientation as long as the recording is ongoing using
+ the contentOrientation property of QWindow and unlock it again once the recording
+ is finished.
*/
-qreal QMediaRecorder::volume() const
+void QMediaRecorder::record()
{
- return d_func()->control ? d_func()->control->volume() : 1.0;
-}
+ Q_D(QMediaRecorder);
+ if (!d->control || !d->captureSession)
+ return;
-void QMediaRecorder::setVolume(qreal volume)
-{
- Q_D(QMediaRecorder);
+ if (d->control->state() == QMediaRecorder::PausedState) {
+ d->control->resume();
+ } else {
+ auto oldMediaFormat = d->encoderSettings.mediaFormat();
- if (d->control) {
- volume = qMax(qreal(0.0), volume);
- d->control->setVolume(volume);
+ 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();
+
+ auto settings = d->encoderSettings;
+ d->control->record(d->encoderSettings);
+
+ if (settings != d->encoderSettings)
+ emit encoderSettingsChanged();
+
+ if (oldMediaFormat != d->encoderSettings.mediaFormat())
+ emit mediaFormatChanged();
}
}
-
/*!
- Returns a list of supported container formats.
-*/
-QStringList QMediaRecorder::supportedContainers() const
-{
- return d_func()->formatControl ?
- d_func()->formatControl->supportedContainers() : QStringList();
-}
+ \qmlmethod QtMultimedia::MediaRecorder::pause()
+ \brief Pauses recording.
-/*!
- Returns a description of a container \a format.
-*/
-QString QMediaRecorder::containerDescription(const QString &format) const
-{
- return d_func()->formatControl ?
- d_func()->formatControl->containerDescription(format) : QString();
-}
+ The recorder state is changed to QMediaRecorder.PausedState.
+ Depending on the platform, pausing recording may be not supported.
+ In this case the recorder state is unchanged.
+*/
/*!
- Returns the selected container format.
+ Pauses recording.
+
+ The recorder state is changed to QMediaRecorder::PausedState.
+
+ Depending on the platform, pausing recording may be not supported.
+ In this case the recorder state is unchanged.
*/
-QString QMediaRecorder::containerFormat() const
+void QMediaRecorder::pause()
{
- return d_func()->formatControl ?
- d_func()->formatControl->containerFormat() : QString();
+ Q_D(QMediaRecorder);
+ if (d->control && d->captureSession)
+ d->control->pause();
}
-
/*!
- Returns a list of supported audio codecs.
+ \qmlmethod QtMultimedia::MediaRecorder::stop()
+ \brief Stops the recording.
+
+ 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.
*/
-QStringList QMediaRecorder::supportedAudioCodecs() const
-{
- return d_func()->audioControl ?
- d_func()->audioControl->supportedAudioCodecs() : QStringList();
-}
/*!
- Returns a description of an audio \a codec.
+ 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.
*/
-QString QMediaRecorder::audioCodecDescription(const QString &codec) const
+void QMediaRecorder::stop()
{
- return d_func()->audioControl ?
- d_func()->audioControl->codecDescription(codec) : QString();
+ Q_D(QMediaRecorder);
+ if (d->control && d->captureSession)
+ d->control->stop();
}
+/*!
+ \qmlproperty enumeration QtMultimedia::MediaRecorder::recorderState
+ \brief This property holds the current media recorder state.
+
+ The state property represents the user request and is changed synchronously
+ during record(), pause() or stop() calls.
+ RecorderSstate may also change asynchronously when recording fails.
+ \value MediaRecorder.StoppedState The recorder is not active.
+ \value MediaRecorder.RecordingState The recording is requested.
+ \value MediaRecorder.PausedState The recorder is pause.
+*/
/*!
- Returns a list of supported audio sample rates.
+ \enum QMediaRecorder::RecorderState
- If non null audio \a settings parameter is passed, the returned list is
- reduced to sample rates supported with partial settings applied.
+ \value StoppedState The recorder is not active.
+ \value RecordingState The recording is requested.
+ \value PausedState The recorder is paused.
+*/
+/*!
+ \qmlproperty enumeration QtMultimedia::MediaRecorder::error
+ \brief This property holds the current media recorder error state.
- This can be used to query the list of sample rates, supported by specific
- audio codec.
+ \value MediaRecorder.NoError Not in an error state.
+ \value MediaRecorder.ResourceError Not enough system resources
+ \value MediaRecorder.FormatError the current format is not supported.
+ \value MediaRecorder.OutOfSpaceError No space left on device.
+ \value MediaRecorder.LocationNotWriteable The output location is not writable.
+*/
+/*!
+ \enum QMediaRecorder::Error
- If the encoder supports arbitrary sample rates within the supported rates
- range, *\a continuous is set to true, otherwise *\a continuous is set to
- false.
+ \value NoError No Errors.
+ \value ResourceError Device is not ready or not available.
+ \value FormatError Current format is not supported.
+ \value OutOfSpaceError No space left on device.
+ \value LocationNotWritable The output location is not writable.
*/
-QList<int> QMediaRecorder::supportedAudioSampleRates(const QAudioEncoderSettings &settings, bool *continuous) const
-{
- if (continuous)
- *continuous = false;
+/*!
+ \property QMediaRecorder::recorderState
+ \brief The current state of the media recorder.
- return d_func()->audioControl ?
- d_func()->audioControl->supportedSampleRates(settings, continuous) : QList<int>();
-}
+ The state property represents the user request and is changed synchronously
+ during record(), pause() or stop() calls.
+ Recorder state may also change asynchronously when recording fails.
+*/
/*!
- Returns a list of resolutions video can be encoded at.
+ \qmlsignal QtMultimedia::MediaRecorder::recorderStateChanged(RecorderState state)
+ \brief Signals that a media recorder's \a state has changed.
+*/
- If non null video \a settings parameter is passed, the returned list is
- reduced to resolution supported with partial settings like video codec or
- framerate applied.
+/*!
+ \fn QMediaRecorder::recorderStateChanged(QMediaRecorder::RecorderState state)
- If the encoder supports arbitrary resolutions within the supported range,
- *\a continuous is set to true, otherwise *\a continuous is set to false.
+ Signals that a media recorder's \a state has changed.
+*/
- \sa QVideoEncoderSettings::resolution()
+/*!
+ \qmlsignal QtMultimedia::MediaRecorder::durationChanged(qint64 duration)
+ \brief Signals that the \a duration of the recorded media has changed.
*/
-QList<QSize> QMediaRecorder::supportedResolutions(const QVideoEncoderSettings &settings, bool *continuous) const
-{
- if (continuous)
- *continuous = false;
- return d_func()->videoControl ?
- d_func()->videoControl->supportedResolutions(settings, continuous) : QList<QSize>();
-}
+/*!
+ \fn QMediaRecorder::durationChanged(qint64 duration)
+ Signals that the \a duration of the recorded media has changed.
+*/
/*!
- Returns a list of frame rates video can be encoded at.
+ \qmlsignal QtMultimedia::MediaRecorder::actualLocationChanged(const QUrl &location)
+ \brief Signals that the actual \a location of the recorded media has changed.
- If non null video \a settings parameter is passed, the returned list is
- reduced to frame rates supported with partial settings like video codec or
- resolution applied.
+ This signal is usually emitted when recording starts.
+*/
+/*!
+ \fn QMediaRecorder::actualLocationChanged(const QUrl &location)
- If the encoder supports arbitrary frame rates within the supported range,
- *\a continuous is set to true, otherwise *\a continuous is set to false.
+ Signals that the actual \a location of the recorded media has changed.
+ This signal is usually emitted when recording starts.
+*/
+/*!
+ \qmlsignal QtMultimedia::MediaRecorder::errorOccurred(Error error, const QString &errorString)
+ \brief Signals that an \a error has occurred.
- \sa QVideoEncoderSettings::frameRate()
+ The \a errorString contains a description of the error.
*/
-QList<qreal> QMediaRecorder::supportedFrameRates(const QVideoEncoderSettings &settings, bool *continuous) const
-{
- if (continuous)
- *continuous = false;
+/*!
+ \fn QMediaRecorder::errorOccurred(QMediaRecorder::Error error, const QString &errorString)
- return d_func()->videoControl ?
- d_func()->videoControl->supportedFrameRates(settings, continuous) : QList<qreal>();
-}
+ Signals that an \a error has occurred, with \a errorString containing
+ a description of the error.
+*/
/*!
- Returns a list of supported video codecs.
+ \qmlproperty mediaMetaData QtMultimedia::MediaRecorder::metaData
+
+ \brief This property holds meta data associated with the recording.
+
+ When a recording is started, any meta-data assigned will be attached to that
+ recording.
+
+ \note Ensure that meta-data is assigned correctly by assigning it before
+ starting the recording.
+
+ \sa mediaMetaData
*/
-QStringList QMediaRecorder::supportedVideoCodecs() const
-{
- return d_func()->videoControl ?
- d_func()->videoControl->supportedVideoCodecs() : QStringList();
-}
/*!
- Returns a description of a video \a codec.
+ \property QMediaRecorder::metaData
- \sa setEncodingSettings()
+ Returns the metaData associated with the recording.
*/
-QString QMediaRecorder::videoCodecDescription(const QString &codec) const
+QMediaMetaData QMediaRecorder::metaData() const
{
- return d_func()->videoControl ?
- d_func()->videoControl->videoCodecDescription(codec) : QString();
+ Q_D(const QMediaRecorder);
+
+ return d->control ? d->control->metaData() : QMediaMetaData{};
}
/*!
- Returns the audio encoder settings being used.
+ Sets the meta data to \a metaData.
- \sa setEncodingSettings()
+ \note To ensure that meta-data is set correctly, it should be set before starting the recording.
+ Once the recording is started, any meta-data set will be attached to the next recording.
*/
-
-QAudioEncoderSettings QMediaRecorder::audioSettings() const
+void QMediaRecorder::setMetaData(const QMediaMetaData &metaData)
{
- return d_func()->audioControl ?
- d_func()->audioControl->audioSettings() : QAudioEncoderSettings();
+ Q_D(QMediaRecorder);
+
+ if (d->control && d->captureSession)
+ d->control->setMetaData(metaData);
}
/*!
- Returns the video encoder settings being used.
-
- \sa setEncodingSettings()
+ Adds \a metaData to the recorded media.
*/
-
-QVideoEncoderSettings QMediaRecorder::videoSettings() const
+void QMediaRecorder::addMetaData(const QMediaMetaData &metaData)
{
- return d_func()->videoControl ?
- d_func()->videoControl->videoSettings() : QVideoEncoderSettings();
+ auto data = this->metaData();
+ // merge data
+ for (auto &&[key, value] : metaData.asKeyValueRange())
+ data.insert(key, value);
+ setMetaData(data);
}
/*!
- Sets the audio encoder \a settings.
+ \property QMediaRecorder::autoStop
- If some parameters are not specified, or null settings are passed, the
- encoder will choose default encoding parameters, depending on media
- source properties.
+ This property controls whether the media recorder stops automatically when
+ all media inputs have reported the end of the stream or have been deactivated.
- It's only possible to change settings when the encoder is in the
- QMediaEncoder::StoppedState state.
+ The end of the stream is reported by sending an empty media frame,
+ which you can send explicitly via \l QVideoFrameInput or \l QAudioBufferInput.
- \sa audioSettings(), videoSettings(), containerFormat()
+ Video inputs, specificly, \l QCamera, \l QScreenCapture and \l QWindowCapture,
+ can be deactivated via the function \c setActive.
+
+ Defaults to \c false.
+
+ \sa QCamera, QScreenCapture, QWindowCapture
*/
-void QMediaRecorder::setAudioSettings(const QAudioEncoderSettings &settings)
+bool QMediaRecorder::autoStop() const
+{
+ Q_D(const QMediaRecorder);
+
+ return d->autoStop;
+}
+
+void QMediaRecorder::setAutoStop(bool autoStop)
{
Q_D(QMediaRecorder);
- //restart camera if it can't apply new settings in the Active state
- d->restartCamera();
+ if (d->autoStop == autoStop)
+ return;
- if (d->audioControl) {
- d->audioControl->setAudioSettings(settings);
- d->applySettingsLater();
- }
+ d->autoStop = autoStop;
+ d->control->updateAutoStop();
+ emit autoStopChanged();
}
/*!
- Sets the video encoder \a settings.
-
- If some parameters are not specified, or null settings are passed, the
- encoder will choose default encoding parameters, depending on media
- source properties.
+ \qmlsignal QtMultimedia::MediaRecorder::metaDataChanged()
- It's only possible to change settings when the encoder is in the
- QMediaEncoder::StoppedState state.
+ \brief Signals that a media object's meta-data has changed.
- \sa audioSettings(), videoSettings(), containerFormat()
+ If multiple meta-data elements are changed metaDataChanged() is emitted
+ once.
*/
+/*!
+ \fn QMediaRecorder::metaDataChanged()
-void QMediaRecorder::setVideoSettings(const QVideoEncoderSettings &settings)
-{
- Q_D(QMediaRecorder);
+ Signals that a media object's meta-data has changed.
- d->restartCamera();
+ If multiple meta-data elements are changed metaDataChanged() is emitted
+ once.
+*/
- if (d->videoControl) {
- d->videoControl->setVideoSettings(settings);
- d->applySettingsLater();
- }
+/*!
+ Returns the media capture session.
+*/
+QMediaCaptureSession *QMediaRecorder::captureSession() const
+{
+ Q_D(const QMediaRecorder);
+ return d->captureSession;
}
-
/*!
- Sets the media \a container format.
+ \qmlproperty enumeration QtMultimedia::MediaRecorder::quality
- If the container format is not specified, the
- encoder will choose format, depending on media source properties
- and encoding settings selected.
+ Enumerates quality encoding levels.
- It's only possible to change settings when the encoder is in the
- QMediaEncoder::StoppedState state.
+ \value MediaRecorder.VeryLowQuality
+ \value MediaRecorder.LowQuality
+ \value MediaRecorder.NormalQuality
+ \value MediaRecorder.HighQuality
+ \value MediaRecorder.VeryHighQuality
+*/
+/*!
+ \enum QMediaRecorder::Quality
- \sa audioSettings(), videoSettings(), containerFormat()
+ Enumerates quality encoding levels.
+
+ \value VeryLowQuality
+ \value LowQuality
+ \value NormalQuality
+ \value HighQuality
+ \value VeryHighQuality
*/
-void QMediaRecorder::setContainerFormat(const QString &container)
-{
- Q_D(QMediaRecorder);
+/*!
+ \enum QMediaRecorder::EncodingMode
- d->restartCamera();
+ Enumerates encoding modes.
- if (d->formatControl) {
- d->formatControl->setContainerFormat(container);
- d->applySettingsLater();
- }
-}
+ \value ConstantQualityEncoding Encoding will aim to have a constant quality, adjusting bitrate to fit.
+ \value ConstantBitRateEncoding Encoding will use a constant bit rate, adjust quality to fit.
+ \value AverageBitRateEncoding Encoding will try to keep an average bitrate setting, but will use
+ more or less as needed.
+ \value TwoPassEncoding The media will first be processed to determine the characteristics,
+ and then processed a second time allocating more bits to the areas
+ that need it.
+*/
/*!
- Sets the \a audio and \a video encoder settings and \a container format.
- If some parameters are not specified, or null settings are passed, the
- encoder will choose default encoding parameters, depending on media
- source properties.
+ \qmlproperty MediaFormat QtMultimedia::MediaRecorder::mediaFormat
- It's only possible to change settings when the encoder is in the
- QMediaEncoder::StoppedState state.
+ \brief This property holds the current MediaFormat of the recorder.
+*/
+/*!
+ \property QMediaRecorder::mediaFormat
- \sa audioSettings(), videoSettings(), containerFormat()
+ Returns the recording media format.
*/
+QMediaFormat QMediaRecorder::mediaFormat() const
+{
+ Q_D(const QMediaRecorder);
+ return d->encoderSettings.mediaFormat();
+}
-void QMediaRecorder::setEncodingSettings(const QAudioEncoderSettings &audio,
- const QVideoEncoderSettings &video,
- const QString &container)
+void QMediaRecorder::setMediaFormat(const QMediaFormat &format)
{
Q_D(QMediaRecorder);
+ if (d->encoderSettings.mediaFormat() == format)
+ return;
+ d->encoderSettings.setMediaFormat(format);
+ emit mediaFormatChanged();
+}
- d->restartCamera();
-
- if (d->audioControl)
- d->audioControl->setAudioSettings(audio);
+/*!
- if (d->videoControl)
- d->videoControl->setVideoSettings(video);
+ \qmlproperty enumeration QtMultimedia::MediaRecorder::encodingMode
+ \since 6.6
+ \brief This property holds the encoding mode.
+ \sa QMediaRecorder::EncodingMode
+*/
- if (d->formatControl)
- d->formatControl->setContainerFormat(container);
+/*!
+ Returns the encoding mode.
- d->applySettingsLater();
+ \sa EncodingMode
+*/
+QMediaRecorder::EncodingMode QMediaRecorder::encodingMode() const
+{
+ Q_D(const QMediaRecorder);
+ return d->encoderSettings.encodingMode();
}
/*!
- Start recording.
-
- While the recorder state is changed immediately to QMediaRecorder::RecordingState,
- recording may start asynchronously, with statusChanged(QMediaRecorder::RecordingStatus)
- signal emitted when recording starts.
+ \fn void QMediaRecorder::encodingModeChanged()
- If recording fails error() signal is emitted
- with recorder state being reset back to QMediaRecorder::StoppedState.
+ Signals when the encoding mode changes.
*/
+/*!
+ Sets the encoding \a mode setting.
-void QMediaRecorder::record()
+ If ConstantQualityEncoding is set, the quality
+ encoding parameter is used and bit rates are ignored,
+ otherwise the bitrates are used.
+
+ \sa encodingMode(), EncodingMode
+*/
+void QMediaRecorder::setEncodingMode(EncodingMode mode)
{
Q_D(QMediaRecorder);
-
- d->actualLocation.clear();
-
- if (d->settingsChanged)
- d->_q_applySettings();
-
- // reset error
- d->error = NoError;
- d->errorString = QString();
-
- if (d->control)
- d->control->setState(RecordingState);
+ if (d->encoderSettings.encodingMode() == mode)
+ return;
+ d->encoderSettings.setEncodingMode(mode);
+ emit encodingModeChanged();
}
/*!
- Pause recording.
-
- The recorder state is changed to QMediaRecorder::PausedState.
+ \property QMediaRecorder::quality
- Depending on platform recording pause may be not supported,
- in this case the recorder state stays unchanged.
+ Returns the recording quality.
*/
-
-void QMediaRecorder::pause()
+QMediaRecorder::Quality QMediaRecorder::quality() const
{
- Q_D(QMediaRecorder);
- if (d->control)
- d->control->setState(PausedState);
+ Q_D(const QMediaRecorder);
+ return d->encoderSettings.quality();
}
/*!
- Stop recording.
+ \fn void QMediaRecorder::qualityChanged()
- The recorder state is changed to QMediaRecorder::StoppedState.
+ Signals when the recording quality changes.
*/
-
-void QMediaRecorder::stop()
+void QMediaRecorder::setQuality(Quality quality)
{
Q_D(QMediaRecorder);
- if (d->control)
- d->control->setState(StoppedState);
+ if (d->encoderSettings.quality() == quality)
+ return;
+ d->encoderSettings.setQuality(quality);
+ emit qualityChanged();
}
/*!
- \enum QMediaRecorder::State
+ \qmlproperty Size QtMultimedia::MediaRecorder::videoResolution
+ \since 6.6
+ \brief This property holds the resolution of the encoded video.
- \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.
+ 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.
*/
-/*!
- \enum QMediaRecorder::Status
- \value UnavailableStatus
- The recorder is not available or not supported by connected media object.
- \value UnloadedStatus
- The recorder is avilable but not loaded.
- \value LoadingStatus
- The recorder is initializing.
- \value LoadedStatus
- The recorder is initialized and ready to record media.
- \value StartingStatus
- Recording is requested but not active yet.
- \value RecordingStatus
- Recording is active.
- \value PausedStatus
- Recording is paused.
- \value FinalizingStatus
- Recording is stopped with media being finalized.
+/*!
+ Returns the resolution of the encoded video.
*/
+QSize QMediaRecorder::videoResolution() const
+{
+ Q_D(const QMediaRecorder);
+ return d->encoderSettings.videoResolution();
+}
/*!
- \enum QMediaRecorder::Error
+ \fn void QMediaRecorder::videoResolutionChanged()
- \value NoError No Errors.
- \value ResourceError Device is not ready or not available.
- \value FormatError Current format is not supported.
- \value OutOfSpaceError No space left on device.
+ Signals when the video recording resolution changes.
*/
-
/*!
- \property QMediaRecorder::state
- \brief The current state of the media recorder.
+ Sets the resolution of the encoded video to \a{size}.
- The state property represents the user request and is changed synchronously
- during record(), pause() or stop() calls.
- Recorder state may also change asynchronously when recording fails.
+ Pass an empty QSize to make the recorder choose an optimal resolution based
+ on what is available from the video source and the limitations of the codec.
*/
+void QMediaRecorder::setVideoResolution(const QSize &size)
+{
+ Q_D(QMediaRecorder);
+ if (d->encoderSettings.videoResolution() == size)
+ return;
+ d->encoderSettings.setVideoResolution(size);
+ emit videoResolutionChanged();
+}
-/*!
- \property QMediaRecorder::status
- \brief The current status of the media recorder.
+/*! \fn void QMediaRecorder::setVideoResolution(int width, int height)
- The status is changed asynchronously and represents the actual status
- of media recorder.
+ Sets the \a width and \a height of the resolution of the encoded video.
+
+ \overload
*/
/*!
- \fn QMediaRecorder::stateChanged(State state)
+ \qmlproperty real QtMultimedia::MediaRecorder::videoFrameRate
+ \since 6.6
+ \brief This property holds the video frame rate.
- Signals that a media recorder's \a state has changed.
+ 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.
*/
/*!
- \fn QMediaRecorder::durationChanged(qint64 duration)
-
- Signals that the \a duration of the recorded media has changed.
+ Returns the video frame rate.
*/
+qreal QMediaRecorder::videoFrameRate() const
+{
+ Q_D(const QMediaRecorder);
+ return d->encoderSettings.videoFrameRate();
+}
/*!
- \fn QMediaRecorder::actualLocationChanged(const QUrl &location)
+ \fn void QMediaRecorder::videoFrameRateChanged()
- Signals that the actual \a location of the recorded media has changed.
- This signal is usually emitted when recording starts.
+ Signals when the recording video frame rate changes.
*/
-
/*!
- \fn QMediaRecorder::error(QMediaRecorder::Error error)
+ Sets the video \a frameRate.
- Signals that an \a error has occurred.
+ 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.
*/
+void QMediaRecorder::setVideoFrameRate(qreal frameRate)
+{
+ Q_D(QMediaRecorder);
+ if (d->encoderSettings.videoFrameRate() == frameRate)
+ return;
+ d->encoderSettings.setVideoFrameRate(frameRate);
+ emit videoFrameRateChanged();
+}
/*!
- \fn QMediaRecorder::availabilityChanged(bool available)
-
- Signals that the media recorder is now available (if \a available is true), or not.
+ \qmlproperty int QtMultimedia::MediaRecorder::videoBitRate
+ \since 6.6
+ \brief This property holds the bit rate of the compressed video stream in bits per second.
*/
/*!
- \fn QMediaRecorder::availabilityChanged(QMultimedia::AvailabilityStatus availability)
-
- Signals that the service availability has changed to \a availability.
+ Returns the bit rate of the compressed video stream in bits per second.
*/
+int QMediaRecorder::videoBitRate() const
+{
+ Q_D(const QMediaRecorder);
+ return d->encoderSettings.videoBitRate();
+}
/*!
- \fn QMediaRecorder::mutedChanged(bool muted)
+ \fn void QMediaRecorder::videoBitRateChanged()
- Signals that the \a muted state has changed. If true the recording is being muted.
+ Signals when the recording video bit rate changes.
*/
-
/*!
- \property QMediaRecorder::metaDataAvailable
- \brief whether access to a media object's meta-data is available.
+ Sets the video \a bitRate in bits per second.
+*/
+void QMediaRecorder::setVideoBitRate(int bitRate)
+{
+ Q_D(QMediaRecorder);
+ if (d->encoderSettings.videoBitRate() == bitRate)
+ return;
+ d->encoderSettings.setVideoBitRate(bitRate);
+ emit videoBitRateChanged();
+}
- If this is true there is meta-data available, otherwise there is no meta-data available.
+/*!
+ \qmlproperty int QtMultimedia::MediaRecorder::audioBitRate
+ \since 6.6
+ \brief This property holds the bit rate of the compressed audio stream in bits per second.
*/
-bool QMediaRecorder::isMetaDataAvailable() const
+/*!
+ Returns the bit rate of the compressed audio stream in bits per second.
+*/
+int QMediaRecorder::audioBitRate() const
{
Q_D(const QMediaRecorder);
-
- return d->metaDataControl
- ? d->metaDataControl->isMetaDataAvailable()
- : false;
+ return d->encoderSettings.audioBitRate();
}
/*!
- \fn QMediaRecorder::metaDataAvailableChanged(bool available)
+ \fn void QMediaRecorder::audioBitRateChanged()
- Signals that the \a available state of a media object's meta-data has changed.
+ Signals when the recording audio bit rate changes.
*/
-
/*!
- \property QMediaRecorder::metaDataWritable
- \brief whether a media object's meta-data is writable.
-
- If this is true the meta-data is writable, otherwise the meta-data is read-only.
+ Sets the audio \a bitRate in bits per second.
*/
-
-bool QMediaRecorder::isMetaDataWritable() const
+void QMediaRecorder::setAudioBitRate(int bitRate)
{
- Q_D(const QMediaRecorder);
-
- return d->metaDataControl
- ? d->metaDataControl->isWritable()
- : false;
+ Q_D(QMediaRecorder);
+ if (d->encoderSettings.audioBitRate() == bitRate)
+ return;
+ d->encoderSettings.setAudioBitRate(bitRate);
+ emit audioBitRateChanged();
}
/*!
- \fn QMediaRecorder::metaDataWritableChanged(bool writable)
-
- Signals that the \a writable state of a media object's meta-data has changed.
+ \qmlproperty int QtMultimedia::MediaRecorder::audioChannelCount
+ \since 6.6
+ \brief This property holds the number of audio channels.
*/
/*!
- Returns the value associated with a meta-data \a key.
+ Returns the number of audio channels.
*/
-QVariant QMediaRecorder::metaData(const QString &key) const
+int QMediaRecorder::audioChannelCount() const
{
Q_D(const QMediaRecorder);
-
- return d->metaDataControl
- ? d->metaDataControl->metaData(key)
- : QVariant();
+ return d->encoderSettings.audioChannelCount();
}
/*!
- Sets a \a value for a meta-data \a key.
+ \fn void QMediaRecorder::audioChannelCountChanged()
- \note To ensure that meta data is set corretly, it should be set before starting the recording.
- Once the recording is stopped, any meta data set will be attached to the next recording.
+ Signals when the recording audio channel count changes.
*/
-void QMediaRecorder::setMetaData(const QString &key, const QVariant &value)
+/*!
+ Sets the number of audio \a channels.
+
+ A value of -1 indicates the recorder should make an optimal choice based on
+ what is available from the audio source and the limitations of the codec.
+*/
+void QMediaRecorder::setAudioChannelCount(int channels)
{
Q_D(QMediaRecorder);
-
- if (d->metaDataControl)
- d->metaDataControl->setMetaData(key, value);
+ if (d->encoderSettings.audioChannelCount() == channels)
+ return;
+ d->encoderSettings.setAudioChannelCount(channels);
+ emit audioChannelCountChanged();
}
/*!
- Returns a list of keys there is meta-data available for.
+ \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.
*/
-QStringList QMediaRecorder::availableMetaData() const
+int QMediaRecorder::audioSampleRate() const
{
Q_D(const QMediaRecorder);
-
- return d->metaDataControl
- ? d->metaDataControl->availableMetaData()
- : QStringList();
+ return d->encoderSettings.audioSampleRate();
}
-
/*!
- \fn QMediaRecorder::metaDataChanged()
+ \fn void QMediaRecorder::audioSampleRateChanged()
- Signals that a media object's meta-data has changed.
-
- If multiple meta-data elements are changed,
- metaDataChanged(const QString &key, const QVariant &value) signal is emitted
- for each of them with metaDataChanged() changed emitted once.
+ Signals when the recording audio sample rate changes.
*/
-
/*!
- \fn QMediaRecorder::metaDataChanged(const QString &key, const QVariant &value)
+ Sets the audio \a sampleRate in Hz.
- Signal the changes of one meta-data element \a value with the given \a key.
+ A value of \c -1 indicates the recorder should make an optimal choice based
+ on what is available from the audio source, and the limitations of the codec.
*/
+void QMediaRecorder::setAudioSampleRate(int sampleRate)
+{
+ Q_D(QMediaRecorder);
+ if (d->encoderSettings.audioSampleRate() == sampleRate)
+ return;
+ d->encoderSettings.setAudioSampleRate(sampleRate);
+ emit audioSampleRateChanged();
+}
QT_END_NAMESPACE
diff --git a/src/multimedia/recording/qmediarecorder.h b/src/multimedia/recording/qmediarecorder.h
index 0fdcf80e4..a73d9f8af 100644
--- a/src/multimedia/recording/qmediarecorder.h
+++ b/src/multimedia/recording/qmediarecorder.h
@@ -1,50 +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$
-**
-****************************************************************************/
-
-#ifndef QMEDIARECORDER_H
-#define QMEDIARECORDER_H
-
-#include <QtMultimedia/qmultimedia.h>
-#include <QtMultimedia/qmediaobject.h>
-#include <QtMultimedia/qmediaencodersettings.h>
-#include <QtMultimedia/qmediabindableinterface.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
+
+#ifndef QMediaRecorder_H
+#define QMediaRecorder_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qsize.h>
+#include <QtMultimedia/qtmultimediaglobal.h>
#include <QtMultimedia/qmediaenumdebug.h>
+#include <QtMultimedia/qmediametadata.h>
#include <QtCore/qpair.h>
@@ -53,171 +17,168 @@ QT_BEGIN_NAMESPACE
class QUrl;
class QSize;
class QAudioFormat;
-QT_END_NAMESPACE
-
-QT_BEGIN_NAMESPACE
-
-class QMediaRecorderService;
-class QAudioEncoderSettings;
-class QVideoEncoderSettings;
+class QCamera;
+class QCameraDevice;
+class QMediaFormat;
+class QAudioDevice;
+class QMediaCaptureSession;
+class QPlatformMediaRecorder;
class QMediaRecorderPrivate;
-class Q_MULTIMEDIA_EXPORT QMediaRecorder : public QObject, public QMediaBindableInterface
+class Q_MULTIMEDIA_EXPORT QMediaRecorder : public QObject
{
Q_OBJECT
- Q_INTERFACES(QMediaBindableInterface)
- Q_ENUMS(State)
- Q_ENUMS(Status)
- Q_ENUMS(Error)
- Q_PROPERTY(QMediaRecorder::State state READ state NOTIFY stateChanged)
- Q_PROPERTY(QMediaRecorder::Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(QMediaRecorder::RecorderState recorderState READ recorderState NOTIFY recorderStateChanged)
Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged)
Q_PROPERTY(QUrl outputLocation READ outputLocation WRITE setOutputLocation)
Q_PROPERTY(QUrl actualLocation READ actualLocation NOTIFY actualLocationChanged)
- Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
- Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged)
- Q_PROPERTY(bool metaDataAvailable READ isMetaDataAvailable NOTIFY metaDataAvailableChanged)
- Q_PROPERTY(bool metaDataWritable READ isMetaDataWritable NOTIFY metaDataWritableChanged)
+ Q_PROPERTY(QMediaMetaData metaData READ metaData WRITE setMetaData NOTIFY metaDataChanged)
+ 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 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)
+ Q_PROPERTY(bool autoStop READ autoStop WRITE setAutoStop NOTIFY autoStopChanged)
public:
+ enum Quality
+ {
+ VeryLowQuality,
+ LowQuality,
+ NormalQuality,
+ HighQuality,
+ VeryHighQuality
+ };
+ Q_ENUM(Quality)
- enum State
+ enum EncodingMode
+ {
+ ConstantQualityEncoding,
+ ConstantBitRateEncoding,
+ AverageBitRateEncoding,
+ TwoPassEncoding
+ };
+ Q_ENUM(EncodingMode)
+
+ enum RecorderState
{
StoppedState,
RecordingState,
PausedState
};
-
- enum Status {
- UnavailableStatus,
- UnloadedStatus,
- LoadingStatus,
- LoadedStatus,
- StartingStatus,
- RecordingStatus,
- PausedStatus,
- FinalizingStatus
- };
+ Q_ENUM(RecorderState)
enum Error
{
NoError,
ResourceError,
FormatError,
- OutOfSpaceError
+ OutOfSpaceError,
+ LocationNotWritable
};
+ Q_ENUM(Error)
- explicit QMediaRecorder(QMediaObject *mediaObject, QObject *parent = nullptr);
+ QMediaRecorder(QObject *parent = nullptr);
~QMediaRecorder();
- QMediaObject *mediaObject() const override;
-
bool isAvailable() const;
- QMultimedia::AvailabilityStatus availability() const;
QUrl outputLocation() const;
- bool setOutputLocation(const QUrl &location);
+ void setOutputLocation(const QUrl &location);
+
+ void setOutputDevice(QIODevice *device);
+ QIODevice *outputDevice() const;
QUrl actualLocation() const;
- State state() const;
- Status status() const;
+ RecorderState recorderState() const;
Error error() const;
QString errorString() const;
qint64 duration() const;
- bool isMuted() const;
- qreal volume() const;
+ QMediaFormat mediaFormat() const;
+ void setMediaFormat(const QMediaFormat &format);
- QStringList supportedContainers() const;
- QString containerDescription(const QString &format) const;
+ EncodingMode encodingMode() const;
+ void setEncodingMode(EncodingMode);
- QStringList supportedAudioCodecs() const;
- QString audioCodecDescription(const QString &codecName) const;
+ Quality quality() const;
+ void setQuality(Quality quality);
- QList<int> supportedAudioSampleRates(const QAudioEncoderSettings &settings = QAudioEncoderSettings(),
- bool *continuous = nullptr) const;
+ QSize videoResolution() const;
+ void setVideoResolution(const QSize &);
+ void setVideoResolution(int width, int height) { setVideoResolution(QSize(width, height)); }
- QStringList supportedVideoCodecs() const;
- QString videoCodecDescription(const QString &codecName) const;
+ qreal videoFrameRate() const;
+ void setVideoFrameRate(qreal frameRate);
- QList<QSize> supportedResolutions(const QVideoEncoderSettings &settings = QVideoEncoderSettings(),
- bool *continuous = nullptr) const;
+ int videoBitRate() const;
+ void setVideoBitRate(int bitRate);
- QList<qreal> supportedFrameRates(const QVideoEncoderSettings &settings = QVideoEncoderSettings(),
- bool *continuous = nullptr) const;
+ int audioBitRate() const;
+ void setAudioBitRate(int bitRate);
- QAudioEncoderSettings audioSettings() const;
- QVideoEncoderSettings videoSettings() const;
- QString containerFormat() const;
+ int audioChannelCount() const;
+ void setAudioChannelCount(int channels);
- void setAudioSettings(const QAudioEncoderSettings &audioSettings);
- void setVideoSettings(const QVideoEncoderSettings &videoSettings);
- void setContainerFormat(const QString &container);
+ int audioSampleRate() const;
+ void setAudioSampleRate(int sampleRate);
- void setEncodingSettings(const QAudioEncoderSettings &audioSettings,
- const QVideoEncoderSettings &videoSettings = QVideoEncoderSettings(),
- const QString &containerMimeType = QString());
+ QMediaMetaData metaData() const;
+ void setMetaData(const QMediaMetaData &metaData);
+ void addMetaData(const QMediaMetaData &metaData);
- bool isMetaDataAvailable() const;
- bool isMetaDataWritable() const;
+ bool autoStop() const;
+ void setAutoStop(bool autoStop);
- QVariant metaData(const QString &key) const;
- void setMetaData(const QString &key, const QVariant &value);
- QStringList availableMetaData() const;
+ QMediaCaptureSession *captureSession() const;
+ QPlatformMediaRecorder *platformRecoder() const;
public Q_SLOTS:
void record();
void pause();
void stop();
- void setMuted(bool muted);
- void setVolume(qreal volume);
Q_SIGNALS:
- void stateChanged(QMediaRecorder::State state);
- void statusChanged(QMediaRecorder::Status status);
+ void recorderStateChanged(RecorderState state);
void durationChanged(qint64 duration);
- void mutedChanged(bool muted);
- void volumeChanged(qreal volume);
void actualLocationChanged(const QUrl &location);
+ void encoderSettingsChanged();
- void error(QMediaRecorder::Error error);
+ void errorOccurred(Error error, const QString &errorString);
+ void errorChanged();
- void metaDataAvailableChanged(bool available);
- void metaDataWritableChanged(bool writable);
void metaDataChanged();
- void metaDataChanged(const QString &key, const QVariant &value);
- void availabilityChanged(bool available);
- void availabilityChanged(QMultimedia::AvailabilityStatus availability);
+ void mediaFormatChanged();
+ void encodingModeChanged();
+ void qualityChanged();
+ void videoResolutionChanged();
+ void videoFrameRateChanged();
+ void videoBitRateChanged();
+ void audioBitRateChanged();
+ void audioChannelCountChanged();
+ void audioSampleRateChanged();
+ void autoStopChanged();
-protected:
- QMediaRecorder(QMediaRecorderPrivate &dd, QMediaObject *mediaObject, QObject *parent = nullptr);
- bool setMediaObject(QMediaObject *object) override;
-
- QMediaRecorderPrivate *d_ptr;
private:
+ QMediaRecorderPrivate *d_ptr;
+ friend class QMediaCaptureSession;
+ void setCaptureSession(QMediaCaptureSession *session);
Q_DISABLE_COPY(QMediaRecorder)
Q_DECLARE_PRIVATE(QMediaRecorder)
- Q_PRIVATE_SLOT(d_func(), void _q_stateChanged(QMediaRecorder::State))
- Q_PRIVATE_SLOT(d_func(), void _q_error(int, const QString &))
- Q_PRIVATE_SLOT(d_func(), void _q_serviceDestroyed())
- Q_PRIVATE_SLOT(d_func(), void _q_notify())
- Q_PRIVATE_SLOT(d_func(), void _q_updateActualLocation(const QUrl &))
- Q_PRIVATE_SLOT(d_func(), void _q_updateNotifyInterval(int))
- Q_PRIVATE_SLOT(d_func(), void _q_applySettings())
- Q_PRIVATE_SLOT(d_func(), void _q_availabilityChanged(QMultimedia::AvailabilityStatus))
};
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QMediaRecorder::State)
-Q_DECLARE_METATYPE(QMediaRecorder::Status)
-Q_DECLARE_METATYPE(QMediaRecorder::Error)
-
-Q_MEDIA_ENUM_DEBUG(QMediaRecorder, State)
-Q_MEDIA_ENUM_DEBUG(QMediaRecorder, Status)
+Q_MEDIA_ENUM_DEBUG(QMediaRecorder, RecorderState)
Q_MEDIA_ENUM_DEBUG(QMediaRecorder, Error)
-#endif // QMEDIARECORDER_H
+#endif // QMediaRecorder_H
diff --git a/src/multimedia/recording/qmediarecorder_p.h b/src/multimedia/recording/qmediarecorder_p.h
index f634d016e..896f6c368 100644
--- a/src/multimedia/recording/qmediarecorder_p.h
+++ b/src/multimedia/recording/qmediarecorder_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 QMEDIARECORDER_P_H
-#define QMEDIARECORDER_P_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
+
+#ifndef QMediaRecorder_P_H
+#define QMediaRecorder_P_H
//
// W A R N I N G
@@ -52,60 +16,39 @@
//
#include "qmediarecorder.h"
-#include "qmediaobject_p.h"
+#include "qcamera.h"
#include <QtCore/qurl.h>
+#include <QtCore/qpointer.h>
+#include "private/qplatformmediarecorder_p.h"
QT_BEGIN_NAMESPACE
-class QMediaRecorderControl;
-class QMediaContainerControl;
-class QAudioEncoderSettingsControl;
-class QVideoEncoderSettingsControl;
-class QMetaDataWriterControl;
-class QMediaAvailabilityControl;
+class QPlatformMediaRecorder;
class QTimer;
-class QMediaRecorderPrivate
+class Q_MULTIMEDIA_EXPORT QMediaRecorderPrivate
{
- Q_DECLARE_NON_CONST_PUBLIC(QMediaRecorder)
+ Q_DECLARE_PUBLIC(QMediaRecorder)
public:
QMediaRecorderPrivate();
- virtual ~QMediaRecorderPrivate() {}
-
- void applySettingsLater();
- void restartCamera();
-
- QMediaObject *mediaObject;
- QMediaRecorderControl *control;
- QMediaContainerControl *formatControl;
- QAudioEncoderSettingsControl *audioControl;
- QVideoEncoderSettingsControl *videoControl;
- QMetaDataWriterControl *metaDataControl;
- QMediaAvailabilityControl *availabilityControl;
+ static QString msgFailedStartRecording();
- bool settingsChanged;
+ QMediaCaptureSession *captureSession = nullptr;
+ QPlatformMediaRecorder *control = nullptr;
+ QString initErrorMessage;
+ bool autoStop = false;
- QTimer* notifyTimer;
+ bool settingsChanged = false;
- QMediaRecorder::State state;
- QMediaRecorder::Error error;
- QString errorString;
- QUrl actualLocation;
+ QMediaEncoderSettings encoderSettings;
- void _q_stateChanged(QMediaRecorder::State state);
- void _q_error(int error, const QString &errorString);
- void _q_serviceDestroyed();
- void _q_updateActualLocation(const QUrl &);
- void _q_notify();
- void _q_updateNotifyInterval(int ms);
- void _q_applySettings();
- void _q_availabilityChanged(QMultimedia::AvailabilityStatus availability);
-
- QMediaRecorder *q_ptr;
+ QMediaRecorder *q_ptr = nullptr;
};
+#undef Q_DECLARE_NON_CONST_PUBLIC
+
QT_END_NAMESPACE
#endif
diff --git a/src/multimedia/recording/qscreencapture-limitations.qdocinc b/src/multimedia/recording/qscreencapture-limitations.qdocinc
new file mode 100644
index 000000000..240a1a389
--- /dev/null
+++ b/src/multimedia/recording/qscreencapture-limitations.qdocinc
@@ -0,0 +1,25 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ //! [content]
+ \section1 Screen Capture Limitations
+ On Qt 6.5.2 and above, the following limitations apply to using \1ScreenCapture:
+ \list
+ \li It is only supported with the FFmpeg backend.
+ \li It is unsupported on Linux with Wayland compositor, due to Wayland
+ protocol restrictions and limitations.
+ \li It is not supported on mobile operating systems, except on Android.
+ There, you might run into performance issues as the class is currently
+ implemented via QScreen::grabWindow, which is not optimal for the use case.
+ \li On embedded with EGLFS, it has limited functionality. For Qt Quick
+ applications, the class is currently implemented via
+ QQuickWindow::grabWindow, which can cause performance issues.
+ \li In most cases, we set a screen capture frame rate that equals the screen
+ refresh rate, except on Windows, where the rate might be flexible.
+ Such a frame rate (75/120 FPS) might cause performance issues on weak
+ CPUs if the captured screen is of 4K resolution. On EGLFS, the capture
+ frame rate is currently locked to 30 FPS.
+ \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/qvideoframeinput.cpp b/src/multimedia/recording/qvideoframeinput.cpp
new file mode 100644
index 000000000..99500bb65
--- /dev/null
+++ b/src/multimedia/recording/qvideoframeinput.cpp
@@ -0,0 +1,181 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qvideoframeinput.h"
+#include "qmediaframeinput_p.h"
+#include "qmediainputencoderinterface_p.h"
+#include "qplatformvideoframeinput_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QVideoFrameInputPrivate : public QMediaFrameInputPrivate
+{
+public:
+ QVideoFrameInputPrivate(QVideoFrameInput *q) : q(q) { }
+
+ bool sendVideoFrame(const QVideoFrame &frame)
+ {
+ return sendMediaFrame([&]() { emit m_platfromVideoFrameInput->newVideoFrame(frame); });
+ }
+
+ void initialize(QVideoFrameFormat format = {})
+ {
+ m_platfromVideoFrameInput = std::make_unique<QPlatformVideoFrameInput>(std::move(format));
+ addUpdateSignal(m_platfromVideoFrameInput.get(), &QPlatformVideoFrameInput::encoderUpdated);
+ }
+
+ void uninitialize()
+ {
+ m_platfromVideoFrameInput.reset();
+
+ if (captureSession())
+ captureSession()->setVideoFrameInput(nullptr);
+ }
+
+ QPlatformVideoFrameInput *platfromVideoFrameInput() const
+ {
+ return m_platfromVideoFrameInput.get();
+ }
+
+protected:
+ void updateCaptureSessionConnections(QMediaCaptureSession *prevSession,
+ QMediaCaptureSession *newSession) override
+ {
+ if (prevSession)
+ removeUpdateSignal(prevSession, &QMediaCaptureSession::videoOutputChanged);
+
+ if (newSession)
+ addUpdateSignal(newSession, &QMediaCaptureSession::videoOutputChanged);
+ }
+
+ bool checkIfCanSendMediaFrame() const override
+ {
+ if (auto encoderInterface = m_platfromVideoFrameInput->encoderInterface())
+ return encoderInterface->canPushFrame();
+
+ return captureSession()->videoOutput() || captureSession()->videoSink();
+ }
+
+ void emitReadyToSendMediaFrame() override { emit q->readyToSendVideoFrame(); }
+
+private:
+ QVideoFrameInput *q = nullptr;
+ std::unique_ptr<QPlatformVideoFrameInput> m_platfromVideoFrameInput;
+};
+
+/*!
+ \class QVideoFrameInput
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \ingroup multimedia_video
+ \since 6.8
+
+ \brief The QVideoFrameInput class is used for providing custom video frames
+ to \l QMediaRecorder or a video output through \l QMediaCaptureSession.
+
+ \sa QMediaRecorder, QMediaCaptureSession, QVideoSink
+*/
+
+/*!
+ Constructs a new QVideoFrameInput object with \a parent.
+*/
+QVideoFrameInput::QVideoFrameInput(QObject *parent) : QVideoFrameInput({}, parent) { }
+
+/*!
+ Constructs a new QVideoFrameInput object with video frame \a format and \a parent.
+
+ The specified \a format will work as a hint for the initialization of the matching
+ video encoder upon invoking \l QMediaRecorder::record().
+ If the format is not specified or not valid, the video encoder will be initialized
+ upon sending the first frame.
+ Sending of video frames with another pixel format and size after initialization
+ of the matching video encoder might cause a performance penalty during recording.
+
+ We recommend specifying the format if you know in advance what kind of frames you're
+ going to send.
+*/
+QVideoFrameInput::QVideoFrameInput(const QVideoFrameFormat &format, QObject *parent)
+ : QObject(*new QVideoFrameInputPrivate(this), parent)
+{
+ Q_D(QVideoFrameInput);
+ d->initialize(format);
+}
+
+/*!
+ Destroys the object.
+ */
+QVideoFrameInput::~QVideoFrameInput()
+{
+ Q_D(QVideoFrameInput);
+ d->uninitialize();
+}
+
+/*!
+ Sends \l QVideoFrame to \l QMediaRecorder or a video output
+ through \l QMediaCaptureSession.
+
+ Returns \c true if the specified \a frame has been sent successfully
+ to the destination. Returns \c false, if the frame hasn't been sent,
+ which can happen if the instance is not assigned to
+ \l QMediaCaptureSession, the session doesn't have video outputs or
+ a media recorder, the media recorder is not started or its queue is full.
+ The signal \l readyToSendVideoFrame will be sent as soon as
+ the destination is able to handle a new frame.
+
+ Sending of an empty video frame is treated by \l QMediaRecorder
+ as an end of the input stream. QMediaRecorder stops the recording
+ automatically if \l QMediaRecorder::autoStop is \c true and
+ all the inputs have reported the end of the stream.
+*/
+bool QVideoFrameInput::sendVideoFrame(const QVideoFrame &frame)
+{
+ Q_D(QVideoFrameInput);
+ return d->sendVideoFrame(frame);
+}
+
+/*!
+ Returns the video frame format that was specified
+ upon construction of the video frame input.
+*/
+QVideoFrameFormat QVideoFrameInput::format() const
+{
+ Q_D(const QVideoFrameInput);
+ return d->platfromVideoFrameInput()->frameFormat();
+}
+
+/*!
+ Returns the capture session this video frame input is connected to, or
+ a \c nullptr if the video frame input is not connected to a capture session.
+
+ Use QMediaCaptureSession::setVideoFrameInput() to connect
+ the video frame input to a session.
+*/
+QMediaCaptureSession *QVideoFrameInput::captureSession() const
+{
+ Q_D(const QVideoFrameInput);
+ return d->captureSession();
+}
+
+void QVideoFrameInput::setCaptureSession(QMediaCaptureSession *captureSession)
+{
+ Q_D(QVideoFrameInput);
+ d->setCaptureSession(captureSession);
+}
+
+QPlatformVideoFrameInput *QVideoFrameInput::platformVideoFrameInput() const
+{
+ Q_D(const QVideoFrameInput);
+ return d->platfromVideoFrameInput();
+}
+
+/*!
+ \fn void QVideoFrameInput::readyToSendVideoFrame()
+
+ Signals that a new frame can be sent to the video frame input.
+ After receiving the signal, if you have frames to be sent, invoke \l sendVideoFrame
+ once or in a loop until it returns \c false.
+
+ \sa sendVideoFrame()
+*/
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/recording/qvideoframeinput.h b/src/multimedia/recording/qvideoframeinput.h
new file mode 100644
index 000000000..fbe56b7db
--- /dev/null
+++ b/src/multimedia/recording/qvideoframeinput.h
@@ -0,0 +1,48 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QVIDEOFRAMEINPUT_H
+#define QVIDEOFRAMEINPUT_H
+
+#include <QtMultimedia/qtmultimediaexports.h>
+#include <QtMultimedia/qvideoframe.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPlatformVideoFrameInput;
+class QVideoFrameInputPrivate;
+class QMediaCaptureSession;
+
+class Q_MULTIMEDIA_EXPORT QVideoFrameInput : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QVideoFrameInput(QObject *parent = nullptr);
+
+ explicit QVideoFrameInput(const QVideoFrameFormat &format, QObject *parent = nullptr);
+
+ ~QVideoFrameInput() override;
+
+ bool sendVideoFrame(const QVideoFrame &frame);
+
+ QVideoFrameFormat format() const;
+
+ QMediaCaptureSession *captureSession() const;
+
+Q_SIGNALS:
+ void readyToSendVideoFrame();
+
+private:
+ void setCaptureSession(QMediaCaptureSession *captureSession);
+
+ QPlatformVideoFrameInput *platformVideoFrameInput() const;
+
+ friend class QMediaCaptureSession;
+ Q_DISABLE_COPY(QVideoFrameInput)
+ Q_DECLARE_PRIVATE(QVideoFrameInput)
+};
+
+QT_END_NAMESPACE
+
+#endif // QVIDEOFRAMEINPUT_H
diff --git a/src/multimedia/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/recording/recording.pri b/src/multimedia/recording/recording.pri
deleted file mode 100644
index 20ed99e04..000000000
--- a/src/multimedia/recording/recording.pri
+++ /dev/null
@@ -1,14 +0,0 @@
-INCLUDEPATH += recording
-
-PUBLIC_HEADERS += \
- recording/qaudiorecorder.h \
- recording/qmediaencodersettings.h \
- recording/qmediarecorder.h \
-
-PRIVATE_HEADERS += \
- recording/qmediarecorder_p.h \
-
-SOURCES += \
- recording/qaudiorecorder.cpp \
- recording/qmediaencodersettings.cpp \
- recording/qmediarecorder.cpp
diff --git a/src/multimedia/shaders/abgr.frag b/src/multimedia/shaders/abgr.frag
new file mode 100644
index 000000000..7eadb092d
--- /dev/null
+++ b/src/multimedia/shaders/abgr.frag
@@ -0,0 +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(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
new file mode 100644
index 000000000..1adbc8dba
--- /dev/null
+++ b/src/multimedia/shaders/argb.frag
@@ -0,0 +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(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
new file mode 100644
index 000000000..92c3f71fe
--- /dev/null
+++ b/src/multimedia/shaders/ayuv.frag
@@ -0,0 +1,25 @@
+#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;
+
+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
new file mode 100644
index 000000000..0ba0e4c9e
--- /dev/null
+++ b/src/multimedia/shaders/bgra.frag
@@ -0,0 +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(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
new file mode 100755
index 000000000..8a012d265
--- /dev/null
+++ b/src/multimedia/shaders/compile.bat
@@ -0,0 +1,16 @@
+:: Copyright (C) 2019 The Qt Company Ltd.
+:: 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 -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
+
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o nv12.frag.qsb nv12.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o nv21.frag.qsb nv21.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o uyvy.frag.qsb uyvy.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o yuyv.frag.qsb yuyv.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o ayuv.frag.qsb ayuv.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o p010be.frag.qsb p010be.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o p010be.frag.qsb p010be.frag
diff --git a/src/multimedia/shaders/externalsampler.frag b/src/multimedia/shaders/externalsampler.frag
new file mode 100644
index 000000000..f786bc4e1
--- /dev/null
+++ b/src/multimedia/shaders/externalsampler.frag
@@ -0,0 +1,14 @@
+#version 440
+#extension GL_GOOGLE_include_directive : enable
+
+#include "uniformbuffer.glsl"
+
+layout(location = 0) in vec2 texCoord;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D plane1Texture;
+
+void main()
+{
+ fragColor = vec4(1., 0., 0., 0.);
+}
diff --git a/src/multimedia/shaders/externalsampler.vert b/src/multimedia/shaders/externalsampler.vert
new file mode 100644
index 000000000..e693370dc
--- /dev/null
+++ b/src/multimedia/shaders/externalsampler.vert
@@ -0,0 +1,16 @@
+#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;
+
+out gl_PerVertex { vec4 gl_Position; };
+
+void main() {
+ texCoord = (ubuf.colorMatrix * vec4(vertexTexCoord, 0.0, 1.0)).xy;
+ gl_Position = ubuf.matrix * vertexPosition;
+}
diff --git a/src/multimedia/shaders/externalsampler_gles.frag b/src/multimedia/shaders/externalsampler_gles.frag
new file mode 100644
index 000000000..1292acebc
--- /dev/null
+++ b/src/multimedia/shaders/externalsampler_gles.frag
@@ -0,0 +1,28 @@
+#extension GL_OES_EGL_image_external : require
+precision highp float;
+precision highp int;
+
+struct buf
+{
+ mat4 matrix;
+ mat4 colorMatrix;
+ float opacity;
+ float width;
+ float masteringWhite;
+ float maxLum;
+};
+
+uniform buf ubuf;
+
+uniform samplerExternalOES plane1Texture;
+
+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
new file mode 100644
index 000000000..18401d420
--- /dev/null
+++ b/src/multimedia/shaders/imc2.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;
+
+void main()
+{
+ float Y = texture(plane1Texture, texCoord).r;
+ float x = texCoord.x/2.;
+ 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
new file mode 100644
index 000000000..574a5f49b
--- /dev/null
+++ b/src/multimedia/shaders/imc4.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;
+
+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;
+ 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
new file mode 100644
index 000000000..20399d9f0
--- /dev/null
+++ b/src/multimedia/shaders/nv12.frag
@@ -0,0 +1,27 @@
+#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;
+
+void main()
+{
+ float Y = texture(plane1Texture, texCoord).r;
+ 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
new file mode 100644
index 000000000..c3f641be5
--- /dev/null
+++ b/src/multimedia/shaders/nv21.frag
@@ -0,0 +1,27 @@
+#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;
+
+void main()
+{
+ float Y = texture(plane1Texture, texCoord).r;
+ 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
new file mode 100644
index 000000000..e693370dc
--- /dev/null
+++ b/src/multimedia/shaders/rectsampler.vert
@@ -0,0 +1,16 @@
+#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;
+
+out gl_PerVertex { vec4 gl_Position; };
+
+void main() {
+ texCoord = (ubuf.colorMatrix * vec4(vertexTexCoord, 0.0, 1.0)).xy;
+ gl_Position = ubuf.matrix * vertexPosition;
+}
diff --git a/src/multimedia/shaders/rectsampler_bgra.frag b/src/multimedia/shaders/rectsampler_bgra.frag
new file mode 100644
index 000000000..8b1b9a4ad
--- /dev/null
+++ b/src/multimedia/shaders/rectsampler_bgra.frag
@@ -0,0 +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(binding = 1) uniform sampler2DRect rgbTexture;
+
+void main()
+{
+ 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
new file mode 100644
index 000000000..b53e0dc71
--- /dev/null
+++ b/src/multimedia/shaders/rgba.frag
@@ -0,0 +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(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
new file mode 100644
index 000000000..26a83da3f
--- /dev/null
+++ b/src/multimedia/shaders/uyvy.frag
@@ -0,0 +1,27 @@
+#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;
+
+void main()
+{
+ int x = int(floor(texCoord.x * ubuf.width));
+ bool rightSubPixel = (x/2*2 != x);
+ 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
new file mode 100644
index 000000000..ce170824e
--- /dev/null
+++ b/src/multimedia/shaders/vertex.vert
@@ -0,0 +1,16 @@
+#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;
+
+out gl_PerVertex { vec4 gl_Position; };
+
+void main() {
+ texCoord = vertexTexCoord;
+ gl_Position = ubuf.matrix * vertexPosition;
+}
diff --git a/src/multimedia/shaders/y.frag b/src/multimedia/shaders/y.frag
new file mode 100644
index 000000000..8c25fc762
--- /dev/null
+++ b/src/multimedia/shaders/y.frag
@@ -0,0 +1,25 @@
+#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;
+
+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
new file mode 100644
index 000000000..228147943
--- /dev/null
+++ b/src/multimedia/shaders/yuv_triplanar.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;
+ float U = texture(plane2Texture, texCoord).r;
+ 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
new file mode 100644
index 000000000..0f6e65b6d
--- /dev/null
+++ b/src/multimedia/shaders/yuyv.frag
@@ -0,0 +1,27 @@
+#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;
+
+void main()
+{
+ int x = int(floor(texCoord.x * ubuf.width));
+ bool rightSubPixel = (x/2*2 != x);
+ 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
new file mode 100644
index 000000000..ac2cbdf63
--- /dev/null
+++ b/src/multimedia/shaders/yvu_triplanar.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;
+ float V = texture(plane2Texture, texCoord).r;
+ 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 793241be9..7368082b1 100644
--- a/src/multimedia/video/qabstractvideobuffer.cpp
+++ b/src/multimedia/video/qabstractvideobuffer.cpp
@@ -1,397 +1,139 @@
-/****************************************************************************
-**
-** 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 "qabstractvideobuffer_p.h"
-
-#include <qvariant.h>
-
-#include <QDebug>
+// 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 "qabstractvideobuffer.h"
QT_BEGIN_NAMESPACE
-static void qRegisterAbstractVideoBufferMetaTypes()
-{
- qRegisterMetaType<QAbstractVideoBuffer::HandleType>();
- qRegisterMetaType<QAbstractVideoBuffer::MapMode>();
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterAbstractVideoBufferMetaTypes)
-
-int QAbstractVideoBufferPrivate::map(
- QAbstractVideoBuffer::MapMode mode,
- int *numBytes,
- int bytesPerLine[4],
- uchar *data[4])
-{
- data[0] = q_ptr->map(mode, numBytes, bytesPerLine);
- return data[0] ? 1 : 0;
-}
-
/*!
\class QAbstractVideoBuffer
+ \since 6.8
\brief The QAbstractVideoBuffer class is an abstraction for video data.
\inmodule QtMultimedia
\ingroup multimedia
\ingroup multimedia_video
- The QVideoFrame class makes use of a QAbstractVideoBuffer internally to reference a buffer of
- video data. Quite often video data buffers may reside in video memory rather than system
- memory, and this class provides an abstraction of the location.
-
- In addition, creating a subclass of QAbstractVideoBuffer will allow you to construct video
- frames from preallocated or static buffers, in cases where the QVideoFrame constructors
- taking a QByteArray or a QImage do not suffice. This may be necessary when implementing
- a new hardware accelerated video system, for example.
+ The \l QVideoFrame class makes use of a QAbstractVideoBuffer internally to reference a buffer of
+ video data. Creating a subclass of QAbstractVideoBuffer allows you to construct video
+ frames from preallocated or static buffers. The subclass can contain a hardware buffer,
+ and implement access to the data by mapping the buffer to CPU memory.
The contents of a buffer can be accessed by mapping the buffer to memory using the map()
- function, which returns a pointer to memory containing the contents of the video buffer.
- The memory returned by map() is released by calling the unmap() function.
-
- The handle() of a buffer may also be used to manipulate its contents using type specific APIs.
- The type of a buffer's handle is given by the handleType() function.
+ function, which returns a structure containing information about plane layout of the current
+ video data.
- \sa QVideoFrame
+ \sa QVideoFrame, QVideoFrameFormat, QtVideo::MapMode
*/
/*!
- \enum QAbstractVideoBuffer::HandleType
-
- Identifies the type of a video buffers handle.
-
- \value NoHandle The buffer has no handle, its data can only be accessed by mapping the buffer.
- \value GLTextureHandle The handle of the buffer is an OpenGL texture ID.
- \value MTLTextureHandle The handle of the buffer is an Metal texture ID.
- \value XvShmImageHandle The handle contains pointer to shared memory XVideo image.
- \value CoreImageHandle The handle contains pointer to \macos CIImage.
- \value QPixmapHandle The handle of the buffer is a QPixmap.
- \value EGLImageHandle The handle of the buffer is an EGLImageKHR.
- \value UserHandle Start value for user defined handle types.
-
- \sa handleType()
-*/
+ \class QAbstractVideoBuffer::MapData
+ \brief The QAbstractVideoBuffer::MapData structure describes the mapped plane layout.
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \ingroup multimedia_video
-/*!
- \enum QAbstractVideoBuffer::MapMode
+ The structure contains a number of mapped planes, and plane data for each plane,
+ specificly, a number of bytes per line, a data pointer, and a data size.
+ The structure doesn't hold any ownership of the data it refers to.
- Enumerates how a video buffer's data is mapped to system memory.
+ A defaultly created structure means that no data has been mapped.
- \value NotMapped The video buffer is not mapped to memory.
- \value ReadOnly The mapped memory is populated with data from the video buffer when mapped, but
- the content of the mapped memory may be discarded when unmapped.
- \value WriteOnly The mapped memory is uninitialized when mapped, but the possibly modified content
- will be used to populate the video buffer when unmapped.
- \value ReadWrite The mapped memory is populated with data from the video buffer, and the
- video buffer is repopulated with the content of the mapped memory when it is unmapped.
+ All the values in the structure default to zeros.
- \sa mapMode(), map()
+ \sa QAbstractVideoBuffer::map
*/
/*!
- Constructs an abstract video buffer of the given \a type.
-*/
-QAbstractVideoBuffer::QAbstractVideoBuffer(HandleType type)
- : d_ptr(nullptr)
- , m_type(type)
-{
-}
+ \variable QAbstractVideoBuffer::MapData::planeCount
-/*!
- \internal
-*/
-QAbstractVideoBuffer::QAbstractVideoBuffer(QAbstractVideoBufferPrivate &dd, HandleType type)
- : d_ptr(&dd)
- , m_type(type)
-{
- d_ptr->q_ptr = this;
-}
+ The number of planes of the mapped video data. If the format of the data
+ is multiplanar, and the value is \c 1, the actual plane layout will
+ be calculated upon invoking of \l QVideoFrame::map from the frame height,
+ \c{bytesPerLine[0]}, and \c{dataSize[0]}.
-/*!
- Destroys an abstract video buffer.
+ Defaults to \c 0.
*/
-QAbstractVideoBuffer::~QAbstractVideoBuffer()
-{
- delete d_ptr;
-}
/*!
- Releases the video buffer.
+ \variable QAbstractVideoBuffer::MapData::bytesPerLine
- QVideoFrame calls QAbstractVideoBuffer::release when the buffer is not used
- any more and can be destroyed or returned to the buffer pool.
+ The array of numbrers of bytes per line for each
+ plane from \c 0 to \c{planeCount - 1}.
- The default implementation deletes the buffer instance.
+ The values of the array default to \c 0.
*/
-void QAbstractVideoBuffer::release()
-{
- delete this;
-}
/*!
- Returns the type of a video buffer's handle.
+ \variable QAbstractVideoBuffer::MapData::data
- \sa handle()
-*/
-QAbstractVideoBuffer::HandleType QAbstractVideoBuffer::handleType() const
-{
- return m_type;
-}
-
-/*!
- \fn QAbstractVideoBuffer::mapMode() const
-
- Returns the mode a video buffer is mapped in.
+ The array of pointers to the mapped video pixel data
+ for each plane from \c 0 to \c{planeCount - 1}.
+ The implementation of QAbstractVideoBuffer must hold ownership of the data
+ at least until \l QAbstractVideoBuffer::unmap is called.
- \sa map()
+ The values of the array default to \c nullptr.
*/
/*!
- \fn QAbstractVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine)
-
- Maps the contents of a video buffer to memory.
-
- In some cases the video buffer might be stored in video memory or otherwise inaccessible
- memory, so it is necessary to map the buffer before accessing the pixel data. This may involve
- copying the contents around, so avoid mapping and unmapping unless required.
-
- The map \a mode indicates whether the contents of the mapped memory should be read from and/or
- written to the buffer. If the map mode includes the \c QAbstractVideoBuffer::ReadOnly flag the
- mapped memory will be populated with the content of the buffer when initially mapped. If the map
- mode includes the \c QAbstractVideoBuffer::WriteOnly flag the content of the possibly modified
- mapped memory will be written back to the buffer when unmapped.
-
- When access to the data is no longer needed be sure to call the unmap() function to release the
- mapped memory and possibly update the buffer contents.
+ \variable QAbstractVideoBuffer::MapData::dataSize
- Returns a pointer to the mapped memory region, or a null pointer if the mapping failed. The
- size in bytes of the mapped memory region is returned in \a numBytes, and the line stride in \a
- bytesPerLine.
+ The array of sizes in bytes of the mapped video pixel data
+ for each plane from \c 0 to \c{planeCount - 1}.
- \note Writing to memory that is mapped as read-only is undefined, and may result in changes
- to shared data or crashes.
-
- \sa unmap(), mapMode()
+ The values of the array default to \c 0.
*/
-
+// must be out-of-line to ensure correct working of dynamic_cast when QHwVideoBuffer is created in tests
/*!
- Independently maps the planes of a video buffer to memory.
+ Destroys a video buffer.
+*/
+QAbstractVideoBuffer::~QAbstractVideoBuffer() = default;
- The map \a mode indicates whether the contents of the mapped memory should be read from and/or
- written to the buffer. If the map mode includes the \c QAbstractVideoBuffer::ReadOnly flag the
- mapped memory will be populated with the content of the buffer when initially mapped. If the map
- mode includes the \c QAbstractVideoBuffer::WriteOnly flag the content of the possibly modified
- mapped memory will be written back to the buffer when unmapped.
+/*! \fn QAbstractVideoBuffer::MapData QAbstractVideoBuffer::map(QtVideo::MapMode mode)
- When access to the data is no longer needed be sure to call the unmap() function to release the
- mapped memory and possibly update the buffer contents.
+ Maps the planes of a video buffer to memory.
- Returns the number of planes in the mapped video data. For each plane the line stride of that
- plane will be returned in \a bytesPerLine, and a pointer to the plane data will be returned in
- \a data. The accumulative size of the mapped data is returned in \a numBytes.
+ Returns a \l MapData structure that contains information about the plane layout of
+ the mapped current video data. If the mapping fails, the method returns the default structure.
+ For CPU memory buffers, the data is considered as already mapped, so the function
+ just returns the plane layout of the preallocated underlying data.
- Not all buffer implementations will map more than the first plane, if this returns a single
- plane for a planar format the additional planes will have to be calculated from the line stride
- of the first plane and the frame height. Mapping a buffer with QVideoFrame will do this for
- you.
+ The map \a mode indicates whether the contents of the mapped memory should be read from and/or
+ written to the buffer. If the map mode includes the \c QtVideo::MapMode::WriteOnly flag,
+ the content of the possibly modified mapped memory is expected to be written back
+ to the buffer when unmapped.
- To implement this function create a derivative of QAbstractPlanarVideoBuffer and implement
- its map function instance instead.
+ When access to the data is no longer needed, the \l unmap function is called
+ to release the mapped memory and possibly update the buffer contents.
- \since 5.4
+ If the format of the video data is multiplanar, the method may map the whole pixel data
+ as a single plane. In this case, mapping a buffer with \l QVideoFrame
+ will calculate additional planes from the specified line stride of the first plane,
+ the frame height, and the data size.
*/
-int QAbstractVideoBuffer::mapPlanes(MapMode mode, int *numBytes, int bytesPerLine[4], uchar *data[4])
-{
- if (d_ptr) {
- return d_ptr->map(mode, numBytes, bytesPerLine, data);
- } else {
- data[0] = map(mode, numBytes, bytesPerLine);
-
- return data[0] ? 1 : 0;
- }
-}
/*!
\fn QAbstractVideoBuffer::unmap()
Releases the memory mapped by the map() function.
- If the \l {QAbstractVideoBuffer::MapMode}{MapMode} included the \c QAbstractVideoBuffer::WriteOnly
+ If the \l {QtVideo::MapMode}{MapMode} included the \c QtVideo::MapMode::WriteOnly
flag this will write the current content of the mapped memory back to the video frame.
- \sa map()
-*/
-
-/*!
- Returns a type specific handle to the data buffer.
-
- The type of the handle is given by handleType() function.
-
- \sa handleType()
-*/
-QVariant QAbstractVideoBuffer::handle() const
-{
- return QVariant();
-}
-
-
-int QAbstractPlanarVideoBufferPrivate::map(
- QAbstractVideoBuffer::MapMode mode, int *numBytes, int bytesPerLine[4], uchar *data[4])
-{
- return q_func()->map(mode, numBytes, bytesPerLine, data);
-}
-
-/*!
- \class QAbstractPlanarVideoBuffer
- \brief The QAbstractPlanarVideoBuffer class is an abstraction for planar video data.
- \inmodule QtMultimedia
- \ingroup QtMultimedia
- \ingroup multimedia
- \ingroup multimedia_video
-
- QAbstractPlanarVideoBuffer extends QAbstractVideoBuffer to support mapping
- non-continuous planar video data. Implement this instead of QAbstractVideoBuffer when the
- abstracted video data stores planes in separate buffers or includes padding between planes
- which would interfere with calculating offsets from the bytes per line and frame height.
-
- \sa QAbstractVideoBuffer::mapPlanes()
- \since 5.4
-*/
-
-/*!
- Constructs an abstract planar video buffer of the given \a type.
-*/
-QAbstractPlanarVideoBuffer::QAbstractPlanarVideoBuffer(HandleType type)
- : QAbstractVideoBuffer(*new QAbstractPlanarVideoBufferPrivate, type)
-{
-}
-
-/*!
- \internal
-*/
-QAbstractPlanarVideoBuffer::QAbstractPlanarVideoBuffer(
- QAbstractPlanarVideoBufferPrivate &dd, HandleType type)
- : QAbstractVideoBuffer(dd, type)
-{
-}
-/*!
- Destroys an abstract planar video buffer.
-*/
-QAbstractPlanarVideoBuffer::~QAbstractPlanarVideoBuffer()
-{
-}
+ For CPU video buffers, the function may be not overridden.
+ The default implementation of \c unmap does nothing.
-/*!
- \internal
+ \sa map()
*/
-uchar *QAbstractPlanarVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine)
-{
- uchar *data[4];
- int strides[4];
- if (map(mode, numBytes, strides, data) > 0) {
- if (bytesPerLine)
- *bytesPerLine = strides[0];
- return data[0];
- } else {
- return nullptr;
- }
-}
/*!
- \fn int QAbstractPlanarVideoBuffer::map(MapMode mode, int *numBytes, int bytesPerLine[4], uchar *data[4])
-
- Maps the contents of a video buffer to memory.
+ \fn QAbstractVideoBuffer::format() const
- The map \a mode indicates whether the contents of the mapped memory should be read from and/or
- written to the buffer. If the map mode includes the \c QAbstractVideoBuffer::ReadOnly flag the
- mapped memory will be populated with the content of the buffer when initially mapped. If the map
- mode includes the \c QAbstractVideoBuffer::WriteOnly flag the content of the possibly modified
- mapped memory will be written back to the buffer when unmapped.
-
- When access to the data is no longer needed be sure to call the unmap() function to release the
- mapped memory and possibly update the buffer contents.
+ Gets \l QVideoFrameFormat of the underlying video buffer.
- Returns the number of planes in the mapped video data. For each plane the line stride of that
- plane will be returned in \a bytesPerLine, and a pointer to the plane data will be returned in
- \a data. The accumulative size of the mapped data is returned in \a numBytes.
-
- \sa QAbstractVideoBuffer::map(), QAbstractVideoBuffer::unmap(), QAbstractVideoBuffer::mapMode()
+ The format must be available upon construction of \l QVideoFrame.
+ QVideoFrame will contain won instance of the given format, that
+ can be detached and modified.
*/
-#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug dbg, QAbstractVideoBuffer::HandleType type)
-{
- QDebugStateSaver saver(dbg);
- dbg.nospace();
- switch (type) {
- case QAbstractVideoBuffer::NoHandle:
- return dbg << "NoHandle";
- case QAbstractVideoBuffer::GLTextureHandle:
- return dbg << "GLTextureHandle";
- case QAbstractVideoBuffer::MTLTextureHandle:
- return dbg << "MTLTextureHandle";
- case QAbstractVideoBuffer::XvShmImageHandle:
- return dbg << "XvShmImageHandle";
- case QAbstractVideoBuffer::CoreImageHandle:
- return dbg << "CoreImageHandle";
- case QAbstractVideoBuffer::QPixmapHandle:
- return dbg << "QPixmapHandle";
- default:
- return dbg << "UserHandle(" << int(type) << ')';
- }
-}
-
-QDebug operator<<(QDebug dbg, QAbstractVideoBuffer::MapMode mode)
-{
- QDebugStateSaver saver(dbg);
- dbg.nospace();
- switch (mode) {
- case QAbstractVideoBuffer::ReadOnly:
- return dbg << "ReadOnly";
- case QAbstractVideoBuffer::ReadWrite:
- return dbg << "ReadWrite";
- case QAbstractVideoBuffer::WriteOnly:
- return dbg << "WriteOnly";
- default:
- return dbg << "NotMapped";
- }
-}
-#endif
-
QT_END_NAMESPACE
diff --git a/src/multimedia/video/qabstractvideobuffer.h b/src/multimedia/video/qabstractvideobuffer.h
index b3f31b377..3e046f3b4 100644
--- a/src/multimedia/video/qabstractvideobuffer.h
+++ b/src/multimedia/video/qabstractvideobuffer.h
@@ -1,131 +1,32 @@
-/****************************************************************************
-**
-** 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
#ifndef QABSTRACTVIDEOBUFFER_H
#define QABSTRACTVIDEOBUFFER_H
-#include <QtMultimedia/qtmultimediaglobal.h>
-#include <QtMultimedia/qmultimedia.h>
-
-
-#include <QtCore/qmetatype.h>
+#include <QtMultimedia/qtmultimediaexports.h>
+#include <QtMultimedia/qvideoframeformat.h>
+#include <QtMultimedia/qtvideo.h>
QT_BEGIN_NAMESPACE
-
-class QVariant;
-
-class QAbstractVideoBufferPrivate;
-
class Q_MULTIMEDIA_EXPORT QAbstractVideoBuffer
{
public:
- enum HandleType
+ struct MapData
{
- NoHandle,
- GLTextureHandle,
- MTLTextureHandle,
- XvShmImageHandle,
- CoreImageHandle,
- QPixmapHandle,
- EGLImageHandle,
- UserHandle = 1000
+ int planeCount = 0;
+ int bytesPerLine[4] = {};
+ uchar *data[4] = {};
+ int dataSize[4] = {};
};
- enum MapMode
- {
- NotMapped = 0x00,
- ReadOnly = 0x01,
- WriteOnly = 0x02,
- ReadWrite = ReadOnly | WriteOnly
- };
-
- QAbstractVideoBuffer(HandleType type);
virtual ~QAbstractVideoBuffer();
- virtual void release();
-
- HandleType handleType() const;
-
- virtual MapMode mapMode() const = 0;
-
- virtual uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) = 0;
- int mapPlanes(MapMode mode, int *numBytes, int bytesPerLine[4], uchar *data[4]);
- virtual void unmap() = 0;
-
- virtual QVariant handle() const;
-
-protected:
- QAbstractVideoBuffer(QAbstractVideoBufferPrivate &dd, HandleType type);
-
- QAbstractVideoBufferPrivate *d_ptr; // For expansion, not used currently
- HandleType m_type;
-
-private:
- Q_DECLARE_PRIVATE(QAbstractVideoBuffer)
- Q_DISABLE_COPY(QAbstractVideoBuffer)
-};
-
-class QAbstractPlanarVideoBufferPrivate;
-class Q_MULTIMEDIA_EXPORT QAbstractPlanarVideoBuffer : public QAbstractVideoBuffer
-{
-public:
- QAbstractPlanarVideoBuffer(HandleType type);
- virtual ~QAbstractPlanarVideoBuffer();
-
- uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) override;
- virtual int map(MapMode mode, int *numBytes, int bytesPerLine[4], uchar *data[4]) = 0;
-
-protected:
- QAbstractPlanarVideoBuffer(QAbstractPlanarVideoBufferPrivate &dd, HandleType type);
-
-private:
- Q_DISABLE_COPY(QAbstractPlanarVideoBuffer)
+ virtual MapData map(QtVideo::MapMode mode) = 0;
+ virtual void unmap() { }
+ virtual QVideoFrameFormat format() const = 0;
};
-#ifndef QT_NO_DEBUG_STREAM
-Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, QAbstractVideoBuffer::HandleType);
-Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, QAbstractVideoBuffer::MapMode);
-#endif
-
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QAbstractVideoBuffer::HandleType)
-Q_DECLARE_METATYPE(QAbstractVideoBuffer::MapMode)
-
#endif
diff --git a/src/multimedia/video/qabstractvideobuffer_p.h b/src/multimedia/video/qabstractvideobuffer_p.h
deleted file mode 100644
index 4877d3120..000000000
--- a/src/multimedia/video/qabstractvideobuffer_p.h
+++ /dev/null
@@ -1,97 +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 QABSTRACTVIDEOBUFFER_P_H
-#define QABSTRACTVIDEOBUFFER_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/qshareddata.h>
-#include "qabstractvideobuffer.h"
-
-#include <qtmultimediaglobal.h>
-#include <qmultimedia.h>
-
-
-QT_BEGIN_NAMESPACE
-
-class QAbstractVideoBufferPrivate
-{
-public:
- QAbstractVideoBufferPrivate()
- : q_ptr(nullptr)
- {}
-
- virtual ~QAbstractVideoBufferPrivate()
- {}
-
- virtual int map(
- QAbstractVideoBuffer::MapMode mode,
- int *numBytes,
- int bytesPerLine[4],
- uchar *data[4]);
-
- QAbstractVideoBuffer *q_ptr;
-};
-
-class QAbstractPlanarVideoBufferPrivate : QAbstractVideoBufferPrivate
-{
-public:
- QAbstractPlanarVideoBufferPrivate()
- {}
-
- int map(QAbstractVideoBuffer::MapMode mode, int *numBytes, int bytesPerLine[4], uchar *data[4]) override;
-
-private:
- Q_DECLARE_PUBLIC(QAbstractPlanarVideoBuffer)
-};
-
-QT_END_NAMESPACE
-
-
-#endif
diff --git a/src/multimedia/video/qabstractvideofilter.cpp b/src/multimedia/video/qabstractvideofilter.cpp
deleted file mode 100644
index 84dd8e0f2..000000000
--- a/src/multimedia/video/qabstractvideofilter.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 "qabstractvideofilter.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QAbstractVideoFilter
- \since 5.5
- \brief The QAbstractVideoFilter class represents a filter that is applied to the video frames
- received by a VideoOutput type.
- \inmodule QtMultimedia
-
- \ingroup multimedia
- \ingroup multimedia_video
-
- QAbstractVideoFilter provides a convenient way for applications to run image
- processing, computer vision algorithms or any generic transformation or
- calculation on the output of a VideoOutput type, regardless of the source
- (video or camera). By providing a simple interface it allows applications and
- third parties to easily develop QML types that provide image processing
- algorithms using popular frameworks like \l{http://opencv.org}{OpenCV}. Due to
- the close integration with the final stages of the Qt Multimedia video
- pipeline, accelerated and possibly zero-copy solutions are feasible too: for
- instance, a plugin providing OpenCL-based algorithms can use OpenCL's OpenGL
- interop to use the OpenGL textures created by a hardware accelerated video
- decoder, without additional readbacks and copies.
-
- \note QAbstractVideoFilter is not always the best choice. To apply effects or
- transformations using OpenGL shaders to the image shown on screen, the
- standard Qt Quick approach of using ShaderEffect items in combination with
- VideoOutput should be used. VideoFilter is not a replacement for this. It is
- rather targeted for performing computations (that do not necessarily change
- the image shown on screen) and computer vision algorithms provided by
- external frameworks.
-
- QAbstractVideoFilter is meant to be subclassed. The subclasses are then registered to
- the QML engine, so they can be used as a QML type. The list of filters are
- assigned to a VideoOutput type via its \l{QtMultimedia::VideoOutput::filters}{filters}
- property.
-
- A single filter represents one transformation or processing step on
- a video frame. The output is a modified video frame, some arbitrary data or
- both. For example, image transformations will result in a different image,
- whereas an algorithm for detecting objects on an image will likely provide
- a list of rectangles.
-
- Arbitrary data can be represented as properties on the QAbstractVideoFilter subclass
- and on the QObject or QJSValue instances passed to its signals. What exactly
- these properties and signals are, is up to the individual video
- filters. Completion of the operations can be indicated by
- signals. Computations that do not result in a modified image will pass the
- input image through so that subsequent filters can be placed after them.
-
- Properties set on QAbstractVideoFilter serve as input to the computation, similarly
- to how uniform values are specified in ShaderEffect types. The changed
- property values are taken into use when the next video frame is processed.
-
- The typical usage is to subclass QAbstractVideoFilter and QVideoFilterRunnable:
-
- \badcode
- class MyFilterRunnable : public QVideoFilterRunnable {
- public:
- QVideoFrame run(QVideoFrame *input, const QVideoSurfaceFormat &surfaceFormat, RunFlags flags) { ... }
- };
-
- class MyFilter : public QAbstractVideoFilter {
- public:
- QVideoFilterRunnable *createFilterRunnable() { return new MyFilterRunnable; }
- signals:
- void finished(QObject *result);
- };
-
- int main(int argc, char **argv) {
- ...
- qmlRegisterType<MyFilter>("my.uri", 1, 0, "MyFilter");
- ...
- }
- \endcode
-
- MyFilter is thus accessible from QML:
-
- \badcode
- import my.uri 1.0
-
- Camera {
- id: camera
- }
- MyFilter {
- id: filter
- // set properties, they can also be animated
- onFinished: console.log("results of the computation: " + result)
- }
- VideoOutput {
- source: camera
- filters: [ filter ]
- anchors.fill: parent
- }
- \endcode
-
- This also allows providing filters in QML plugins, separately from the application.
-
- \sa VideoOutput, Camera, MediaPlayer, QVideoFilterRunnable
-*/
-
-/*!
- \class QVideoFilterRunnable
- \since 5.5
- \brief The QVideoFilterRunnable class represents the implementation of a filter
- that owns all graphics and computational resources, and performs the actual filtering
- or calculations.
- \inmodule QtMultimedia
-
- \ingroup multimedia
- \ingroup multimedia_video
-
- Video filters are split into QAbstractVideoFilter and corresponding QVideoFilterRunnable
- instances, similar to QQuickItem and QSGNode. This is necessary to support
- threaded rendering scenarios. When using the threaded render loop of the Qt
- Quick scene graph, all rendering happens on a dedicated thread.
- QVideoFilterRunnable instances always live on this thread and all its functions,
- run(), the constructor, and the destructor, are guaranteed to be invoked on
- that thread with the OpenGL context bound. QAbstractVideoFilter instances live on
- the main (GUI) thread, like any other QObject and QQuickItem instances
- created from QML.
-
- Once created, QVideoFilterRunnable instances are managed by Qt Multimedia and
- will be automatically destroyed and recreated when necessary, for example
- when the scene graph is invalidated or the QQuickWindow changes or is closed.
- Creation happens via the QAbstractVideoFilter::createFilterRunnable() factory function.
-
- \sa QAbstractVideoFilter
- */
-
-/*!
- \fn QVideoFrame QVideoFilterRunnable::run(QVideoFrame *input, const QVideoSurfaceFormat &surfaceFormat, RunFlags flags)
-
- Reimplement this function to perform filtering or computation on the \a
- input video frame. Like the constructor and destructor, this function is
- always called on the render thread with the OpenGL context bound.
-
- Implementations that do not modify the video frame can simply return \a input.
-
- It is safe to access properties of the associated QAbstractVideoFilter instance from
- this function.
-
- \a input will not be mapped, it is up to this function to call QVideoFrame::map()
- and QVideoFrame::unmap() as necessary.
-
- \a surfaceFormat provides additional information, for example it can be used
- to determine which way is up in the input image as that is important for
- filters to operate on multiple platforms with multiple cameras.
-
- \a flags contains additional information about the filter's invocation. For
- example the LastInChain flag indicates that the filter is the last in a
- VideoOutput's associated filter list. This can be very useful in cases where
- multiple filters are chained together and the work is performed on image data
- in some custom format (for example a format specific to some computer vision
- framework). To avoid conversion on every filter in the chain, all
- intermediate filters can return a QVideoFrame hosting data in the custom
- format. Only the last, where the flag is set, returns a QVideoFrame in a
- format compatible with Qt.
-
- Filters that want to expose the results of their computation to Javascript
- code in QML can declare their own custom signals in the QAbstractVideoFilter
- subclass to indicate the completion of the operation. For filters that only
- calculate some results and do not modify the video frame, it is also possible
- to operate asynchronously. They can queue the necessary operations using the
- compute API and return from this function without emitting any signals. The
- signal indicating the completion is then emitted only when the compute API
- indicates that the operations were done and the results are available. Note
- that it is strongly recommended to represent the filter's output data as a
- separate instance of QJSValue or a QObject-derived class which is passed as a
- parameter to the signal and becomes exposed to the Javascript engine. In case
- of QObject the ownership of this object is controlled by the standard QML
- rules: if it has no parent, ownership is transferred to the Javascript engine,
- otherwise it stays with the emitter. Note that the signal connection may be
- queued,for example when using the threaded render loop of Qt Quick, and so the
- object must stay valid for a longer time, destroying it right after calling
- this function is not safe. Using a dedicated results object is guaranteed to
- be safe even when using threaded rendering. The same is not necessarily true
- for properties on the QAbstractVideoFilter instance itself: properties can
- safely be read in run() since the gui thread is blocked during that time but
- writing may become problematic.
-
- \note Avoid time consuming operations in this function as they block the
- entire rendering of the application.
-
- \note The handleType() and pixelFormat() of \a input is completely up to the
- video decoding backend on the platform in use. On some platforms different
- forms of input are used depending on the graphics stack. For example, when
- playing back videos on Windows with the WMF backend, QVideoFrame contains
- OpenGL-wrapped Direct3D textures in case of using ANGLE, but regular pixel
- data when using desktop OpenGL (opengl32.dll). Similarly, the video file
- format will often decide if the data is RGB or YUV, but this may also depend
- on the decoder and the configuration in use. The returned video frame does
- not have to be in the same format as the input, for example a filter with an
- input of a QVideoFrame backed by system memory can output a QVideoFrame with
- an OpenGL texture handle.
-
- \sa QVideoFrame, QVideoSurfaceFormat
- */
-
-/*!
- \enum QVideoFilterRunnable::RunFlag
-
- \value LastInChain Indicates that the filter runnable's associated QAbstractVideoFilter
- is the last in the corresponding VideoOutput type's filters list, meaning
- that the returned frame is the one that is going to be presented to the scene
- graph without invoking any further filters.
- */
-
-class QAbstractVideoFilterPrivate
-{
-public:
- QAbstractVideoFilterPrivate() :
- active(true)
- { }
-
- bool active;
-};
-
-/*!
- \internal
- */
-QVideoFilterRunnable::~QVideoFilterRunnable()
-{
-}
-
-/*!
- Constructs a new QAbstractVideoFilter instance with parent object \a parent.
- */
-QAbstractVideoFilter::QAbstractVideoFilter(QObject *parent) :
- QObject(parent),
- d_ptr(new QAbstractVideoFilterPrivate)
-{
-}
-
-/*!
- \internal
- */
-QAbstractVideoFilter::~QAbstractVideoFilter()
-{
- delete d_ptr;
-}
-
-/*!
- \property QAbstractVideoFilter::active
- \brief the active status of the filter.
-
- This is true if the filter is active, false otherwise.
-
- By default filters are active. When set to \c false, the filter will be
- ignored by the VideoOutput type.
- */
-bool QAbstractVideoFilter::isActive() const
-{
- Q_D(const QAbstractVideoFilter);
- return d->active;
-}
-
-void QAbstractVideoFilter::setActive(bool v)
-{
- Q_D(QAbstractVideoFilter);
- if (d->active != v) {
- d->active = v;
- emit activeChanged();
- }
-}
-
-/*!
- \fn QVideoFilterRunnable *QAbstractVideoFilter::createFilterRunnable()
-
- Factory function to create a new instance of a QVideoFilterRunnable subclass
- corresponding to this filter.
-
- This function is called on the thread on which the Qt Quick scene graph
- performs rendering, with the OpenGL context bound. Ownership of the returned
- instance is transferred: the returned instance will live on the render thread
- and will be destroyed automatically when necessary.
-
- Typically, implementations of the function will simply construct a new
- QVideoFilterRunnable instance, passing \c this to the constructor as the
- filter runnables must know their associated QAbstractVideoFilter instance to
- access dynamic properties and optionally emit signals.
- */
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/video/qabstractvideofilter.h b/src/multimedia/video/qabstractvideofilter.h
deleted file mode 100644
index 6263f4730..000000000
--- a/src/multimedia/video/qabstractvideofilter.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$
-**
-****************************************************************************/
-
-#ifndef QABSTRACTVIDEOFILTER_H
-#define QABSTRACTVIDEOFILTER_H
-
-#include <QtCore/qobject.h>
-#include <QtMultimedia/qvideoframe.h>
-#include <QtMultimedia/qvideosurfaceformat.h>
-
-QT_BEGIN_NAMESPACE
-
-class QAbstractVideoFilterPrivate;
-
-class Q_MULTIMEDIA_EXPORT QVideoFilterRunnable
-{
-public:
- enum RunFlag {
- LastInChain = 0x01
- };
- Q_DECLARE_FLAGS(RunFlags, RunFlag)
-
- virtual ~QVideoFilterRunnable();
- virtual QVideoFrame run(QVideoFrame *input, const QVideoSurfaceFormat &surfaceFormat, RunFlags flags) = 0;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QVideoFilterRunnable::RunFlags)
-
-class Q_MULTIMEDIA_EXPORT QAbstractVideoFilter : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged)
-
-public:
- explicit QAbstractVideoFilter(QObject *parent = nullptr);
- ~QAbstractVideoFilter();
-
- bool isActive() const;
- void setActive(bool v);
-
- virtual QVideoFilterRunnable *createFilterRunnable() = 0;
-
-Q_SIGNALS:
- void activeChanged();
-
-private:
- Q_DECLARE_PRIVATE(QAbstractVideoFilter)
- Q_DISABLE_COPY(QAbstractVideoFilter)
-
- QAbstractVideoFilterPrivate *d_ptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QABSTRACTVIDEOFILTER_H
diff --git a/src/multimedia/video/qabstractvideosurface.cpp b/src/multimedia/video/qabstractvideosurface.cpp
deleted file mode 100644
index 68a190e40..000000000
--- a/src/multimedia/video/qabstractvideosurface.cpp
+++ /dev/null
@@ -1,389 +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$
-**
-****************************************************************************/
-
-//TESTED_COMPONENT=src/multimedia
-
-#include "qabstractvideosurface.h"
-
-#include "qvideosurfaceformat.h"
-
-#include <QtCore/qvariant.h>
-#include <QDebug>
-
-QT_BEGIN_NAMESPACE
-
-static void qRegisterAbstractVideoSurfaceMetaTypes()
-{
- qRegisterMetaType<QAbstractVideoSurface::Error>();
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterAbstractVideoSurfaceMetaTypes)
-
-
-class QAbstractVideoSurfacePrivate {
-public:
- QAbstractVideoSurfacePrivate()
- : error(QAbstractVideoSurface::NoError),
- active(false)
- {
- }
-
-public:
- QVideoSurfaceFormat surfaceFormat;
- QAbstractVideoSurface::Error error;
- QSize nativeResolution;
- bool active;
-};
-
-/*!
- \class QAbstractVideoSurface
- \brief The QAbstractVideoSurface class is a base class for video presentation surfaces.
- \inmodule QtMultimedia
-
- \ingroup multimedia
- \ingroup multimedia_video
-
- The QAbstractVideoSurface class defines the standard interface that video producers use to
- inter-operate with video presentation surfaces. You can subclass this interface to receive
- video frames from sources like \l {QMediaPlayer}{decoded media} or \l {QCamera}{cameras} to
- perform your own processing.
-
- A video surface presents a continuous stream of identically formatted QVideoFrame instances, where the format
- of each frame is compatible with a stream format supplied when starting a presentation. Each frame
- may have timestamp information that can be used by the surface to decide when to display that
- frame.
-
- A list of pixel formats a surface can present is given by the supportedPixelFormats() function,
- and the isFormatSupported() function will test if a video surface format is supported. If a
- format is not supported the nearestFormat() function may be able to suggest a similar format.
- For example, if a surface supports fixed set of resolutions it may suggest the smallest
- supported resolution that contains the proposed resolution.
-
- The start() function takes a supported format and enables a video surface. Once started a
- surface will begin displaying the frames it receives in the present() function. Surfaces may
- hold a reference to the buffer of a presented video frame until a new frame is presented or
- streaming is stopped. In addition, a video surface may hold a reference to a video frame
- until the \l {QVideoFrame::endTime()}{end timestamp} has passed. The stop() function will
- disable a surface and release any video buffers it holds references to.
-
- \section2 Implementing a subclass of QAbstractVideoSurface
-
- When implementing a subclass of this interface, there are only a handful of functions to
- implement, broken down into two classes:
-
- \list
- \li Format related
- \li Presentation related
- \endlist
-
- For format related functionality, you just have to describe the pixel formats that you
- support (and the nearestFormat() function). For presentation related functionality, you
- have to implement the present() function, and the start() and stop() functions.
-
- \note You must call the base class implementation of start() and stop() in your implementation.
-*/
-
-/*!
- \enum QAbstractVideoSurface::Error
- This enum describes the errors that may be returned by the error() function.
-
- \value NoError No error occurred.
- \value UnsupportedFormatError A video format was not supported.
- \value IncorrectFormatError A video frame was not compatible with the format of the surface.
- \value StoppedError The surface has not been started.
- \value ResourceError The surface could not allocate some resource.
-*/
-
-/*!
- Constructs a video surface with the given \a parent.
-*/
-QAbstractVideoSurface::QAbstractVideoSurface(QObject *parent)
- : QObject(parent),
- d_ptr(new QAbstractVideoSurfacePrivate)
-{
-}
-
-/*!
- Destroys a video surface.
-*/
-QAbstractVideoSurface::~QAbstractVideoSurface()
-{
-}
-
-/*!
- \fn QAbstractVideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const
-
- Returns a list of pixel formats a video surface can present for a given handle \a type.
-
- The pixel formats returned for the QAbstractVideoBuffer::NoHandle type are valid for any buffer
- that can be mapped in read-only mode.
-
- Types that are first in the list can be assumed to be faster to render.
-*/
-
-/*!
- Tests a video surface \a format to determine if a surface can accept it.
-
- Returns true if the format is supported by the surface, and false otherwise.
-*/
-bool QAbstractVideoSurface::isFormatSupported(const QVideoSurfaceFormat &format) const
-{
- return supportedPixelFormats(format.handleType()).contains(format.pixelFormat());
-}
-
-/*!
- Returns a supported video surface format that is similar to \a format.
-
- A similar surface format is one that has the same \l {QVideoSurfaceFormat::pixelFormat()}{pixel
- format} and \l {QVideoSurfaceFormat::handleType()}{handle type} but may differ in some of the other
- properties. For example, if there are restrictions on the \l {QVideoSurfaceFormat::frameSize()}
- {frame sizes} a video surface can accept it may suggest a format with a larger frame size and
- a \l {QVideoSurfaceFormat::viewport()}{viewport} the size of the original frame size.
-
- If the format is already supported it will be returned unchanged, or if there is no similar
- supported format an invalid format will be returned.
-*/
-QVideoSurfaceFormat QAbstractVideoSurface::nearestFormat(const QVideoSurfaceFormat &format) const
-{
- return isFormatSupported(format)
- ? format
- : QVideoSurfaceFormat();
-}
-
-/*!
- \fn QAbstractVideoSurface::supportedFormatsChanged()
-
- Signals that the set of formats supported by a video surface has changed.
-
- \sa supportedPixelFormats(), isFormatSupported()
-*/
-
-/*!
- Returns the format of a video surface.
-*/
-QVideoSurfaceFormat QAbstractVideoSurface::surfaceFormat() const
-{
- Q_D(const QAbstractVideoSurface);
- return d->surfaceFormat;
-}
-
-/*!
- \fn QAbstractVideoSurface::surfaceFormatChanged(const QVideoSurfaceFormat &format)
-
- Signals that the configured \a format of a video surface has changed.
-
- \sa surfaceFormat(), start()
-*/
-
-/*!
- Starts a video surface presenting \a format frames.
-
- Returns true if the surface was started, and false if an error occurred.
-
- \note You must call the base class implementation of start() at the end of your implementation.
- \sa isActive(), stop()
-*/
-bool QAbstractVideoSurface::start(const QVideoSurfaceFormat &format)
-{
- Q_D(QAbstractVideoSurface);
- bool wasActive = d->active;
-
- d->active = true;
- d->surfaceFormat = format;
- d->error = NoError;
-
- emit surfaceFormatChanged(format);
-
- if (!wasActive)
- emit activeChanged(true);
-
- return true;
-}
-
-/*!
- Stops a video surface presenting frames and releases any resources acquired in start().
-
- \note You must call the base class implementation of stop() at the start of your implementation.
- \sa isActive(), start()
-*/
-void QAbstractVideoSurface::stop()
-{
- Q_D(QAbstractVideoSurface);
- if (d->active) {
- d->surfaceFormat = QVideoSurfaceFormat();
- d->active = false;
-
- emit activeChanged(false);
- emit surfaceFormatChanged(surfaceFormat());
- }
-}
-
-/*!
- Indicates whether a video surface has been started.
-
- Returns true if the surface has been started, and false otherwise.
-*/
-bool QAbstractVideoSurface::isActive() const
-{
- Q_D(const QAbstractVideoSurface);
- return d->active;
-}
-
-/*!
- \fn QAbstractVideoSurface::activeChanged(bool active)
-
- Signals that the \a active state of a video surface has changed.
-
- \sa isActive(), start(), stop()
-*/
-
-/*!
- \fn QAbstractVideoSurface::present(const QVideoFrame &frame)
-
- Presents a video \a frame.
-
- Returns true if the frame was presented, and false if an error occurred.
-
- Not all surfaces will block until the presentation of a frame has completed. Calling present()
- on a non-blocking surface may fail if called before the presentation of a previous frame has
- completed. In such cases the surface may not return to a ready state until it has had an
- opportunity to process events.
-
- If present() fails for any other reason the surface should immediately enter the stopped state
- and an error() value will be set.
-
- A video surface must be in the started state for present() to succeed, and the format of the
- video frame must be compatible with the current video surface format.
-
- \sa error()
-*/
-
-/*!
- Returns the last error that occurred.
-
- If a surface fails to start(), or stops unexpectedly this function can be called to discover
- what error occurred.
-*/
-
-QAbstractVideoSurface::Error QAbstractVideoSurface::error() const
-{
- Q_D(const QAbstractVideoSurface);
- return d->error;
-}
-
-/*!
- Sets the value of error() to \a error.
-
- This can be called by implementors of this interface to communicate
- what the most recent error was.
-*/
-void QAbstractVideoSurface::setError(Error error)
-{
- Q_D(QAbstractVideoSurface);
- d->error = error;
-}
-
-/*!
- \property QAbstractVideoSurface::nativeResolution
-
- The native resolution of video surface.
- This is the resolution of video frames the surface
- can render with optimal quality and/or performance.
-
- The native resolution is not always known and can be changed during playback.
- */
-QSize QAbstractVideoSurface::nativeResolution() const
-{
- Q_D(const QAbstractVideoSurface);
- return d->nativeResolution;
-}
-
-/*!
- Set the video surface native \a resolution.
-
- This function can be called by implementors of this interface to specify
- to frame producers what the native resolution of this surface is.
- */
-void QAbstractVideoSurface::setNativeResolution(const QSize &resolution)
-{
- Q_D(QAbstractVideoSurface);
-
- if (d->nativeResolution != resolution) {
- d->nativeResolution = resolution;
-
- emit nativeResolutionChanged(resolution);
- }
-}
-/*!
- \fn QAbstractVideoSurface::nativeResolutionChanged(const QSize &resolution);
-
- Signals the native \a resolution of video surface has changed.
-*/
-
-#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug dbg, const QAbstractVideoSurface::Error& error)
-{
- QDebugStateSaver saver(dbg);
- dbg.nospace();
- switch (error) {
- case QAbstractVideoSurface::UnsupportedFormatError:
- dbg << "UnsupportedFormatError";
- break;
- case QAbstractVideoSurface::IncorrectFormatError:
- dbg << "IncorrectFormatError";
- break;
- case QAbstractVideoSurface::StoppedError:
- dbg << "StoppedError";
- break;
- case QAbstractVideoSurface::ResourceError:
- dbg << "ResourceError";
- break;
- default:
- dbg << "NoError";
- break;
- }
- return dbg;
-}
-#endif
-
-
-QT_END_NAMESPACE
-
-#include "moc_qabstractvideosurface.cpp"
-
diff --git a/src/multimedia/video/qabstractvideosurface.h b/src/multimedia/video/qabstractvideosurface.h
deleted file mode 100644
index c136ba6c1..000000000
--- a/src/multimedia/video/qabstractvideosurface.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 QABSTRACTVIDEOSURFACE_H
-#define QABSTRACTVIDEOSURFACE_H
-
-#include <QtCore/qobject.h>
-#include <QtMultimedia/qvideoframe.h>
-
-QT_BEGIN_NAMESPACE
-
-class QRectF;
-class QVideoSurfaceFormat;
-
-class QAbstractVideoSurfacePrivate;
-
-class Q_MULTIMEDIA_EXPORT QAbstractVideoSurface : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(QSize nativeResolution READ nativeResolution NOTIFY nativeResolutionChanged)
-public:
- enum Error
- {
- NoError,
- UnsupportedFormatError,
- IncorrectFormatError,
- StoppedError,
- ResourceError
- };
-
- explicit QAbstractVideoSurface(QObject *parent = nullptr);
- ~QAbstractVideoSurface();
-
- virtual QList<QVideoFrame::PixelFormat> supportedPixelFormats(
- QAbstractVideoBuffer::HandleType type = QAbstractVideoBuffer::NoHandle) const = 0;
- virtual bool isFormatSupported(const QVideoSurfaceFormat &format) const;
- virtual QVideoSurfaceFormat nearestFormat(const QVideoSurfaceFormat &format) const;
-
- QVideoSurfaceFormat surfaceFormat() const;
-
- QSize nativeResolution() const;
-
- virtual bool start(const QVideoSurfaceFormat &format);
- virtual void stop();
-
- bool isActive() const;
-
- virtual bool present(const QVideoFrame &frame) = 0;
-
- Error error() const;
-
-Q_SIGNALS:
- void activeChanged(bool active);
- void surfaceFormatChanged(const QVideoSurfaceFormat &format);
- void supportedFormatsChanged();
- void nativeResolutionChanged(const QSize &resolution);
-
-protected:
- void setError(Error error);
- void setNativeResolution(const QSize &resolution);
-
-private:
- Q_DECLARE_PRIVATE(QAbstractVideoSurface)
- QScopedPointer<QAbstractVideoSurfacePrivate> d_ptr;
-};
-
-#ifndef QT_NO_DEBUG_STREAM
-Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, const QAbstractVideoSurface::Error &);
-#endif
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QAbstractVideoSurface*)
-Q_DECLARE_METATYPE(QAbstractVideoSurface::Error)
-
-#endif
diff --git a/src/multimedia/video/qhwvideobuffer.cpp b/src/multimedia/video/qhwvideobuffer.cpp
new file mode 100644
index 000000000..ecd3435d0
--- /dev/null
+++ b/src/multimedia/video/qhwvideobuffer.cpp
@@ -0,0 +1,17 @@
+// 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 "qhwvideobuffer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QVideoFrameTextures::~QVideoFrameTextures() = default;
+
+QHwVideoBuffer::QHwVideoBuffer(QVideoFrame::HandleType type, QRhi *rhi) : m_type(type), m_rhi(rhi)
+{
+}
+
+// must be out-of-line to ensure correct working of dynamic_cast when QHwVideoBuffer is created in tests
+QHwVideoBuffer::~QHwVideoBuffer() = default;
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/video/qhwvideobuffer_p.h b/src/multimedia/video/qhwvideobuffer_p.h
new file mode 100644
index 000000000..fabf82dce
--- /dev/null
+++ b/src/multimedia/video/qhwvideobuffer_p.h
@@ -0,0 +1,58 @@
+// 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 QHWVIDEOBUFFER_P_H
+#define QHWVIDEOBUFFER_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 "qabstractvideobuffer.h"
+#include "qvideoframe.h"
+
+#include <QtGui/qmatrix4x4.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRhi;
+class QRhiTexture;
+
+class Q_MULTIMEDIA_EXPORT QVideoFrameTextures
+{
+public:
+ virtual ~QVideoFrameTextures();
+ virtual QRhiTexture *texture(uint plane) const = 0;
+};
+
+class Q_MULTIMEDIA_EXPORT QHwVideoBuffer : public QAbstractVideoBuffer
+{
+public:
+ QHwVideoBuffer(QVideoFrame::HandleType type, QRhi *rhi = nullptr);
+
+ ~QHwVideoBuffer() override;
+
+ QVideoFrame::HandleType handleType() const { return m_type; }
+ QRhi *rhi() const { return m_rhi; }
+
+ QVideoFrameFormat format() const override { return {}; }
+
+ virtual std::unique_ptr<QVideoFrameTextures> mapTextures(QRhi *) { return {}; }
+ virtual quint64 textureHandle(QRhi *, int /*plane*/) const { return 0; }
+ virtual QMatrix4x4 externalTextureMatrix() const { return {}; }
+
+protected:
+ QVideoFrame::HandleType m_type;
+ QRhi *m_rhi = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QHWVIDEOBUFFER_P_H
diff --git a/src/multimedia/video/qimagevideobuffer.cpp b/src/multimedia/video/qimagevideobuffer.cpp
index 28dacefc6..400b89319 100644
--- a/src/multimedia/video/qimagevideobuffer.cpp
+++ b/src/multimedia/video/qimagevideobuffer.cpp
@@ -1,110 +1,78 @@
-/****************************************************************************
-**
-** 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) 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 "qabstractvideobuffer_p.h"
-
-#include <qimage.h>
-#include <qvariant.h>
+#include "qvideoframeformat.h"
QT_BEGIN_NAMESPACE
-/*!
- * \class QImageVideoBuffer
- * \internal
- *
- * A video buffer class for a QImage.
- */
-class QImageVideoBufferPrivate : public QAbstractVideoBufferPrivate
-{
-public:
- QImageVideoBufferPrivate()
- : mapMode(QAbstractVideoBuffer::NotMapped)
- {
- }
-
- QAbstractVideoBuffer::MapMode mapMode;
- QImage image;
-};
-
-QImageVideoBuffer::QImageVideoBuffer(const QImage &image)
- : QAbstractVideoBuffer(*new QImageVideoBufferPrivate, NoHandle)
-{
- Q_D(QImageVideoBuffer);
-
- d->image = image;
-}
+namespace {
-QImageVideoBuffer::~QImageVideoBuffer()
+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;
+ }
}
-QAbstractVideoBuffer::MapMode QImageVideoBuffer::mapMode() const
+QImage fixImage(QImage image)
{
- return d_func()->mapMode;
-}
+ if (image.format() == QImage::Format_Invalid)
+ return image;
-uchar *QImageVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine)
-{
- Q_D(QImageVideoBuffer);
+ const auto frameFormat = QVideoFrameFormat::pixelFormatFromImageFormat(image.format());
+ if (frameFormat != QVideoFrameFormat::Format_Invalid)
+ return image;
- if (d->mapMode == NotMapped && d->image.bits() && mode != NotMapped) {
- d->mapMode = mode;
+ return image.convertToFormat(fixImageFormat(image.format()));
+}
- if (numBytes)
- *numBytes = int(d->image.sizeInBytes());
+} // namespace
- if (bytesPerLine)
- *bytesPerLine = d->image.bytesPerLine();
+QImageVideoBuffer::QImageVideoBuffer(QImage image) : m_image(fixImage(std::move(image))) { }
- return d->image.bits();
- } else {
- return nullptr;
+QAbstractVideoBuffer::MapData QImageVideoBuffer::map(QtVideo::MapMode mode)
+{
+ MapData mapData;
+
+ if (!m_image.isNull()) {
+ mapData.planeCount = 1;
+ mapData.bytesPerLine[0] = m_image.bytesPerLine();
+ if (mode == QtVideo::MapMode::ReadOnly)
+ mapData.data[0] = const_cast<uint8_t *>(m_image.constBits());
+ else
+ mapData.data[0] = m_image.bits();
+ mapData.dataSize[0] = m_image.sizeInBytes();
}
+
+ return mapData;
}
-void QImageVideoBuffer::unmap()
+QImage QImageVideoBuffer::underlyingImage() const
{
- Q_D(QImageVideoBuffer);
-
- d->mapMode = NotMapped;
+ return m_image;
}
QT_END_NAMESPACE
diff --git a/src/multimedia/video/qimagevideobuffer_p.h b/src/multimedia/video/qimagevideobuffer_p.h
index f2b88dd9b..4ea894ba8 100644
--- a/src/multimedia/video/qimagevideobuffer_p.h
+++ b/src/multimedia/video/qimagevideobuffer_p.h
@@ -1,45 +1,12 @@
-/****************************************************************************
-**
-** 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) 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 <qabstractvideobuffer.h>
+#include <qimage.h>
+
//
// W A R N I N G
// -------------
@@ -51,29 +18,23 @@
// We mean it.
//
-#include <qabstractvideobuffer.h>
-
QT_BEGIN_NAMESPACE
-
-class QImage;
-
-class QImageVideoBufferPrivate;
-
class Q_MULTIMEDIA_EXPORT QImageVideoBuffer : public QAbstractVideoBuffer
{
- Q_DECLARE_PRIVATE(QImageVideoBuffer)
public:
- QImageVideoBuffer(const QImage &image);
- ~QImageVideoBuffer();
+ QImageVideoBuffer(QImage image);
+
+ MapData map(QtVideo::MapMode mode) override;
- MapMode mapMode() const override;
+ QVideoFrameFormat format() const override { return {}; }
- uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) override;
- void unmap() override;
+ QImage underlyingImage() const;
+
+private:
+ QImage m_image;
};
QT_END_NAMESPACE
-
-#endif
+#endif // QIMAGEVIDEOBUFFER_P_H
diff --git a/src/multimedia/video/qmemoryvideobuffer.cpp b/src/multimedia/video/qmemoryvideobuffer.cpp
index febcd66c8..0940d2ca4 100644
--- a/src/multimedia/video/qmemoryvideobuffer.cpp
+++ b/src/multimedia/video/qmemoryvideobuffer.cpp
@@ -1,63 +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 "qmemoryvideobuffer_p.h"
-#include "qabstractvideobuffer_p.h"
-#include <qbytearray.h>
-
QT_BEGIN_NAMESPACE
-class QMemoryVideoBufferPrivate : public QAbstractVideoBufferPrivate
-{
-public:
- QMemoryVideoBufferPrivate()
- : bytesPerLine(0)
- , mapMode(QAbstractVideoBuffer::NotMapped)
- {
- }
-
- int bytesPerLine;
- QAbstractVideoBuffer::MapMode mapMode;
- QByteArray data;
-};
-
/*!
\class QMemoryVideoBuffer
\brief The QMemoryVideoBuffer class provides a system memory allocated video data buffer.
@@ -70,58 +17,36 @@ public:
/*!
Constructs a video buffer with an image stride of \a bytesPerLine from a byte \a array.
*/
-QMemoryVideoBuffer::QMemoryVideoBuffer(const QByteArray &array, int bytesPerLine)
- : QAbstractVideoBuffer(*new QMemoryVideoBufferPrivate, NoHandle)
+QMemoryVideoBuffer::QMemoryVideoBuffer(QByteArray data, int bytesPerLine)
+ : m_bytesPerLine(bytesPerLine), m_data(std::move(data))
{
- Q_D(QMemoryVideoBuffer);
-
- d->data = array;
- d->bytesPerLine = bytesPerLine;
}
/*!
Destroys a system memory allocated video buffer.
*/
-QMemoryVideoBuffer::~QMemoryVideoBuffer()
-{
-}
+QMemoryVideoBuffer::~QMemoryVideoBuffer() = default;
/*!
\reimp
*/
-QAbstractVideoBuffer::MapMode QMemoryVideoBuffer::mapMode() const
+QAbstractVideoBuffer::MapData QMemoryVideoBuffer::map(QtVideo::MapMode mode)
{
- return d_func()->mapMode;
-}
-
-/*!
- \reimp
-*/
-uchar *QMemoryVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine)
-{
- Q_D(QMemoryVideoBuffer);
-
- if (d->mapMode == NotMapped && d->data.size() && mode != NotMapped) {
- d->mapMode = mode;
-
- if (numBytes)
- *numBytes = d->data.size();
-
- if (bytesPerLine)
- *bytesPerLine = d->bytesPerLine;
-
- return reinterpret_cast<uchar *>(d->data.data());
- } else {
- return nullptr;
+ MapData mapData;
+
+ if (!m_data.isEmpty()) {
+ mapData.planeCount = 1;
+ mapData.bytesPerLine[0] = m_bytesPerLine;
+ // avoid detaching and extra copying in case the underlyingByteArray is
+ // being held by textures or anything else.
+ if (mode == QtVideo::MapMode::ReadOnly)
+ mapData.data[0] = reinterpret_cast<uchar *>(const_cast<char *>(m_data.constData()));
+ else
+ mapData.data[0] = reinterpret_cast<uchar *>(m_data.data());
+ mapData.dataSize[0] = m_data.size();
}
-}
-/*!
- \reimp
-*/
-void QMemoryVideoBuffer::unmap()
-{
- d_func()->mapMode = NotMapped;
+ return mapData;
}
QT_END_NAMESPACE
diff --git a/src/multimedia/video/qmemoryvideobuffer_p.h b/src/multimedia/video/qmemoryvideobuffer_p.h
index e1b1f83a9..1bd5d6be2 100644
--- a/src/multimedia/video/qmemoryvideobuffer_p.h
+++ b/src/multimedia/video/qmemoryvideobuffer_p.h
@@ -1,46 +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 <qabstractvideobuffer.h>
+#include "qabstractvideobuffer.h"
//
// W A R N I N G
@@ -55,20 +19,19 @@
QT_BEGIN_NAMESPACE
-
-class QMemoryVideoBufferPrivate;
-
class Q_MULTIMEDIA_EXPORT QMemoryVideoBuffer : public QAbstractVideoBuffer
{
- Q_DECLARE_PRIVATE(QMemoryVideoBuffer)
public:
- QMemoryVideoBuffer(const QByteArray &data, int bytesPerLine);
- ~QMemoryVideoBuffer();
+ QMemoryVideoBuffer(QByteArray data, int bytesPerLine);
+ ~QMemoryVideoBuffer() override;
+
+ MapData map(QtVideo::MapMode mode) override;
- MapMode mapMode() const override;
+ QVideoFrameFormat format() const override { return {}; }
- uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) override;
- void unmap() override;
+private:
+ int m_bytesPerLine = 0;
+ 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..b971afbce
--- /dev/null
+++ b/src/multimedia/video/qtvideo.cpp
@@ -0,0 +1,51 @@
+// 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
+*/
+
+/*!
+ \enum QtVideo::MapMode
+
+ Enumerates how a video buffer's data is mapped to system memory.
+
+ \value NotMapped
+ The video buffer is not mapped to memory.
+ \value ReadOnly
+ The mapped memory is populated with data from the video buffer when mapped,
+ but the content of the mapped memory may be discarded when unmapped.
+ \value WriteOnly
+ The mapped memory is uninitialized when mapped, but the possibly modified
+ content will be used to populate the video buffer when unmapped.
+ \value ReadWrite
+ The mapped memory is populated with data from the video
+ buffer, and the video buffer is repopulated with the content of the mapped
+ memory when it is unmapped.
+
+ \sa QVideoFrame::mapMode(), map()
+*/
+
+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..4106f568a
--- /dev/null
+++ b/src/multimedia/video/qtvideo.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 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)
+
+enum class MapMode {
+ NotMapped = 0x00,
+ ReadOnly = 0x01,
+ WriteOnly = 0x02,
+ ReadWrite = ReadOnly | WriteOnly,
+};
+Q_ENUM_NS(MapMode)
+
+constexpr MapMode operator&(MapMode lhs, MapMode rhs)
+{
+ return MapMode(qToUnderlying(lhs) & qToUnderlying(rhs));
+}
+
+constexpr MapMode operator|(MapMode lhs, MapMode rhs)
+{
+ return MapMode(qToUnderlying(lhs) | qToUnderlying(rhs));
+}
+
+constexpr MapMode &operator&=(MapMode &lhs, MapMode rhs)
+{
+ return (lhs = lhs & rhs);
+}
+
+constexpr MapMode &operator|=(MapMode &lhs, MapMode rhs)
+{
+ return (lhs = lhs | rhs);
+}
+
+} // namespace QtVideo
+
+QT_END_NAMESPACE
+
+#endif // QTVIDEO_H
diff --git a/src/multimedia/video/qvideoframe.cpp b/src/multimedia/video/qvideoframe.cpp
index 712b6b8f3..9da4ea3b8 100644
--- a/src/multimedia/video/qvideoframe.cpp
+++ b/src/multimedia/video/qvideoframe.cpp
@@ -1,123 +1,28 @@
-/****************************************************************************
-**
-** 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 "qimagevideobuffer_p.h"
+#include "qvideoframe_p.h"
+#include "qvideotexturehelper_p.h"
+#include "qmultimediautils_p.h"
#include "qmemoryvideobuffer_p.h"
-#include "qvideoframeconversionhelper_p.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 <rhi/qrhi.h>
#include <QDebug>
QT_BEGIN_NAMESPACE
-static void qRegisterVideoFrameMetaTypes()
-{
- qRegisterMetaType<QVideoFrame>();
- qRegisterMetaType<QVideoFrame::FieldType>();
- qRegisterMetaType<QVideoFrame::PixelFormat>();
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterVideoFrameMetaTypes)
-
-
-class QVideoFramePrivate : public QSharedData
-{
-public:
- QVideoFramePrivate()
- : startTime(-1)
- , endTime(-1)
- , mappedBytes(0)
- , planeCount(0)
- , pixelFormat(QVideoFrame::Format_Invalid)
- , fieldType(QVideoFrame::ProgressiveFrame)
- , buffer(nullptr)
- , mappedCount(0)
- {
- memset(data, 0, sizeof(data));
- memset(bytesPerLine, 0, sizeof(bytesPerLine));
- }
-
- QVideoFramePrivate(const QSize &size, QVideoFrame::PixelFormat format)
- : size(size)
- , startTime(-1)
- , endTime(-1)
- , mappedBytes(0)
- , planeCount(0)
- , pixelFormat(format)
- , fieldType(QVideoFrame::ProgressiveFrame)
- , buffer(nullptr)
- , mappedCount(0)
- {
- memset(data, 0, sizeof(data));
- memset(bytesPerLine, 0, sizeof(bytesPerLine));
- }
-
- ~QVideoFramePrivate()
- {
- if (buffer)
- buffer->release();
- }
-
- QSize size;
- qint64 startTime;
- qint64 endTime;
- uchar *data[4];
- int bytesPerLine[4];
- int mappedBytes;
- int planeCount;
- QVideoFrame::PixelFormat pixelFormat;
- QVideoFrame::FieldType fieldType;
- QAbstractVideoBuffer *buffer;
- int mappedCount;
- QMutex mapMutex;
- QVariantMap metadata;
-
-private:
- Q_DISABLE_COPY(QVideoFramePrivate)
-};
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QVideoFramePrivate);
/*!
\class QVideoFrame
@@ -134,253 +39,212 @@ private:
frames can vary greatly, and some pixel formats offer greater compression opportunities at
the expense of ease of use.
- The pixel contents of a video frame can be mapped to memory using the map() function. While
- mapped, the video data can accessed using the bits() function, which returns a pointer to a
- buffer. The total size of this buffer is given by the mappedBytes() function, and the size of
- each line is given by bytesPerLine(). The return value of the handle() function may also be
- used to access frame data using the internal buffer's native APIs (for example - an OpenGL
- texture handle).
+ The pixel contents of a video frame can be mapped to memory using the map() function. After
+ a successful call to map(), the video data can be accessed through various functions. Some of
+ the YUV pixel formats provide the data in several planes. The planeCount() method will return
+ the amount of planes that being used.
+
+ While mapped, the video data of each plane can accessed using the bits() function, which
+ returns a pointer to a buffer. The size of this buffer is given by the mappedBytes() function,
+ and the size of each line is given by bytesPerLine(). The return value of the handle()
+ function may also be used to access frame data using the internal buffer's native APIs
+ (for example - an OpenGL texture handle).
A video frame can also have timestamp information associated with it. These timestamps can be
- used by an implementation of \l QAbstractVideoSurface to determine when to start and stop
- displaying the frame, but not all surfaces might respect this setting.
+ used to determine when to start and stop displaying the frame.
- The video pixel data in a QVideoFrame is encapsulated in a QAbstractVideoBuffer. A QVideoFrame
- may be constructed from any buffer type by subclassing the QAbstractVideoBuffer class.
+ QVideoFrame objects can consume a significant amount of memory or system resources and
+ should not be held for longer than required by the application.
\note Since video frames can be expensive to copy, QVideoFrame is explicitly shared, so any
change made to a video frame will also apply to any copies.
+
+ \sa QAbstractVideoBuffer, QVideoFrameFormat, QtVideo::MapMode
*/
/*!
- \enum QVideoFrame::PixelFormat
-
- Enumerates video data types.
-
- \value Format_Invalid
- The frame is invalid.
-
- \value Format_ARGB32
- The frame is stored using a 32-bit ARGB format (0xAARRGGBB). This is equivalent to
- QImage::Format_ARGB32.
-
- \value Format_ARGB32_Premultiplied
- The frame stored using a premultiplied 32-bit ARGB format (0xAARRGGBB). This is equivalent
- to QImage::Format_ARGB32_Premultiplied.
+ \enum QVideoFrame::HandleType
- \value Format_RGB32
- The frame stored using a 32-bit RGB format (0xffRRGGBB). This is equivalent to
- QImage::Format_RGB32
+ Identifies the type of a video buffers handle.
- \value Format_RGB24
- The frame is stored using a 24-bit RGB format (8-8-8). This is equivalent to
- QImage::Format_RGB888
+ \value NoHandle
+ The buffer has no handle, its data can only be accessed by mapping the buffer.
+ \value RhiTextureHandle
+ The handle of the buffer is defined by The Qt Rendering Hardware Interface
+ (RHI). RHI is Qt's internal graphics abstraction for 3D APIs, such as
+ OpenGL, Vulkan, Metal, and Direct 3D.
- \value Format_RGB565
- The frame is stored using a 16-bit RGB format (5-6-5). This is equivalent to
- QImage::Format_RGB16.
-
- \value Format_RGB555
- The frame is stored using a 16-bit RGB format (5-5-5). This is equivalent to
- QImage::Format_RGB555.
-
- \value Format_ARGB8565_Premultiplied
- The frame is stored using a 24-bit premultiplied ARGB format (8-5-6-5).
-
- \value Format_BGRA32
- The frame is stored using a 32-bit BGRA format (0xBBGGRRAA).
-
- \value Format_BGRA32_Premultiplied
- The frame is stored using a premultiplied 32bit BGRA format.
-
- \value Format_ABGR32
- The frame is stored using a 32-bit ABGR format (0xAABBGGRR).
-
- \value Format_BGR32
- The frame is stored using a 32-bit BGR format (0xBBGGRRff).
+ \sa handleType()
+*/
- \value Format_BGR24
- The frame is stored using a 24-bit BGR format (0xBBGGRR).
- \value Format_BGR565
- The frame is stored using a 16-bit BGR format (5-6-5).
+/*!
+ Constructs a null video frame.
+*/
+QVideoFrame::QVideoFrame()
+{
+}
- \value Format_BGR555
- The frame is stored using a 16-bit BGR format (5-5-5).
+#if QT_DEPRECATED_SINCE(6, 8)
- \value Format_BGRA5658_Premultiplied
- The frame is stored using a 24-bit premultiplied BGRA format (5-6-5-8).
+/*!
+ \internal
+ Constructs a video frame from a \a buffer with the given pixel \a format and \a size in pixels.
- \value Format_AYUV444
- The frame is stored using a packed 32-bit AYUV format (0xAAYYUUVV).
+ \note This doesn't increment the reference count of the video buffer.
+*/
+QVideoFrame::QVideoFrame(QAbstractVideoBuffer *buffer, const QVideoFrameFormat &format)
+ : d(new QVideoFramePrivate(format, std::unique_ptr<QAbstractVideoBuffer>(buffer)))
+{
+}
- \value Format_AYUV444_Premultiplied
- The frame is stored using a packed premultiplied 32-bit AYUV format (0xAAYYUUVV).
+/*!
+ \internal
+*/
+QAbstractVideoBuffer *QVideoFrame::videoBuffer() const
+{
+ return d ? d->videoBuffer.get() : nullptr;
+}
- \value Format_YUV444
- The frame is stored using a 24-bit packed YUV format (8-8-8).
+#endif
- \value Format_YUV420P
- The frame is stored using an 8-bit per component planar YUV format with the U and V planes
- horizontally and vertically sub-sampled, i.e. the height and width of the U and V planes are
- half that of the Y plane.
+/*!
+ Constructs a video frame of the given pixel \a format.
- \value Format_YUV422P
- The frame is stored using an 8-bit per component planar YUV format with the U and V planes
- horizontally sub-sampled, i.e. the width of the U and V planes are
- half that of the Y plane, and height of U and V planes is the same as Y.
+*/
+QVideoFrame::QVideoFrame(const QVideoFrameFormat &format)
+ : d(new QVideoFramePrivate(format))
+{
+ auto *textureDescription = QVideoTextureHelper::textureDescription(format.pixelFormat());
+ qsizetype bytes = textureDescription->bytesForSize(format.frameSize());
+ if (bytes > 0) {
+ QByteArray data;
+ data.resize(bytes);
- \value Format_YV12
- The frame is stored using an 8-bit per component planar YVU format with the V and U planes
- horizontally and vertically sub-sampled, i.e. the height and width of the V and U planes are
- half that of the Y plane.
+ // Check the memory was successfully allocated.
+ if (!data.isEmpty())
+ d->videoBuffer = std::make_unique<QMemoryVideoBuffer>(
+ data, textureDescription->strideForWidth(format.frameWidth()));
+ }
+}
- \value Format_UYVY
- The frame is stored using an 8-bit per component packed YUV format with the U and V planes
- horizontally sub-sampled (U-Y-V-Y), i.e. two horizontally adjacent pixels are stored as a 32-bit
- macropixel which has a Y value for each pixel and common U and V values.
+/*!
+ Constructs a QVideoFrame from a QImage.
+ \since 6.8
+
+ If the QImage::Format matches one of the formats in
+ QVideoFrameFormat::PixelFormat, the QVideoFrame will hold an instance of
+ the \a image and use that format without any pixel format conversion.
+ In this case, pixel data will be copied only if you call \l{QVideoFrame::map}
+ with \c WriteOnly flag while keeping the original image.
+
+ Otherwise, if the QImage::Format matches none of video formats,
+ 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);
- \value Format_YUYV
- The frame is stored using an 8-bit per component packed YUV format with the U and V planes
- horizontally sub-sampled (Y-U-Y-V), i.e. two horizontally adjacent pixels are stored as a 32-bit
- macropixel which has a Y value for each pixel and common U and V values.
+ // If the QImage::Format is not convertible to QVideoFrameFormat,
+ // QImageVideoBuffer automatically converts image to a compatible
+ // (A)RGB format.
+ const QImage &bufferImage = buffer->underlyingImage();
- \value Format_NV12
- The frame is stored using an 8-bit per component semi-planar YUV format with a Y plane (Y)
- followed by a horizontally and vertically sub-sampled, packed UV plane (U-V).
+ if (bufferImage.isNull())
+ return;
- \value Format_NV21
- The frame is stored using an 8-bit per component semi-planar YUV format with a Y plane (Y)
- followed by a horizontally and vertically sub-sampled, packed VU plane (V-U).
+ // `bufferImage` is now supported by QVideoFrameFormat::pixelFormatFromImageFormat()
+ QVideoFrameFormat format = {
+ bufferImage.size(), QVideoFrameFormat::pixelFormatFromImageFormat(bufferImage.format())
+ };
- \value Format_IMC1
- The frame is stored using an 8-bit per component planar YUV format with the U and V planes
- horizontally and vertically sub-sampled. This is similar to the Format_YUV420P type, except
- that the bytes per line of the U and V planes are padded out to the same stride as the Y plane.
+ Q_ASSERT(format.isValid());
- \value Format_IMC2
- The frame is stored using an 8-bit per component planar YUV format with the U and V planes
- horizontally and vertically sub-sampled. This is similar to the Format_YUV420P type, except
- that the lines of the U and V planes are interleaved, i.e. each line of U data is followed by a
- line of V data creating a single line of the same stride as the Y data.
+ d = new QVideoFramePrivate{ std::move(format), std::move(buffer) };
+}
- \value Format_IMC3
- The frame is stored using an 8-bit per component planar YVU format with the V and U planes
- horizontally and vertically sub-sampled. This is similar to the Format_YV12 type, except that
- the bytes per line of the V and U planes are padded out to the same stride as the Y plane.
+/*!
+ Constructs a QVideoFrame from a \l QAbstractVideoBuffer.
- \value Format_IMC4
- The frame is stored using an 8-bit per component planar YVU format with the V and U planes
- horizontally and vertically sub-sampled. This is similar to the Format_YV12 type, except that
- the lines of the V and U planes are interleaved, i.e. each line of V data is followed by a line
- of U data creating a single line of the same stride as the Y data.
+ \since 6.8
- \value Format_Y8
- The frame is stored using an 8-bit greyscale format.
+ The specified \a videoBuffer refers to an instance a reimplemented
+ \l QAbstractVideoBuffer. The instance is expected to contain a preallocated custom
+ video buffer and must implement \l QAbstractVideoBuffer::format,
+ \l QAbstractVideoBuffer::map, and \l QAbstractVideoBuffer::unmap for GPU content.
- \value Format_Y16
- The frame is stored using a 16-bit linear greyscale format. Little endian.
+ If \a videoBuffer is null or gets an invalid \l QVideoFrameFormat,
+ the constructors creates an invalid video frame.
- \value Format_Jpeg
- The frame is stored in compressed Jpeg format.
+ The created frame will hold ownership of the specified video buffer for its lifetime.
+ Considering that QVideoFrame is implemented via a shared private object,
+ the specified video buffer will be destroyed upon destruction of the last copy
+ of the created video frame.
- \value Format_CameraRaw
- The frame is stored using a device specific camera raw format.
+ Note, if a video frame has been passed to \l QMediaRecorder or a rendering pipeline,
+ the lifetime of the frame is undefined, and the media recorder can destroy it
+ in a different thread.
- \value Format_AdobeDng
- The frame is stored using raw Adobe Digital Negative (DNG) format.
+ QVideoFrame will contain own instance of QVideoFrameFormat.
+ Upon invoking \l setStreamFrameRate, \l setMirrored, or \l setRotation,
+ the inner format can be modified, and \l surfaceFormat will return
+ a detached instance.
- \value Format_User
- Start value for user defined pixel formats.
+ \sa QAbstractVideoBuffer, QVideoFrameFormat
*/
+QVideoFrame::QVideoFrame(std::unique_ptr<QAbstractVideoBuffer> videoBuffer)
+{
+ if (!videoBuffer)
+ return;
-/*!
- \enum QVideoFrame::FieldType
-
- Specifies the field an interlaced video frame belongs to.
-
- \value ProgressiveFrame The frame is not interlaced.
- \value TopField The frame contains a top field.
- \value BottomField The frame contains a bottom field.
- \value InterlacedFrame The frame contains a merged top and bottom field.
-*/
+ QVideoFrameFormat format = videoBuffer->format();
+ if (!format.isValid())
+ return;
-/*!
- Constructs a null video frame.
-*/
-QVideoFrame::QVideoFrame()
- : d(new QVideoFramePrivate)
-{
+ d = new QVideoFramePrivate{ std::move(format), std::move(videoBuffer) };
}
/*!
- Constructs a video frame from a \a buffer with the given pixel \a format and \a size in pixels.
+ Constructs a shallow copy of \a other. Since QVideoFrame is
+ explicitly shared, these two instances will reflect the same frame.
- \note This doesn't increment the reference count of the video buffer.
*/
-QVideoFrame::QVideoFrame(
- QAbstractVideoBuffer *buffer, const QSize &size, PixelFormat format)
- : d(new QVideoFramePrivate(size, format))
-{
- d->buffer = buffer;
-}
+QVideoFrame::QVideoFrame(const QVideoFrame &other) = default;
/*!
- Constructs a video frame of the given pixel \a format and \a size in pixels.
+ \fn QVideoFrame::QVideoFrame(QVideoFrame &&other)
- The \a bytesPerLine (stride) is the length of each scan line in bytes, and \a bytes is the total
- number of bytes that must be allocated for the frame.
+ Constructs a QVideoFrame by moving from \a other.
*/
-QVideoFrame::QVideoFrame(int bytes, const QSize &size, int bytesPerLine, PixelFormat format)
- : d(new QVideoFramePrivate(size, format))
-{
- if (bytes > 0) {
- QByteArray data;
- data.resize(bytes);
-
- // Check the memory was successfully allocated.
- if (!data.isEmpty())
- d->buffer = new QMemoryVideoBuffer(data, bytesPerLine);
- }
-}
/*!
- Constructs a video frame from an \a image.
-
- \note This will construct an invalid video frame if there is no frame type equivalent to the
- image format.
+ \fn void QVideoFrame::swap(QVideoFrame &other) noexcept
- \sa pixelFormatFromImageFormat()
+ Swaps the current video frame with \a other.
*/
-QVideoFrame::QVideoFrame(const QImage &image)
- : d(new QVideoFramePrivate(
- image.size(), pixelFormatFromImageFormat(image.format())))
-{
- if (d->pixelFormat != Format_Invalid)
- d->buffer = new QImageVideoBuffer(image);
-}
/*!
- Constructs a shallow copy of \a other. Since QVideoFrame is
- explicitly shared, these two instances will reflect the same frame.
+ \fn QVideoFrame &QVideoFrame::operator=(QVideoFrame &&other)
+ Moves \a other into this QVideoFrame.
*/
-QVideoFrame::QVideoFrame(const QVideoFrame &other)
- : d(other.d)
-{
-}
/*!
Assigns the contents of \a other to this video frame. Since QVideoFrame is
explicitly shared, these two instances will reflect the same frame.
*/
-QVideoFrame &QVideoFrame::operator =(const QVideoFrame &other)
-{
- d = other.d;
-
- return *this;
-}
+QVideoFrame &QVideoFrame::operator =(const QVideoFrame &other) = default;
/*!
\return \c true if this QVideoFrame and \a other reflect the same frame.
@@ -402,18 +266,7 @@ bool QVideoFrame::operator!=(const QVideoFrame &other) const
/*!
Destroys a video frame.
*/
-QVideoFrame::~QVideoFrame()
-{
-}
-
-/*!
- \return underlying video buffer or \c null if there is none.
- \since 5.13
-*/
-QAbstractVideoBuffer *QVideoFrame::buffer() const
-{
- return d->buffer;
-}
+QVideoFrame::~QVideoFrame() = default;
/*!
Identifies whether a video frame is valid.
@@ -424,24 +277,34 @@ QAbstractVideoBuffer *QVideoFrame::buffer() const
*/
bool QVideoFrame::isValid() const
{
- return d->buffer != nullptr;
+ return d && d->videoBuffer && d->format.pixelFormat() != QVideoFrameFormat::Format_Invalid;
+}
+
+/*!
+ Returns the pixel format of this video frame.
+*/
+QVideoFrameFormat::PixelFormat QVideoFrame::pixelFormat() const
+{
+ return d ? d->format.pixelFormat() : QVideoFrameFormat::Format_Invalid;
}
/*!
- Returns the color format of a video frame.
+ Returns the surface format of this video frame.
*/
-QVideoFrame::PixelFormat QVideoFrame::pixelFormat() const
+QVideoFrameFormat QVideoFrame::surfaceFormat() const
{
- return d->pixelFormat;
+ return d ? d->format : QVideoFrameFormat{};
}
/*!
Returns the type of a video frame's handle.
+ The handle type could either be NoHandle, meaning that the frame is memory
+ based, or a RHI texture.
*/
-QAbstractVideoBuffer::HandleType QVideoFrame::handleType() const
+QVideoFrame::HandleType QVideoFrame::handleType() const
{
- return d->buffer ? d->buffer->handleType() : QAbstractVideoBuffer::NoHandle;
+ return (d && d->hwVideoBuffer) ? d->hwVideoBuffer->handleType() : QVideoFrame::NoHandle;
}
/*!
@@ -449,7 +312,7 @@ QAbstractVideoBuffer::HandleType QVideoFrame::handleType() const
*/
QSize QVideoFrame::size() const
{
- return d->size;
+ return d ? d->format.frameSize() : QSize();
}
/*!
@@ -457,7 +320,7 @@ QSize QVideoFrame::size() const
*/
int QVideoFrame::width() const
{
- return d->size.width();
+ return size().width();
}
/*!
@@ -465,49 +328,31 @@ int QVideoFrame::width() const
*/
int QVideoFrame::height() const
{
- return d->size.height();
-}
-
-/*!
- Returns the field an interlaced video frame belongs to.
-
- If the video is not interlaced this will return WholeFrame.
-*/
-QVideoFrame::FieldType QVideoFrame::fieldType() const
-{
- return d->fieldType;
-}
-
-/*!
- Sets the \a field an interlaced video frame belongs to.
-*/
-void QVideoFrame::setFieldType(QVideoFrame::FieldType field)
-{
- d->fieldType = field;
+ return size().height();
}
/*!
Identifies if a video frame's contents are currently mapped to system memory.
- This is a convenience function which checks that the \l {QAbstractVideoBuffer::MapMode}{MapMode}
- of the frame is not equal to QAbstractVideoBuffer::NotMapped.
+ This is a convenience function which checks that the \l {QtVideo::MapMode}{MapMode}
+ of the frame is not equal to QtVideo::MapMode::NotMapped.
Returns true if the contents of the video frame are mapped to system memory, and false
otherwise.
- \sa mapMode(), QAbstractVideoBuffer::MapMode
+ \sa mapMode(), QtVideo::MapMode
*/
bool QVideoFrame::isMapped() const
{
- return d->buffer != nullptr && d->buffer->mapMode() != QAbstractVideoBuffer::NotMapped;
+ return d && d->mapMode != QtVideo::MapMode::NotMapped;
}
/*!
Identifies if the mapped contents of a video frame will be persisted when the frame is unmapped.
- This is a convenience function which checks if the \l {QAbstractVideoBuffer::MapMode}{MapMode}
- contains the QAbstractVideoBuffer::WriteOnly flag.
+ This is a convenience function which checks if the \l {QtVideo::MapMode}{MapMode}
+ contains the QtVideo::MapMode::WriteOnly flag.
Returns true if the video frame will be updated when unmapped, and false otherwise.
@@ -515,37 +360,37 @@ bool QVideoFrame::isMapped() const
Depending on the buffer implementation the changes may be persisted, or worse alter a shared
buffer.
- \sa mapMode(), QAbstractVideoBuffer::MapMode
+ \sa mapMode(), QtVideo::MapMode
*/
bool QVideoFrame::isWritable() const
{
- return d->buffer != nullptr && (d->buffer->mapMode() & QAbstractVideoBuffer::WriteOnly);
+ return d && (d->mapMode & QtVideo::MapMode::WriteOnly) != QtVideo::MapMode::NotMapped;
}
/*!
Identifies if the mapped contents of a video frame were read from the frame when it was mapped.
- This is a convenience function which checks if the \l {QAbstractVideoBuffer::MapMode}{MapMode}
- contains the QAbstractVideoBuffer::WriteOnly flag.
+ This is a convenience function which checks if the \l {QtVideo::MapMode}{MapMode}
+ contains the QtVideo::MapMode::WriteOnly flag.
Returns true if the contents of the mapped memory were read from the video frame, and false
otherwise.
- \sa mapMode(), QAbstractVideoBuffer::MapMode
+ \sa mapMode(), QtVideo::MapMode
*/
bool QVideoFrame::isReadable() const
{
- return d->buffer != nullptr && (d->buffer->mapMode() & QAbstractVideoBuffer::ReadOnly);
+ return d && (d->mapMode & QtVideo::MapMode::ReadOnly) != QtVideo::MapMode::NotMapped;
}
/*!
Returns the mode a video frame was mapped to system memory in.
- \sa map(), QAbstractVideoBuffer::MapMode
+ \sa map(), QtVideo::MapMode
*/
-QAbstractVideoBuffer::MapMode QVideoFrame::mapMode() const
+QVideoFrame::MapMode QVideoFrame::mapMode() const
{
- return d->buffer != nullptr ? d->buffer->mapMode() : QAbstractVideoBuffer::NotMapped;
+ return static_cast<QVideoFrame::MapMode>(d ? d->mapMode : QtVideo::MapMode::NotMapped);
}
/*!
@@ -556,9 +401,9 @@ QAbstractVideoBuffer::MapMode QVideoFrame::mapMode() const
copying the contents around, so avoid mapping and unmapping unless required.
The map \a mode indicates whether the contents of the mapped memory should be read from and/or
- written to the frame. If the map mode includes the \c QAbstractVideoBuffer::ReadOnly flag the
+ written to the frame. If the map mode includes the \c QtVideo::MapMode::ReadOnly flag the
mapped memory will be populated with the content of the video frame when initially mapped. If the map
- mode includes the \c QAbstractVideoBuffer::WriteOnly flag the content of the possibly modified
+ mode includes the \c QtVideo::MapMode::WriteOnly flag the content of the possibly modified
mapped memory will be written back to the frame when unmapped.
While mapped the contents of a video frame can be accessed directly through the pointer returned
@@ -578,120 +423,197 @@ QAbstractVideoBuffer::MapMode QVideoFrame::mapMode() const
\sa unmap(), mapMode(), bits()
*/
-bool QVideoFrame::map(QAbstractVideoBuffer::MapMode mode)
+bool QVideoFrame::map(QtVideo::MapMode mode)
{
- QMutexLocker lock(&d->mapMutex);
-
- if (!d->buffer)
+ if (!d || !d->videoBuffer)
return false;
- if (mode == QAbstractVideoBuffer::NotMapped)
+ QMutexLocker lock(&d->mapMutex);
+ if (mode == QtVideo::MapMode::NotMapped)
return false;
if (d->mappedCount > 0) {
//it's allowed to map the video frame multiple times in read only mode
- if (d->buffer->mapMode() == QAbstractVideoBuffer::ReadOnly
- && mode == QAbstractVideoBuffer::ReadOnly) {
+ if (d->mapMode == QtVideo::MapMode::ReadOnly && mode == QtVideo::MapMode::ReadOnly) {
d->mappedCount++;
return true;
- } else {
- return false;
}
+
+ return false;
}
- Q_ASSERT(d->data[0] == nullptr);
- Q_ASSERT(d->bytesPerLine[0] == 0);
- Q_ASSERT(d->planeCount == 0);
- Q_ASSERT(d->mappedBytes == 0);
+ Q_ASSERT(d->mapData.data[0] == nullptr);
+ Q_ASSERT(d->mapData.bytesPerLine[0] == 0);
+ Q_ASSERT(d->mapData.planeCount == 0);
+ Q_ASSERT(d->mapData.dataSize[0] == 0);
- d->planeCount = d->buffer->mapPlanes(mode, &d->mappedBytes, d->bytesPerLine, d->data);
- if (d->planeCount == 0)
+ d->mapData = d->videoBuffer->map(mode);
+ if (d->mapData.planeCount == 0)
return false;
- if (d->planeCount > 1) {
- // If the plane count is derive the additional planes for planar formats.
- } else switch (d->pixelFormat) {
- case Format_Invalid:
- case Format_ARGB32:
- case Format_ARGB32_Premultiplied:
- case Format_RGB32:
- case Format_RGB24:
- case Format_RGB565:
- case Format_RGB555:
- case Format_ARGB8565_Premultiplied:
- case Format_BGRA32:
- case Format_BGRA32_Premultiplied:
- case Format_ABGR32:
- case Format_BGR32:
- case Format_BGR24:
- case Format_BGR565:
- case Format_BGR555:
- case Format_BGRA5658_Premultiplied:
- case Format_AYUV444:
- case Format_AYUV444_Premultiplied:
- case Format_YUV444:
- case Format_UYVY:
- case Format_YUYV:
- case Format_Y8:
- case Format_Y16:
- case Format_Jpeg:
- case Format_CameraRaw:
- case Format_AdobeDng:
- case Format_User:
- // Single plane or opaque format.
- break;
- case Format_YUV420P:
- case Format_YUV422P:
- case Format_YV12: {
- // The UV stride is usually half the Y stride and is 32-bit aligned.
- // However it's not always the case, at least on Windows where the
- // UV planes are sometimes not aligned.
- // We calculate the stride using the UV byte count to always
- // have a correct stride.
- const int height = d->size.height();
- const int yStride = d->bytesPerLine[0];
- const int uvHeight = d->pixelFormat == Format_YUV422P ? height : height / 2;
- const int uvStride = (d->mappedBytes - (yStride * height)) / uvHeight / 2;
-
- // Three planes, the second and third vertically (and horizontally for other than Format_YUV422P formats) subsampled.
- d->planeCount = 3;
- d->bytesPerLine[2] = d->bytesPerLine[1] = uvStride;
- d->data[1] = d->data[0] + (yStride * height);
- d->data[2] = d->data[1] + (uvStride * uvHeight);
- break;
- }
- case Format_NV12:
- case Format_NV21:
- case Format_IMC2:
- case Format_IMC4: {
- // Semi planar, Full resolution Y plane with interleaved subsampled U and V planes.
- d->planeCount = 2;
- d->bytesPerLine[1] = d->bytesPerLine[0];
- d->data[1] = d->data[0] + (d->bytesPerLine[0] * d->size.height());
- break;
- }
- case Format_IMC1:
- case Format_IMC3: {
- // Three planes, the second and third vertically and horizontally subsumpled,
- // but with lines padded to the width of the first plane.
- d->planeCount = 3;
- d->bytesPerLine[2] = d->bytesPerLine[1] = d->bytesPerLine[0];
- d->data[1] = d->data[0] + (d->bytesPerLine[0] * d->size.height());
- d->data[2] = d->data[1] + (d->bytesPerLine[1] * d->size.height() / 2);
- break;
- }
- default:
- break;
+ d->mapMode = mode;
+
+ if (d->mapData.planeCount == 1) {
+ auto pixelFmt = d->format.pixelFormat();
+ // If the plane count is 1 derive the additional planes for planar formats.
+ switch (pixelFmt) {
+ case QVideoFrameFormat::Format_Invalid:
+ case QVideoFrameFormat::Format_ARGB8888:
+ case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
+ case QVideoFrameFormat::Format_XRGB8888:
+ case QVideoFrameFormat::Format_BGRA8888:
+ case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
+ case QVideoFrameFormat::Format_BGRX8888:
+ case QVideoFrameFormat::Format_ABGR8888:
+ case QVideoFrameFormat::Format_XBGR8888:
+ case QVideoFrameFormat::Format_RGBA8888:
+ case QVideoFrameFormat::Format_RGBX8888:
+ case QVideoFrameFormat::Format_AYUV:
+ case QVideoFrameFormat::Format_AYUV_Premultiplied:
+ case QVideoFrameFormat::Format_UYVY:
+ case QVideoFrameFormat::Format_YUYV:
+ case QVideoFrameFormat::Format_Y8:
+ case QVideoFrameFormat::Format_Y16:
+ case QVideoFrameFormat::Format_Jpeg:
+ case QVideoFrameFormat::Format_SamplerExternalOES:
+ case QVideoFrameFormat::Format_SamplerRect:
+ // 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.
+ // However it's not always the case, at least on Windows where the
+ // UV planes are sometimes not aligned.
+ // We calculate the stride using the UV byte count to always
+ // have a correct stride.
+ const int height = this->height();
+ const int yStride = d->mapData.bytesPerLine[0];
+ const int uvHeight = pixelFmt == QVideoFrameFormat::Format_YUV422P ? height : height / 2;
+ const int uvStride = (d->mapData.dataSize[0] - (yStride * height)) / uvHeight / 2;
+
+ // Three planes, the second and third vertically (and horizontally for other than Format_YUV422P formats) subsampled.
+ d->mapData.planeCount = 3;
+ d->mapData.bytesPerLine[2] = d->mapData.bytesPerLine[1] = uvStride;
+ d->mapData.dataSize[0] = yStride * height;
+ d->mapData.dataSize[1] = uvStride * uvHeight;
+ d->mapData.dataSize[2] = uvStride * uvHeight;
+ d->mapData.data[1] = d->mapData.data[0] + d->mapData.dataSize[0];
+ d->mapData.data[2] = d->mapData.data[1] + d->mapData.dataSize[1];
+ break;
+ }
+ case QVideoFrameFormat::Format_NV12:
+ case QVideoFrameFormat::Format_NV21:
+ case QVideoFrameFormat::Format_IMC2:
+ case QVideoFrameFormat::Format_IMC4:
+ case QVideoFrameFormat::Format_P010:
+ case QVideoFrameFormat::Format_P016: {
+ // Semi planar, Full resolution Y plane with interleaved subsampled U and V planes.
+ d->mapData.planeCount = 2;
+ d->mapData.bytesPerLine[1] = d->mapData.bytesPerLine[0];
+ int size = d->mapData.dataSize[0];
+ d->mapData.dataSize[0] = (d->mapData.bytesPerLine[0] * height());
+ d->mapData.dataSize[1] = size - d->mapData.dataSize[0];
+ d->mapData.data[1] = d->mapData.data[0] + d->mapData.dataSize[0];
+ break;
+ }
+ case QVideoFrameFormat::Format_IMC1:
+ case QVideoFrameFormat::Format_IMC3: {
+ // Three planes, the second and third vertically and horizontally subsumpled,
+ // but with lines padded to the width of the first plane.
+ d->mapData.planeCount = 3;
+ d->mapData.bytesPerLine[2] = d->mapData.bytesPerLine[1] = d->mapData.bytesPerLine[0];
+ d->mapData.dataSize[0] = (d->mapData.bytesPerLine[0] * height());
+ d->mapData.dataSize[1] = (d->mapData.bytesPerLine[0] * height() / 2);
+ d->mapData.dataSize[2] = (d->mapData.bytesPerLine[0] * height() / 2);
+ d->mapData.data[1] = d->mapData.data[0] + d->mapData.dataSize[0];
+ d->mapData.data[2] = d->mapData.data[1] + d->mapData.dataSize[1];
+ break;
+ }
+ }
}
d->mappedCount++;
+
+ // unlock mapMutex to avoid potential deadlock imageMutex <--> mapMutex
+ lock.unlock();
+
+ if ((mode & QtVideo::MapMode::WriteOnly) != QtVideo::MapMode::NotMapped) {
+ QMutexLocker lock(&d->imageMutex);
+ d->image = {};
+ }
+
return true;
}
+#if QT_DEPRECATED_SINCE(6, 8)
+
+/*!
+ \deprecated [6.8] Use \c QtVideo::MapMode instead. The values of this enum
+ are consistent with values of \c QtVideo::MapMode.
+ \enum QVideoFrame::MapMode
+
+ Enumerates how a video buffer's data is mapped to system memory.
+
+ \value NotMapped
+ The video buffer is not mapped to memory.
+ \value ReadOnly
+ The mapped memory is populated with data from the video buffer when mapped,
+ but the content of the mapped memory may be discarded when unmapped.
+ \value WriteOnly
+ The mapped memory is uninitialized when mapped, but the possibly modified
+ content will be used to populate the video buffer when unmapped.
+ \value ReadWrite
+ The mapped memory is populated with data from the video
+ buffer, and the video buffer is repopulated with the content of the mapped
+ memory when it is unmapped.
+
+ \sa mapMode(), map()
+*/
+
+/*!
+ \deprecated [6.8] Use \c QVideoFrame::map(Qt::Video::MapMode) instead.
+ Maps the contents of a video frame to system (CPU addressable) memory.
+
+ In some cases the video frame data might be stored in video memory or otherwise inaccessible
+ memory, so it is necessary to map a frame before accessing the pixel data. This may involve
+ copying the contents around, so avoid mapping and unmapping unless required.
+
+ The map \a mode indicates whether the contents of the mapped memory should be read from and/or
+ written to the frame. If the map mode includes the \c QVideoFrame::ReadOnly flag the
+ mapped memory will be populated with the content of the video frame when initially mapped. If the map
+ mode includes the \c QVideoFrame::WriteOnly flag the content of the possibly modified
+ mapped memory will be written back to the frame when unmapped.
+
+ While mapped the contents of a video frame can be accessed directly through the pointer returned
+ by the bits() function.
+
+ When access to the data is no longer needed, be sure to call the unmap() function to release the
+ mapped memory and possibly update the video frame contents.
+
+ If the video frame has been mapped in read only mode, it is permissible to map it
+ multiple times in read only mode (and unmap it a corresponding number of times). In all
+ other cases it is necessary to unmap the frame first before mapping a second time.
+
+ \note Writing to memory that is mapped as read-only is undefined, and may result in changes
+ to shared data or crashes.
+
+ Returns true if the frame was mapped to memory in the given \a mode and false otherwise.
+
+ \sa unmap(), mapMode(), bits()
+*/
+bool QVideoFrame::map(QVideoFrame::MapMode mode)
+{
+ return map(static_cast<QtVideo::MapMode>(mode));
+}
+
+#endif
+
/*!
Releases the memory mapped by the map() function.
- If the \l {QAbstractVideoBuffer::MapMode}{MapMode} included the QAbstractVideoBuffer::WriteOnly
+ If the \l {QtVideo::MapMode}{MapMode} included the QtVideo::MapMode::WriteOnly
flag this will persist the current content of the mapped memory to the video frame.
unmap() should not be called if map() function failed.
@@ -700,11 +622,11 @@ bool QVideoFrame::map(QAbstractVideoBuffer::MapMode mode)
*/
void QVideoFrame::unmap()
{
- QMutexLocker lock(&d->mapMutex);
-
- if (!d->buffer)
+ if (!d || !d->videoBuffer)
return;
+ QMutexLocker lock(&d->mapMutex);
+
if (d->mappedCount == 0) {
qWarning() << "QVideoFrame::unmap() was called more times then QVideoFrame::map()";
return;
@@ -713,31 +635,13 @@ void QVideoFrame::unmap()
d->mappedCount--;
if (d->mappedCount == 0) {
- d->mappedBytes = 0;
- d->planeCount = 0;
- memset(d->bytesPerLine, 0, sizeof(d->bytesPerLine));
- memset(d->data, 0, sizeof(d->data));
-
- d->buffer->unmap();
+ d->mapData = {};
+ d->mapMode = QtVideo::MapMode::NotMapped;
+ d->videoBuffer->unmap();
}
}
/*!
- Returns the number of bytes in a scan line.
-
- \note For planar formats this is the bytes per line of the first plane only. The bytes per line of subsequent
- planes should be calculated as per the frame \l{QVideoFrame::PixelFormat}{pixel format}.
-
- This value is only valid while the frame data is \l {map()}{mapped}.
-
- \sa bits(), map(), mappedBytes()
-*/
-int QVideoFrame::bytesPerLine() const
-{
- return d->bytesPerLine[0];
-}
-
-/*!
Returns the number of bytes in a scan line of a \a plane.
This value is only valid while the frame data is \l {map()}{mapped}.
@@ -748,23 +652,9 @@ int QVideoFrame::bytesPerLine() const
int QVideoFrame::bytesPerLine(int plane) const
{
- return plane >= 0 && plane < d->planeCount ? d->bytesPerLine[plane] : 0;
-}
-
-/*!
- Returns a pointer to the start of the frame data buffer.
-
- This value is only valid while the frame data is \l {map()}{mapped}.
-
- Changes made to data accessed via this pointer (when mapped with write access)
- are only guaranteed to have been persisted when unmap() is called and when the
- buffer has been mapped for writing.
-
- \sa map(), mappedBytes(), bytesPerLine()
-*/
-uchar *QVideoFrame::bits()
-{
- return d->data[0];
+ if (!d)
+ return 0;
+ return plane >= 0 && plane < d->mapData.planeCount ? d->mapData.bytesPerLine[plane] : 0;
}
/*!
@@ -781,22 +671,9 @@ uchar *QVideoFrame::bits()
*/
uchar *QVideoFrame::bits(int plane)
{
- return plane >= 0 && plane < d->planeCount ? d->data[plane] : nullptr;
-}
-
-/*!
- Returns a pointer to the start of the frame data buffer.
-
- This value is only valid while the frame data is \l {map()}{mapped}.
-
- If the buffer was not mapped with read access, the contents of this
- buffer will initially be uninitialized.
-
- \sa map(), mappedBytes(), bytesPerLine()
-*/
-const uchar *QVideoFrame::bits() const
-{
- return d->data[0];
+ if (!d)
+ return nullptr;
+ return plane >= 0 && plane < d->mapData.planeCount ? d->mapData.data[plane] : nullptr;
}
/*!
@@ -812,45 +689,37 @@ const uchar *QVideoFrame::bits() const
*/
const uchar *QVideoFrame::bits(int plane) const
{
- return plane >= 0 && plane < d->planeCount ? d->data[plane] : nullptr;
+ if (!d)
+ return nullptr;
+ return plane >= 0 && plane < d->mapData.planeCount ? d->mapData.data[plane] : nullptr;
}
/*!
- Returns the number of bytes occupied by the mapped frame data.
+ Returns the number of bytes occupied by plane \a plane of the mapped frame data.
This value is only valid while the frame data is \l {map()}{mapped}.
\sa map()
*/
-int QVideoFrame::mappedBytes() const
+int QVideoFrame::mappedBytes(int plane) const
{
- return d->mappedBytes;
+ if (!d)
+ return 0;
+ return plane >= 0 && plane < d->mapData.planeCount ? d->mapData.dataSize[plane] : 0;
}
/*!
Returns the number of planes in the video frame.
- This value is only valid while the frame data is \l {map()}{mapped}.
-
\sa map()
\since 5.4
*/
int QVideoFrame::planeCount() const
{
- return d->planeCount;
-}
-
-/*!
- Returns a type specific handle to a video frame's buffer.
-
- For an OpenGL texture this would be the texture ID.
-
- \sa QAbstractVideoBuffer::handle()
-*/
-QVariant QVideoFrame::handle() const
-{
- return d->buffer != nullptr ? d->buffer->handle() : QVariant();
+ if (!d)
+ return 0;
+ return d->format.planeCount();
}
/*!
@@ -861,6 +730,8 @@ QVariant QVideoFrame::handle() const
*/
qint64 QVideoFrame::startTime() const
{
+ if (!d)
+ return -1;
return d->startTime;
}
@@ -872,6 +743,8 @@ qint64 QVideoFrame::startTime() const
*/
void QVideoFrame::setStartTime(qint64 time)
{
+ if (!d)
+ return;
d->startTime = time;
}
@@ -883,6 +756,8 @@ void QVideoFrame::setStartTime(qint64 time)
*/
qint64 QVideoFrame::endTime() const
{
+ if (!d)
+ return -1;
return d->endTime;
}
@@ -894,363 +769,205 @@ qint64 QVideoFrame::endTime() const
*/
void QVideoFrame::setEndTime(qint64 time)
{
+ if (!d)
+ return;
d->endTime = time;
}
+#if QT_DEPRECATED_SINCE(6, 7)
/*!
- Returns any extra metadata associated with this frame.
- */
-QVariantMap QVideoFrame::availableMetaData() const
-{
- return d->metadata;
-}
+ \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
+*/
/*!
- Returns any metadata for this frame for the given \a key.
+ \fn void QVideoFrame::setRotationAngle(RotationAngle)
+ \deprecated [6.7] Use \c QVideoFrame::setRotation instead.
- This might include frame specific information from
- a camera, or subtitles from a decoded video stream.
+ Sets the \a angle the frame should be rotated clockwise before displaying.
+*/
- See the documentation for the relevant video frame
- producer for further information about available metadata.
- */
-QVariant QVideoFrame::metaData(const QString &key) const
+/*!
+ \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)
{
- return d->metadata.value(key);
+ if (d)
+ d->format.setRotation(angle);
}
/*!
- Sets the metadata for the given \a key to \a value.
-
- If \a value is a null variant, any metadata for this key will be removed.
-
- The producer of the video frame might use this to associate
- certain data with this frame, or for an intermediate processor
- to add information for a consumer of this frame.
+ Returns the angle the frame should be rotated clockwise before displaying.
*/
-void QVideoFrame::setMetaData(const QString &key, const QVariant &value)
+QtVideo::Rotation QVideoFrame::rotation() const
{
- if (!value.isNull())
- d->metadata.insert(key, value);
- else
- d->metadata.remove(key);
+ return d ? d->format.rotation() : QtVideo::Rotation::None;
}
/*!
- Returns a video pixel format equivalent to an image \a format. If there is no equivalent
- format QVideoFrame::InvalidType is returned instead.
-
- \note In general \l QImage does not handle YUV formats.
-
+ Sets the \a mirrored flag for the frame and
+ sets the flag to the underlying \l surfaceFormat.
*/
-QVideoFrame::PixelFormat QVideoFrame::pixelFormatFromImageFormat(QImage::Format format)
+void QVideoFrame::setMirrored(bool mirrored)
{
- switch (format) {
- case QImage::Format_RGB32:
- case QImage::Format_RGBX8888:
- return Format_RGB32;
- case QImage::Format_ARGB32:
- case QImage::Format_RGBA8888:
- return Format_ARGB32;
- case QImage::Format_ARGB32_Premultiplied:
- case QImage::Format_RGBA8888_Premultiplied:
- return Format_ARGB32_Premultiplied;
- case QImage::Format_RGB16:
- return Format_RGB565;
- case QImage::Format_ARGB8565_Premultiplied:
- return Format_ARGB8565_Premultiplied;
- case QImage::Format_RGB555:
- return Format_RGB555;
- case QImage::Format_RGB888:
- return Format_RGB24;
- default:
- return Format_Invalid;
- }
+ if (d)
+ d->format.setMirrored(mirrored);
}
/*!
- Returns an image format equivalent to a video frame pixel \a format. If there is no equivalent
- format QImage::Format_Invalid is returned instead.
-
- \note In general \l QImage does not handle YUV formats.
-
+ Returns whether the frame should be mirrored before displaying.
*/
-QImage::Format QVideoFrame::imageFormatFromPixelFormat(PixelFormat format)
+bool QVideoFrame::mirrored() const
{
- switch (format) {
- case Format_Invalid:
- return QImage::Format_Invalid;
- case Format_ARGB32:
- return QImage::Format_ARGB32;
- case Format_ARGB32_Premultiplied:
- return QImage::Format_ARGB32_Premultiplied;
- case Format_RGB32:
- return QImage::Format_RGB32;
- case Format_RGB24:
- return QImage::Format_RGB888;
- case Format_RGB565:
- return QImage::Format_RGB16;
- case Format_RGB555:
- return QImage::Format_RGB555;
- case Format_ARGB8565_Premultiplied:
- return QImage::Format_ARGB8565_Premultiplied;
- case Format_BGRA32:
- case Format_BGRA32_Premultiplied:
- case Format_BGR32:
- case Format_BGR24:
- return QImage::Format_Invalid;
- case Format_BGR565:
- case Format_BGR555:
- case Format_BGRA5658_Premultiplied:
- case Format_AYUV444:
- case Format_AYUV444_Premultiplied:
- case Format_YUV444:
- case Format_YUV420P:
- case Format_YUV422P:
- case Format_YV12:
- case Format_UYVY:
- case Format_YUYV:
- case Format_NV12:
- case Format_NV21:
- case Format_IMC1:
- case Format_IMC2:
- case Format_IMC3:
- case Format_IMC4:
- case Format_Y8:
- case Format_Y16:
- case Format_Jpeg:
- case Format_CameraRaw:
- case Format_AdobeDng:
- return QImage::Format_Invalid;
- case Format_User:
- default:
- return QImage::Format_Invalid;
- }
- return QImage::Format_Invalid;
+ return d && d->format.isMirrored();
}
+/*!
+ Sets the frame \a rate of a video stream in frames per second.
+*/
+void QVideoFrame::setStreamFrameRate(qreal rate)
+{
+ if (d)
+ d->format.setStreamFrameRate(rate);
+}
-extern void QT_FASTCALL qt_convert_BGRA32_to_ARGB32(const QVideoFrame&, uchar*);
-extern void QT_FASTCALL qt_convert_BGR24_to_ARGB32(const QVideoFrame&, uchar*);
-extern void QT_FASTCALL qt_convert_BGR565_to_ARGB32(const QVideoFrame&, uchar*);
-extern void QT_FASTCALL qt_convert_BGR555_to_ARGB32(const QVideoFrame&, uchar*);
-extern void QT_FASTCALL qt_convert_AYUV444_to_ARGB32(const QVideoFrame&, uchar*);
-extern void QT_FASTCALL qt_convert_YUV444_to_ARGB32(const QVideoFrame&, uchar*);
-extern void QT_FASTCALL qt_convert_YUV420P_to_ARGB32(const QVideoFrame&, uchar*);
-extern void QT_FASTCALL qt_convert_YV12_to_ARGB32(const QVideoFrame&, uchar*);
-extern void QT_FASTCALL qt_convert_UYVY_to_ARGB32(const QVideoFrame&, uchar*);
-extern void QT_FASTCALL qt_convert_YUYV_to_ARGB32(const QVideoFrame&, uchar*);
-extern void QT_FASTCALL qt_convert_NV12_to_ARGB32(const QVideoFrame&, uchar*);
-extern void QT_FASTCALL qt_convert_NV21_to_ARGB32(const QVideoFrame&, uchar*);
-
-static VideoFrameConvertFunc qConvertFuncs[QVideoFrame::NPixelFormats] = {
- /* Format_Invalid */ nullptr, // Not needed
- /* Format_ARGB32 */ nullptr, // Not needed
- /* Format_ARGB32_Premultiplied */ nullptr, // Not needed
- /* Format_RGB32 */ nullptr, // Not needed
- /* Format_RGB24 */ nullptr, // Not needed
- /* Format_RGB565 */ nullptr, // Not needed
- /* Format_RGB555 */ nullptr, // Not needed
- /* Format_ARGB8565_Premultiplied */ nullptr, // Not needed
- /* Format_BGRA32 */ qt_convert_BGRA32_to_ARGB32,
- /* Format_BGRA32_Premultiplied */ qt_convert_BGRA32_to_ARGB32,
- /* Format_ABGR32 */ nullptr,
- /* Format_BGR32 */ qt_convert_BGRA32_to_ARGB32,
- /* Format_BGR24 */ qt_convert_BGR24_to_ARGB32,
- /* Format_BGR565 */ qt_convert_BGR565_to_ARGB32,
- /* Format_BGR555 */ qt_convert_BGR555_to_ARGB32,
- /* Format_BGRA5658_Premultiplied */ nullptr,
- /* Format_AYUV444 */ qt_convert_AYUV444_to_ARGB32,
- /* Format_AYUV444_Premultiplied */ nullptr,
- /* Format_YUV444 */ qt_convert_YUV444_to_ARGB32,
- /* Format_YUV420P */ qt_convert_YUV420P_to_ARGB32,
- /* Format_YUV422P */ nullptr,
- /* Format_YV12 */ qt_convert_YV12_to_ARGB32,
- /* Format_UYVY */ qt_convert_UYVY_to_ARGB32,
- /* Format_YUYV */ qt_convert_YUYV_to_ARGB32,
- /* Format_NV12 */ qt_convert_NV12_to_ARGB32,
- /* Format_NV21 */ qt_convert_NV21_to_ARGB32,
- /* Format_IMC1 */ nullptr,
- /* Format_IMC2 */ nullptr,
- /* Format_IMC3 */ nullptr,
- /* Format_IMC4 */ nullptr,
- /* Format_Y8 */ nullptr,
- /* Format_Y16 */ nullptr,
- /* Format_Jpeg */ nullptr, // Not needed
- /* Format_CameraRaw */ nullptr,
- /* Format_AdobeDng */ nullptr,
-};
-
-static void qInitConvertFuncsAsm()
+/*!
+ Returns the frame rate of a video stream in frames per second.
+*/
+qreal QVideoFrame::streamFrameRate() const
{
-#ifdef QT_COMPILER_SUPPORTS_SSE2
- extern void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_sse2(const QVideoFrame&, uchar*);
- if (qCpuHasFeature(SSE2)){
- qConvertFuncs[QVideoFrame::Format_BGRA32] = qt_convert_BGRA32_to_ARGB32_sse2;
- qConvertFuncs[QVideoFrame::Format_BGRA32_Premultiplied] = qt_convert_BGRA32_to_ARGB32_sse2;
- qConvertFuncs[QVideoFrame::Format_BGR32] = qt_convert_BGRA32_to_ARGB32_sse2;
- }
-#endif
-#ifdef QT_COMPILER_SUPPORTS_SSSE3
- extern void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_ssse3(const QVideoFrame&, uchar*);
- if (qCpuHasFeature(SSSE3)){
- qConvertFuncs[QVideoFrame::Format_BGRA32] = qt_convert_BGRA32_to_ARGB32_ssse3;
- qConvertFuncs[QVideoFrame::Format_BGRA32_Premultiplied] = qt_convert_BGRA32_to_ARGB32_ssse3;
- qConvertFuncs[QVideoFrame::Format_BGR32] = qt_convert_BGRA32_to_ARGB32_ssse3;
- }
-#endif
-#ifdef QT_COMPILER_SUPPORTS_AVX2
- extern void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_avx2(const QVideoFrame&, uchar*);
- if (qCpuHasFeature(AVX2)){
- qConvertFuncs[QVideoFrame::Format_BGRA32] = qt_convert_BGRA32_to_ARGB32_avx2;
- qConvertFuncs[QVideoFrame::Format_BGRA32_Premultiplied] = qt_convert_BGRA32_to_ARGB32_avx2;
- qConvertFuncs[QVideoFrame::Format_BGR32] = qt_convert_BGRA32_to_ARGB32_avx2;
- }
-#endif
+ return d ? d->format.streamFrameRate() : 0.;
}
/*!
Based on the pixel format converts current video frame to image.
\since 5.15
*/
-QImage QVideoFrame::image() const
+QImage QVideoFrame::toImage() const
{
- QVideoFrame frame = *this;
- QImage result;
-
- if (!frame.isValid() || !frame.map(QAbstractVideoBuffer::ReadOnly))
- return result;
-
- // Formats supported by QImage don't need conversion
- QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat());
- if (imageFormat != QImage::Format_Invalid) {
- result = QImage(frame.bits(), frame.width(), frame.height(), frame.bytesPerLine(), imageFormat).copy();
- }
+ if (!isValid())
+ return {};
- // Load from JPG
- else if (frame.pixelFormat() == QVideoFrame::Format_Jpeg) {
- result.loadFromData(frame.bits(), frame.mappedBytes(), "JPG");
- }
+ QMutexLocker lock(&d->imageMutex);
- // Need conversion
- else {
- static bool initAsmFuncsDone = false;
- if (!initAsmFuncsDone) {
- qInitConvertFuncsAsm();
- initAsmFuncsDone = true;
- }
- VideoFrameConvertFunc convert = qConvertFuncs[frame.pixelFormat()];
- if (!convert) {
- qWarning() << Q_FUNC_INFO << ": unsupported pixel format" << frame.pixelFormat();
- } else {
- result = QImage(frame.width(), frame.height(), QImage::Format_ARGB32);
- 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 d->image;
+}
- return result;
+/*!
+ Returns the subtitle text that should be rendered together with this video frame.
+*/
+QString QVideoFrame::subtitleText() const
+{
+ return d ? d->subtitleText : QString();
}
-#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug dbg, QVideoFrame::PixelFormat pf)
+/*!
+ Sets the subtitle text that should be rendered together with this video frame to \a text.
+*/
+void QVideoFrame::setSubtitleText(const QString &text)
{
- QDebugStateSaver saver(dbg);
- dbg.nospace();
- switch (pf) {
- case QVideoFrame::Format_Invalid:
- return dbg << "Format_Invalid";
- case QVideoFrame::Format_ARGB32:
- return dbg << "Format_ARGB32";
- case QVideoFrame::Format_ARGB32_Premultiplied:
- return dbg << "Format_ARGB32_Premultiplied";
- case QVideoFrame::Format_RGB32:
- return dbg << "Format_RGB32";
- case QVideoFrame::Format_RGB24:
- return dbg << "Format_RGB24";
- case QVideoFrame::Format_RGB565:
- return dbg << "Format_RGB565";
- case QVideoFrame::Format_RGB555:
- return dbg << "Format_RGB555";
- case QVideoFrame::Format_ARGB8565_Premultiplied:
- return dbg << "Format_ARGB8565_Premultiplied";
- case QVideoFrame::Format_BGRA32:
- return dbg << "Format_BGRA32";
- case QVideoFrame::Format_BGRA32_Premultiplied:
- return dbg << "Format_BGRA32_Premultiplied";
- case QVideoFrame::Format_ABGR32:
- return dbg << "Format_ABGR32";
- case QVideoFrame::Format_BGR32:
- return dbg << "Format_BGR32";
- case QVideoFrame::Format_BGR24:
- return dbg << "Format_BGR24";
- case QVideoFrame::Format_BGR565:
- return dbg << "Format_BGR565";
- case QVideoFrame::Format_BGR555:
- return dbg << "Format_BGR555";
- case QVideoFrame::Format_BGRA5658_Premultiplied:
- return dbg << "Format_BGRA5658_Premultiplied";
- case QVideoFrame::Format_AYUV444:
- return dbg << "Format_AYUV444";
- case QVideoFrame::Format_AYUV444_Premultiplied:
- return dbg << "Format_AYUV444_Premultiplied";
- case QVideoFrame::Format_YUV444:
- return dbg << "Format_YUV444";
- case QVideoFrame::Format_YUV420P:
- return dbg << "Format_YUV420P";
- case QVideoFrame::Format_YUV422P:
- return dbg << "Format_YUV422P";
- case QVideoFrame::Format_YV12:
- return dbg << "Format_YV12";
- case QVideoFrame::Format_UYVY:
- return dbg << "Format_UYVY";
- case QVideoFrame::Format_YUYV:
- return dbg << "Format_YUYV";
- case QVideoFrame::Format_NV12:
- return dbg << "Format_NV12";
- case QVideoFrame::Format_NV21:
- return dbg << "Format_NV21";
- case QVideoFrame::Format_IMC1:
- return dbg << "Format_IMC1";
- case QVideoFrame::Format_IMC2:
- return dbg << "Format_IMC2";
- case QVideoFrame::Format_IMC3:
- return dbg << "Format_IMC3";
- case QVideoFrame::Format_IMC4:
- return dbg << "Format_IMC4";
- case QVideoFrame::Format_Y8:
- return dbg << "Format_Y8";
- case QVideoFrame::Format_Y16:
- return dbg << "Format_Y16";
- case QVideoFrame::Format_Jpeg:
- return dbg << "Format_Jpeg";
- case QVideoFrame::Format_AdobeDng:
- return dbg << "Format_AdobeDng";
- case QVideoFrame::Format_CameraRaw:
- return dbg << "Format_CameraRaw";
-
- default:
- return dbg << QString(QLatin1String("UserType(%1)" )).arg(int(pf)).toLatin1().constData();
- }
+ if (!d)
+ return;
+ d->subtitleText = text;
}
-QDebug operator<<(QDebug dbg, QVideoFrame::FieldType f)
+/*!
+ Uses a QPainter, \a{painter}, to render this QVideoFrame to \a rect.
+ The PaintOptions \a options can be used to specify a background color and
+ how \a rect should be filled with the video.
+
+ \note that rendering will usually happen without hardware acceleration when
+ using this method.
+*/
+void QVideoFrame::paint(QPainter *painter, const QRectF &rect, const PaintOptions &options)
{
- QDebugStateSaver saver(dbg);
- dbg.nospace();
- switch (f) {
- case QVideoFrame::TopField:
- return dbg << "TopField";
- case QVideoFrame::BottomField:
- return dbg << "BottomField";
- case QVideoFrame::InterlacedFrame:
- return dbg << "InterlacedFrame";
- default:
- return dbg << "ProgressiveFrame";
+ if (!isValid()) {
+ painter->fillRect(rect, options.backgroundColor);
+ return;
+ }
+
+ QRectF targetRect = rect;
+ QSizeF size = qRotatedFrameSize(*this);
+
+ size.scale(targetRect.size(), options.aspectRatioMode);
+
+ if (options.aspectRatioMode == 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
+ if (options.backgroundColor != Qt::transparent && rect != targetRect) {
+ if (targetRect.top() > rect.top()) {
+ QRectF top(rect.left(), rect.top(), rect.width(), targetRect.top() - rect.top());
+ painter->fillRect(top, Qt::black);
+ }
+ if (targetRect.left() > rect.left()) {
+ QRectF top(rect.left(), targetRect.top(), targetRect.left() - rect.left(), targetRect.height());
+ painter->fillRect(top, Qt::black);
+ }
+ if (targetRect.right() < rect.right()) {
+ QRectF top(targetRect.right(), targetRect.top(), rect.right() - targetRect.right(), targetRect.height());
+ painter->fillRect(top, Qt::black);
+ }
+ if (targetRect.bottom() < rect.bottom()) {
+ QRectF top(rect.left(), targetRect.bottom(), rect.width(), rect.bottom() - targetRect.bottom());
+ painter->fillRect(top, Qt::black);
+ }
+ }
+ }
+
+ if (map(QtVideo::MapMode::ReadOnly)) {
+ const QTransform oldTransform = painter->transform();
+ QTransform transform = oldTransform;
+ transform.translate(targetRect.center().x() - size.width()/2,
+ targetRect.center().y() - size.height()/2);
+ painter->setTransform(transform);
+ QImage image = toImage();
+ painter->drawImage({{}, size}, image, {{},image.size()});
+ painter->setTransform(oldTransform);
+
+ unmap();
+ } else if (isValid()) {
+ // #### error handling
+ } else {
+ painter->fillRect(rect, Qt::black);
}
+
+ if ((options.paintFlags & PaintOptions::DontDrawSubtitles) || d->subtitleText.isEmpty())
+ return;
+
+ // draw subtitles
+ auto text = d->subtitleText;
+ text.replace(QLatin1Char('\n'), QChar::LineSeparator);
+
+ QVideoTextureHelper::SubtitleLayout layout;
+ layout.update(targetRect.size().toSize(), this->subtitleText());
+ layout.draw(painter, targetRect.topLeft());
}
+#ifndef QT_NO_DEBUG_STREAM
static QString qFormatTimeStamps(qint64 start, qint64 end)
{
// Early out for invalid.
@@ -1269,56 +986,68 @@ 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'));
- else
- return QString::fromLatin1("@%1:%2.%3")
- .arg(s_minutes, 2, 10, QLatin1Char('0'))
- .arg(s_seconds, 2, 10, QLatin1Char('0'))
- .arg(s_millis, 2, 10, QLatin1Char('0'));
- } else if (end == -1) {
+ 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'));
+ }
+
+ 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'));
- else
- return QString::fromLatin1("%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'));
- } else {
- const int e_millis = end % 1000000;
- end /= 1000000;
- const int e_seconds = end % 60;
- end /= 60;
- const int e_minutes = end % 60;
- end /= 60;
-
- if (start > 0 || end > 0)
- return QString::fromLatin1("%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'))
- .arg(s_millis, 2, 10, QLatin1Char('0'))
- .arg(end, 1, 10, QLatin1Char('0'))
- .arg(e_minutes, 2, 10, QLatin1Char('0'))
- .arg(e_seconds, 2, 10, QLatin1Char('0'))
- .arg(e_millis, 2, 10, QLatin1Char('0'));
- else
- return QString::fromLatin1("%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'))
- .arg(e_minutes, 2, 10, QLatin1Char('0'))
- .arg(e_seconds, 2, 10, QLatin1Char('0'))
- .arg(e_millis, 2, 10, QLatin1Char('0'));
+ 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'));
}
+
+ const int e_millis = end % 1000000;
+ end /= 1000000;
+ const int e_seconds = end % 60;
+ end /= 60;
+ const int e_minutes = end % 60;
+ end /= 60;
+
+ if (start > 0 || end > 0)
+ 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'))
+ .arg(s_millis, 2, 10, QLatin1Char('0'))
+ .arg(end, 1, 10, QLatin1Char('0'))
+ .arg(e_minutes, 2, 10, QLatin1Char('0'))
+ .arg(e_seconds, 2, 10, QLatin1Char('0'))
+ .arg(e_millis, 2, 10, QLatin1Char('0'));
+ 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'))
+ .arg(e_minutes, 2, 10, QLatin1Char('0'))
+ .arg(e_seconds, 2, 10, QLatin1Char('0'))
+ .arg(e_millis, 2, 10, QLatin1Char('0'));
+}
+
+QDebug operator<<(QDebug dbg, QVideoFrame::HandleType type)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace();
+ switch (type) {
+ case QVideoFrame::NoHandle:
+ return dbg << "NoHandle";
+ case QVideoFrame::RhiTextureHandle:
+ return dbg << "RhiTextureHandle";
+ }
+ return dbg;
}
QDebug operator<<(QDebug dbg, const QVideoFrame& f)
@@ -1330,8 +1059,6 @@ QDebug operator<<(QDebug dbg, const QVideoFrame& f)
<< f.handleType() << ", "
<< f.mapMode() << ", "
<< qFormatTimeStamps(f.startTime(), f.endTime()).toLatin1().constData();
- if (f.availableMetaData().count())
- dbg << ", metaData: " << f.availableMetaData();
dbg << ')';
return dbg;
}
diff --git a/src/multimedia/video/qvideoframe.h b/src/multimedia/video/qvideoframe.h
index 268e82d70..146547830 100644
--- a/src/multimedia/video/qvideoframe.h
+++ b/src/multimedia/video/qvideoframe.h
@@ -1,191 +1,171 @@
-/****************************************************************************
-**
-** 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>
#include <QtCore/qshareddata.h>
#include <QtGui/qimage.h>
-#include <QtMultimedia/qabstractvideobuffer.h>
-#include <QtCore/qvariant.h>
QT_BEGIN_NAMESPACE
class QSize;
-
class QVideoFramePrivate;
+class QAbstractVideoBuffer;
+class QRhi;
+class QRhiResourceUpdateBatch;
+class QRhiTexture;
+
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QVideoFramePrivate, Q_MULTIMEDIA_EXPORT)
class Q_MULTIMEDIA_EXPORT QVideoFrame
{
+ Q_GADGET
public:
- enum FieldType
+
+ enum HandleType
{
- ProgressiveFrame,
- TopField,
- BottomField,
- InterlacedFrame
+ NoHandle,
+ RhiTextureHandle
};
- enum PixelFormat
+ enum MapMode
{
- Format_Invalid,
- Format_ARGB32,
- Format_ARGB32_Premultiplied,
- Format_RGB32,
- Format_RGB24,
- Format_RGB565,
- Format_RGB555,
- Format_ARGB8565_Premultiplied,
- Format_BGRA32,
- Format_BGRA32_Premultiplied,
- Format_ABGR32,
- Format_BGR32,
- Format_BGR24,
- Format_BGR565,
- Format_BGR555,
- Format_BGRA5658_Premultiplied,
-
- Format_AYUV444,
- Format_AYUV444_Premultiplied,
- Format_YUV444,
- Format_YUV420P,
- Format_YUV422P,
- Format_YV12,
- Format_UYVY,
- Format_YUYV,
- Format_NV12,
- Format_NV21,
- Format_IMC1,
- Format_IMC2,
- Format_IMC3,
- Format_IMC4,
- Format_Y8,
- Format_Y16,
-
- Format_Jpeg,
-
- Format_CameraRaw,
- Format_AdobeDng,
-
-#ifndef Q_QDOC
- NPixelFormats,
-#endif
- Format_User = 1000
+ NotMapped Q_DECL_ENUMERATOR_DEPRECATED_X("Use QtVideo::MapMode::NotMapped instead")
+ = static_cast<int>(QtVideo::MapMode::NotMapped),
+ ReadOnly Q_DECL_ENUMERATOR_DEPRECATED_X("Use QtVideo::MapMode::ReadOnly instead")
+ = static_cast<int>(QtVideo::MapMode::ReadOnly),
+ WriteOnly Q_DECL_ENUMERATOR_DEPRECATED_X("Use QtVideo::MapMode::WriteOnly instead")
+ = static_cast<int>(QtVideo::MapMode::WriteOnly),
+ ReadWrite Q_DECL_ENUMERATOR_DEPRECATED_X("Use QtVideo::MapMode::ReadWrite instead")
+ = static_cast<int>(QtVideo::MapMode::ReadWrite)
};
+#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(QAbstractVideoBuffer *buffer, const QSize &size, PixelFormat format);
- QVideoFrame(int bytes, const QSize &size, int bytesPerLine, PixelFormat format);
- QVideoFrame(const QImage &image);
+ QVideoFrame(const QVideoFrameFormat &format);
+ explicit QVideoFrame(const QImage &image);
+ explicit QVideoFrame(std::unique_ptr<QAbstractVideoBuffer> videoBuffer);
QVideoFrame(const QVideoFrame &other);
~QVideoFrame();
+ QVideoFrame(QVideoFrame &&other) noexcept = default;
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QVideoFrame)
+ void swap(QVideoFrame &other) noexcept
+ { d.swap(other.d); }
+
+
QVideoFrame &operator =(const QVideoFrame &other);
bool operator==(const QVideoFrame &other) const;
bool operator!=(const QVideoFrame &other) const;
- QAbstractVideoBuffer *buffer() const;
bool isValid() const;
- PixelFormat pixelFormat() const;
+ QVideoFrameFormat::PixelFormat pixelFormat() const;
- QAbstractVideoBuffer::HandleType handleType() const;
+ QVideoFrameFormat surfaceFormat() const;
+ QVideoFrame::HandleType handleType() const;
QSize size() const;
int width() const;
int height() const;
- FieldType fieldType() const;
- void setFieldType(FieldType);
-
bool isMapped() const;
bool isReadable() const;
bool isWritable() const;
- QAbstractVideoBuffer::MapMode mapMode() const;
+ QVideoFrame::MapMode mapMode() const;
- bool map(QAbstractVideoBuffer::MapMode mode);
+ bool map(QtVideo::MapMode mode);
+#if QT_DEPRECATED_SINCE(6, 8)
+ QT_DEPRECATED_VERSION_X_6_7("Use QVideoFrame::map(QtVideo::MapMode) instead")
+ bool map(QVideoFrame::MapMode mode);
+#endif
void unmap();
- int bytesPerLine() const;
int bytesPerLine(int plane) const;
- uchar *bits();
uchar *bits(int plane);
- const uchar *bits() const;
const uchar *bits(int plane) const;
- int mappedBytes() const;
+ int mappedBytes(int plane) const;
int planeCount() const;
- QVariant handle() const;
-
qint64 startTime() const;
void setStartTime(qint64 time);
qint64 endTime() const;
void setEndTime(qint64 time);
- QVariantMap availableMetaData() const;
- QVariant metaData(const QString &key) const;
- void setMetaData(const QString &key, const QVariant &value);
+#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;
+
+ void setStreamFrameRate(qreal rate);
+ qreal streamFrameRate() const;
- QImage image() const;
+ QImage toImage() const;
- static PixelFormat pixelFormatFromImageFormat(QImage::Format format);
- static QImage::Format imageFormatFromPixelFormat(PixelFormat format);
+ struct PaintOptions {
+ QColor backgroundColor = Qt::transparent;
+ Qt::AspectRatioMode aspectRatioMode = Qt::KeepAspectRatio;
+ enum PaintFlag {
+ DontDrawSubtitles = 0x1
+ };
+ Q_DECLARE_FLAGS(PaintFlags, PaintFlag)
+ PaintFlags paintFlags = {};
+ };
+
+ QString subtitleText() const;
+ void setSubtitleText(const QString &text);
+
+ void paint(QPainter *painter, const QRectF &rect, const PaintOptions &options);
+#if QT_DEPRECATED_SINCE(6, 8)
+ QT_DEPRECATED_VERSION_X_6_8("The constructor is internal and deprecated")
+ QVideoFrame(QAbstractVideoBuffer *buffer, const QVideoFrameFormat &format);
+
+ QT_DEPRECATED_VERSION_X_6_8("The method is internal and deprecated")
+ QAbstractVideoBuffer *videoBuffer() const;
+#endif
private:
+ friend class QVideoFramePrivate;
QExplicitlySharedDataPointer<QVideoFramePrivate> d;
};
+Q_DECLARE_SHARED(QVideoFrame)
+
#ifndef QT_NO_DEBUG_STREAM
Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, const QVideoFrame&);
-Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, QVideoFrame::FieldType);
-Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, QVideoFrame::PixelFormat);
+Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, QVideoFrame::HandleType);
#endif
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QVideoFrame)
-Q_DECLARE_METATYPE(QVideoFrame::FieldType)
-Q_DECLARE_METATYPE(QVideoFrame::PixelFormat)
#endif
diff --git a/src/multimedia/video/qvideoframe_p.h b/src/multimedia/video/qvideoframe_p.h
new file mode 100644
index 000000000..2ca798fbe
--- /dev/null
+++ b/src/multimedia/video/qvideoframe_p.h
@@ -0,0 +1,93 @@
+// 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 "qhwvideobuffer_p.h"
+
+#include <qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+class QVideoFramePrivate : public QSharedData
+{
+public:
+ QVideoFramePrivate() = default;
+
+ ~QVideoFramePrivate()
+ {
+ if (videoBuffer && mapMode != QtVideo::MapMode::NotMapped)
+ videoBuffer->unmap();
+ }
+
+ template <typename Buffer>
+ static QVideoFrame createFrame(std::unique_ptr<Buffer> buffer, QVideoFrameFormat format)
+ {
+ QVideoFrame result;
+ result.d.reset(new QVideoFramePrivate(std::move(format), std::move(buffer)));
+ return result;
+ }
+
+ template <typename Buffer = QAbstractVideoBuffer>
+ QVideoFramePrivate(QVideoFrameFormat format, std::unique_ptr<Buffer> buffer = nullptr)
+ : format{ std::move(format) }, videoBuffer{ std::move(buffer) }
+ {
+ if constexpr (std::is_base_of_v<QHwVideoBuffer, Buffer>)
+ hwVideoBuffer = static_cast<QHwVideoBuffer *>(videoBuffer.get());
+ else if constexpr (std::is_same_v<QAbstractVideoBuffer, Buffer>)
+ hwVideoBuffer = dynamic_cast<QHwVideoBuffer *>(videoBuffer.get());
+ // else hwVideoBuffer == nullptr
+ }
+
+ static QVideoFramePrivate *handle(QVideoFrame &frame) { return frame.d.get(); };
+
+ static QHwVideoBuffer *hwBuffer(const QVideoFrame &frame)
+ {
+ return frame.d ? frame.d->hwVideoBuffer : nullptr;
+ };
+
+ static QAbstractVideoBuffer *buffer(const QVideoFrame &frame)
+ {
+ return frame.d ? frame.d->videoBuffer.get() : nullptr;
+ };
+
+ QVideoFrame adoptThisByVideoFrame()
+ {
+ QVideoFrame frame;
+ frame.d = QExplicitlySharedDataPointer(this, QAdoptSharedDataTag{});
+ return frame;
+ }
+
+ qint64 startTime = -1;
+ qint64 endTime = -1;
+ QAbstractVideoBuffer::MapData mapData;
+ QtVideo::MapMode mapMode = QtVideo::MapMode::NotMapped;
+ QVideoFrameFormat format;
+ std::unique_ptr<QAbstractVideoBuffer> videoBuffer;
+ QHwVideoBuffer *hwVideoBuffer = nullptr;
+ int mappedCount = 0;
+ QMutex mapMutex;
+ QString subtitleText;
+ 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 3a461592f..d3f2b0403 100644
--- a/src/multimedia/video/qvideoframeconversionhelper.cpp
+++ b/src/multimedia/video/qvideoframeconversionhelper.cpp
@@ -1,43 +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 "qvideoframeconversionhelper_p.h"
+#include "qrgb.h"
+
+#include <mutex>
QT_BEGIN_NAMESPACE
@@ -66,37 +33,63 @@ static inline void planarYUV420_to_ARGB32(const uchar *y, int yStride,
quint32 *rgb,
int width, int height)
{
- quint32 *rgb0 = rgb;
- quint32 *rgb1 = rgb + width;
+ height &= ~1;
- for (int j = 0; j < height; j += 2) {
+ for (int j = 0; j + 1 < height; j += 2) {
const uchar *lineY0 = y;
const uchar *lineY1 = y + yStride;
const uchar *lineU = u;
const uchar *lineV = v;
- for (int i = 0; i < width; i += 2) {
+ quint32 *rgb0 = rgb;
+ quint32 *rgb1 = rgb + width;
+ for (int i = 0; i + 1 < width; i += 2) {
EXPAND_UV(*lineU, *lineV);
lineU += uvPixelStride;
lineV += uvPixelStride;
- *rgb0++ = qYUVToARGB32(*lineY0++, rv, guv, bu);
- *rgb0++ = qYUVToARGB32(*lineY0++, rv, guv, bu);
- *rgb1++ = qYUVToARGB32(*lineY1++, rv, guv, bu);
- *rgb1++ = qYUVToARGB32(*lineY1++, rv, guv, bu);
+ rgb0[i] = qYUVToARGB32(*lineY0++, rv, guv, bu);
+ rgb0[i + 1] = qYUVToARGB32(*lineY0++, rv, guv, bu);
+ rgb1[i] = qYUVToARGB32(*lineY1++, rv, guv, bu);
+ rgb1[i + 1] = qYUVToARGB32(*lineY1++, rv, guv, bu);
}
y += yStride << 1; // stride * 2
u += uStride;
v += vStride;
- rgb0 += width;
- rgb1 += width;
+ rgb += width << 1; // width * 2
}
}
+static inline void planarYUV422_to_ARGB32(const uchar *y, int yStride,
+ const uchar *u, int uStride,
+ const uchar *v, int vStride,
+ int uvPixelStride,
+ quint32 *rgb,
+ int width, int height)
+{
+ for (int j = 0; j < height; ++j) {
+ const uchar *lineY0 = y;
+ const uchar *lineU = u;
+ const uchar *lineV = v;
+
+ for (int i = 0; i + 1 < width; i += 2) {
+ EXPAND_UV(*lineU, *lineV);
+ lineU += uvPixelStride;
+ lineV += uvPixelStride;
+ rgb[i] = qYUVToARGB32(*lineY0++, rv, guv, bu);
+ rgb[i+1] = qYUVToARGB32(*lineY0++, rv, guv, bu);
+ }
-void QT_FASTCALL qt_convert_YUV420P_to_ARGB32(const QVideoFrame &frame, uchar *output)
+ y += yStride; // stride * 2
+ u += uStride;
+ v += vStride;
+ rgb += width;
+ }
+}
+
+static void QT_FASTCALL qt_convert_YUV420P_to_ARGB32(const QVideoFrame &frame, uchar *output)
{
FETCH_INFO_TRIPLANAR(frame)
planarYUV420_to_ARGB32(plane1, plane1Stride,
@@ -107,7 +100,19 @@ void QT_FASTCALL qt_convert_YUV420P_to_ARGB32(const QVideoFrame &frame, uchar *o
width, height);
}
-void QT_FASTCALL qt_convert_YV12_to_ARGB32(const QVideoFrame &frame, uchar *output)
+static void QT_FASTCALL qt_convert_YUV422P_to_ARGB32(const QVideoFrame &frame, uchar *output)
+{
+ FETCH_INFO_TRIPLANAR(frame)
+ planarYUV422_to_ARGB32(plane1, plane1Stride,
+ plane2, plane2Stride,
+ plane3, plane3Stride,
+ 1,
+ reinterpret_cast<quint32*>(output),
+ width, height);
+}
+
+
+static void QT_FASTCALL qt_convert_YV12_to_ARGB32(const QVideoFrame &frame, uchar *output)
{
FETCH_INFO_TRIPLANAR(frame)
planarYUV420_to_ARGB32(plane1, plane1Stride,
@@ -118,7 +123,7 @@ void QT_FASTCALL qt_convert_YV12_to_ARGB32(const QVideoFrame &frame, uchar *outp
width, height);
}
-void QT_FASTCALL qt_convert_AYUV444_to_ARGB32(const QVideoFrame &frame, uchar *output)
+static void QT_FASTCALL qt_convert_AYUV_to_ARGB32(const QVideoFrame &frame, uchar *output)
{
FETCH_INFO_PACKED(frame)
MERGE_LOOPS(width, height, stride, 4)
@@ -136,17 +141,17 @@ void QT_FASTCALL qt_convert_AYUV444_to_ARGB32(const QVideoFrame &frame, uchar *o
EXPAND_UV(u, v);
- *rgb++ = qYUVToARGB32(y, rv, guv, bu, a);
+ *rgb++ = qPremultiply(qYUVToARGB32(y, rv, guv, bu, a));
}
src += stride;
}
}
-void QT_FASTCALL qt_convert_YUV444_to_ARGB32(const QVideoFrame &frame, uchar *output)
+static void QT_FASTCALL qt_convert_AYUV_Premultiplied_to_ARGB32(const QVideoFrame &frame, uchar *output)
{
FETCH_INFO_PACKED(frame)
- MERGE_LOOPS(width, height, stride, 3)
+ MERGE_LOOPS(width, height, stride, 4)
quint32 *rgb = reinterpret_cast<quint32*>(output);
@@ -154,20 +159,21 @@ void QT_FASTCALL qt_convert_YUV444_to_ARGB32(const QVideoFrame &frame, uchar *ou
const uchar *lineSrc = src;
for (int j = 0; j < width; ++j) {
+ int a = *lineSrc++;
int y = *lineSrc++;
int u = *lineSrc++;
int v = *lineSrc++;
EXPAND_UV(u, v);
- *rgb++ = qYUVToARGB32(y, rv, guv, bu);
+ *rgb++ = qYUVToARGB32(y, rv, guv, bu, a);
}
src += stride;
}
}
-void QT_FASTCALL qt_convert_UYVY_to_ARGB32(const QVideoFrame &frame, uchar *output)
+static void QT_FASTCALL qt_convert_UYVY_to_ARGB32(const QVideoFrame &frame, uchar *output)
{
FETCH_INFO_PACKED(frame)
MERGE_LOOPS(width, height, stride, 2)
@@ -176,8 +182,7 @@ void QT_FASTCALL qt_convert_UYVY_to_ARGB32(const QVideoFrame &frame, uchar *outp
for (int i = 0; i < height; ++i) {
const uchar *lineSrc = src;
-
- for (int j = 0; j < width; j += 2) {
+ for (int j = 0; j + 1 < width; j += 2) {
int u = *lineSrc++;
int y0 = *lineSrc++;
int v = *lineSrc++;
@@ -185,15 +190,16 @@ void QT_FASTCALL qt_convert_UYVY_to_ARGB32(const QVideoFrame &frame, uchar *outp
EXPAND_UV(u, v);
- *rgb++ = qYUVToARGB32(y0, rv, guv, bu);
- *rgb++ = qYUVToARGB32(y1, rv, guv, bu);
+ rgb[j] = qYUVToARGB32(y0, rv, guv, bu);
+ rgb[j+1] = qYUVToARGB32(y1, rv, guv, bu);
}
src += stride;
+ rgb += width;
}
}
-void QT_FASTCALL qt_convert_YUYV_to_ARGB32(const QVideoFrame &frame, uchar *output)
+static void QT_FASTCALL qt_convert_YUYV_to_ARGB32(const QVideoFrame &frame, uchar *output)
{
FETCH_INFO_PACKED(frame)
MERGE_LOOPS(width, height, stride, 2)
@@ -202,8 +208,7 @@ void QT_FASTCALL qt_convert_YUYV_to_ARGB32(const QVideoFrame &frame, uchar *outp
for (int i = 0; i < height; ++i) {
const uchar *lineSrc = src;
-
- for (int j = 0; j < width; j += 2) {
+ for (int j = 0; j + 1 < width; j += 2) {
int y0 = *lineSrc++;
int u = *lineSrc++;
int y1 = *lineSrc++;
@@ -211,15 +216,16 @@ void QT_FASTCALL qt_convert_YUYV_to_ARGB32(const QVideoFrame &frame, uchar *outp
EXPAND_UV(u, v);
- *rgb++ = qYUVToARGB32(y0, rv, guv, bu);
- *rgb++ = qYUVToARGB32(y1, rv, guv, bu);
+ rgb[j] = qYUVToARGB32(y0, rv, guv, bu);
+ rgb[j+1] = qYUVToARGB32(y1, rv, guv, bu);
}
src += stride;
+ rgb += width;
}
}
-void QT_FASTCALL qt_convert_NV12_to_ARGB32(const QVideoFrame &frame, uchar *output)
+static void QT_FASTCALL qt_convert_NV12_to_ARGB32(const QVideoFrame &frame, uchar *output)
{
FETCH_INFO_BIPLANAR(frame)
planarYUV420_to_ARGB32(plane1, plane1Stride,
@@ -230,7 +236,7 @@ void QT_FASTCALL qt_convert_NV12_to_ARGB32(const QVideoFrame &frame, uchar *outp
width, height);
}
-void QT_FASTCALL qt_convert_NV21_to_ARGB32(const QVideoFrame &frame, uchar *output)
+static void QT_FASTCALL qt_convert_NV21_to_ARGB32(const QVideoFrame &frame, uchar *output)
{
FETCH_INFO_BIPLANAR(frame)
planarYUV420_to_ARGB32(plane1, plane1Stride,
@@ -241,7 +247,63 @@ void QT_FASTCALL qt_convert_NV21_to_ARGB32(const QVideoFrame &frame, uchar *outp
width, height);
}
-void QT_FASTCALL qt_convert_BGRA32_to_ARGB32(const QVideoFrame &frame, uchar *output)
+static void QT_FASTCALL qt_convert_IMC1_to_ARGB32(const QVideoFrame &frame, uchar *output)
+{
+ FETCH_INFO_TRIPLANAR(frame)
+ Q_ASSERT(plane1Stride == plane2Stride);
+ Q_ASSERT(plane1Stride == plane3Stride);
+
+ planarYUV420_to_ARGB32(plane1, plane1Stride,
+ plane3, plane3Stride,
+ plane2, plane2Stride,
+ 1,
+ reinterpret_cast<quint32*>(output),
+ width, height);
+}
+
+static void QT_FASTCALL qt_convert_IMC2_to_ARGB32(const QVideoFrame &frame, uchar *output)
+{
+ FETCH_INFO_BIPLANAR(frame)
+ Q_ASSERT(plane1Stride == plane2Stride);
+
+ planarYUV420_to_ARGB32(plane1, plane1Stride,
+ plane2 + (plane1Stride >> 1), plane1Stride,
+ plane2, plane1Stride,
+ 1,
+ reinterpret_cast<quint32*>(output),
+ width, height);
+}
+
+static void QT_FASTCALL qt_convert_IMC3_to_ARGB32(const QVideoFrame &frame, uchar *output)
+{
+ FETCH_INFO_TRIPLANAR(frame)
+ Q_ASSERT(plane1Stride == plane2Stride);
+ Q_ASSERT(plane1Stride == plane3Stride);
+
+ planarYUV420_to_ARGB32(plane1, plane1Stride,
+ plane2, plane2Stride,
+ plane3, plane3Stride,
+ 1,
+ reinterpret_cast<quint32*>(output),
+ width, height);
+}
+
+static void QT_FASTCALL qt_convert_IMC4_to_ARGB32(const QVideoFrame &frame, uchar *output)
+{
+ FETCH_INFO_BIPLANAR(frame)
+ Q_ASSERT(plane1Stride == plane2Stride);
+
+ planarYUV420_to_ARGB32(plane1, plane1Stride,
+ plane2, plane1Stride,
+ plane2 + (plane1Stride >> 1), plane1Stride,
+ 1,
+ reinterpret_cast<quint32*>(output),
+ width, height);
+}
+
+
+template<typename Pixel>
+static void QT_FASTCALL qt_convert_to_ARGB32(const QVideoFrame &frame, uchar *output)
{
FETCH_INFO_PACKED(frame)
MERGE_LOOPS(width, height, stride, 4)
@@ -249,106 +311,320 @@ void QT_FASTCALL qt_convert_BGRA32_to_ARGB32(const QVideoFrame &frame, uchar *ou
quint32 *argb = reinterpret_cast<quint32*>(output);
for (int y = 0; y < height; ++y) {
- const quint32 *bgra = reinterpret_cast<const quint32*>(src);
+ const Pixel *data = reinterpret_cast<const Pixel *>(src);
int x = 0;
for (; x < width - 3; x += 4) {
- *argb++ = qConvertBGRA32ToARGB32(*bgra++);
- *argb++ = qConvertBGRA32ToARGB32(*bgra++);
- *argb++ = qConvertBGRA32ToARGB32(*bgra++);
- *argb++ = qConvertBGRA32ToARGB32(*bgra++);
+ // 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
- for (; x < width; ++x)
- *argb++ = qConvertBGRA32ToARGB32(*bgra++);
+ for (; x < width; ++x) {
+ *argb++ = qPremultiply(data->convert());
+ ++data;
+ }
src += stride;
}
}
-void QT_FASTCALL qt_convert_BGR24_to_ARGB32(const QVideoFrame &frame, uchar *output)
+template<typename Pixel>
+static void QT_FASTCALL qt_convert_premultiplied_to_ARGB32(const QVideoFrame &frame, uchar *output)
{
FETCH_INFO_PACKED(frame)
- MERGE_LOOPS(width, height, stride, 3)
+ MERGE_LOOPS(width, height, stride, 4)
quint32 *argb = reinterpret_cast<quint32*>(output);
for (int y = 0; y < height; ++y) {
- const uchar *bgr = src;
+ const Pixel *data = reinterpret_cast<const Pixel *>(src);
int x = 0;
for (; x < width - 3; x += 4) {
- *argb++ = qConvertBGR24ToARGB32(bgr);
- bgr += 3;
- *argb++ = qConvertBGR24ToARGB32(bgr);
- bgr += 3;
- *argb++ = qConvertBGR24ToARGB32(bgr);
- bgr += 3;
- *argb++ = qConvertBGR24ToARGB32(bgr);
- bgr += 3;
+ // 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
for (; x < width; ++x) {
- *argb++ = qConvertBGR24ToARGB32(bgr);
- bgr += 3;
+ *argb++ = data->convert();
+ ++data;
}
src += stride;
}
}
-void QT_FASTCALL qt_convert_BGR565_to_ARGB32(const QVideoFrame &frame, uchar *output)
+static inline void planarYUV420_16bit_to_ARGB32(const uchar *y, int yStride,
+ const uchar *u, int uStride,
+ const uchar *v, int vStride,
+ int uvPixelStride,
+ quint32 *rgb,
+ int width, int height)
{
- FETCH_INFO_PACKED(frame)
- MERGE_LOOPS(width, height, stride, 2)
+ height &= ~1;
- quint32 *argb = reinterpret_cast<quint32*>(output);
+ for (int j = 0; j + 1 < height; j += 2) {
+ const uchar *lineY0 = y;
+ const uchar *lineY1 = y + yStride;
+ const uchar *lineU = u;
+ const uchar *lineV = v;
- for (int y = 0; y < height; ++y) {
- const quint16 *bgr = reinterpret_cast<const quint16*>(src);
+ quint32 *rgb0 = rgb;
+ quint32 *rgb1 = rgb + width;
- int x = 0;
- for (; x < width - 3; x += 4) {
- *argb++ = qConvertBGR565ToARGB32(*bgr++);
- *argb++ = qConvertBGR565ToARGB32(*bgr++);
- *argb++ = qConvertBGR565ToARGB32(*bgr++);
- *argb++ = qConvertBGR565ToARGB32(*bgr++);
- }
+ for (int i = 0; i + 1 < width; i += 2) {
+ EXPAND_UV(*lineU, *lineV);
+ lineU += uvPixelStride;
+ lineV += uvPixelStride;
- // leftovers
- for (; x < width; ++x)
- *argb++ = qConvertBGR565ToARGB32(*bgr++);
+ *rgb0++ = qYUVToARGB32(*lineY0, rv, guv, bu);
+ lineY0 += 2;
+ *rgb0++ = qYUVToARGB32(*lineY0, rv, guv, bu);
+ lineY0 += 2;
+ *rgb1++ = qYUVToARGB32(*lineY1, rv, guv, bu);
+ lineY1 += 2;
+ *rgb1++ = qYUVToARGB32(*lineY1, rv, guv, bu);
+ lineY1 += 2;
+ }
- src += stride;
+ y += yStride << 1; // stride * 2
+ u += uStride;
+ v += vStride;
+ rgb += width * 2;
}
}
-void QT_FASTCALL qt_convert_BGR555_to_ARGB32(const QVideoFrame &frame, uchar *output)
+
+static void QT_FASTCALL qt_convert_P016_to_ARGB32(const QVideoFrame &frame, uchar *output)
{
- FETCH_INFO_PACKED(frame)
- MERGE_LOOPS(width, height, stride, 2)
+ FETCH_INFO_BIPLANAR(frame)
+ planarYUV420_16bit_to_ARGB32(plane1 + 1, plane1Stride,
+ plane2 + 1, plane2Stride,
+ plane2 + 3, plane2Stride,
+ 4,
+ reinterpret_cast<quint32*>(output),
+ width, height);
+}
+
+template <typename Y>
+static void QT_FASTCALL qt_convert_Y_to_ARGB32(const QVideoFrame &frame, uchar *output)
+{
+ FETCH_INFO_PACKED(frame)
+ MERGE_LOOPS(width, height, stride, (int)sizeof(Y))
quint32 *argb = reinterpret_cast<quint32*>(output);
+ using Pixel = YPixel<Y>;
+
for (int y = 0; y < height; ++y) {
- const quint16 *bgr = reinterpret_cast<const quint16*>(src);
+ const Pixel *pixel = reinterpret_cast<const Pixel *>(src);
int x = 0;
for (; x < width - 3; x += 4) {
- *argb++ = qConvertBGR555ToARGB32(*bgr++);
- *argb++ = qConvertBGR555ToARGB32(*bgr++);
- *argb++ = qConvertBGR555ToARGB32(*bgr++);
- *argb++ = qConvertBGR555ToARGB32(*bgr++);
+ *argb++ = pixel->convert();
+ ++pixel;
+ *argb++ = pixel->convert();
+ ++pixel;
+ *argb++ = pixel->convert();
+ ++pixel;
+ *argb++ = pixel->convert();
+ ++pixel;
}
// leftovers
- for (; x < width; ++x)
- *argb++ = qConvertBGR555ToARGB32(*bgr++);
+ for (; x < width; ++x) {
+ *argb++ = pixel->convert();
+ ++pixel;
+ }
src += stride;
}
+ 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>,
+ /* Format_ARGB8888_Premultiplied */ qt_convert_premultiplied_to_ARGB32<ARGB8888>,
+ /* Format_XRGB8888 */ qt_convert_premultiplied_to_ARGB32<XRGB8888>,
+ /* Format_BGRA8888 */ qt_convert_to_ARGB32<BGRA8888>,
+ /* Format_BGRA8888_Premultiplied */ qt_convert_premultiplied_to_ARGB32<BGRA8888>,
+ /* Format_BGRX8888 */ qt_convert_premultiplied_to_ARGB32<BGRX8888>,
+ /* Format_ABGR8888 */ qt_convert_to_ARGB32<ABGR8888>,
+ /* Format_XBGR8888 */ qt_convert_premultiplied_to_ARGB32<XBGR8888>,
+ /* Format_RGBA8888 */ qt_convert_to_ARGB32<RGBA8888>,
+ /* Format_RGBX8888 */ qt_convert_premultiplied_to_ARGB32<RGBX8888>,
+ /* Format_AYUV */ qt_convert_AYUV_to_ARGB32,
+ /* Format_AYUV_Premultiplied */ qt_convert_AYUV_Premultiplied_to_ARGB32,
+ /* Format_YUV420P */ qt_convert_YUV420P_to_ARGB32,
+ /* Format_YUV422P */ qt_convert_YUV422P_to_ARGB32,
+ /* Format_YV12 */ qt_convert_YV12_to_ARGB32,
+ /* Format_UYVY */ qt_convert_UYVY_to_ARGB32,
+ /* Format_YUYV */ qt_convert_YUYV_to_ARGB32,
+ /* Format_NV12 */ qt_convert_NV12_to_ARGB32,
+ /* Format_NV21 */ qt_convert_NV21_to_ARGB32,
+ /* Format_IMC1 */ qt_convert_IMC1_to_ARGB32,
+ /* Format_IMC2 */ qt_convert_IMC2_to_ARGB32,
+ /* Format_IMC3 */ qt_convert_IMC3_to_ARGB32,
+ /* Format_IMC4 */ qt_convert_IMC4_to_ARGB32,
+ /* Format_Y8 */ qt_convert_Y_to_ARGB32<uchar>,
+ /* Format_Y16 */ qt_convert_Y_to_ARGB32<ushort>,
+ /* Format_P010 */ qt_convert_P016_to_ARGB32,
+ /* Format_P016 */ qt_convert_P016_to_ARGB32,
+ /* Format_Jpeg */ nullptr, // Not needed
+};
+
+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_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_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
+ extern void QT_FASTCALL qt_convert_ARGB8888_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output);
+ extern void QT_FASTCALL qt_convert_ABGR8888_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output);
+ extern void QT_FASTCALL qt_convert_RGBA8888_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output);
+ extern void QT_FASTCALL qt_convert_BGRA8888_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output);
+ if (qCpuHasFeature(SSSE3)){
+ qConvertFuncs[QVideoFrameFormat::Format_ARGB8888] = qt_convert_ARGB8888_to_ARGB32_ssse3;
+ qConvertFuncs[QVideoFrameFormat::Format_ARGB8888_Premultiplied] = qt_convert_ARGB8888_to_ARGB32_ssse3;
+ 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_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_RGBA8888] = qt_convert_RGBA8888_to_ARGB32_ssse3;
+ qConvertFuncs[QVideoFrameFormat::Format_RGBX8888] = qt_convert_RGBA8888_to_ARGB32_ssse3;
+ }
+#endif
+#ifdef QT_COMPILER_SUPPORTS_AVX2
+ extern void QT_FASTCALL qt_convert_ARGB8888_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output);
+ 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_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_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)
+{
+ 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 4df08f162..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"
@@ -43,29 +7,51 @@
QT_BEGIN_NAMESPACE
-void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output)
+namespace {
+
+template<int a, int r, int g, int b>
+void convert_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output)
{
FETCH_INFO_PACKED(frame)
MERGE_LOOPS(width, height, stride, 4)
quint32 *argb = reinterpret_cast<quint32*>(output);
- const __m256i shuffleMask = _mm256_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3,
- 12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3);
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ __m256i shuffleMask = _mm256_set_epi8(12 + a, 12 + r, 12 + g, 12 + b,
+ 8 + a, 8 + r, 8 + g, 8 + b,
+ 4 + a, 4 + r, 4 + g, 4 + b,
+ 0 + a, 0 + r, 0 + g, 0 + b,
+ 12 + a, 12 + r, 12 + g, 12 + b,
+ 8 + a, 8 + r, 8 + g, 8 + b,
+ 4 + a, 4 + r, 4 + g, 4 + b,
+ 0 + a, 0 + r, 0 + g, 0 + b);
+#else
+ __m256i shuffleMask = _mm256_set_epi8(15 - a, 15 - r, 15 - g, 15 - b,
+ 11 - a, 11 - r, 11 - g, 11 - b,
+ 7 - a, 7 - r, 7 - g, 7 - b,
+ 3 - a, 3 - r, 3 - g, 3 - b,
+ 15 - a, 15 - r, 15 - g, 15 - b,
+ 11 - a, 11 - r, 11 - g, 11 - b,
+ 7 - a, 7 - r, 7 - g, 7 - b,
+ 3 - a, 3 - r, 3 - g, 3 - b);
+#endif
+
+ using Pixel = const ArgbPixel<a, r, g, b>;
for (int y = 0; y < height; ++y) {
- const quint32 *bgra = reinterpret_cast<const quint32*>(src);
+ auto *pixel = reinterpret_cast<const Pixel *>(src);
int x = 0;
- ALIGN(32, argb, x, width) {
- *argb = qConvertBGRA32ToARGB32(*bgra);
- ++bgra;
+ QT_MEDIA_ALIGN(32, argb, x, width) {
+ *argb = pixel->convert();
+ ++pixel;
++argb;
}
for (; x < width - 15; x += 16) {
- __m256i pixelData = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(bgra));
- __m256i pixelData2 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(bgra + 8));
- bgra += 16;
+ __m256i pixelData = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(pixel));
+ __m256i pixelData2 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(pixel + 8));
+ pixel += 16;
pixelData = _mm256_shuffle_epi8(pixelData, shuffleMask);
pixelData2 = _mm256_shuffle_epi8(pixelData2, shuffleMask);
_mm256_store_si256(reinterpret_cast<__m256i*>(argb), pixelData);
@@ -75,8 +61,8 @@ void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_avx2(const QVideoFrame &frame, ucha
// leftovers
for (; x < width; ++x) {
- *argb = qConvertBGRA32ToARGB32(*bgra);
- ++bgra;
+ *argb = pixel->convert();
+ ++pixel;
++argb;
}
@@ -84,6 +70,66 @@ void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_avx2(const QVideoFrame &frame, ucha
}
}
+}
+
+
+void QT_FASTCALL qt_convert_ARGB8888_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output)
+{
+ convert_to_ARGB32_avx2<0, 1, 2, 3>(frame, 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_FASTCALL qt_convert_RGBA8888_to_ARGB32_avx2(const QVideoFrame &frame, uchar *output)
+{
+ convert_to_ARGB32_avx2<3, 0, 1, 2>(frame, 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 b7837db2a..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
@@ -54,40 +18,93 @@
#include <qvideoframe.h>
#include <private/qsimd_p.h>
+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);
-inline quint32 qConvertBGRA32ToARGB32(quint32 bgra)
-{
- return (((bgra & 0xFF000000) >> 24)
- | ((bgra & 0x00FF0000) >> 8)
- | ((bgra & 0x0000FF00) << 8)
- | ((bgra & 0x000000FF) << 24));
-}
+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);
-inline quint32 qConvertBGR24ToARGB32(const uchar *bgr)
+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 ArgbPixel
{
- return 0xFF000000 | bgr[0] | bgr[1] << 8 | bgr[2] << 16;
-}
+ quint32 data;
+ inline quint32 convert() const
+ {
+#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
+ }
+};
-inline quint32 qConvertBGR565ToARGB32(quint16 bgr)
+template<int r, int g, int b>
+struct RgbPixel
{
- return 0xff000000
- | ((((bgr) >> 8) & 0xf8) | (((bgr) >> 13) & 0x7))
- | ((((bgr) << 5) & 0xfc00) | (((bgr) >> 1) & 0x300))
- | ((((bgr) << 19) & 0xf80000) | (((bgr) << 14) & 0x70000));
-}
+ 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
+ }
+};
-inline quint32 qConvertBGR555ToARGB32(quint16 bgr)
+template<typename Y>
+struct YPixel
{
- return 0xff000000
- | ((((bgr) >> 7) & 0xf8) | (((bgr) >> 12) & 0x7))
- | ((((bgr) << 6) & 0xf800) | (((bgr) << 1) & 0x700))
- | ((((bgr) << 19) & 0xf80000) | (((bgr) << 11) & 0x70000));
-}
+ Y data;
+ static constexpr uint shift = (sizeof(Y) - 1)*8;
+ inline quint32 convert() const
+ {
+ uint y = (data >> shift) & 0xff;
+ return (0xff000000)
+ | (y << 16)
+ | (y << 8)
+ | (y);
+ }
+
+};
+
+
+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(); \
- int stride = frame.bytesPerLine(); \
+ const uchar *src = frame.bits(0); \
+ int stride = frame.bytesPerLine(0); \
int width = frame.width(); \
int height = frame.height();
@@ -116,8 +133,10 @@ inline quint32 qConvertBGR555ToARGB32(quint16 bgr)
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
+
#endif // QVIDEOFRAMECONVERSIONHELPER_P_H
diff --git a/src/multimedia/video/qvideoframeconversionhelper_sse2.cpp b/src/multimedia/video/qvideoframeconversionhelper_sse2.cpp
index 50e12c07b..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"
@@ -43,40 +7,50 @@
QT_BEGIN_NAMESPACE
-void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output)
+namespace {
+
+template<int a, int r, int b, int g>
+void convert_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output)
{
FETCH_INFO_PACKED(frame)
MERGE_LOOPS(width, height, stride, 4)
quint32 *argb = reinterpret_cast<quint32*>(output);
const __m128i zero = _mm_setzero_si128();
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ const uchar shuffle = _MM_SHUFFLE(a, r, b, g);
+#else
+ const uchar shuffle = _MM_SHUFFLE(3-a, 3-r, 3-b, 3-g);
+#endif
+
+ using Pixel = const ArgbPixel<a, r, g, b>;
for (int y = 0; y < height; ++y) {
- const quint32 *bgra = reinterpret_cast<const quint32*>(src);
+ auto *pixel = reinterpret_cast<const Pixel *>(src);
int x = 0;
- ALIGN(16, argb, x, width) {
- *argb = qConvertBGRA32ToARGB32(*bgra);
- ++bgra;
+ QT_MEDIA_ALIGN(16, argb, x, width) {
+ *argb = pixel->convert();
+ ++pixel;
++argb;
}
for (; x < width - 3; x += 4) {
- __m128i pixelData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(bgra));
- bgra += 4;
- __m128i gaComponents = _mm_unpacklo_epi8(pixelData, zero);
- __m128i brComponents = _mm_unpackhi_epi8(pixelData, zero);
- gaComponents = _mm_shufflelo_epi16(_mm_shufflehi_epi16(gaComponents, _MM_SHUFFLE(0, 1, 2, 3)), _MM_SHUFFLE(0, 1, 2, 3)); // swap GA
- brComponents = _mm_shufflelo_epi16(_mm_shufflehi_epi16(brComponents, _MM_SHUFFLE(0, 1, 2, 3)), _MM_SHUFFLE(0, 1, 2, 3)); // swap BR
- pixelData = _mm_packus_epi16(gaComponents, brComponents);
+ __m128i pixelData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(pixel));
+ pixel += 4;
+ __m128i lowPixels = _mm_unpacklo_epi8(pixelData, zero);
+ __m128i highPixels = _mm_unpackhi_epi8(pixelData, zero);
+ lowPixels = _mm_shufflelo_epi16(_mm_shufflehi_epi16(lowPixels, shuffle), shuffle);
+ highPixels = _mm_shufflelo_epi16(_mm_shufflehi_epi16(highPixels, shuffle), shuffle);
+ pixelData = _mm_packus_epi16(lowPixels, highPixels);
_mm_store_si128(reinterpret_cast<__m128i*>(argb), pixelData);
argb += 4;
}
// leftovers
for (; x < width; ++x) {
- *argb = qConvertBGRA32ToARGB32(*bgra);
- ++bgra;
+ *argb = pixel->convert();
+ ++pixel;
++argb;
}
@@ -84,6 +58,66 @@ void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_sse2(const QVideoFrame &frame, ucha
}
}
+}
+
+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_FASTCALL qt_convert_ABGR8888_to_ARGB32_sse2(const QVideoFrame &frame, uchar *output)
+{
+ convert_to_ARGB32_sse2<0, 3, 2, 1>(frame, 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_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 1e87c8e5c..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"
@@ -43,28 +7,43 @@
QT_BEGIN_NAMESPACE
-void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output)
+namespace {
+
+template<int a, int r, int g, int b>
+void convert_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output)
{
FETCH_INFO_PACKED(frame)
MERGE_LOOPS(width, height, stride, 4)
quint32 *argb = reinterpret_cast<quint32*>(output);
- __m128i shuffleMask = _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3);
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ __m128i shuffleMask = _mm_set_epi8(12 + a, 12 + r, 12 + g, 12 + b,
+ 8 + a, 8 + r, 8 + g, 8 + b,
+ 4 + a, 4 + r, 4 + g, 4 + b,
+ 0 + a, 0 + r, 0 + g, 0 + b);
+#else
+ __m128i shuffleMask = _mm_set_epi8(15 - a, 15 - r, 15 - g, 15 - b,
+ 11 - a, 11 - r, 11 - g, 11 - b,
+ 7 - a, 7 - r, 7 - g, 7 - b,
+ 3 - a, 3 - r, 3 - g, 3 - b);
+#endif
+
+ using Pixel = const ArgbPixel<a, r, g, b>;
for (int y = 0; y < height; ++y) {
- const quint32 *bgra = reinterpret_cast<const quint32*>(src);
+ const auto *pixel = reinterpret_cast<const Pixel *>(src);
int x = 0;
- ALIGN(16, argb, x, width) {
- *argb = qConvertBGRA32ToARGB32(*bgra);
- ++bgra;
+ QT_MEDIA_ALIGN(16, argb, x, width) {
+ *argb = pixel->convert();
+ ++pixel;
++argb;
}
for (; x < width - 7; x += 8) {
- __m128i pixelData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(bgra));
- __m128i pixelData2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(bgra + 4));
- bgra += 8;
+ __m128i pixelData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(pixel));
+ __m128i pixelData2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(pixel + 4));
+ pixel += 8;
pixelData = _mm_shuffle_epi8(pixelData, shuffleMask);
pixelData2 = _mm_shuffle_epi8(pixelData2, shuffleMask);
_mm_store_si128(reinterpret_cast<__m128i*>(argb), pixelData);
@@ -74,8 +53,8 @@ void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_ssse3(const QVideoFrame &frame, uch
// leftovers
for (; x < width; ++x) {
- *argb = qConvertBGRA32ToARGB32(*bgra);
- ++bgra;
+ *argb = pixel->convert();
+ ++pixel;
++argb;
}
@@ -83,6 +62,28 @@ void QT_FASTCALL qt_convert_BGRA32_to_ARGB32_ssse3(const QVideoFrame &frame, uch
}
}
+}
+
+void QT_FASTCALL qt_convert_ARGB8888_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output)
+{
+ convert_to_ARGB32_ssse3<0, 1, 2, 3>(frame, 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_FASTCALL qt_convert_RGBA8888_to_ARGB32_ssse3(const QVideoFrame &frame, uchar *output)
+{
+ convert_to_ARGB32_ssse3<3, 0, 1, 2>(frame, 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);
+}
+
QT_END_NAMESPACE
#endif
diff --git a/src/multimedia/video/qvideoframeconverter.cpp b/src/multimedia/video/qvideoframeconverter.cpp
new file mode 100644
index 000000000..7883f91a5
--- /dev/null
+++ b/src/multimedia/video/qvideoframeconverter.cpp
@@ -0,0 +1,462 @@
+// 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 "qabstractvideobuffer.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/qguiapplication_p.h>
+#include <rhi/qrhi.h>
+
+#ifdef Q_OS_DARWIN
+#include <QtCore/private/qcore_mac_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+Q_STATIC_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(QtVideo::MapMode::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(QtVideo::MapMode::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, bool forceCpu)
+{
+#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);
+
+ if (forceCpu) // For test purposes
+ return convertCPU(frame, rotation, mirrorX, mirrorY);
+
+ QRhi *rhi = nullptr;
+
+ if (QHwVideoBuffer *buffer = QVideoFramePrivate::hwBuffer(frame))
+ rhi = buffer->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(QtVideo::MapMode::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..ad6cea9e4
--- /dev/null
+++ b/src/multimedia/video/qvideoframeconverter_p.h
@@ -0,0 +1,36 @@
+// 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, bool forceCpu = 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
new file mode 100644
index 000000000..b3177234f
--- /dev/null
+++ b/src/multimedia/video/qvideoframeformat.cpp
@@ -0,0 +1,1044 @@
+// 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"
+
+#include <qdebug.h>
+#include <qlist.h>
+#include <qmetatype.h>
+#include <qpair.h>
+#include <qvariant.h>
+#include <qmatrix4x4.h>
+
+static void initResource() {
+ Q_INIT_RESOURCE(qtmultimedia_shaders);
+}
+
+QT_BEGIN_NAMESPACE
+
+class QVideoFrameFormatPrivate : public QSharedData
+{
+public:
+ QVideoFrameFormatPrivate() = default;
+
+ QVideoFrameFormatPrivate(
+ const QSize &size,
+ QVideoFrameFormat::PixelFormat format)
+ : pixelFormat(format)
+ , frameSize(size)
+ , viewport(QPoint(0, 0), size)
+ {
+ }
+
+ bool operator ==(const QVideoFrameFormatPrivate &other) const
+ {
+ if (pixelFormat == other.pixelFormat
+ && scanLineDirection == other.scanLineDirection
+ && frameSize == other.frameSize
+ && viewport == other.viewport
+ && frameRatesEqual(frameRate, other.frameRate)
+ && colorSpace == other.colorSpace
+ && mirrored == other.mirrored
+ && rotation == other.rotation)
+ return true;
+
+ return false;
+ }
+
+ inline static bool frameRatesEqual(qreal r1, qreal r2)
+ {
+ return qAbs(r1 - r2) <= 0.00001 * qMin(qAbs(r1), qAbs(r2));
+ }
+
+ QVideoFrameFormat::PixelFormat pixelFormat = QVideoFrameFormat::Format_Invalid;
+ QVideoFrameFormat::Direction scanLineDirection = QVideoFrameFormat::TopToBottom;
+ QSize frameSize;
+ QVideoFrameFormat::ColorSpace colorSpace = QVideoFrameFormat::ColorSpace_Undefined;
+ QVideoFrameFormat::ColorTransfer colorTransfer = QVideoFrameFormat::ColorTransfer_Unknown;
+ QVideoFrameFormat::ColorRange colorRange = QVideoFrameFormat::ColorRange_Unknown;
+ QRect viewport;
+ float frameRate = 0.0;
+ float maxLuminance = -1.;
+ bool mirrored = false;
+ QtVideo::Rotation rotation = QtVideo::Rotation::None;
+};
+
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QVideoFrameFormatPrivate);
+
+/*!
+ \class QVideoFrameFormat
+ \brief The QVideoFrameFormat class specifies the stream format of a video presentation
+ surface.
+ \inmodule QtMultimedia
+
+ \ingroup multimedia
+ \ingroup multimedia_video
+
+ 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 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().
+ A stream may have a viewport less than the entire region of a frame to allow for videos smaller
+ than the nearest optimal size of a video frame. For example the width of a frame may be
+ extended so that the start of each scan line is eight byte aligned.
+
+ Other common properties are the scanLineDirection(), frameRate() and the yCrCbColorSpace().
+*/
+
+/*!
+ \enum QVideoFrameFormat::PixelFormat
+
+ Enumerates video data types.
+
+ \value Format_Invalid
+ The frame is invalid.
+
+ \value Format_ARGB8888
+ The frame is stored using a ARGB format with 8 bits per component.
+
+ \value Format_ARGB8888_Premultiplied
+ The frame stored using a premultiplied ARGB format with 8 bits per component.
+
+ \value Format_XRGB8888
+ The frame stored using a 32 bits per pixel RGB format (0xff, R, G, B).
+
+ \value Format_BGRA8888
+ The frame is stored using a 32-bit BGRA format (0xBBGGRRAA).
+
+ \value Format_BGRA8888_Premultiplied
+ The frame is stored using a premultiplied 32bit BGRA format.
+
+ \value Format_ABGR8888
+ The frame is stored using a 32-bit ABGR format (0xAABBGGRR).
+
+ \value Format_XBGR8888
+ The frame is stored using a 32-bit BGR format (0xffBBGGRR).
+
+ \value Format_RGBA8888
+ The frame is stored in memory as the bytes R, G, B, A/X, with R at the lowest address and A/X at the highest address.
+
+ \value Format_BGRX8888
+ The frame is stored in format 32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian
+
+ \value Format_RGBX8888
+ The frame is stored in memory as the bytes R, G, B, A/X, with R at the lowest address and A/X at the highest address.
+
+ \value Format_AYUV
+ The frame is stored using a packed 32-bit AYUV format (0xAAYYUUVV).
+
+ \value Format_AYUV_Premultiplied
+ The frame is stored using a packed premultiplied 32-bit AYUV format (0xAAYYUUVV).
+
+ \value Format_YUV420P
+ The frame is stored using an 8-bit per component planar YUV format with the U and V planes
+ horizontally and vertically sub-sampled, i.e. the height and width of the U and V planes are
+ half that of the Y plane.
+
+ \value Format_YUV422P
+ The frame is stored using an 8-bit per component planar YUV format with the U and V planes
+ horizontally sub-sampled, i.e. the width of the U and V planes are
+ half that of the Y plane, and height of U and V planes is the same as Y.
+
+ \value Format_YV12
+ The frame is stored using an 8-bit per component planar YVU format with the V and U planes
+ horizontally and vertically sub-sampled, i.e. the height and width of the V and U planes are
+ half that of the Y plane.
+
+ \value Format_UYVY
+ The frame is stored using an 8-bit per component packed YUV format with the U and V planes
+ horizontally sub-sampled (U-Y-V-Y), i.e. two horizontally adjacent pixels are stored as a 32-bit
+ macropixel which has a Y value for each pixel and common U and V values.
+
+ \value Format_YUYV
+ The frame is stored using an 8-bit per component packed YUV format with the U and V planes
+ horizontally sub-sampled (Y-U-Y-V), i.e. two horizontally adjacent pixels are stored as a 32-bit
+ macropixel which has a Y value for each pixel and common U and V values.
+
+ \value Format_NV12
+ The frame is stored using an 8-bit per component semi-planar YUV format with a Y plane (Y)
+ followed by a horizontally and vertically sub-sampled, packed UV plane (U-V).
+
+ \value Format_NV21
+ The frame is stored using an 8-bit per component semi-planar YUV format with a Y plane (Y)
+ followed by a horizontally and vertically sub-sampled, packed VU plane (V-U).
+
+ \value Format_IMC1
+ The frame is stored using an 8-bit per component planar YUV format with the U and V planes
+ horizontally and vertically sub-sampled. This is similar to the Format_YUV420P type, except
+ that the bytes per line of the U and V planes are padded out to the same stride as the Y plane.
+
+ \value Format_IMC2
+ The frame is stored using an 8-bit per component planar YUV format with the U and V planes
+ horizontally and vertically sub-sampled. This is similar to the Format_YUV420P type, except
+ that the lines of the U and V planes are interleaved, i.e. each line of U data is followed by a
+ line of V data creating a single line of the same stride as the Y data.
+
+ \value Format_IMC3
+ The frame is stored using an 8-bit per component planar YVU format with the V and U planes
+ horizontally and vertically sub-sampled. This is similar to the Format_YV12 type, except that
+ the bytes per line of the V and U planes are padded out to the same stride as the Y plane.
+
+ \value Format_IMC4
+ The frame is stored using an 8-bit per component planar YVU format with the V and U planes
+ horizontally and vertically sub-sampled. This is similar to the Format_YV12 type, except that
+ the lines of the V and U planes are interleaved, i.e. each line of V data is followed by a line
+ of U data creating a single line of the same stride as the Y data.
+
+ \value Format_P010
+ The frame is stored using a 16bit per component semi-planar YUV format with a Y plane (Y)
+ followed by a horizontally and vertically sub-sampled, packed UV plane (U-V). Only the 10 most
+ significant bits of each component are being used.
+
+ \value Format_P016
+ The frame is stored using a 16bit per component semi-planar YUV format with a Y plane (Y)
+ followed by a horizontally and vertically sub-sampled, packed UV plane (U-V).
+
+ \value Format_Y8
+ The frame is stored using an 8-bit greyscale format.
+
+ \value Format_Y16
+ The frame is stored using a 16-bit linear greyscale format. Little endian.
+
+ \value Format_Jpeg
+ The frame is stored in compressed Jpeg format.
+
+ \value Format_SamplerExternalOES
+ 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 (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.
+*/
+
+/*!
+ \enum QVideoFrameFormat::Direction
+
+ Enumerates the layout direction of video scan lines.
+
+ \value TopToBottom Scan lines are arranged from the top of the frame to the bottom.
+ \value BottomToTop Scan lines are arranged from the bottom of the frame to the top.
+*/
+
+/*!
+ \enum QVideoFrameFormat::YCbCrColorSpace
+
+ \deprecated Use QVideoFrameFormat::ColorSpace instead.
+
+ Enumerates the Y'CbCr color space of video frames.
+
+ \value YCbCr_Undefined
+ No color space is specified.
+
+ \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 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.
+ 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 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.
+*/
+
+/*!
+ Constructs a null video stream format.
+*/
+QVideoFrameFormat::QVideoFrameFormat()
+ : d(new QVideoFrameFormatPrivate)
+{
+ initResource();
+}
+
+/*!
+ Constructs a video stream with the given frame \a size and pixel \a format.
+*/
+QVideoFrameFormat::QVideoFrameFormat(
+ const QSize& size, QVideoFrameFormat::PixelFormat format)
+ : d(new QVideoFrameFormatPrivate(size, format))
+{
+}
+
+/*!
+ Constructs a copy of \a other.
+*/
+QVideoFrameFormat::QVideoFrameFormat(const QVideoFrameFormat &other) = default;
+
+/*!
+ \fn QVideoFrameFormat::QVideoFrameFormat(QVideoFrameFormat &&other)
+
+ Constructs a QVideoFrameFormat by moving from \a other.
+*/
+
+/*!
+ \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;
+
+/*!
+ \fn QVideoFrameFormat &QVideoFrameFormat::operator =(QVideoFrameFormat &&other)
+
+ Moves \a other into this QVideoFrameFormat.
+*/
+
+/*!
+ Destroys a video stream description.
+*/
+QVideoFrameFormat::~QVideoFrameFormat() = default;
+
+/*!
+ Identifies if a video surface format has a valid pixel format and frame size.
+
+ Returns true if the format is valid, and false otherwise.
+*/
+bool QVideoFrameFormat::isValid() const
+{
+ return d->pixelFormat != Format_Invalid && d->frameSize.isValid();
+}
+
+/*!
+ Returns true if \a other is the same as this video format, and false if they are different.
+*/
+bool QVideoFrameFormat::operator ==(const QVideoFrameFormat &other) const
+{
+ return d == other.d || *d == *other.d;
+}
+
+/*!
+ Returns true if \a other is different to this video format, and false if they are the same.
+*/
+bool QVideoFrameFormat::operator !=(const QVideoFrameFormat &other) const
+{
+ return d != other.d && !(*d == *other.d);
+}
+
+/*!
+ \internal
+*/
+void QVideoFrameFormat::detach()
+{
+ d.detach();
+}
+
+/*!
+ Returns the pixel format of frames in a video stream.
+*/
+QVideoFrameFormat::PixelFormat QVideoFrameFormat::pixelFormat() const
+{
+ return d->pixelFormat;
+}
+
+/*!
+ Returns the dimensions of frames in a video stream.
+
+ \sa frameWidth(), frameHeight()
+*/
+QSize QVideoFrameFormat::frameSize() const
+{
+ return d->frameSize;
+}
+
+/*!
+ Returns the width of frames in a video stream.
+
+ \sa frameSize(), frameHeight()
+*/
+int QVideoFrameFormat::frameWidth() const
+{
+ return d->frameSize.width();
+}
+
+/*!
+ Returns the height of frame in a video stream.
+*/
+int QVideoFrameFormat::frameHeight() const
+{
+ return d->frameSize.height();
+}
+
+/*!
+ Returns the number of planes used.
+ This number is depending on the pixel format and is
+ 1 for RGB based formats, and a number between 1 and 3 for
+ YUV based formats.
+*/
+int QVideoFrameFormat::planeCount() const
+{
+ return QVideoTextureHelper::textureDescription(d->pixelFormat)->nplanes;
+}
+
+/*!
+ Sets the size of frames in a video stream to \a size.
+
+ This will reset the viewport() to fill the entire frame.
+*/
+void QVideoFrameFormat::setFrameSize(const QSize &size)
+{
+ detach();
+ d->frameSize = size;
+ d->viewport = QRect(QPoint(0, 0), size);
+}
+
+/*!
+ \overload
+
+ Sets the \a width and \a height of frames in a video stream.
+
+ This will reset the viewport() to fill the entire frame.
+*/
+void QVideoFrameFormat::setFrameSize(int width, int height)
+{
+ detach();
+ d->frameSize = QSize(width, height);
+ d->viewport = QRect(0, 0, width, height);
+}
+
+/*!
+ Returns the viewport of a video stream.
+
+ The viewport is the region of a video frame that is actually displayed.
+
+ By default the viewport covers an entire frame.
+*/
+QRect QVideoFrameFormat::viewport() const
+{
+ return d->viewport;
+}
+
+/*!
+ Sets the viewport of a video stream to \a viewport.
+*/
+void QVideoFrameFormat::setViewport(const QRect &viewport)
+{
+ detach();
+ d->viewport = viewport;
+}
+
+/*!
+ Returns the direction of scan lines.
+*/
+QVideoFrameFormat::Direction QVideoFrameFormat::scanLineDirection() const
+{
+ return d->scanLineDirection;
+}
+
+/*!
+ Sets the \a direction of scan lines.
+*/
+void QVideoFrameFormat::setScanLineDirection(Direction direction)
+{
+ detach();
+ d->scanLineDirection = direction;
+}
+
+#if QT_DEPRECATED_SINCE(6, 8)
+/*!
+ Returns the frame rate of a video stream in frames per second.
+*/
+qreal QVideoFrameFormat::frameRate() const
+{
+ return streamFrameRate();
+}
+
+/*!
+ Sets the frame \a rate of a video stream in frames per second.
+*/
+void QVideoFrameFormat::setFrameRate(qreal rate)
+{
+ setStreamFrameRate(rate);
+}
+#endif
+
+/*!
+ Returns the frame rate of a video stream in frames per second.
+*/
+qreal QVideoFrameFormat::streamFrameRate() const
+{
+ return d->frameRate;
+}
+
+/*!
+ Sets the frame \a rate of a video stream in frames per second.
+*/
+void QVideoFrameFormat::setStreamFrameRate(qreal rate)
+{
+ detach();
+ 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 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->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;
+}
+
+/*!
+ Returns \c true if the surface is mirrored around its vertical axis.
+ This is typically needed for video frames coming from a front camera of a mobile device.
+
+ \note The mirroring here differs from QImage::mirrored, as a vertically mirrored QImage
+ will be mirrored around its x-axis.
+
+ \since 5.11
+ */
+bool QVideoFrameFormat::isMirrored() const
+{
+ return d->mirrored;
+}
+
+/*!
+ Sets if the surface is \a mirrored around its vertical axis.
+ This is typically needed for video frames coming from a front camera of a mobile device.
+ Default value is false.
+
+ \note The mirroring here differs from QImage::mirrored, as a vertically mirrored QImage
+ will be mirrored around its x-axis.
+
+ \since 5.11
+ */
+void QVideoFrameFormat::setMirrored(bool mirrored)
+{
+ detach();
+ d->mirrored = mirrored;
+}
+
+/*!
+ Returns the rotation angle the matching video frame should be rotated clockwise before displaying.
+ */
+QtVideo::Rotation QVideoFrameFormat::rotation() const
+{
+ return d->rotation;
+}
+
+/*!
+ Sets the \a rotation angle the matching video frame should be rotated clockwise before displaying.
+ */
+void QVideoFrameFormat::setRotation(QtVideo::Rotation rotation)
+{
+ detach();
+ d->rotation = rotation;
+}
+
+/*!
+ \internal
+*/
+QString QVideoFrameFormat::vertexShaderFileName() const
+{
+ return QVideoTextureHelper::vertexShaderFileName(*this);
+}
+
+/*!
+ \internal
+*/
+QString QVideoFrameFormat::fragmentShaderFileName() const
+{
+ return QVideoTextureHelper::fragmentShaderFileName(*this);
+}
+
+/*!
+ \internal
+*/
+void QVideoFrameFormat::updateUniformData(QByteArray *dst, const QVideoFrame &frame, const QMatrix4x4 &transform, float opacity) const
+{
+ 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
+ format QVideoFrameFormat::Format_Invalid is returned instead.
+
+ \note In general \l QImage does not handle YUV formats.
+
+*/
+QVideoFrameFormat::PixelFormat QVideoFrameFormat::pixelFormatFromImageFormat(QImage::Format format)
+{
+ switch (format) {
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ case QImage::Format_RGB32:
+ return QVideoFrameFormat::Format_BGRX8888;
+ case QImage::Format_ARGB32:
+ return QVideoFrameFormat::Format_BGRA8888;
+ case QImage::Format_ARGB32_Premultiplied:
+ return QVideoFrameFormat::Format_BGRA8888_Premultiplied;
+#else
+ case QImage::Format_RGB32:
+ return QVideoFrameFormat::Format_XRGB8888;
+ case QImage::Format_ARGB32:
+ return QVideoFrameFormat::Format_ARGB8888;
+ case QImage::Format_ARGB32_Premultiplied:
+ return QVideoFrameFormat::Format_ARGB8888_Premultiplied;
+#endif
+ case QImage::Format_RGBA8888:
+ return QVideoFrameFormat::Format_RGBA8888;
+ case QImage::Format_RGBA8888_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:
+ return QVideoFrameFormat::Format_Y8;
+ case QImage::Format_Grayscale16:
+ return QVideoFrameFormat::Format_Y16;
+ default:
+ return QVideoFrameFormat::Format_Invalid;
+ }
+}
+
+/*!
+ Returns an image format equivalent to a video frame pixel \a format. If there is no equivalent
+ format QImage::Format_Invalid is returned instead.
+
+ \note In general \l QImage does not handle YUV formats.
+
+*/
+QImage::Format QVideoFrameFormat::imageFormatFromPixelFormat(QVideoFrameFormat::PixelFormat format)
+{
+ switch (format) {
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ case QVideoFrameFormat::Format_BGRA8888:
+ return QImage::Format_ARGB32;
+ case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
+ return QImage::Format_ARGB32_Premultiplied;
+ case QVideoFrameFormat::Format_BGRX8888:
+ return QImage::Format_RGB32;
+ case QVideoFrameFormat::Format_ARGB8888:
+ case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
+ case QVideoFrameFormat::Format_XRGB8888:
+ return QImage::Format_Invalid;
+#else
+ case QVideoFrameFormat::Format_ARGB8888:
+ return QImage::Format_ARGB32;
+ case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
+ return QImage::Format_ARGB32_Premultiplied;
+ case QVideoFrameFormat::Format_XRGB8888:
+ return QImage::Format_RGB32;
+ case QVideoFrameFormat::Format_BGRA8888:
+ case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
+ case QVideoFrameFormat::Format_BGRX8888:
+ return QImage::Format_Invalid;
+#endif
+ case QVideoFrameFormat::Format_RGBA8888:
+ return QImage::Format_RGBA8888;
+ case QVideoFrameFormat::Format_RGBX8888:
+ return QImage::Format_RGBX8888;
+ case QVideoFrameFormat::Format_Y8:
+ return QImage::Format_Grayscale8;
+ case QVideoFrameFormat::Format_Y16:
+ return QImage::Format_Grayscale16;
+ case QVideoFrameFormat::Format_ABGR8888:
+ case QVideoFrameFormat::Format_XBGR8888:
+ 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:
+ case QVideoFrameFormat::Format_YUYV:
+ case QVideoFrameFormat::Format_NV12:
+ case QVideoFrameFormat::Format_NV21:
+ case QVideoFrameFormat::Format_IMC1:
+ case QVideoFrameFormat::Format_IMC2:
+ case QVideoFrameFormat::Format_IMC3:
+ case QVideoFrameFormat::Format_IMC4:
+ case QVideoFrameFormat::Format_P010:
+ case QVideoFrameFormat::Format_P016:
+ case QVideoFrameFormat::Format_Jpeg:
+ case QVideoFrameFormat::Format_Invalid:
+ case QVideoFrameFormat::Format_SamplerExternalOES:
+ case QVideoFrameFormat::Format_SamplerRect:
+ return QImage::Format_Invalid;
+ }
+ 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);
+ dbg.nospace();
+ switch (cs) {
+ case QVideoFrameFormat::YCbCr_BT601:
+ dbg << "YCbCr_BT601";
+ break;
+ case QVideoFrameFormat::YCbCr_BT709:
+ dbg << "YCbCr_BT709";
+ break;
+ case QVideoFrameFormat::YCbCr_JPEG:
+ dbg << "YCbCr_JPEG";
+ break;
+ case QVideoFrameFormat::YCbCr_xvYCC601:
+ dbg << "YCbCr_xvYCC601";
+ break;
+ 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)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace();
+ switch (dir) {
+ case QVideoFrameFormat::BottomToTop:
+ dbg << "BottomToTop";
+ break;
+ case QVideoFrameFormat::TopToBottom:
+ dbg << "TopToBottom";
+ break;
+ }
+ return dbg;
+}
+
+QDebug operator<<(QDebug dbg, const QVideoFrameFormat &f)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace();
+ dbg << "QVideoFrameFormat(" << f.pixelFormat() << ", " << f.frameSize()
+ << ", viewport=" << f.viewport()
+ << ", colorSpace=" << f.colorSpace()
+ << ')'
+ << "\n pixel format=" << f.pixelFormat()
+ << "\n frame size=" << f.frameSize()
+ << "\n viewport=" << f.viewport()
+ << "\n colorSpace=" << f.colorSpace()
+ << "\n frameRate=" << f.streamFrameRate()
+ << "\n mirrored=" << f.isMirrored();
+
+ return dbg;
+}
+
+QDebug operator<<(QDebug dbg, QVideoFrameFormat::PixelFormat pf)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace();
+
+ auto format = QVideoFrameFormat::pixelFormatToString(pf);
+ if (format.isEmpty())
+ return dbg;
+
+ dbg.noquote() << QStringLiteral("Format_") << format;
+ return dbg;
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/video/qvideoframeformat.h b/src/multimedia/video/qvideoframeformat.h
new file mode 100644
index 000000000..9b3879108
--- /dev/null
+++ b/src/multimedia/video/qvideoframeformat.h
@@ -0,0 +1,225 @@
+// 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
+
+#include <QtMultimedia/qtmultimediaglobal.h>
+#include <QtMultimedia/qtvideo.h>
+
+#include <QtCore/qlist.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qsize.h>
+#include <QtGui/qimage.h>
+
+QT_BEGIN_NAMESPACE
+
+
+class QDebug;
+
+class QVideoFrameFormatPrivate;
+class QVideoFrame;
+class QMatrix4x4;
+
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QVideoFrameFormatPrivate, Q_MULTIMEDIA_EXPORT)
+
+class Q_MULTIMEDIA_EXPORT QVideoFrameFormat
+{
+ Q_GADGET
+public:
+ enum PixelFormat
+ {
+ Format_Invalid,
+ Format_ARGB8888,
+ Format_ARGB8888_Premultiplied,
+ Format_XRGB8888,
+ Format_BGRA8888,
+ Format_BGRA8888_Premultiplied,
+ Format_BGRX8888,
+ Format_ABGR8888,
+ Format_XBGR8888,
+ Format_RGBA8888,
+ Format_RGBX8888,
+
+ Format_AYUV,
+ Format_AYUV_Premultiplied,
+ Format_YUV420P,
+ Format_YUV422P,
+ Format_YV12,
+ Format_UYVY,
+ Format_YUYV,
+ Format_NV12,
+ Format_NV21,
+ Format_IMC1,
+ Format_IMC2,
+ Format_IMC3,
+ Format_IMC4,
+ Format_Y8,
+ Format_Y16,
+
+ Format_P010,
+ Format_P016,
+
+ Format_SamplerExternalOES,
+ Format_Jpeg,
+ Format_SamplerRect,
+
+ Format_YUV420P10
+ };
+ Q_ENUM(PixelFormat)
+#ifndef Q_QDOC
+ static constexpr int NPixelFormats = Format_YUV420P10 + 1;
+#endif
+
+ enum Direction
+ {
+ TopToBottom,
+ BottomToTop
+ };
+
+#if QT_DEPRECATED_SINCE(6, 4)
+ enum YCbCrColorSpace
+ {
+ 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();
+ QVideoFrameFormat(const QSize &size, PixelFormat pixelFormat);
+ QVideoFrameFormat(const QVideoFrameFormat &format);
+ ~QVideoFrameFormat();
+
+ QVideoFrameFormat(QVideoFrameFormat &&other) noexcept = default;
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QVideoFrameFormat);
+ void swap(QVideoFrameFormat &other) noexcept
+ { d.swap(other.d); }
+
+ void detach();
+
+ QVideoFrameFormat &operator=(const QVideoFrameFormat &format);
+
+ bool operator==(const QVideoFrameFormat &format) const;
+ bool operator!=(const QVideoFrameFormat &format) const;
+
+ bool isValid() const;
+
+ QVideoFrameFormat::PixelFormat pixelFormat() const;
+
+ QSize frameSize() const;
+ void setFrameSize(const QSize &size);
+ void setFrameSize(int width, int height);
+
+ int frameWidth() const;
+ int frameHeight() const;
+
+ int planeCount() const;
+
+ QRect viewport() const;
+ void setViewport(const QRect &viewport);
+
+ Direction scanLineDirection() const;
+ void setScanLineDirection(Direction direction);
+
+#if QT_DEPRECATED_SINCE(6, 8)
+ QT_DEPRECATED_VERSION_X_6_8("Use streamFrameRate()")
+ qreal frameRate() const;
+ QT_DEPRECATED_VERSION_X_6_8("Use setStreamFrameRate()")
+ void setFrameRate(qreal rate);
+#endif
+
+ qreal streamFrameRate() const;
+ void setStreamFrameRate(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);
+
+ QtVideo::Rotation rotation() const;
+ void setRotation(QtVideo::Rotation rotation);
+
+ QString vertexShaderFileName() const;
+ 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;
+};
+
+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
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QVideoFrameFormat)
+
+#endif
+
diff --git a/src/multimedia/video/qvideooutputorientationhandler.cpp b/src/multimedia/video/qvideooutputorientationhandler.cpp
index e21efb37d..ff91bd7fb 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"
@@ -44,14 +8,18 @@
QT_BEGIN_NAMESPACE
+bool QVideoOutputOrientationHandler::m_isRecording = false;
+
QVideoOutputOrientationHandler::QVideoOutputOrientationHandler(QObject *parent)
: QObject(parent)
, m_currentOrientation(0)
{
QScreen *screen = QGuiApplication::primaryScreen();
+ if (!screen)
+ return;
- connect(screen, SIGNAL(orientationChanged(Qt::ScreenOrientation)),
- this, SLOT(screenOrientationChanged(Qt::ScreenOrientation)));
+ connect(screen, &QScreen::orientationChanged, this,
+ &QVideoOutputOrientationHandler::screenOrientationChanged);
screenOrientationChanged(screen->orientation());
}
@@ -63,7 +31,12 @@ int QVideoOutputOrientationHandler::currentOrientation() const
void QVideoOutputOrientationHandler::screenOrientationChanged(Qt::ScreenOrientation orientation)
{
+ if (m_isRecording)
+ return;
+
const QScreen *screen = QGuiApplication::primaryScreen();
+ if (!screen)
+ return;
const int angle = (360 - screen->angleBetween(screen->nativeOrientation(), orientation)) % 360;
@@ -75,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 d04a781ab..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
@@ -65,6 +30,9 @@ public:
int currentOrientation() const;
+ static void setIsRecording(bool isRecording) { m_isRecording = isRecording; }
+ static bool isRecording() { return m_isRecording; }
+
Q_SIGNALS:
void orientationChanged(int angle);
@@ -73,6 +41,7 @@ private Q_SLOTS:
private:
int m_currentOrientation;
+ static bool m_isRecording;
};
QT_END_NAMESPACE
diff --git a/src/multimedia/video/qvideoprobe.cpp b/src/multimedia/video/qvideoprobe.cpp
deleted file mode 100644
index f7995b297..000000000
--- a/src/multimedia/video/qvideoprobe.cpp
+++ /dev/null
@@ -1,218 +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$
-**
-****************************************************************************/
-
-
-/*!
- \class QVideoProbe
- \inmodule QtMultimedia
-
- \ingroup multimedia
- \ingroup multimedia_video
-
- \brief The QVideoProbe class allows you to monitor video frames being played or recorded.
-
- \code
- QMediaPlayer *player = new QMediaPlayer();
- QVideoProbe *probe = new QVideoProbe;
-
- connect(probe, SIGNAL(videoFrameProbed(QVideoFrame)), this, SLOT(processFrame(QVideoFrame)));
-
- probe->setSource(player); // Returns true, hopefully.
-
- player->setVideoOutput(myVideoSurface);
- player->setMedia(QUrl::fromLocalFile("observation.mp4"));
- player->play(); // Start receiving frames as they get presented to myVideoSurface
- \endcode
-
- This same approach works with the QCamera object as well, to receive viewfinder or video
- frames as they are captured.
-
- \sa QAudioProbe, QMediaPlayer, QCamera
-*/
-
-#include "qvideoprobe.h"
-#include "qmediavideoprobecontrol.h"
-#include "qmediaservice.h"
-#include "qmediarecorder.h"
-#include "qsharedpointer.h"
-#include "qpointer.h"
-
-QT_BEGIN_NAMESPACE
-
-class QVideoProbePrivate {
-public:
- QPointer<QMediaObject> source;
- QPointer<QMediaVideoProbeControl> probee;
-};
-
-/*!
- Creates a new QVideoProbe class with \a parent. After setting the
- source to monitor with \l setSource(), the \l videoFrameProbed()
- signal will be emitted when video frames are flowing in the
- source media object.
- */
-QVideoProbe::QVideoProbe(QObject *parent)
- : QObject(parent)
- , d(new QVideoProbePrivate)
-{
-
-}
-
-/*!
- Destroys this probe and disconnects from any
- media object.
- */
-QVideoProbe::~QVideoProbe()
-{
- if (d->source) {
- // Disconnect
- if (d->probee) {
- disconnect(d->probee.data(), SIGNAL(videoFrameProbed(QVideoFrame)), this, SIGNAL(videoFrameProbed(QVideoFrame)));
- disconnect(d->probee.data(), SIGNAL(flush()), this, SIGNAL(flush()));
- }
- d->source.data()->service()->releaseControl(d->probee.data());
- }
-}
-
-/*!
- Sets the media object to monitor to \a source.
-
- If \a source is zero, this probe will be deactivated
- and this function wil return true.
-
- If the media object does not support monitoring
- video, this function will return false.
-
- Any previously monitored objects will no longer be monitored.
- Passing in the same object will be ignored, but
- monitoring will continue.
- */
-bool QVideoProbe::setSource(QMediaObject *source)
-{
- // Need to:
- // 1) disconnect from current source if necessary
- // 2) see if new one has the probe control
- // 3) connect if so
-
- // in case source was destroyed but probe control is still valid
- if (!d->source && d->probee) {
- disconnect(d->probee.data(), SIGNAL(videoFrameProbed(QVideoFrame)), this, SIGNAL(videoFrameProbed(QVideoFrame)));
- disconnect(d->probee.data(), SIGNAL(flush()), this, SIGNAL(flush()));
- d->probee.clear();
- }
-
- if (source != d->source.data()) {
- if (d->source) {
- Q_ASSERT(d->probee);
- disconnect(d->probee.data(), SIGNAL(videoFrameProbed(QVideoFrame)), this, SIGNAL(videoFrameProbed(QVideoFrame)));
- disconnect(d->probee.data(), SIGNAL(flush()), this, SIGNAL(flush()));
- d->source.data()->service()->releaseControl(d->probee.data());
- d->source.clear();
- d->probee.clear();
- }
-
- if (source) {
- QMediaService *service = source->service();
- if (service) {
- d->probee = service->requestControl<QMediaVideoProbeControl*>();
- }
-
- if (d->probee) {
- connect(d->probee.data(), SIGNAL(videoFrameProbed(QVideoFrame)), this, SIGNAL(videoFrameProbed(QVideoFrame)));
- connect(d->probee.data(), SIGNAL(flush()), this, SIGNAL(flush()));
- d->source = source;
- }
- }
- }
-
- return (!source || d->probee != nullptr);
-}
-
-/*!
- Starts monitoring the given \a mediaRecorder.
-
- If there is no mediaObject associated with \a mediaRecorder, or if it is
- zero, this probe will be deactivated and this function wil return true.
-
- If the media recorder instance does not support monitoring
- video, this function will return false.
-
- Any previously monitored objects will no longer be monitored.
- Passing in the same object will be ignored, but
- monitoring will continue.
- */
-bool QVideoProbe::setSource(QMediaRecorder *mediaRecorder)
-{
- QMediaObject *source = mediaRecorder ? mediaRecorder->mediaObject() : nullptr;
- bool result = setSource(source);
-
- if (!mediaRecorder)
- return true;
-
- if (mediaRecorder && !source)
- return false;
-
- return result;
-}
-
-/*!
- Returns true if this probe is monitoring something, or false otherwise.
-
- The source being monitored does not need to be active.
- */
-bool QVideoProbe::isActive() const
-{
- return d->probee != nullptr;
-}
-
-/*!
- \fn QVideoProbe::videoFrameProbed(const QVideoFrame &frame)
-
- This signal should be emitted when a video \a frame is processed in the
- media service.
-*/
-
-/*!
- \fn QVideoProbe::flush()
-
- This signal should be emitted when it is required to release all frames.
- Application must release all outstanding references to video frames.
-*/
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/video/qvideoprobe.h b/src/multimedia/video/qvideoprobe.h
deleted file mode 100644
index 38f5ca05a..000000000
--- a/src/multimedia/video/qvideoprobe.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 QVIDEOPROBE_H
-#define QVIDEOPROBE_H
-
-#include <QtCore/QObject>
-#include <QtMultimedia/qvideoframe.h>
-
-QT_BEGIN_NAMESPACE
-
-class QMediaObject;
-class QMediaRecorder;
-
-class QVideoProbePrivate;
-class Q_MULTIMEDIA_EXPORT QVideoProbe : public QObject
-{
- Q_OBJECT
-public:
- explicit QVideoProbe(QObject *parent = nullptr);
- ~QVideoProbe();
-
- bool setSource(QMediaObject *source);
- bool setSource(QMediaRecorder *source);
-
- bool isActive() const;
-
-Q_SIGNALS:
- void videoFrameProbed(const QVideoFrame &frame);
- void flush();
-
-private:
- QVideoProbePrivate *d;
-};
-
-QT_END_NAMESPACE
-
-#endif // QVIDEOPROBE_H
diff --git a/src/multimedia/video/qvideosink.cpp b/src/multimedia/video/qvideosink.cpp
new file mode 100644
index 000000000..4551a8960
--- /dev/null
+++ b/src/multimedia/video/qvideosink.cpp
@@ -0,0 +1,194 @@
+// 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"
+
+#include "qvideoframeformat.h"
+#include "qvideoframe.h"
+#include "qmediaplayer.h"
+#include "qmediacapturesession.h"
+
+#include <qvariant.h>
+#include <qpainter.h>
+#include <qmatrix4x4.h>
+#include <QDebug>
+#include <private/qplatformmediaintegration_p.h>
+#include <private/qplatformvideosink_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QVideoSinkPrivate {
+public:
+ QVideoSinkPrivate(QVideoSink *q)
+ : q_ptr(q)
+ {
+ auto maybeVideoSink = QPlatformMediaIntegration::instance()->createVideoSink(q);
+ if (maybeVideoSink) {
+ videoSink = maybeVideoSink.value();
+ } else {
+ qWarning() << "Failed to create QVideoSink" << maybeVideoSink.error();
+ }
+ }
+ ~QVideoSinkPrivate()
+ {
+ delete videoSink;
+ }
+ void unregisterSource()
+ {
+ if (!source)
+ return;
+ auto *old = source;
+ source = nullptr;
+ if (auto *player = qobject_cast<QMediaPlayer *>(old))
+ player->setVideoSink(nullptr);
+ else if (auto *capture = qobject_cast<QMediaCaptureSession *>(old))
+ capture->setVideoSink(nullptr);
+ }
+
+ QVideoSink *q_ptr = nullptr;
+ QPlatformVideoSink *videoSink = nullptr;
+ QObject *source = nullptr;
+ QRhi *rhi = nullptr;
+};
+
+/*!
+ \class QVideoSink
+
+ \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 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
+ in QVideoSink.
+
+ QVideoFrame objects can consume a significant amount of memory or system resources and
+ should thus not be held for longer than required by the application.
+
+ \sa QMediaPlayer, QMediaCaptureSession
+
+*/
+
+/*!
+ Constructs a new QVideoSink object with \a parent.
+ */
+QVideoSink::QVideoSink(QObject *parent)
+ : QObject(parent),
+ d(new QVideoSinkPrivate(this))
+{
+ qRegisterMetaType<QVideoFrame>();
+}
+
+/*!
+ Destroys the object.
+ */
+QVideoSink::~QVideoSink()
+{
+ disconnect(this);
+ d->unregisterSource();
+ delete d;
+}
+
+/*!
+ Returns the QRhi instance being used to create texture data in the video frames.
+ */
+QRhi *QVideoSink::rhi() const
+{
+ return d->rhi;
+}
+
+/*!
+ \internal
+ Sets the QRhi instance being used to create texture data in the video frames
+ to \a rhi.
+ */
+void QVideoSink::setRhi(QRhi *rhi)
+{
+ if (d->rhi == rhi)
+ return;
+ d->rhi = rhi;
+ if (d->videoSink)
+ d->videoSink->setRhi(rhi);
+}
+
+/*!
+ \internal
+*/
+QPlatformVideoSink *QVideoSink::platformVideoSink() const
+{
+ return d->videoSink;
+}
+
+/*!
+ Returns the current video frame.
+ */
+QVideoFrame QVideoSink::videoFrame() const
+{
+ 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)
+{
+ if (d->videoSink)
+ d->videoSink->setVideoFrame(frame);
+}
+
+/*!
+ \property QVideoSink::subtitleText
+
+ Returns the current subtitle text.
+*/
+QString QVideoSink::subtitleText() const
+{
+ return d->videoSink ? d->videoSink->subtitleText() : QString{};
+}
+
+/*!
+ Sets the current \a subtitle text.
+*/
+void QVideoSink::setSubtitleText(const QString &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.
+ */
+QSize QVideoSink::videoSize() const
+{
+ return d->videoSink ? d->videoSink->nativeSize() : QSize{};
+}
+
+void QVideoSink::setSource(QObject *source)
+{
+ if (d->source == source)
+ return;
+ if (source)
+ d->unregisterSource();
+ d->source = source;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qvideosink.cpp"
+
+
diff --git a/src/multimedia/video/qvideosink.h b/src/multimedia/video/qvideosink.h
new file mode 100644
index 000000000..1a2e77834
--- /dev/null
+++ b/src/multimedia/video/qvideosink.h
@@ -0,0 +1,57 @@
+// 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
+
+#include <QtMultimedia/qtmultimediaglobal.h>
+#include <QtCore/qobject.h>
+#include <QtGui/qwindowdefs.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRectF;
+class QVideoFrameFormat;
+class QVideoFrame;
+
+class QVideoSinkPrivate;
+class QPlatformVideoSink;
+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();
+
+ QRhi *rhi() const;
+ void setRhi(QRhi *rhi);
+
+ QSize videoSize() const;
+
+ QString subtitleText() const;
+ void setSubtitleText(const QString &subtitle);
+
+ void setVideoFrame(const QVideoFrame &frame);
+ QVideoFrame videoFrame() const;
+
+ QPlatformVideoSink *platformVideoSink() const;
+Q_SIGNALS:
+ void videoFrameChanged(const QVideoFrame &frame) QT6_ONLY(const);
+ void subtitleTextChanged(const QString &subtitleText) QT6_ONLY(const);
+ void videoSizeChanged();
+
+private:
+ friend class QMediaPlayerPrivate;
+ friend class QMediaCaptureSessionPrivate;
+ void setSource(QObject *source);
+
+ QVideoSinkPrivate *d = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/video/qvideosurfaceformat.cpp b/src/multimedia/video/qvideosurfaceformat.cpp
deleted file mode 100644
index 400352b50..000000000
--- a/src/multimedia/video/qvideosurfaceformat.cpp
+++ /dev/null
@@ -1,678 +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 "qvideosurfaceformat.h"
-
-#include <qdebug.h>
-#include <qlist.h>
-#include <qmetatype.h>
-#include <qpair.h>
-#include <qvariant.h>
-
-QT_BEGIN_NAMESPACE
-
-static void qRegisterVideoSurfaceFormatMetaTypes()
-{
- qRegisterMetaType<QVideoSurfaceFormat>();
- qRegisterMetaType<QVideoSurfaceFormat::Direction>();
- qRegisterMetaType<QVideoSurfaceFormat::YCbCrColorSpace>();
-}
-
-Q_CONSTRUCTOR_FUNCTION(qRegisterVideoSurfaceFormatMetaTypes)
-
-
-class QVideoSurfaceFormatPrivate : public QSharedData
-{
-public:
- QVideoSurfaceFormatPrivate()
- : pixelFormat(QVideoFrame::Format_Invalid)
- , handleType(QAbstractVideoBuffer::NoHandle)
- , scanLineDirection(QVideoSurfaceFormat::TopToBottom)
- , pixelAspectRatio(1, 1)
- , ycbcrColorSpace(QVideoSurfaceFormat::YCbCr_Undefined)
- , frameRate(0.0)
- , mirrored(false)
- {
- }
-
- QVideoSurfaceFormatPrivate(
- const QSize &size,
- QVideoFrame::PixelFormat format,
- QAbstractVideoBuffer::HandleType type)
- : pixelFormat(format)
- , handleType(type)
- , scanLineDirection(QVideoSurfaceFormat::TopToBottom)
- , frameSize(size)
- , pixelAspectRatio(1, 1)
- , ycbcrColorSpace(QVideoSurfaceFormat::YCbCr_Undefined)
- , viewport(QPoint(0, 0), size)
- , frameRate(0.0)
- , mirrored(false)
- {
- }
-
- QVideoSurfaceFormatPrivate(const QVideoSurfaceFormatPrivate &other)
- : QSharedData(other)
- , pixelFormat(other.pixelFormat)
- , handleType(other.handleType)
- , scanLineDirection(other.scanLineDirection)
- , frameSize(other.frameSize)
- , pixelAspectRatio(other.pixelAspectRatio)
- , ycbcrColorSpace(other.ycbcrColorSpace)
- , viewport(other.viewport)
- , frameRate(other.frameRate)
- , mirrored(other.mirrored)
- , propertyNames(other.propertyNames)
- , propertyValues(other.propertyValues)
- {
- }
-
- bool operator ==(const QVideoSurfaceFormatPrivate &other) const
- {
- if (pixelFormat == other.pixelFormat
- && handleType == other.handleType
- && scanLineDirection == other.scanLineDirection
- && frameSize == other.frameSize
- && pixelAspectRatio == other.pixelAspectRatio
- && viewport == other.viewport
- && frameRatesEqual(frameRate, other.frameRate)
- && ycbcrColorSpace == other.ycbcrColorSpace
- && mirrored == other.mirrored
- && propertyNames.count() == other.propertyNames.count()) {
- for (int i = 0; i < propertyNames.count(); ++i) {
- int j = other.propertyNames.indexOf(propertyNames.at(i));
-
- if (j == -1 || propertyValues.at(i) != other.propertyValues.at(j))
- return false;
- }
- return true;
- } else {
- return false;
- }
- }
-
- inline static bool frameRatesEqual(qreal r1, qreal r2)
- {
- return qAbs(r1 - r2) <= 0.00001 * qMin(qAbs(r1), qAbs(r2));
- }
-
- QVideoFrame::PixelFormat pixelFormat;
- QAbstractVideoBuffer::HandleType handleType;
- QVideoSurfaceFormat::Direction scanLineDirection;
- QSize frameSize;
- QSize pixelAspectRatio;
- QVideoSurfaceFormat::YCbCrColorSpace ycbcrColorSpace;
- QRect viewport;
- qreal frameRate;
- bool mirrored;
- QList<QByteArray> propertyNames;
- QList<QVariant> propertyValues;
-};
-
-/*!
- \class QVideoSurfaceFormat
- \brief The QVideoSurfaceFormat class specifies the stream format of a video presentation
- surface.
- \inmodule QtMultimedia
-
- \ingroup multimedia
- \ingroup multimedia_video
-
- A video surface presents a stream of video frames. The surface's format 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 surface are the pixel format
- given by pixelFormat(), and the frame dimensions given by frameSize().
-
- If the surface is to present frames using a frame's handle a surface format will also include
- a handle type which is given by the handleType() function.
-
- The region of a frame that is actually displayed on a video surface is given by the viewport().
- A stream may have a viewport less than the entire region of a frame to allow for videos smaller
- than the nearest optimal size of a video frame. For example the width of a frame may be
- extended so that the start of each scan line is eight byte aligned.
-
- Other common properties are the pixelAspectRatio(), scanLineDirection(), and frameRate().
- Additionally a stream may have some additional type specific properties which are listed by the
- dynamicPropertyNames() function and can be accessed using the property(), and setProperty()
- functions.
-*/
-
-/*!
- \enum QVideoSurfaceFormat::Direction
-
- Enumerates the layout direction of video scan lines.
-
- \value TopToBottom Scan lines are arranged from the top of the frame to the bottom.
- \value BottomToTop Scan lines are arranged from the bottom of the frame to the top.
-*/
-
-/*!
- \enum QVideoSurfaceFormat::YCbCrColorSpace
-
- Enumerates the Y'CbCr color space of video frames.
-
- \value YCbCr_Undefined
- No color space is specified.
-
- \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.
-
- \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.
-
- \value YCbCr_xvYCC601
- The BT.601 color space with the value range extended to 0 to 255.
- It is backward compatibile with BT.601 and uses values outside BT.601 range to represent a
- wider range of colors.
-
- \value YCbCr_xvYCC709
- 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.
-*/
-
-/*!
- Constructs a null video stream format.
-*/
-QVideoSurfaceFormat::QVideoSurfaceFormat()
- : d(new QVideoSurfaceFormatPrivate)
-{
-}
-
-/*!
- Contructs a description of stream which receives stream of \a type buffers with given frame
- \a size and pixel \a format.
-*/
-QVideoSurfaceFormat::QVideoSurfaceFormat(
- const QSize& size, QVideoFrame::PixelFormat format, QAbstractVideoBuffer::HandleType type)
- : d(new QVideoSurfaceFormatPrivate(size, format, type))
-{
-}
-
-/*!
- Constructs a copy of \a other.
-*/
-QVideoSurfaceFormat::QVideoSurfaceFormat(const QVideoSurfaceFormat &other)
- : d(other.d)
-{
-}
-
-/*!
- Assigns the values of \a other to this object.
-*/
-QVideoSurfaceFormat &QVideoSurfaceFormat::operator =(const QVideoSurfaceFormat &other)
-{
- d = other.d;
-
- return *this;
-}
-
-/*!
- Destroys a video stream description.
-*/
-QVideoSurfaceFormat::~QVideoSurfaceFormat()
-{
-}
-
-/*!
- Identifies if a video surface format has a valid pixel format and frame size.
-
- Returns true if the format is valid, and false otherwise.
-*/
-bool QVideoSurfaceFormat::isValid() const
-{
- return d->pixelFormat != QVideoFrame::Format_Invalid && d->frameSize.isValid();
-}
-
-/*!
- Returns true if \a other is the same as this video format, and false if they are different.
-*/
-bool QVideoSurfaceFormat::operator ==(const QVideoSurfaceFormat &other) const
-{
- return d == other.d || *d == *other.d;
-}
-
-/*!
- Returns true if \a other is different to this video format, and false if they are the same.
-*/
-bool QVideoSurfaceFormat::operator !=(const QVideoSurfaceFormat &other) const
-{
- return d != other.d && !(*d == *other.d);
-}
-
-/*!
- Returns the pixel format of frames in a video stream.
-*/
-QVideoFrame::PixelFormat QVideoSurfaceFormat::pixelFormat() const
-{
- return d->pixelFormat;
-}
-
-/*!
- Returns the type of handle the surface uses to present the frame data.
-
- If the handle type is \c QAbstractVideoBuffer::NoHandle, buffers with any handle type are valid
- provided they can be \l {QAbstractVideoBuffer::map()}{mapped} with the
- QAbstractVideoBuffer::ReadOnly flag. If the handleType() is not QAbstractVideoBuffer::NoHandle
- then the handle type of the buffer must be the same as that of the surface format.
-*/
-QAbstractVideoBuffer::HandleType QVideoSurfaceFormat::handleType() const
-{
- return d->handleType;
-}
-
-/*!
- Returns the dimensions of frames in a video stream.
-
- \sa frameWidth(), frameHeight()
-*/
-QSize QVideoSurfaceFormat::frameSize() const
-{
- return d->frameSize;
-}
-
-/*!
- Returns the width of frames in a video stream.
-
- \sa frameSize(), frameHeight()
-*/
-int QVideoSurfaceFormat::frameWidth() const
-{
- return d->frameSize.width();
-}
-
-/*!
- Returns the height of frame in a video stream.
-*/
-int QVideoSurfaceFormat::frameHeight() const
-{
- return d->frameSize.height();
-}
-
-/*!
- Sets the size of frames in a video stream to \a size.
-
- This will reset the viewport() to fill the entire frame.
-*/
-void QVideoSurfaceFormat::setFrameSize(const QSize &size)
-{
- d->frameSize = size;
- d->viewport = QRect(QPoint(0, 0), size);
-}
-
-/*!
- \overload
-
- Sets the \a width and \a height of frames in a video stream.
-
- This will reset the viewport() to fill the entire frame.
-*/
-void QVideoSurfaceFormat::setFrameSize(int width, int height)
-{
- d->frameSize = QSize(width, height);
- d->viewport = QRect(0, 0, width, height);
-}
-
-/*!
- Returns the viewport of a video stream.
-
- The viewport is the region of a video frame that is actually displayed.
-
- By default the viewport covers an entire frame.
-*/
-QRect QVideoSurfaceFormat::viewport() const
-{
- return d->viewport;
-}
-
-/*!
- Sets the viewport of a video stream to \a viewport.
-*/
-void QVideoSurfaceFormat::setViewport(const QRect &viewport)
-{
- d->viewport = viewport;
-}
-
-/*!
- Returns the direction of scan lines.
-*/
-QVideoSurfaceFormat::Direction QVideoSurfaceFormat::scanLineDirection() const
-{
- return d->scanLineDirection;
-}
-
-/*!
- Sets the \a direction of scan lines.
-*/
-void QVideoSurfaceFormat::setScanLineDirection(Direction direction)
-{
- d->scanLineDirection = direction;
-}
-
-/*!
- Returns the frame rate of a video stream in frames per second.
-*/
-qreal QVideoSurfaceFormat::frameRate() const
-{
- return d->frameRate;
-}
-
-/*!
- Sets the frame \a rate of a video stream in frames per second.
-*/
-void QVideoSurfaceFormat::setFrameRate(qreal rate)
-{
- d->frameRate = rate;
-}
-
-/*!
- Returns a video stream's pixel aspect ratio.
-*/
-QSize QVideoSurfaceFormat::pixelAspectRatio() const
-{
- return d->pixelAspectRatio;
-}
-
-/*!
- Sets a video stream's pixel aspect \a ratio.
-*/
-void QVideoSurfaceFormat::setPixelAspectRatio(const QSize &ratio)
-{
- d->pixelAspectRatio = ratio;
-}
-
-/*!
- \overload
-
- Sets the \a horizontal and \a vertical elements of a video stream's pixel aspect ratio.
-*/
-void QVideoSurfaceFormat::setPixelAspectRatio(int horizontal, int vertical)
-{
- d->pixelAspectRatio = QSize(horizontal, vertical);
-}
-
-/*!
- Returns the Y'CbCr color space of a video stream.
-*/
-QVideoSurfaceFormat::YCbCrColorSpace QVideoSurfaceFormat::yCbCrColorSpace() const
-{
- return d->ycbcrColorSpace;
-}
-
-/*!
- Sets the Y'CbCr color \a space of a video stream.
- It is only used with raw YUV frame types.
-*/
-void QVideoSurfaceFormat::setYCbCrColorSpace(QVideoSurfaceFormat::YCbCrColorSpace space)
-{
- d->ycbcrColorSpace = space;
-}
-
-/*!
- Returns \c true if the surface is mirrored around its vertical axis.
- This is typically needed for video frames coming from a front camera of a mobile device.
-
- \note The mirroring here differs from QImage::mirrored, as a vertically mirrored QImage
- will be mirrored around its x-axis.
-
- \since 5.11
- */
-bool QVideoSurfaceFormat::isMirrored() const
-{
- return d->mirrored;
-}
-
-/*!
- Sets if the surface is \a mirrored around its vertical axis.
- This is typically needed for video frames coming from a front camera of a mobile device.
- Default value is false.
-
- \note The mirroring here differs from QImage::mirrored, as a vertically mirrored QImage
- will be mirrored around its x-axis.
-
- \since 5.11
- */
-void QVideoSurfaceFormat::setMirrored(bool mirrored)
-{
- d->mirrored = mirrored;
-}
-
-/*!
- Returns a suggested size in pixels for the video stream.
-
- This is the size of the viewport scaled according to the pixel aspect ratio.
-*/
-QSize QVideoSurfaceFormat::sizeHint() const
-{
- QSize size = d->viewport.size();
-
- if (d->pixelAspectRatio.height() != 0)
- size.setWidth(size.width() * d->pixelAspectRatio.width() / d->pixelAspectRatio.height());
-
- return size;
-}
-
-/*!
- Returns a list of video format dynamic property names.
-*/
-QList<QByteArray> QVideoSurfaceFormat::propertyNames() const
-{
- return (QList<QByteArray>()
- << "handleType"
- << "pixelFormat"
- << "frameSize"
- << "frameWidth"
- << "viewport"
- << "scanLineDirection"
- << "frameRate"
- << "pixelAspectRatio"
- << "sizeHint"
- << "yCbCrColorSpace"
- << "mirrored")
- + d->propertyNames;
-}
-
-/*!
- Returns the value of the video format's \a name property.
-*/
-QVariant QVideoSurfaceFormat::property(const char *name) const
-{
- if (qstrcmp(name, "handleType") == 0) {
- return QVariant::fromValue(d->handleType);
- } else if (qstrcmp(name, "pixelFormat") == 0) {
- return QVariant::fromValue(d->pixelFormat);
- } else if (qstrcmp(name, "frameSize") == 0) {
- return d->frameSize;
- } else if (qstrcmp(name, "frameWidth") == 0) {
- return d->frameSize.width();
- } else if (qstrcmp(name, "frameHeight") == 0) {
- return d->frameSize.height();
- } else if (qstrcmp(name, "viewport") == 0) {
- return d->viewport;
- } else if (qstrcmp(name, "scanLineDirection") == 0) {
- return QVariant::fromValue(d->scanLineDirection);
- } else if (qstrcmp(name, "frameRate") == 0) {
- return QVariant::fromValue(d->frameRate);
- } else if (qstrcmp(name, "pixelAspectRatio") == 0) {
- return QVariant::fromValue(d->pixelAspectRatio);
- } else if (qstrcmp(name, "sizeHint") == 0) {
- return sizeHint();
- } else if (qstrcmp(name, "yCbCrColorSpace") == 0) {
- return QVariant::fromValue(d->ycbcrColorSpace);
- } else if (qstrcmp(name, "mirrored") == 0) {
- return d->mirrored;
- } else {
- int id = 0;
- for (; id < d->propertyNames.count() && d->propertyNames.at(id) != name; ++id) {}
-
- return id < d->propertyValues.count()
- ? d->propertyValues.at(id)
- : QVariant();
- }
-}
-
-/*!
- Sets the video format's \a name property to \a value.
-
- Trying to set a read only property will be ignored.
-
-*/
-void QVideoSurfaceFormat::setProperty(const char *name, const QVariant &value)
-{
- if (qstrcmp(name, "handleType") == 0) {
- // read only.
- } else if (qstrcmp(name, "pixelFormat") == 0) {
- // read only.
- } else if (qstrcmp(name, "frameSize") == 0) {
- if (value.canConvert<QSize>()) {
- d->frameSize = qvariant_cast<QSize>(value);
- d->viewport = QRect(QPoint(0, 0), d->frameSize);
- }
- } else if (qstrcmp(name, "frameWidth") == 0) {
- // read only.
- } else if (qstrcmp(name, "frameHeight") == 0) {
- // read only.
- } else if (qstrcmp(name, "viewport") == 0) {
- if (value.canConvert<QRect>())
- d->viewport = qvariant_cast<QRect>(value);
- } else if (qstrcmp(name, "scanLineDirection") == 0) {
- if (value.canConvert<Direction>())
- d->scanLineDirection = qvariant_cast<Direction>(value);
- } else if (qstrcmp(name, "frameRate") == 0) {
- if (value.canConvert<qreal>())
- d->frameRate = qvariant_cast<qreal>(value);
- } else if (qstrcmp(name, "pixelAspectRatio") == 0) {
- if (value.canConvert<QSize>())
- d->pixelAspectRatio = qvariant_cast<QSize>(value);
- } else if (qstrcmp(name, "sizeHint") == 0) {
- // read only.
- } else if (qstrcmp(name, "yCbCrColorSpace") == 0) {
- if (value.canConvert<YCbCrColorSpace>())
- d->ycbcrColorSpace = qvariant_cast<YCbCrColorSpace>(value);
- } else if (qstrcmp(name, "mirrored") == 0) {
- if (value.canConvert<bool>())
- d->mirrored = qvariant_cast<bool>(value);
- } else {
- int id = 0;
- for (; id < d->propertyNames.count() && d->propertyNames.at(id) != name; ++id) {}
-
- if (id < d->propertyValues.count()) {
- if (value.isNull()) {
- d->propertyNames.removeAt(id);
- d->propertyValues.removeAt(id);
- } else {
- d->propertyValues[id] = value;
- }
- } else if (!value.isNull()) {
- d->propertyNames.append(QByteArray(name));
- d->propertyValues.append(value);
- }
- }
-}
-
-
-#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug dbg, QVideoSurfaceFormat::YCbCrColorSpace cs)
-{
- QDebugStateSaver saver(dbg);
- dbg.nospace();
- switch (cs) {
- case QVideoSurfaceFormat::YCbCr_BT601:
- dbg << "YCbCr_BT601";
- break;
- case QVideoSurfaceFormat::YCbCr_BT709:
- dbg << "YCbCr_BT709";
- break;
- case QVideoSurfaceFormat::YCbCr_JPEG:
- dbg << "YCbCr_JPEG";
- break;
- case QVideoSurfaceFormat::YCbCr_xvYCC601:
- dbg << "YCbCr_xvYCC601";
- break;
- case QVideoSurfaceFormat::YCbCr_xvYCC709:
- dbg << "YCbCr_xvYCC709";
- break;
- case QVideoSurfaceFormat::YCbCr_CustomMatrix:
- dbg << "YCbCr_CustomMatrix";
- break;
- default:
- dbg << "YCbCr_Undefined";
- break;
- }
- return dbg;
-}
-
-QDebug operator<<(QDebug dbg, QVideoSurfaceFormat::Direction dir)
-{
- QDebugStateSaver saver(dbg);
- dbg.nospace();
- switch (dir) {
- case QVideoSurfaceFormat::BottomToTop:
- dbg << "BottomToTop";
- break;
- case QVideoSurfaceFormat::TopToBottom:
- dbg << "TopToBottom";
- break;
- }
- return dbg;
-}
-
-QDebug operator<<(QDebug dbg, const QVideoSurfaceFormat &f)
-{
- QDebugStateSaver saver(dbg);
- dbg.nospace();
- dbg << "QVideoSurfaceFormat(" << f.pixelFormat() << ", " << f.frameSize()
- << ", viewport=" << f.viewport() << ", pixelAspectRatio=" << f.pixelAspectRatio()
- << ", handleType=" << f.handleType() << ", yCbCrColorSpace=" << f.yCbCrColorSpace()
- << ')';
-
- const auto propertyNames = f.propertyNames();
- for (const QByteArray& propertyName : propertyNames)
- dbg << "\n " << propertyName.data() << " = " << f.property(propertyName.data());
-
- return dbg;
-}
-#endif
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/video/qvideosurfaceformat.h b/src/multimedia/video/qvideosurfaceformat.h
deleted file mode 100644
index 1d1990c77..000000000
--- a/src/multimedia/video/qvideosurfaceformat.h
+++ /dev/null
@@ -1,146 +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 QVIDEOSURFACEFORMAT_H
-#define QVIDEOSURFACEFORMAT_H
-
-#include <QtCore/qlist.h>
-#include <QtCore/qpair.h>
-#include <QtCore/qshareddata.h>
-#include <QtCore/qsize.h>
-#include <QtGui/qimage.h>
-#include <QtMultimedia/qvideoframe.h>
-
-QT_BEGIN_NAMESPACE
-
-
-class QDebug;
-
-class QVideoSurfaceFormatPrivate;
-
-class Q_MULTIMEDIA_EXPORT QVideoSurfaceFormat
-{
-public:
- enum Direction
- {
- TopToBottom,
- BottomToTop
- };
-
- enum YCbCrColorSpace
- {
- YCbCr_Undefined,
- YCbCr_BT601,
- YCbCr_BT709,
- YCbCr_xvYCC601,
- YCbCr_xvYCC709,
- YCbCr_JPEG,
-#ifndef Q_QDOC
- YCbCr_CustomMatrix
-#endif
- };
-
- QVideoSurfaceFormat();
- QVideoSurfaceFormat(
- const QSize &size,
- QVideoFrame::PixelFormat pixelFormat,
- QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle);
- QVideoSurfaceFormat(const QVideoSurfaceFormat &format);
- ~QVideoSurfaceFormat();
-
- QVideoSurfaceFormat &operator =(const QVideoSurfaceFormat &format);
-
- bool operator ==(const QVideoSurfaceFormat &format) const;
- bool operator !=(const QVideoSurfaceFormat &format) const;
-
- bool isValid() const;
-
- QVideoFrame::PixelFormat pixelFormat() const;
- QAbstractVideoBuffer::HandleType handleType() const;
-
- QSize frameSize() const;
- void setFrameSize(const QSize &size);
- void setFrameSize(int width, int height);
-
- int frameWidth() const;
- int frameHeight() const;
-
- QRect viewport() const;
- void setViewport(const QRect &viewport);
-
- Direction scanLineDirection() const;
- void setScanLineDirection(Direction direction);
-
- qreal frameRate() const;
- void setFrameRate(qreal rate);
-
- QSize pixelAspectRatio() const;
- void setPixelAspectRatio(const QSize &ratio);
- void setPixelAspectRatio(int width, int height);
-
- YCbCrColorSpace yCbCrColorSpace() const;
- void setYCbCrColorSpace(YCbCrColorSpace colorSpace);
-
- bool isMirrored() const;
- void setMirrored(bool mirrored);
-
- QSize sizeHint() const;
-
- QList<QByteArray> propertyNames() const;
- QVariant property(const char *name) const;
- void setProperty(const char *name, const QVariant &value);
-
-private:
- QSharedDataPointer<QVideoSurfaceFormatPrivate> d;
-};
-
-#ifndef QT_NO_DEBUG_STREAM
-Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, const QVideoSurfaceFormat &);
-Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, QVideoSurfaceFormat::Direction);
-Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, QVideoSurfaceFormat::YCbCrColorSpace);
-#endif
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QVideoSurfaceFormat)
-Q_DECLARE_METATYPE(QVideoSurfaceFormat::Direction)
-Q_DECLARE_METATYPE(QVideoSurfaceFormat::YCbCrColorSpace)
-
-#endif
-
diff --git a/src/multimedia/video/qvideosurfaceoutput.cpp b/src/multimedia/video/qvideosurfaceoutput.cpp
deleted file mode 100644
index ebc9e1cb6..000000000
--- a/src/multimedia/video/qvideosurfaceoutput.cpp
+++ /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$
-**
-****************************************************************************/
-
-#include "qvideosurfaceoutput_p.h"
-
-#include <qabstractvideosurface.h>
-#include <qmediaservice.h>
-#include <qvideorenderercontrol.h>
-
-/*!
- * \class QVideoSurfaceOutput
- * \internal
- */
-QVideoSurfaceOutput::QVideoSurfaceOutput(QObject*parent)
- : QObject(parent)
-{
-}
-
-QVideoSurfaceOutput::~QVideoSurfaceOutput()
-{
- if (m_control) {
- m_control.data()->setSurface(nullptr);
- m_service.data()->releaseControl(m_control.data());
- }
-}
-
-QMediaObject *QVideoSurfaceOutput::mediaObject() const
-{
- return m_object.data();
-}
-
-void QVideoSurfaceOutput::setVideoSurface(QAbstractVideoSurface *surface)
-{
- m_surface = surface;
-
- if (m_control)
- m_control.data()->setSurface(surface);
-}
-
-bool QVideoSurfaceOutput::setMediaObject(QMediaObject *object)
-{
- if (m_control) {
- m_control.data()->setSurface(nullptr);
- m_service.data()->releaseControl(m_control.data());
- }
- m_control.clear();
- m_service.clear();
- m_object.clear();
-
- if (object) {
- if (QMediaService *service = object->service()) {
- if (QMediaControl *control = service->requestControl(QVideoRendererControl_iid)) {
- if ((m_control = qobject_cast<QVideoRendererControl *>(control))) {
- m_service = service;
- m_object = object;
- m_control.data()->setSurface(m_surface.data());
-
- return true;
- }
- service->releaseControl(control);
- }
- }
- }
- return false;
-}
diff --git a/src/multimedia/video/qvideosurfaceoutput_p.h b/src/multimedia/video/qvideosurfaceoutput_p.h
deleted file mode 100644
index 5d050bcb0..000000000
--- a/src/multimedia/video/qvideosurfaceoutput_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 QVIDEOSURFACEOUTPUT_P_H
-#define QVIDEOSURFACEOUTPUT_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 <qmediabindableinterface.h>
-
-#include <QtCore/qsharedpointer.h>
-#include <QtCore/qpointer.h>
-
-QT_BEGIN_NAMESPACE
-
-
-class QAbstractVideoSurface;
-class QVideoRendererControl;
-
-class QVideoSurfaceOutput : public QObject, public QMediaBindableInterface
-{
- Q_OBJECT
- Q_INTERFACES(QMediaBindableInterface)
-public:
- QVideoSurfaceOutput(QObject *parent = nullptr);
- ~QVideoSurfaceOutput();
-
- QMediaObject *mediaObject() const override;
-
- void setVideoSurface(QAbstractVideoSurface *surface);
-
-protected:
- bool setMediaObject(QMediaObject *object) override;
-
-private:
- QPointer<QAbstractVideoSurface> m_surface;
- QPointer<QVideoRendererControl> m_control;
- QPointer<QMediaService> m_service;
- QPointer<QMediaObject> m_object;
-};
-
-QT_END_NAMESPACE
-
-
-#endif
diff --git a/src/multimedia/video/qvideosurfaces.cpp b/src/multimedia/video/qvideosurfaces.cpp
deleted file mode 100644
index 7ce1bd932..000000000
--- a/src/multimedia/video/qvideosurfaces.cpp
+++ /dev/null
@@ -1,102 +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$
-**
-****************************************************************************/
-
-#include "qvideosurfaces_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QVideoSurfaces::QVideoSurfaces(const QList<QAbstractVideoSurface *> &s, QObject *parent)
- : QAbstractVideoSurface(parent), m_surfaces(s)
-{
- for (auto a : s) {
- connect(a, &QAbstractVideoSurface::supportedFormatsChanged, this, [this, a] {
- auto context = property("GLContext").value<QObject *>();
- if (!context)
- setProperty("GLContext", a->property("GLContext"));
-
- emit supportedFormatsChanged();
- });
- }
-}
-
-QVideoSurfaces::~QVideoSurfaces()
-{
-}
-
-QList<QVideoFrame::PixelFormat> QVideoSurfaces::supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const
-{
- QList<QVideoFrame::PixelFormat> result;
- QMap<QVideoFrame::PixelFormat, int> formats;
- for (auto &s : m_surfaces) {
- for (auto &p : s->supportedPixelFormats(type)) {
- if (++formats[p] == m_surfaces.size())
- result << p;
- }
- }
-
- return result;
-}
-
-bool QVideoSurfaces::start(const QVideoSurfaceFormat &format)
-{
- bool result = true;
- for (auto &s : m_surfaces)
- result &= s->start(format);
-
- return result && QAbstractVideoSurface::start(format);
-}
-
-void QVideoSurfaces::stop()
-{
- for (auto &s : m_surfaces)
- s->stop();
-
- QAbstractVideoSurface::stop();
-}
-
-bool QVideoSurfaces::present(const QVideoFrame &frame)
-{
- bool result = true;
- for (auto &s : m_surfaces)
- result &= s->present(frame);
-
- return result;
-}
-
-QT_END_NAMESPACE
diff --git a/src/multimedia/video/qvideosurfaces_p.h b/src/multimedia/video/qvideosurfaces_p.h
deleted file mode 100644
index 9074ba458..000000000
--- a/src/multimedia/video/qvideosurfaces_p.h
+++ /dev/null
@@ -1,77 +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$
-**
-****************************************************************************/
-
-#ifndef QVIDEOSURFACES_P_H
-#define QVIDEOSURFACES_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 <QAbstractVideoSurface>
-#include <QList>
-
-QT_BEGIN_NAMESPACE
-
-class QVideoSurfaces : public QAbstractVideoSurface
-{
-public:
- QVideoSurfaces(const QList<QAbstractVideoSurface *> &surfaces, QObject *parent = nullptr);
- ~QVideoSurfaces();
-
- QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const override;
- bool start(const QVideoSurfaceFormat &format) override;
- void stop() override;
- bool present(const QVideoFrame &frame) override;
-
-private:
- QList<QAbstractVideoSurface *> m_surfaces;
- Q_DISABLE_COPY(QVideoSurfaces)
-};
-
-QT_END_NAMESPACE
-
-#endif // QVIDEOSURFACES_P_H
diff --git a/src/multimedia/video/qvideotexturehelper.cpp b/src/multimedia/video/qvideotexturehelper.cpp
new file mode 100644
index 000000000..093989654
--- /dev/null
+++ b/src/multimedia/video/qvideotexturehelper.cpp
@@ -0,0 +1,855 @@
+// 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 "qabstractvideobuffer.h"
+
+#include "qvideotexturehelper_p.h"
+#include "qvideoframeconverter_p.h"
+#include "qvideoframe_p.h"
+
+#include <qpainter.h>
+#include <qloggingcategory.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QVideoTextureHelper
+{
+
+static const TextureDescription descriptions[QVideoFrameFormat::NPixelFormats] = {
+ // Format_Invalid
+ { 0, 0,
+ [](int, int) { return 0; },
+ { QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat},
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_ARGB8888
+ { 1, 4,
+ [](int stride, int height) { return stride*height; },
+ { QRhiTexture::RGBA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_ARGB8888_Premultiplied
+ { 1, 4,
+ [](int stride, int height) { return stride*height; },
+ { QRhiTexture::RGBA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_XRGB8888
+ { 1, 4,
+ [](int stride, int height) { return stride*height; },
+ { QRhiTexture::RGBA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_BGRA8888
+ { 1, 4,
+ [](int stride, int height) { return stride*height; },
+ { 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::BGRA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_BGRX8888
+ { 1, 4,
+ [](int stride, int height) { return stride*height; },
+ { QRhiTexture::BGRA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_ABGR8888
+ { 1, 4,
+ [](int stride, int height) { return stride*height; },
+ { QRhiTexture::RGBA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_XBGR8888
+ { 1, 4,
+ [](int stride, int height) { return stride*height; },
+ { QRhiTexture::RGBA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_RGBA8888
+ { 1, 4,
+ [](int stride, int height) { return stride*height; },
+ { QRhiTexture::RGBA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_RGBX8888
+ { 1, 4,
+ [](int stride, int height) { return stride*height; },
+ { QRhiTexture::RGBA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_AYUV
+ { 1, 4,
+ [](int stride, int height) { return stride*height; },
+ { QRhiTexture::RGBA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_AYUV_Premultiplied
+ { 1, 4,
+ [](int stride, int height) { return stride*height; },
+ { QRhiTexture::RGBA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_YUV420P
+ { 3, 1,
+ [](int stride, int height) { return stride * ((height * 3 / 2 + 1) & ~1); },
+ { QRhiTexture::R8, QRhiTexture::R8, QRhiTexture::R8 },
+ { { 1, 1 }, { 2, 2 }, { 2, 2 } }
+ },
+ // Format_YUV422P
+ { 3, 1,
+ [](int stride, int height) { return stride * height * 2; },
+ { QRhiTexture::R8, QRhiTexture::R8, QRhiTexture::R8 },
+ { { 1, 1 }, { 2, 1 }, { 2, 1 } }
+ },
+ // Format_YV12
+ { 3, 1,
+ [](int stride, int height) { return stride * ((height * 3 / 2 + 1) & ~1); },
+ { QRhiTexture::R8, QRhiTexture::R8, QRhiTexture::R8 },
+ { { 1, 1 }, { 2, 2 }, { 2, 2 } }
+ },
+ // Format_UYVY
+ { 1, 2,
+ [](int stride, int height) { return stride*height; },
+ { QRhiTexture::RGBA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 2, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_YUYV
+ { 1, 2,
+ [](int stride, int height) { return stride*height; },
+ { QRhiTexture::RGBA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 2, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_NV12
+ { 2, 1,
+ [](int stride, int height) { return stride * ((height * 3 / 2 + 1) & ~1); },
+ { QRhiTexture::R8, QRhiTexture::RG8, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 2, 2 }, { 1, 1 } }
+ },
+ // Format_NV21
+ { 2, 1,
+ [](int stride, int height) { return stride * ((height * 3 / 2 + 1) & ~1); },
+ { QRhiTexture::R8, QRhiTexture::RG8, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 2, 2 }, { 1, 1 } }
+ },
+ // Format_IMC1
+ { 3, 1,
+ [](int stride, int height) {
+ // IMC1 requires that U and V components are aligned on a multiple of 16 lines
+ int h = (height + 15) & ~15;
+ h += 2*(((h/2) + 15) & ~15);
+ return stride * h;
+ },
+ { QRhiTexture::R8, QRhiTexture::R8, QRhiTexture::R8 },
+ { { 1, 1 }, { 2, 2 }, { 2, 2 } }
+ },
+ // Format_IMC2
+ { 2, 1,
+ [](int stride, int height) { return 2*stride*height; },
+ { QRhiTexture::R8, QRhiTexture::R8, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 2 }, { 1, 1 } }
+ },
+ // Format_IMC3
+ { 3, 1,
+ [](int stride, int height) {
+ // IMC3 requires that U and V components are aligned on a multiple of 16 lines
+ int h = (height + 15) & ~15;
+ h += 2*(((h/2) + 15) & ~15);
+ return stride * h;
+ },
+ { QRhiTexture::R8, QRhiTexture::R8, QRhiTexture::R8 },
+ { { 1, 1 }, { 2, 2 }, { 2, 2 } }
+ },
+ // Format_IMC4
+ { 2, 1,
+ [](int stride, int height) { return 2*stride*height; },
+ { QRhiTexture::R8, QRhiTexture::R8, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 2 }, { 1, 1 } }
+ },
+ // Format_Y8
+ { 1, 1,
+ [](int stride, int height) { return stride*height; },
+ { QRhiTexture::R8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_Y16
+ { 1, 2,
+ [](int stride, int height) { return stride*height; },
+ { QRhiTexture::R16, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_P010
+ { 2, 2,
+ [](int stride, int height) { return stride * ((height * 3 / 2 + 1) & ~1); },
+ { QRhiTexture::R16, QRhiTexture::RG16, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 2, 2 }, { 1, 1 } }
+ },
+ // Format_P016
+ { 2, 2,
+ [](int stride, int height) { return stride * ((height * 3 / 2 + 1) & ~1); },
+ { QRhiTexture::R16, QRhiTexture::RG16, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 2, 2 }, { 1, 1 } }
+ },
+ // Format_SamplerExternalOES
+ {
+ 1, 0,
+ [](int, int) { return 0; },
+ { QRhiTexture::RGBA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_Jpeg
+ { 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::BGRA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_YUV420P10
+ { 3, 2,
+ [](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)
+{
+ return descriptions + format;
+}
+
+QString vertexShaderFileName(const QVideoFrameFormat &format)
+{
+ auto fmt = format.pixelFormat();
+ Q_UNUSED(fmt);
+
+#if 1//def Q_OS_ANDROID
+ if (fmt == QVideoFrameFormat::Format_SamplerExternalOES)
+ return QStringLiteral(":/qt-project.org/multimedia/shaders/externalsampler.vert.qsb");
+#endif
+#if 1//def Q_OS_MACOS
+ 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(const QVideoFrameFormat &format, QRhiSwapChain::Format surfaceFormat)
+{
+ const char *shader = nullptr;
+ switch (format.pixelFormat()) {
+ case QVideoFrameFormat::Format_Y8:
+ case QVideoFrameFormat::Format_Y16:
+ shader = "y";
+ break;
+ case QVideoFrameFormat::Format_AYUV:
+ case QVideoFrameFormat::Format_AYUV_Premultiplied:
+ shader = "ayuv";
+ break;
+ case QVideoFrameFormat::Format_ARGB8888:
+ case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
+ case QVideoFrameFormat::Format_XRGB8888:
+ shader = "argb";
+ break;
+ case QVideoFrameFormat::Format_ABGR8888:
+ case QVideoFrameFormat::Format_XBGR8888:
+ 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:
+ 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:
+ shader = "yuv_triplanar";
+ break;
+ case QVideoFrameFormat::Format_YUV420P10:
+ shader = "yuv_triplanar_p10";
+ break;
+ case QVideoFrameFormat::Format_YV12:
+ case QVideoFrameFormat::Format_IMC1:
+ shader = "yvu_triplanar";
+ break;
+ case QVideoFrameFormat::Format_IMC2:
+ shader = "imc2";
+ break;
+ case QVideoFrameFormat::Format_IMC4:
+ shader = "imc4";
+ break;
+ case QVideoFrameFormat::Format_UYVY:
+ shader = "uyvy";
+ break;
+ case QVideoFrameFormat::Format_YUYV:
+ 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
+ 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:
+ shader = "nv21";
+ break;
+ case QVideoFrameFormat::Format_SamplerExternalOES:
+#if 1//def Q_OS_ANDROID
+ shader = "externalsampler";
+ break;
+#endif
+ case QVideoFrameFormat::Format_SamplerRect:
+#if 1//def Q_OS_MACOS
+ shader = "rectsampler_bgra";
+ break;
+#endif
+ // fallthrough
+ case QVideoFrameFormat::Format_Invalid:
+ default:
+ 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;
+}
+
+// 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::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.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.0810f,
+ 0.000f, 0.000f, 0.000f, 1.0000f
+ };
+ }
+}
+// clang-format on
+
+// PQ transfer function, see also https://en.wikipedia.org/wiki/Perceptual_quantizer
+// or https://ieeexplore.ieee.org/document/7291452
+static float convertPQFromLinear(float sig)
+{
+ 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;
+}
+
+void updateUniformData(QByteArray *dst, const QVideoFrameFormat &format, const QVideoFrame &frame, const QMatrix4x4 &transform, float opacity, float maxNits)
+{
+#ifndef Q_OS_ANDROID
+ Q_UNUSED(frame);
+#endif
+
+ QMatrix4x4 cmat;
+ switch (format.pixelFormat()) {
+ case QVideoFrameFormat::Format_Invalid:
+ return;
+
+ case QVideoFrameFormat::Format_Jpeg:
+ case QVideoFrameFormat::Format_ARGB8888:
+ case QVideoFrameFormat::Format_ARGB8888_Premultiplied:
+ case QVideoFrameFormat::Format_XRGB8888:
+ case QVideoFrameFormat::Format_BGRA8888:
+ case QVideoFrameFormat::Format_BGRA8888_Premultiplied:
+ case QVideoFrameFormat::Format_BGRX8888:
+ case QVideoFrameFormat::Format_ABGR8888:
+ case QVideoFrameFormat::Format_XBGR8888:
+ case QVideoFrameFormat::Format_RGBA8888:
+ case QVideoFrameFormat::Format_RGBX8888:
+
+ case QVideoFrameFormat::Format_Y8:
+ case QVideoFrameFormat::Format_Y16:
+ break;
+ case QVideoFrameFormat::Format_IMC1:
+ case QVideoFrameFormat::Format_IMC2:
+ case QVideoFrameFormat::Format_IMC3:
+ case QVideoFrameFormat::Format_IMC4:
+ 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:
+ case QVideoFrameFormat::Format_YUYV:
+ case QVideoFrameFormat::Format_NV12:
+ case QVideoFrameFormat::Format_NV21:
+ case QVideoFrameFormat::Format_P010:
+ case QVideoFrameFormat::Format_P016:
+ cmat = colorMatrix(format);
+ break;
+ case QVideoFrameFormat::Format_SamplerExternalOES:
+ // get Android specific transform for the externalsampler texture
+ if (auto hwBuffer = QVideoFramePrivate::hwBuffer(frame))
+ cmat = hwBuffer->externalTextureMatrix();
+ break;
+ case QVideoFrameFormat::Format_SamplerRect:
+ {
+ // Similarly to SamplerExternalOES, the "color matrix" is used here to
+ // transform the texture coordinates. OpenGL texture rectangles expect
+ // non-normalized UVs, so apply a scale to have the fragment shader see
+ // UVs in range [width,height] instead of [0,1].
+ const QSize videoSize = frame.size();
+ cmat.scale(videoSize.width(), videoSize.height());
+ }
+ break;
+ }
+
+ // 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);
+}
+
+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 &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)
+{
+ QHwVideoBuffer *hwBuffer = QVideoFramePrivate::hwBuffer(frame);
+ Q_ASSERT(hwBuffer);
+
+ QVideoFrameFormat fmt = frame.surfaceFormat();
+ QVideoFrameFormat::PixelFormat pixelFormat = fmt.pixelFormat();
+ QSize size = fmt.frameSize();
+
+ const TextureDescription &texDesc = descriptions[pixelFormat];
+ QSize planeSize(size.width()/texDesc.sizeScale[plane].x, size.height()/texDesc.sizeScale[plane].y);
+
+ QRhiTexture::Flags textureFlags = {};
+ if (pixelFormat == QVideoFrameFormat::Format_SamplerExternalOES) {
+#ifdef Q_OS_ANDROID
+ if (rhi->backend() == QRhi::OpenGLES2)
+ textureFlags |= QRhiTexture::ExternalOES;
+#endif
+ }
+ if (pixelFormat == QVideoFrameFormat::Format_SamplerRect) {
+#ifdef Q_OS_MACOS
+ if (rhi->backend() == QRhi::OpenGLES2)
+ textureFlags |= QRhiTexture::TextureRectangleGL;
+#endif
+ }
+
+ if (quint64 handle = hwBuffer->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());
+ }
+
+ // 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;
+ }
+
+ TextureArray takeTextures() { return std::move(m_textures); }
+
+private:
+ TextureArray m_textures;
+ QVideoFrame m_mappedFrame;
+};
+
+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(QtVideo::MapMode::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;
+ }
+
+ // 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)
+{
+ if (!frame.isValid())
+ return {};
+
+ if (QHwVideoBuffer *hwBuffer = QVideoFramePrivate::hwBuffer(frame)) {
+ if (auto textures = hwBuffer->mapTextures(rhi))
+ return textures;
+
+ if (auto textures = createTexturesFromHandles(frame, rhi))
+ return textures;
+ }
+
+ return createTexturesFromMemory(frame, rhi, rub, oldTextures.get());
+}
+
+bool SubtitleLayout::update(const QSize &frameSize, QString text)
+{
+ text.replace(QLatin1Char('\n'), QChar::LineSeparator);
+ if (layout.text() == text && videoSize == frameSize)
+ return false;
+
+ videoSize = frameSize;
+ QFont font;
+ // 0.045 - based on this https://www.md-subs.com/saa-subtitle-font-size
+ qreal fontSize = frameSize.height() * 0.045;
+ font.setPointSize(fontSize);
+
+ layout.setText(text);
+ if (text.isEmpty()) {
+ bounds = {};
+ return true;
+ }
+ layout.setFont(font);
+ QTextOption option;
+ option.setUseDesignMetrics(true);
+ option.setAlignment(Qt::AlignCenter);
+ layout.setTextOption(option);
+
+ QFontMetrics metrics(font);
+ int leading = metrics.leading();
+
+ qreal lineWidth = videoSize.width()*.9;
+ qreal margin = videoSize.width()*.05;
+ qreal height = 0;
+ qreal textWidth = 0;
+ layout.beginLayout();
+ while (1) {
+ QTextLine line = layout.createLine();
+ if (!line.isValid())
+ break;
+
+ line.setLineWidth(lineWidth);
+ height += leading;
+ line.setPosition(QPointF(margin, height));
+ height += line.height();
+ textWidth = qMax(textWidth, line.naturalTextWidth());
+ }
+ layout.endLayout();
+
+ // put subtitles vertically in lower part of the video but not stuck to the bottom
+ int bottomMargin = videoSize.height() / 20;
+ qreal y = videoSize.height() - bottomMargin - height;
+ layout.setPosition(QPointF(0, y));
+ textWidth += fontSize/4.;
+
+ bounds = QRectF((videoSize.width() - textWidth)/2., y, textWidth, height);
+ return true;
+}
+
+void SubtitleLayout::draw(QPainter *painter, const QPointF &translate) const
+{
+ painter->save();
+ painter->translate(translate);
+ painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
+
+ QColor bgColor = Qt::black;
+ bgColor.setAlpha(128);
+ painter->setBrush(bgColor);
+ painter->setPen(Qt::NoPen);
+ painter->drawRect(bounds);
+
+ QTextLayout::FormatRange range;
+ range.start = 0;
+ range.length = layout.text().size();
+ range.format.setForeground(Qt::white);
+ layout.draw(painter, {}, { range });
+ painter->restore();
+}
+
+QImage SubtitleLayout::toImage() const
+{
+ auto size = bounds.size().toSize();
+ if (size.isEmpty())
+ return QImage();
+ QImage img(size, QImage::Format_RGBA8888_Premultiplied);
+ QColor bgColor = Qt::black;
+ bgColor.setAlpha(128);
+ img.fill(bgColor);
+
+ QPainter painter(&img);
+ painter.translate(-bounds.topLeft());
+ QTextLayout::FormatRange range;
+ range.start = 0;
+ range.length = layout.text().size();
+ range.format.setForeground(Qt::white);
+ layout.draw(&painter, {}, { range });
+ return img;
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/video/qvideotexturehelper_p.h b/src/multimedia/video/qvideotexturehelper_p.h
new file mode 100644
index 000000000..982c1b48a
--- /dev/null
+++ b/src/multimedia/video/qvideotexturehelper_p.h
@@ -0,0 +1,93 @@
+// 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
+
+//
+// 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 <rhi/qrhi.h>
+
+#include <QtGui/qtextlayout.h>
+
+QT_BEGIN_NAMESPACE
+
+class QVideoFrame;
+class QTextLayout;
+class QVideoFrameTextures;
+
+namespace QVideoTextureHelper
+{
+
+struct TextureDescription
+{
+ static constexpr int maxPlanes = 3;
+ struct SizeScale {
+ int x;
+ int y;
+ };
+ using BytesRequired = int(*)(int stride, int height);
+
+ inline int strideForWidth(int width) const { return (width*strideFactor + 15) & ~15; }
+ inline int bytesForSize(QSize s) const { return bytesRequired(strideForWidth(s.width()), s.height()); }
+ int widthForPlane(int width, int plane) const
+ {
+ if (plane > nplanes) return 0;
+ return (width + sizeScale[plane].x - 1)/sizeScale[plane].x;
+ }
+ int heightForPlane(int height, int plane) const
+ {
+ if (plane > nplanes) return 0;
+ return (height + sizeScale[plane].y - 1)/sizeScale[plane].y;
+ }
+
+ int nplanes;
+ int strideFactor;
+ BytesRequired bytesRequired;
+ QRhiTexture::Format textureFormat[maxPlanes];
+ SizeScale sizeScale[maxPlanes];
+};
+
+Q_MULTIMEDIA_EXPORT const TextureDescription *textureDescription(QVideoFrameFormat::PixelFormat format);
+
+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
+{
+ QSize videoSize;
+ QRectF bounds;
+ QTextLayout layout;
+
+ bool update(const QSize &frameSize, QString text);
+ void draw(QPainter *painter, const QPointF &translate) const;
+ QImage toImage() const;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/video/qvideowindow.cpp b/src/multimedia/video/qvideowindow.cpp
new file mode 100644
index 000000000..9b88a86df
--- /dev/null
+++ b/src/multimedia/video/qvideowindow.cpp
@@ -0,0 +1,531 @@
+// 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/qhwvideobuffer_p.h>
+#include <private/qmultimediautils_p.h>
+#include <private/qvideoframe_p.h>
+#include <qpa/qplatformintegration.h>
+
+QT_BEGIN_NAMESPACE
+
+static QSurface::SurfaceType platformSurfaceType()
+{
+#if defined(Q_OS_DARWIN)
+ return QSurface::MetalSurface;
+#elif defined (Q_OS_WIN)
+ return QSurface::Direct3DSurface;
+#endif
+
+ auto *integration = QGuiApplicationPrivate::platformIntegration();
+
+ if (!integration->hasCapability(QPlatformIntegration::OpenGL))
+ return QSurface::RasterSurface;
+
+ if (QCoreApplication::testAttribute(Qt::AA_ForceRasterWidgets))
+ return QSurface::RasterSurface;
+
+ if (integration->hasCapability(QPlatformIntegration::RasterGLSurface))
+ return QSurface::RasterGLSurface;
+
+ return QSurface::OpenGLSurface;
+}
+
+QVideoWindowPrivate::QVideoWindowPrivate(QVideoWindow *q)
+ : q(q),
+ m_sink(new QVideoSink)
+{
+ Q_ASSERT(q);
+
+ if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RhiBasedRendering)) {
+ auto surfaceType = ::platformSurfaceType();
+ q->setSurfaceType(surfaceType);
+ switch (surfaceType) {
+ case QSurface::RasterSurface:
+ case QSurface::OpenVGSurface:
+ // can't use those surfaces, need to render in SW
+ m_graphicsApi = QRhi::Null;
+ break;
+ case QSurface::OpenGLSurface:
+ case QSurface::RasterGLSurface:
+ m_graphicsApi = QRhi::OpenGLES2;
+ break;
+ case QSurface::VulkanSurface:
+ m_graphicsApi = QRhi::Vulkan;
+ break;
+ case QSurface::MetalSurface:
+ m_graphicsApi = QRhi::Metal;
+ break;
+ case QSurface::Direct3DSurface:
+ m_graphicsApi = QRhi::D3D11;
+ break;
+ }
+ }
+
+ QObject::connect(m_sink.get(), &QVideoSink::videoFrameChanged, q, &QVideoWindow::setVideoFrame);
+}
+
+QVideoWindowPrivate::~QVideoWindowPrivate()
+{
+ QObject::disconnect(m_sink.get(), &QVideoSink::videoFrameChanged,
+ q, &QVideoWindow::setVideoFrame);
+}
+
+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 vwGetShader(const QString &name)
+{
+ QFile f(name);
+ if (f.open(QIODevice::ReadOnly))
+ return QShader::fromSerialized(f.readAll());
+
+ return QShader();
+}
+
+void QVideoWindowPrivate::initRhi()
+{
+ if (m_graphicsApi == QRhi::Null)
+ return;
+
+ QRhi::Flags rhiFlags = {};//QRhi::EnableDebugMarkers | QRhi::EnableProfiling;
+
+#if QT_CONFIG(opengl)
+ if (m_graphicsApi == QRhi::OpenGLES2) {
+ m_fallbackSurface.reset(QRhiGles2InitParams::newFallbackSurface(q->format()));
+ QRhiGles2InitParams params;
+ params.fallbackSurface = m_fallbackSurface.get();
+ params.window = q;
+ params.format = q->format();
+ m_rhi.reset(QRhi::create(QRhi::OpenGLES2, &params, rhiFlags));
+ }
+#endif
+
+#if QT_CONFIG(vulkan)
+ if (m_graphicsApi == QRhi::Vulkan) {
+ QRhiVulkanInitParams params;
+ params.inst = q->vulkanInstance();
+ params.window = q;
+ m_rhi.reset(QRhi::create(QRhi::Vulkan, &params, rhiFlags));
+ }
+#endif
+
+#ifdef Q_OS_WIN
+ if (m_graphicsApi == QRhi::D3D11) {
+ QRhiD3D11InitParams params;
+ params.enableDebugLayer = true;
+ m_rhi.reset(QRhi::create(QRhi::D3D11, &params, rhiFlags));
+ }
+#endif
+
+#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+ if (m_graphicsApi == QRhi::Metal) {
+ QRhiMetalInitParams params;
+ m_rhi.reset(QRhi::create(QRhi::Metal, &params, rhiFlags));
+ }
+#endif
+ if (!m_rhi)
+ return;
+
+ m_swapChain.reset(m_rhi->newSwapChain());
+ m_swapChain->setWindow(q);
+ m_renderPass.reset(m_swapChain->newCompatibleRenderPassDescriptor());
+ m_swapChain->setRenderPassDescriptor(m_renderPass.get());
+
+ 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, sizeof(QVideoTextureHelper::UniformData)));
+ m_uniformBuf->create();
+
+ m_textureSampler.reset(m_rhi->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
+ QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge));
+ m_textureSampler->create();
+
+ m_shaderResourceBindings.reset(m_rhi->newShaderResourceBindings());
+ m_subtitleResourceBindings.reset(m_rhi->newShaderResourceBindings());
+
+ 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, const QVideoFrameFormat &fmt)
+{
+
+ pipeline->setTopology(QRhiGraphicsPipeline::TriangleStrip);
+ QShader vs = vwGetShader(QVideoTextureHelper::vertexShaderFileName(fmt));
+ Q_ASSERT(vs.isValid());
+ QShader fs = vwGetShader(QVideoTextureHelper::fragmentShaderFileName(fmt, m_swapChain->format()));
+ Q_ASSERT(fs.isValid());
+ pipeline->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) }
+ });
+ pipeline->setVertexInputLayout(inputLayout);
+ pipeline->setShaderResourceBindings(bindings);
+ pipeline->setRenderPassDescriptor(m_renderPass.get());
+ pipeline->create();
+}
+
+void QVideoWindowPrivate::updateTextures(QRhiResourceUpdateBatch *rub)
+{
+ m_texturesDirty = false;
+
+ // We render a 1x1 black pixel when we don't have a video
+ if (!m_currentFrame.isValid())
+ m_currentFrame = QVideoFramePrivate::createFrame(
+ std::make_unique<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->texture(i), m_textureSampler.get());
+ m_shaderResourceBindings->setBindings(bindings, b);
+ m_shaderResourceBindings->create();
+
+ if (fmt != format) {
+ format = fmt;
+ if (!m_graphicsPipeline)
+ m_graphicsPipeline.reset(m_rhi->newGraphicsPipeline());
+
+ setupGraphicsPipeline(m_graphicsPipeline.get(), m_shaderResourceBindings.get(), format);
+ }
+}
+
+void QVideoWindowPrivate::updateSubtitle(QRhiResourceUpdateBatch *rub, const QSize &frameSize)
+{
+ m_subtitleDirty = false;
+ m_hasSubtitle = !m_currentFrame.subtitleText().isEmpty();
+ if (!m_hasSubtitle)
+ return;
+
+ m_subtitleLayout.update(frameSize, m_currentFrame.subtitleText());
+ QSize size = m_subtitleLayout.bounds.size().toSize();
+
+ QImage img = m_subtitleLayout.toImage();
+
+ m_subtitleTexture.reset(m_rhi->newTexture(QRhiTexture::RGBA8, size));
+ m_subtitleTexture->create();
+ rub->uploadTexture(m_subtitleTexture.get(), img);
+
+ QRhiShaderResourceBinding bindings[2];
+
+ bindings[0] = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage,
+ m_subtitleUniformBuf.get());
+
+ bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage,
+ m_subtitleTexture.get(), m_textureSampler.get());
+ m_subtitleResourceBindings->setBindings(bindings, bindings + 2);
+ m_subtitleResourceBindings->create();
+
+ if (!m_subtitlePipeline) {
+ m_subtitlePipeline.reset(m_rhi->newGraphicsPipeline());
+
+ QRhiGraphicsPipeline::TargetBlend blend;
+ blend.enable = true;
+ m_subtitlePipeline->setTargetBlends({ blend });
+ setupGraphicsPipeline(m_subtitlePipeline.get(), m_subtitleResourceBindings.get(), QVideoFrameFormat(QSize(1, 1), QVideoFrameFormat::Format_RGBA8888));
+ }
+}
+
+void QVideoWindowPrivate::init()
+{
+ if (initialized)
+ return;
+ initialized = true;
+
+ initRhi();
+
+ if (!m_rhi)
+ backingStore = new QBackingStore(q);
+ else
+ m_sink->setRhi(m_rhi.get());
+}
+
+void QVideoWindowPrivate::resizeSwapChain()
+{
+ m_hasSwapChain = m_swapChain->createOrResize();
+}
+
+void QVideoWindowPrivate::releaseSwapChain()
+{
+ if (m_hasSwapChain) {
+ m_hasSwapChain = false;
+ m_swapChain->destroy();
+ }
+}
+
+void QVideoWindowPrivate::render()
+{
+ if (!initialized)
+ init();
+
+ if (!q->isExposed() || !isExposed)
+ return;
+
+ QRect rect(0, 0, q->width(), q->height());
+
+ if (backingStore) {
+ if (backingStore->size() != q->size())
+ backingStore->resize(q->size());
+
+ backingStore->beginPaint(rect);
+
+ QPaintDevice *device = backingStore->paintDevice();
+ if (!device)
+ return;
+ QPainter painter(device);
+
+ m_currentFrame.paint(&painter, rect, { Qt::black, aspectRatioMode });
+ painter.end();
+
+ backingStore->endPaint();
+ backingStore->flush(rect);
+ return;
+ }
+
+ 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();
+
+ 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)
+ return;
+ r = m_rhi->beginFrame(m_swapChain.get());
+ }
+ if (r != QRhi::FrameOpSuccess) {
+ qWarning("beginFrame failed with %d, retry", r);
+ q->requestUpdate();
+ return;
+ }
+
+ QRhiResourceUpdateBatch *rub = m_rhi->nextResourceUpdateBatch();
+
+ if (!m_vertexBufReady) {
+ m_vertexBufReady = true;
+ rub->uploadStaticBuffer(m_vertexBuf.get(), g_vw_quad);
+ }
+
+ if (m_texturesDirty)
+ updateTextures(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());
+
+ QMatrix4x4 transform;
+ transform.scale(xscale, yscale);
+
+ 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;
+ 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 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(), st, 1.f);
+ rub->updateDynamicBuffer(m_subtitleUniformBuf.get(), 0, uniformData.size(), uniformData.constData());
+ }
+
+ QRhiCommandBuffer *cb = m_swapChain->currentFrameCommandBuffer();
+ cb->beginPass(m_swapChain->currentFrameRenderTarget(), Qt::black, { 1.0f, 0 }, rub);
+ cb->setGraphicsPipeline(m_graphicsPipeline.get());
+ auto size = m_swapChain->currentPixelSize();
+ cb->setViewport({ 0, 0, float(size.width()), float(size.height()) });
+ cb->setShaderResources(m_shaderResourceBindings.get());
+
+ quint32 vertexOffset = quint32(sizeof(float)) * 16 * frameRotationIndex;
+ const QRhiCommandBuffer::VertexInput vbufBinding(m_vertexBuf.get(), vertexOffset);
+ cb->setVertexInput(0, 1, &vbufBinding);
+ cb->draw(4);
+
+ if (m_hasSubtitle) {
+ cb->setGraphicsPipeline(m_subtitlePipeline.get());
+ cb->setShaderResources(m_subtitleResourceBindings.get());
+ const QRhiCommandBuffer::VertexInput vbufBinding(m_vertexBuf.get(), 0);
+ cb->setVertexInput(0, 1, &vbufBinding);
+ cb->draw(4);
+ }
+
+ cb->endPass();
+
+ m_rhi->endFrame(m_swapChain.get());
+}
+
+/*!
+ \class QVideoWindow
+ \internal
+*/
+QVideoWindow::QVideoWindow(QScreen *screen)
+ : QWindow(screen)
+ , d(new QVideoWindowPrivate(this))
+{
+}
+
+QVideoWindow::QVideoWindow(QWindow *parent)
+ : QWindow(parent)
+ , d(new QVideoWindowPrivate(this))
+{
+}
+
+QVideoWindow::~QVideoWindow() = default;
+
+QVideoSink *QVideoWindow::videoSink() const
+{
+ return d->m_sink.get();
+}
+
+Qt::AspectRatioMode QVideoWindow::aspectRatioMode() const
+{
+ return d->aspectRatioMode;
+}
+
+void QVideoWindow::setAspectRatioMode(Qt::AspectRatioMode mode)
+{
+ if (d->aspectRatioMode == mode)
+ return;
+ d->aspectRatioMode = mode;
+ emit aspectRatioModeChanged(mode);
+}
+
+bool QVideoWindow::event(QEvent *e)
+{
+ switch (e->type()) {
+ case QEvent::UpdateRequest:
+ d->render();
+ return true;
+
+ case QEvent::PlatformSurface:
+ // this is the proper time to tear down the swapchain (while the native window and surface are still around)
+ if (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) {
+ d->releaseSwapChain();
+ d->isExposed = false;
+ }
+ break;
+ case QEvent::Expose:
+ d->isExposed = isExposed();
+ if (d->isExposed)
+ d->render();
+ return true;
+
+ default:
+ break;
+ }
+
+ return QWindow::event(e);
+}
+
+void QVideoWindow::resizeEvent(QResizeEvent *resizeEvent)
+{
+ if (!d->backingStore)
+ return;
+ if (!d->initialized)
+ d->init();
+ d->backingStore->resize(resizeEvent->size());
+}
+
+void QVideoWindow::setVideoFrame(const QVideoFrame &frame)
+{
+ if (d->m_currentFrame.subtitleText() != frame.subtitleText())
+ d->m_subtitleDirty = true;
+ d->m_currentFrame = frame;
+ d->m_texturesDirty = true;
+ if (d->isExposed)
+ requestUpdate();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qvideowindow_p.cpp"
diff --git a/src/multimedia/video/qvideowindow_p.h b/src/multimedia/video/qvideowindow_p.h
new file mode 100644
index 000000000..3305d3b40
--- /dev/null
+++ b/src/multimedia/video/qvideowindow_p.h
@@ -0,0 +1,127 @@
+// 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
+
+//
+// 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 <QWindow>
+#include <QOffscreenSurface>
+#include <qtextlayout.h>
+#include <rhi/qrhi.h>
+#include <qvideoframe.h>
+#include <private/qplatformvideosink_p.h>
+#include <private/qvideotexturehelper_p.h>
+#include <qbackingstore.h>
+
+QT_BEGIN_NAMESPACE
+
+class QVideoWindow;
+
+class QVideoWindowPrivate {
+public:
+ QVideoWindowPrivate(QVideoWindow *q);
+ ~QVideoWindowPrivate();
+ bool canRender() const { return m_useRhi; }
+
+ QRhi *rhi() const { return m_rhi.get(); }
+
+ void init();
+ void render();
+
+ void initRhi();
+
+ void resizeSwapChain();
+ void releaseSwapChain();
+
+ void updateTextures(QRhiResourceUpdateBatch *rub);
+ void updateSubtitle(QRhiResourceUpdateBatch *rub, const QSize &frameSize);
+
+ void setupGraphicsPipeline(QRhiGraphicsPipeline *pipeline, QRhiShaderResourceBindings *bindings, const QVideoFrameFormat &fmt);
+
+ QVideoWindow *q = nullptr;
+ Qt::AspectRatioMode aspectRatioMode = Qt::KeepAspectRatio;
+
+ QBackingStore *backingStore = nullptr;
+
+#if QT_CONFIG(opengl)
+ std::unique_ptr<QOffscreenSurface> m_fallbackSurface;
+#endif
+ std::unique_ptr<QRhi> m_rhi;
+ std::unique_ptr<QRhiSwapChain> m_swapChain;
+ std::unique_ptr<QRhiRenderPassDescriptor> m_renderPass;
+
+ std::unique_ptr<QRhiBuffer> m_vertexBuf;
+ bool m_vertexBufReady = false;
+ std::unique_ptr<QRhiBuffer> m_uniformBuf;
+ std::unique_ptr<QVideoFrameTextures> m_frameTextures;
+ std::unique_ptr<QRhiSampler> m_textureSampler;
+ std::unique_ptr<QRhiShaderResourceBindings> m_shaderResourceBindings;
+ std::unique_ptr<QRhiGraphicsPipeline> m_graphicsPipeline;
+
+ std::unique_ptr<QRhiTexture> m_subtitleTexture;
+ std::unique_ptr<QRhiShaderResourceBindings> m_subtitleResourceBindings;
+ std::unique_ptr<QRhiGraphicsPipeline> m_subtitlePipeline;
+ std::unique_ptr<QRhiBuffer> m_subtitleUniformBuf;
+
+ std::unique_ptr<QVideoSink> m_sink;
+ QRhi::Implementation m_graphicsApi = QRhi::Null;
+ QVideoFrame m_currentFrame;
+ QVideoTextureHelper::SubtitleLayout m_subtitleLayout;
+
+ enum { NVideoFrameSlots = 4 };
+ QVideoFrame m_videoFrameSlots[NVideoFrameSlots];
+
+ bool initialized = false;
+ bool isExposed = false;
+ bool m_useRhi = true;
+ bool m_hasSwapChain = false;
+ bool m_texturesDirty = true;
+ bool m_subtitleDirty = false;
+ bool m_hasSubtitle = false;
+ QVideoFrameFormat format;
+};
+
+class Q_MULTIMEDIA_EXPORT QVideoWindow : public QWindow
+{
+ Q_OBJECT
+public:
+ explicit QVideoWindow(QScreen *screen = nullptr);
+ explicit QVideoWindow(QWindow *parent);
+ ~QVideoWindow();
+
+ Q_INVOKABLE QVideoSink *videoSink() const;
+
+ Qt::AspectRatioMode aspectRatioMode() const;
+
+public Q_SLOTS:
+ void setAspectRatioMode(Qt::AspectRatioMode mode);
+
+Q_SIGNALS:
+ void aspectRatioModeChanged(Qt::AspectRatioMode mode);
+
+protected:
+ bool event(QEvent *e) override;
+ void resizeEvent(QResizeEvent *) override;
+
+private Q_SLOTS:
+ void setVideoFrame(const QVideoFrame &frame);
+
+private:
+ friend class QVideoWindowPrivate;
+ std::unique_ptr<QVideoWindowPrivate> d;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/video/video.pri b/src/multimedia/video/video.pri
deleted file mode 100644
index a3668ba4a..000000000
--- a/src/multimedia/video/video.pri
+++ /dev/null
@@ -1,37 +0,0 @@
-
-INCLUDEPATH += video
-
-PUBLIC_HEADERS += \
- video/qabstractvideobuffer.h \
- video/qabstractvideosurface.h \
- video/qvideoframe.h \
- video/qvideosurfaceformat.h \
- video/qvideoprobe.h \
- video/qabstractvideofilter.h
-
-PRIVATE_HEADERS += \
- video/qabstractvideobuffer_p.h \
- video/qimagevideobuffer_p.h \
- video/qmemoryvideobuffer_p.h \
- video/qvideooutputorientationhandler_p.h \
- video/qvideosurfaceoutput_p.h \
- video/qvideoframeconversionhelper_p.h \
- video/qvideosurfaces_p.h
-
-SOURCES += \
- video/qabstractvideobuffer.cpp \
- video/qabstractvideosurface.cpp \
- video/qimagevideobuffer.cpp \
- video/qmemoryvideobuffer.cpp \
- video/qvideoframe.cpp \
- video/qvideooutputorientationhandler.cpp \
- video/qvideosurfaceformat.cpp \
- video/qvideosurfaceoutput.cpp \
- video/qvideoprobe.cpp \
- video/qabstractvideofilter.cpp \
- video/qvideoframeconversionhelper.cpp \
- video/qvideosurfaces.cpp
-
-SSE2_SOURCES += video/qvideoframeconversionhelper_sse2.cpp
-SSSE3_SOURCES += video/qvideoframeconversionhelper_ssse3.cpp
-AVX2_SOURCES += video/qvideoframeconversionhelper_avx2.cpp
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/wasm/qwasmaudiosink.cpp b/src/multimedia/wasm/qwasmaudiosink.cpp
new file mode 100644
index 000000000..d1068e744
--- /dev/null
+++ b/src/multimedia/wasm/qwasmaudiosink.cpp
@@ -0,0 +1,464 @@
+// 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"
+
+
+#include <emscripten.h>
+#include <AL/al.h>
+#include <AL/alc.h>
+#include <QDebug>
+#include <QtMath>
+#include <QIODevice>
+
+// non native al formats (AL_EXT_float32)
+#define AL_FORMAT_MONO_FLOAT32 0x10010
+#define AL_FORMAT_STEREO_FLOAT32 0x10011
+
+constexpr unsigned int DEFAULT_BUFFER_DURATION = 50'000;
+
+class ALData {
+public:
+ ALCcontext *context = nullptr;
+ ALCdevice *device = nullptr;
+ ALuint source;
+ ALuint *buffers = nullptr;
+ ALuint *buffer = nullptr;
+ ALenum format;
+};
+
+QT_BEGIN_NAMESPACE
+
+class QWasmAudioSinkDevice : public QIODevice {
+
+ QWasmAudioSink *m_out;
+
+public:
+ QWasmAudioSinkDevice(QWasmAudioSink *parent);
+
+protected:
+ qint64 readData(char *data, qint64 maxlen) override;
+ qint64 writeData(const char *data, qint64 len) override;
+};
+
+QWasmAudioSink::QWasmAudioSink(const QByteArray &device, QObject *parent)
+ : QPlatformAudioSink(parent),
+ m_name(device),
+ m_timer(new QTimer(this))
+{
+ m_timer->setSingleShot(false);
+ aldata = new ALData();
+ connect(m_timer, &QTimer::timeout, this, [this](){
+ if (m_pullMode)
+ nextALBuffers();
+ else {
+ unloadALBuffers();
+ m_device->write(nullptr, 0);
+ updateState();
+ }
+ });
+}
+
+QWasmAudioSink::~QWasmAudioSink()
+{
+ delete aldata;
+ if (m_tmpData)
+ delete[] m_tmpData;
+}
+
+void QWasmAudioSink::start(QIODevice *device)
+{
+ Q_ASSERT(device);
+ Q_ASSERT(device->openMode().testFlag(QIODevice::ReadOnly));
+ m_device = device;
+ start(true);
+}
+
+QIODevice *QWasmAudioSink::start()
+{
+ m_device = new QWasmAudioSinkDevice(this);
+ m_device->open(QIODevice::WriteOnly);
+ start(false);
+ return m_device;
+}
+
+void QWasmAudioSink::start(bool mode)
+{
+ auto formatError = [this](){
+ qWarning() << "Unsupported audio format " << m_format;
+ setError(QAudio::OpenError);
+ };
+ switch (m_format.sampleFormat()) {
+ case QAudioFormat::UInt8:
+ switch (m_format.channelCount()) {
+ case 1:
+ aldata->format = AL_FORMAT_MONO8;
+ break;
+ case 2:
+ aldata->format = AL_FORMAT_STEREO8;
+ break;
+ default:
+ return formatError();
+ }
+ break;
+ case QAudioFormat::Int16:
+ switch (m_format.channelCount()) {
+ case 1:
+ aldata->format = AL_FORMAT_MONO16;
+ break;
+ case 2:
+ aldata->format = AL_FORMAT_STEREO16;
+ break;
+ default:
+ return formatError();
+ }
+ break;
+ case QAudioFormat::Float:
+ switch (m_format.channelCount()) {
+ case 1:
+ aldata->format = AL_FORMAT_MONO_FLOAT32;
+ break;
+ case 2:
+ aldata->format = AL_FORMAT_STEREO_FLOAT32;
+ break;
+ default:
+ return formatError();
+ }
+ break;
+ default:
+ return formatError();
+ }
+
+ alGetError();
+ aldata->device = alcOpenDevice(m_name.data());
+ if (!aldata->device) {
+ qWarning() << "Failed to open audio device" << alGetString(alGetError());
+ return setError(QAudio::OpenError);
+ }
+ ALint attrlist[] = {ALC_FREQUENCY, m_format.sampleRate(), 0};
+ aldata->context = alcCreateContext(aldata->device, attrlist);
+
+ if (!aldata->context) {
+ qWarning() << "Failed to create audio context" << alGetString(alGetError());
+ return setError(QAudio::OpenError);
+ }
+ alcMakeContextCurrent(aldata->context);
+
+ alGenSources(1, &aldata->source);
+
+ if (m_bufferSize > 0)
+ m_bufferFragmentsCount = qMax(2,qCeil((qreal)m_bufferSize/(m_bufferFragmentSize)));
+ m_bufferSize = m_bufferFragmentsCount * m_bufferFragmentSize;
+ aldata->buffers = new ALuint[m_bufferFragmentsCount];
+ aldata->buffer = aldata->buffers;
+ alGenBuffers(m_bufferFragmentsCount, aldata->buffers);
+ m_processed = 0;
+ m_tmpDataOffset = 0;
+ m_pullMode = mode;
+ alSourcef(aldata->source, AL_GAIN, m_volume);
+ if (m_pullMode)
+ loadALBuffers();
+ m_timer->setInterval(DEFAULT_BUFFER_DURATION / 3000);
+ m_timer->start();
+ if (m_pullMode)
+ alSourcePlay(aldata->source);
+ m_running = true;
+ m_elapsedTimer.start();
+ updateState();
+}
+
+void QWasmAudioSink::stop()
+{
+ if (!m_running)
+ return;
+ m_elapsedTimer.invalidate();
+ alSourceStop(aldata->source);
+ alSourceRewind(aldata->source);
+ m_timer->stop();
+ m_bufferFragmentsBusyCount = 0;
+ alDeleteSources(1, &aldata->source);
+ alDeleteBuffers(m_bufferFragmentsCount, aldata->buffers);
+ delete[] aldata->buffers;
+ alcMakeContextCurrent(nullptr);
+ alcDestroyContext(aldata->context);
+ alcCloseDevice(aldata->device);
+ m_running = false;
+ m_processed = 0;
+ if (!m_pullMode)
+ m_device->deleteLater();
+ updateState();
+}
+
+void QWasmAudioSink::reset()
+{
+ stop();
+ m_error = QAudio::NoError;
+}
+
+void QWasmAudioSink::suspend()
+{
+ if (!m_running)
+ return;
+
+ m_suspendedInState = m_state;
+ alSourcePause(aldata->source);
+}
+
+void QWasmAudioSink::resume()
+{
+ if (!m_running)
+ return;
+
+ alSourcePlay(aldata->source);
+}
+
+qsizetype QWasmAudioSink::bytesFree() const
+{
+ int processed;
+ alGetSourcei(aldata->source, AL_BUFFERS_PROCESSED, &processed);
+ return m_running ? m_bufferFragmentSize * (m_bufferFragmentsCount - m_bufferFragmentsBusyCount
+ + (qsizetype)processed) : 0;
+}
+
+void QWasmAudioSink::setBufferSize(qsizetype value)
+{
+ if (m_running)
+ return;
+
+ m_bufferSize = value;
+}
+
+qsizetype QWasmAudioSink::bufferSize() const
+{
+ return m_bufferSize;
+}
+
+qint64 QWasmAudioSink::processedUSecs() const
+{
+ int processed;
+ alGetSourcei(aldata->source, AL_BUFFERS_PROCESSED, &processed);
+ return m_format.durationForBytes(m_processed + m_format.bytesForDuration(
+ DEFAULT_BUFFER_DURATION * processed));
+}
+
+QAudio::Error QWasmAudioSink::error() const
+{
+ return m_error;
+}
+
+QAudio::State QWasmAudioSink::state() const
+{
+ if (!m_running)
+ return QAudio::StoppedState;
+ ALint state;
+ alGetSourcei(aldata->source, AL_SOURCE_STATE, &state);
+ switch (state) {
+ case AL_INITIAL:
+ return QAudio::IdleState;
+ case AL_PLAYING:
+ return QAudio::ActiveState;
+ case AL_PAUSED:
+ return QAudio::SuspendedState;
+ case AL_STOPPED:
+ return m_running ? QAudio::IdleState : QAudio::StoppedState;
+ }
+ return QAudio::StoppedState;
+}
+
+void QWasmAudioSink::setFormat(const QAudioFormat &fmt)
+{
+ if (m_running)
+ return;
+ m_format = fmt;
+ if (m_tmpData)
+ delete[] m_tmpData;
+ m_bufferFragmentSize = m_format.bytesForDuration(DEFAULT_BUFFER_DURATION);
+ m_bufferSize = m_bufferFragmentSize * m_bufferFragmentsCount;
+ m_tmpData = new char[m_bufferFragmentSize];
+}
+
+QAudioFormat QWasmAudioSink::format() const
+{
+ return m_format;
+}
+
+void QWasmAudioSink::setVolume(qreal volume)
+{
+ if (m_volume == volume)
+ return;
+ m_volume = volume;
+ if (m_running)
+ alSourcef(aldata->source, AL_GAIN, volume);
+}
+
+qreal QWasmAudioSink::volume() const
+{
+ return m_volume;
+}
+
+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 += size;
+ if (!m_tmpDataOffset || (m_tmpDataOffset != m_bufferFragmentSize &&
+ m_bufferFragmentsBusyCount >= m_bufferFragmentsCount * 2 / 3))
+ return;
+
+ alBufferData(*aldata->buffer, aldata->format, m_tmpData, m_tmpDataOffset,
+ m_format.sampleRate());
+ m_tmpDataOffset = 0;
+ alGetError();
+ alSourceQueueBuffers(aldata->source, 1, aldata->buffer);
+ if (alGetError())
+ return;
+
+ m_bufferFragmentsBusyCount++;
+ m_processed += size;
+ if (++aldata->buffer == aldata->buffers + m_bufferFragmentsCount)
+ aldata->buffer = aldata->buffers;
+}
+
+void QWasmAudioSink::unloadALBuffers()
+{
+ int processed;
+ alGetSourcei(aldata->source, AL_BUFFERS_PROCESSED, &processed);
+
+ if (processed) {
+ auto head = aldata->buffer - m_bufferFragmentsBusyCount;
+ if (head < aldata->buffers) {
+ if (head + processed > aldata->buffers) {
+ auto batch = m_bufferFragmentsBusyCount - (aldata->buffer - aldata->buffers);
+ alGetError();
+ alSourceUnqueueBuffers(aldata->source, batch, head + m_bufferFragmentsCount);
+ if (!alGetError()) {
+ m_bufferFragmentsBusyCount -= batch;
+ m_processed += m_bufferFragmentSize*batch;
+ }
+ processed -= batch;
+ if (!processed)
+ return;
+ head = aldata->buffers;
+ } else {
+ head += m_bufferFragmentsCount;
+ }
+ }
+ alGetError();
+ alSourceUnqueueBuffers(aldata->source, processed, head);
+ if (!alGetError())
+ m_bufferFragmentsBusyCount -= processed;
+ }
+}
+
+void QWasmAudioSink::nextALBuffers()
+{
+ updateState();
+ unloadALBuffers();
+ loadALBuffers();
+ ALint state;
+ alGetSourcei(aldata->source, AL_SOURCE_STATE, &state);
+ if (state != AL_PLAYING && m_error == QAudio::NoError)
+ alSourcePlay(aldata->source);
+ updateState();
+}
+
+void QWasmAudioSink::updateState()
+{
+ auto current = state();
+ if (m_state == current)
+ return;
+ m_state = current;
+
+ if (m_state == QAudio::IdleState && m_running && m_device->bytesAvailable() == 0)
+ setError(QAudio::UnderrunError);
+
+ emit stateChanged(m_state);
+
+}
+
+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),
+ m_out(parent)
+{
+}
+
+qint64 QWasmAudioSinkDevice::readData(char *data, qint64 maxlen)
+{
+ Q_UNUSED(data)
+ Q_UNUSED(maxlen)
+ return 0;
+}
+
+
+qint64 QWasmAudioSinkDevice::writeData(const char *data, qint64 len)
+{
+ ALint state;
+ alGetSourcei(m_out->aldata->source, AL_SOURCE_STATE, &state);
+ if (state != AL_INITIAL)
+ m_out->unloadALBuffers();
+ if (m_out->m_bufferFragmentsBusyCount < m_out->m_bufferFragmentsCount) {
+ bool exceeds = m_out->m_tmpDataOffset + len > m_out->m_bufferFragmentSize;
+ bool flush = m_out->m_bufferFragmentsBusyCount < m_out->m_bufferFragmentsCount * 2 / 3 ||
+ m_out->m_tmpDataOffset + len >= m_out->m_bufferFragmentSize;
+ const char *read;
+ char *tmp = m_out->m_tmpData;
+ int size = 0;
+ if (m_out->m_tmpDataOffset && exceeds) {
+ size = m_out->m_tmpDataOffset + len;
+ tmp = new char[m_out->m_tmpDataOffset + len];
+ std::memcpy(tmp, m_out->m_tmpData, m_out->m_tmpDataOffset);
+ }
+ if (flush && !m_out->m_tmpDataOffset) {
+ read = data;
+ size = len;
+ } else {
+ std::memcpy(tmp + m_out->m_tmpDataOffset, data, len);
+ read = tmp;
+ if (!exceeds) {
+ m_out->m_tmpDataOffset += len;
+ size = m_out->m_tmpDataOffset;
+ }
+ }
+ m_out->m_processed += size;
+ if (size && flush) {
+ alBufferData(*m_out->aldata->buffer, m_out->aldata->format, read, size,
+ m_out->m_format.sampleRate());
+ if (tmp && tmp != m_out->m_tmpData)
+ delete[] tmp;
+ m_out->m_tmpDataOffset = 0;
+ alGetError();
+ alSourceQueueBuffers(m_out->aldata->source, 1, m_out->aldata->buffer);
+ if (alGetError())
+ return 0;
+ m_out->m_bufferFragmentsBusyCount++;
+ if (++m_out->aldata->buffer == m_out->aldata->buffers + m_out->m_bufferFragmentsCount)
+ m_out->aldata->buffer = m_out->aldata->buffers;
+ if (state != AL_PLAYING)
+ alSourcePlay(m_out->aldata->source);
+ }
+ return len;
+ }
+ return 0;
+}
+
+QT_END_NAMESPACE
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/wasm/qwasmaudiosource.cpp b/src/multimedia/wasm/qwasmaudiosource.cpp
new file mode 100644
index 000000000..81f222c4b
--- /dev/null
+++ b/src/multimedia/wasm/qwasmaudiosource.cpp
@@ -0,0 +1,315 @@
+// 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"
+
+#include <emscripten.h>
+#include <AL/al.h>
+#include <AL/alc.h>
+#include <QDataStream>
+#include <QDebug>
+#include <QtMath>
+#include <private/qaudiohelpers_p.h>
+#include <QIODevice>
+
+QT_BEGIN_NAMESPACE
+
+#define AL_FORMAT_MONO_FLOAT32 0x10010
+#define AL_FORMAT_STEREO_FLOAT32 0x10011
+
+constexpr unsigned int DEFAULT_BUFFER_DURATION = 50'000;
+
+class QWasmAudioSourceDevice : public QIODevice
+{
+ QWasmAudioSource *m_in;
+
+public:
+ explicit QWasmAudioSourceDevice(QWasmAudioSource *in);
+
+protected:
+ qint64 readData(char *data, qint64 maxlen) override;
+ qint64 writeData(const char *data, qint64 len) override;
+};
+
+class ALData {
+public:
+ ALCdevice *device = nullptr;
+ ALCcontext *context = nullptr;
+};
+
+void QWasmAudioSource::setError(const QAudio::Error &error)
+{
+ if (m_error == error)
+ return;
+ m_error = error;
+ emit errorChanged(error);
+}
+
+void QWasmAudioSource::writeBuffer()
+{
+ int samples = 0;
+ alcGetIntegerv(aldata->device, ALC_CAPTURE_SAMPLES, 1, &samples);
+ samples = qMin(samples, m_format.framesForBytes(m_bufferSize));
+ auto bytes = m_format.bytesForFrames(samples);
+ auto err = alcGetError(aldata->device);
+ alcCaptureSamples(aldata->device, m_tmpData, samples);
+ err = alcGetError(aldata->device);
+ if (err) {
+ qWarning() << alcGetString(aldata->device, err);
+ return setError(QAudio::FatalError);
+ }
+ if (m_volume < 1)
+ QAudioHelperInternal::qMultiplySamples(m_volume, m_format, m_tmpData, m_tmpData, bytes);
+ m_processed += bytes;
+ m_device->write(m_tmpData,bytes);
+}
+
+QWasmAudioSource::QWasmAudioSource(const QByteArray &device , QObject *parent)
+ : QPlatformAudioSource(parent),
+ m_name(device),
+ m_timer(new QTimer(this))
+{
+ 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)
+{
+ m_device = device;
+ start(true);
+}
+
+QIODevice *QWasmAudioSource::start()
+{
+ m_device = new QWasmAudioSourceDevice(this);
+ m_device->open(QIODevice::ReadOnly);
+ start(false);
+ return m_device;
+}
+
+void QWasmAudioSource::start(bool mode)
+{
+ m_pullMode = mode;
+ auto formatError = [this](){
+ qWarning() << "Unsupported audio format " << m_format;
+ setError(QAudio::OpenError);
+ };
+ ALCenum format;
+ switch (m_format.sampleFormat()) {
+ case QAudioFormat::UInt8:
+ switch (m_format.channelCount()) {
+ case 1:
+ format = AL_FORMAT_MONO8;
+ break;
+ case 2:
+ format = AL_FORMAT_STEREO8;
+ break;
+ default:
+ return formatError();
+ }
+ break;
+ case QAudioFormat::Int16:
+ switch (m_format.channelCount()) {
+ case 1:
+ format = AL_FORMAT_MONO16;
+ break;
+ case 2:
+ format = AL_FORMAT_STEREO16;
+ break;
+ default:
+ return formatError();
+ }
+ break;
+ case QAudioFormat::Float:
+ switch (m_format.channelCount()) {
+ case 1:
+ format = AL_FORMAT_MONO_FLOAT32;
+ break;
+ case 2:
+ format = AL_FORMAT_STEREO_FLOAT32;
+ break;
+ default:
+ return formatError();
+ }
+ break;
+ default:
+ return formatError();
+ }
+ if (m_tmpData)
+ delete[] m_tmpData;
+ if (m_pullMode)
+ m_tmpData = new char[m_bufferSize];
+ else
+ m_tmpData = nullptr;
+ 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));
+
+ auto err = alcGetError(aldata->device);
+ if (err) {
+ qWarning() << "alcCaptureOpenDevice" << alcGetString(aldata->device, err);
+ return setError(QAudio::OpenError);
+ }
+ alcCaptureStart(aldata->device);
+ m_elapsedTimer.start();
+ auto cerr = alcGetError(aldata->device);
+ if (cerr) {
+ qWarning() << "alcCaptureStart" << alcGetString(aldata->device, cerr);
+ return setError(QAudio::OpenError);
+ }
+ m_processed = 0;
+ m_running = true;
+}
+
+void QWasmAudioSource::stop()
+{
+ if (m_pullMode)
+ writeBuffer();
+ alcCaptureStop(aldata->device);
+ alcCaptureCloseDevice(aldata->device);
+ m_elapsedTimer.invalidate();
+ if (m_tmpData) {
+ delete[] m_tmpData;
+ m_tmpData = nullptr;
+ }
+ if (!m_pullMode)
+ m_device->deleteLater();
+ m_timer->stop();
+ m_running = false;
+}
+
+void QWasmAudioSource::reset()
+{
+ stop();
+ if (m_tmpData) {
+ delete[] m_tmpData;
+ m_tmpData = nullptr;
+ }
+ m_running = false;
+ m_processed = 0;
+ m_error = QAudio::NoError;
+}
+
+void QWasmAudioSource::suspend()
+{
+ if (!m_running)
+ return;
+
+ m_suspended = true;
+ alcCaptureStop(aldata->device);
+}
+
+void QWasmAudioSource::resume()
+{
+ if (!m_running)
+ return;
+
+ m_suspended = false;
+ alcCaptureStart(aldata->device);
+}
+
+qsizetype QWasmAudioSource::bytesReady() const
+{
+ if (!m_running)
+ return 0;
+ int samples;
+ alcGetIntegerv(aldata->device, ALC_CAPTURE_SAMPLES, 1, &samples);
+ return m_format.bytesForFrames(samples);
+}
+
+void QWasmAudioSource::setBufferSize(qsizetype value)
+{
+ if (!m_running)
+ return;
+ m_bufferSize = value;
+}
+
+qsizetype QWasmAudioSource::bufferSize() const
+{
+ return m_bufferSize;
+}
+
+qint64 QWasmAudioSource::processedUSecs() const
+{
+ return m_format.durationForBytes(m_processed);
+}
+
+QAudio::Error QWasmAudioSource::error() const
+{
+ return m_error;
+}
+
+QAudio::State QWasmAudioSource::state() const
+{
+ if (m_running)
+ return QAudio::ActiveState;
+ else
+ return QAudio::StoppedState;
+}
+
+void QWasmAudioSource::setFormat(const QAudioFormat &fmt)
+{
+ m_format = fmt;
+ m_bufferSize = m_format.bytesForDuration(DEFAULT_BUFFER_DURATION);
+}
+
+QAudioFormat QWasmAudioSource::format() const
+{
+ return m_format;
+}
+
+void QWasmAudioSource::setVolume(qreal volume)
+{
+ m_volume = volume;
+}
+
+qreal QWasmAudioSource::volume() const
+{
+ return m_volume;
+}
+
+QWasmAudioSourceDevice::QWasmAudioSourceDevice(QWasmAudioSource *in) : QIODevice(in), m_in(in)
+{
+
+}
+
+qint64 QWasmAudioSourceDevice::readData(char *data, qint64 maxlen)
+{
+ int samples;
+ alcGetIntegerv(m_in->aldata->device, ALC_CAPTURE_SAMPLES, 1, &samples);
+ samples = qMin(samples, m_in->m_format.framesForBytes(maxlen));
+ auto bytes = m_in->m_format.bytesForFrames(samples);
+ alcGetError(m_in->aldata->device);
+ alcCaptureSamples(m_in->aldata->device, data, samples);
+ if (m_in->m_volume < 1)
+ QAudioHelperInternal::qMultiplySamples(m_in->m_volume, m_in->m_format, data, data, bytes);
+ auto err = alcGetError(m_in->aldata->device);
+ if (err) {
+ qWarning() << alcGetString(m_in->aldata->device, err);
+ m_in->setError(QAudio::FatalError);
+ return 0;
+ }
+ m_in->m_processed += bytes;
+ return bytes;
+}
+
+qint64 QWasmAudioSourceDevice::writeData(const char *data, qint64 len)
+{
+ Q_UNREACHABLE();
+ Q_UNUSED(data);
+ Q_UNUSED(len);
+ return 0;
+}
+
+QT_END_NAMESPACE
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/windows/qwindowsaudiodevice.cpp b/src/multimedia/windows/qwindowsaudiodevice.cpp
new file mode 100644
index 000000000..f22567cbf
--- /dev/null
+++ b/src/multimedia/windows/qwindowsaudiodevice.cpp
@@ -0,0 +1,229 @@
+// 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 "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 <initguid.h>
+#include <wtypes.h>
+#include <propkeydef.h>
+#include <mmdeviceapi.h>
+
+QT_BEGIN_NAMESPACE
+
+QWindowsAudioDeviceInfo::QWindowsAudioDeviceInfo(QByteArray dev, ComPtr<IMMDevice> immDev, int waveID, const QString &description, QAudioDevice::Mode mode)
+ : QAudioDevicePrivate(dev, mode),
+ m_devId(waveID),
+ m_immDev(std::move(immDev))
+{
+ Q_ASSERT(m_immDev);
+
+ this->description = description;
+
+ 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(m_devId, &woc, sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
+ fmt = woc.dwFormats;
+ } else {
+ WAVEINCAPS woc;
+ if (waveInGetDevCaps(m_devId, &woc, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR)
+ fmt = woc.dwFormats;
+ }
+
+ if (!fmt)
+ return;
+
+ // Check sample size
+ if ((fmt & WAVE_FORMAT_1M08)
+ || (fmt & WAVE_FORMAT_1S08)
+ || (fmt & WAVE_FORMAT_2M08)
+ || (fmt & WAVE_FORMAT_2S08)
+ || (fmt & WAVE_FORMAT_4M08)
+ || (fmt & WAVE_FORMAT_4S08)
+ || (fmt & WAVE_FORMAT_48M08)
+ || (fmt & WAVE_FORMAT_48S08)
+ || (fmt & WAVE_FORMAT_96M08)
+ || (fmt & WAVE_FORMAT_96S08)) {
+ supportedSampleFormats.append(QAudioFormat::UInt8);
+ }
+ if ((fmt & WAVE_FORMAT_1M16)
+ || (fmt & WAVE_FORMAT_1S16)
+ || (fmt & WAVE_FORMAT_2M16)
+ || (fmt & WAVE_FORMAT_2S16)
+ || (fmt & WAVE_FORMAT_4M16)
+ || (fmt & WAVE_FORMAT_4S16)
+ || (fmt & WAVE_FORMAT_48M16)
+ || (fmt & WAVE_FORMAT_48S16)
+ || (fmt & WAVE_FORMAT_96M16)
+ || (fmt & WAVE_FORMAT_96S16)) {
+ supportedSampleFormats.append(QAudioFormat::Int16);
+ }
+
+ minimumSampleRate = std::numeric_limits<int>::max();
+ maximumSampleRate = 0;
+ // Check sample rate
+ if ((fmt & WAVE_FORMAT_1M08)
+ || (fmt & WAVE_FORMAT_1S08)
+ || (fmt & WAVE_FORMAT_1M16)
+ || (fmt & WAVE_FORMAT_1S16)) {
+ minimumSampleRate = qMin(minimumSampleRate, 11025);
+ maximumSampleRate = qMax(maximumSampleRate, 11025);
+ }
+ if ((fmt & WAVE_FORMAT_2M08)
+ || (fmt & WAVE_FORMAT_2S08)
+ || (fmt & WAVE_FORMAT_2M16)
+ || (fmt & WAVE_FORMAT_2S16)) {
+ minimumSampleRate = qMin(minimumSampleRate, 22050);
+ maximumSampleRate = qMax(maximumSampleRate, 22050);
+ }
+ if ((fmt & WAVE_FORMAT_4M08)
+ || (fmt & WAVE_FORMAT_4S08)
+ || (fmt & WAVE_FORMAT_4M16)
+ || (fmt & WAVE_FORMAT_4S16)) {
+ minimumSampleRate = qMin(minimumSampleRate, 44100);
+ maximumSampleRate = qMax(maximumSampleRate, 44100);
+ }
+ if ((fmt & WAVE_FORMAT_48M08)
+ || (fmt & WAVE_FORMAT_48S08)
+ || (fmt & WAVE_FORMAT_48M16)
+ || (fmt & WAVE_FORMAT_48S16)) {
+ minimumSampleRate = qMin(minimumSampleRate, 48000);
+ maximumSampleRate = qMax(maximumSampleRate, 48000);
+ }
+ if ((fmt & WAVE_FORMAT_96M08)
+ || (fmt & WAVE_FORMAT_96S08)
+ || (fmt & WAVE_FORMAT_96M16)
+ || (fmt & WAVE_FORMAT_96S16)) {
+ minimumSampleRate = qMin(minimumSampleRate, 96000);
+ maximumSampleRate = qMax(maximumSampleRate, 96000);
+ }
+ if (minimumSampleRate == std::numeric_limits<int>::max())
+ minimumSampleRate = 0;
+
+ minimumChannelCount = std::numeric_limits<int>::max();
+ maximumChannelCount = 0;
+ // Check channel count
+ if (fmt & WAVE_FORMAT_1M08
+ || fmt & WAVE_FORMAT_1M16
+ || fmt & WAVE_FORMAT_2M08
+ || fmt & WAVE_FORMAT_2M16
+ || fmt & WAVE_FORMAT_4M08
+ || fmt & WAVE_FORMAT_4M16
+ || fmt & WAVE_FORMAT_48M08
+ || fmt & WAVE_FORMAT_48M16
+ || fmt & WAVE_FORMAT_96M08
+ || fmt & WAVE_FORMAT_96M16) {
+ minimumChannelCount = 1;
+ maximumChannelCount = 1;
+ }
+ if (fmt & WAVE_FORMAT_1S08
+ || fmt & WAVE_FORMAT_1S16
+ || fmt & WAVE_FORMAT_2S08
+ || fmt & WAVE_FORMAT_2S16
+ || fmt & WAVE_FORMAT_4S08
+ || fmt & WAVE_FORMAT_4S16
+ || fmt & WAVE_FORMAT_48S08
+ || fmt & WAVE_FORMAT_48S16
+ || fmt & WAVE_FORMAT_96S08
+ || fmt & WAVE_FORMAT_96S16) {
+ minimumChannelCount = qMin(minimumChannelCount, 2);
+ maximumChannelCount = qMax(maximumChannelCount, 2);
+ }
+
+ if (minimumChannelCount == std::numeric_limits<int>::max())
+ minimumChannelCount = 0;
+
+ // WAVEOUTCAPS and WAVEINCAPS contains information only for the previously tested parameters.
+ // WaveOut and WaveInt might actually support more formats, the only way to know is to try
+ // opening the device with it.
+ QAudioFormat testFormat;
+ testFormat.setChannelCount(maximumChannelCount);
+ testFormat.setSampleRate(maximumSampleRate);
+ const QAudioFormat defaultTestFormat(testFormat);
+
+ // Check if float samples are supported
+ testFormat.setSampleFormat(QAudioFormat::Float);
+ if (testSettings(testFormat))
+ supportedSampleFormats.append(QAudioFormat::Float);
+
+ // Check channel counts > 2
+ testFormat = defaultTestFormat;
+ for (int i = 18; i > 2; --i) { // <mmreg.h> defines 18 different channels
+ testFormat.setChannelCount(i);
+ if (testSettings(testFormat)) {
+ maximumChannelCount = i;
+ 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()
+{
+}
+
+bool QWindowsAudioDeviceInfo::testSettings(const QAudioFormat& format) const
+{
+ WAVEFORMATEXTENSIBLE wfx;
+ if (QWindowsAudioUtils::formatToWaveFormatExtensible(format, wfx)) {
+ // query only, do not open device
+ if (mode == QAudioDevice::Output) {
+ return (waveOutOpen(NULL, UINT_PTR(m_devId), &wfx.Format, 0, 0,
+ WAVE_FORMAT_QUERY) == MMSYSERR_NOERROR);
+ } else { // AudioInput
+ return (waveInOpen(NULL, UINT_PTR(m_devId), &wfx.Format, 0, 0,
+ WAVE_FORMAT_QUERY) == MMSYSERR_NOERROR);
+ }
+ }
+
+ return false;
+}
+
+QT_END_NAMESPACE
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/windows/qwindowsmultimediautils.cpp b/src/multimedia/windows/qwindowsmultimediautils.cpp
new file mode 100644
index 000000000..258cb3e96
--- /dev/null
+++ b/src/multimedia/windows/qwindowsmultimediautils.cpp
@@ -0,0 +1,215 @@
+// 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
+
+QVideoFrameFormat::PixelFormat QWindowsMultimediaUtils::pixelFormatFromMediaSubtype(const GUID &subtype)
+{
+ if (subtype == MFVideoFormat_ARGB32)
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ return QVideoFrameFormat::Format_BGRA8888;
+#else
+ return QVideoFrameFormat::Format_ARGB8888;
+#endif
+ if (subtype == MFVideoFormat_RGB32)
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ return QVideoFrameFormat::Format_BGRX8888;
+#else
+ return QVideoFrameFormat::Format_XRGB8888;
+#endif
+ if (subtype == MFVideoFormat_AYUV)
+ return QVideoFrameFormat::Format_AYUV;
+ if (subtype == MFVideoFormat_I420)
+ return QVideoFrameFormat::Format_YUV420P;
+ if (subtype == MFVideoFormat_UYVY)
+ return QVideoFrameFormat::Format_UYVY;
+ if (subtype == MFVideoFormat_YV12)
+ return QVideoFrameFormat::Format_YV12;
+ if (subtype == MFVideoFormat_NV12)
+ return QVideoFrameFormat::Format_NV12;
+ if (subtype == MFVideoFormat_YUY2)
+ return QVideoFrameFormat::Format_YUYV;
+ if (subtype == MFVideoFormat_P010)
+ return QVideoFrameFormat::Format_P010;
+ if (subtype == MFVideoFormat_P016)
+ return QVideoFrameFormat::Format_P016;
+ if (subtype == MFVideoFormat_L8)
+ return QVideoFrameFormat::Format_Y8;
+ if (subtype == MFVideoFormat_L16)
+ return QVideoFrameFormat::Format_Y16;
+ if (subtype == MFVideoFormat_MJPG)
+ return QVideoFrameFormat::Format_Jpeg;
+
+ return QVideoFrameFormat::Format_Invalid;
+}
+
+GUID QWindowsMultimediaUtils::videoFormatForCodec(QMediaFormat::VideoCodec codec)
+{
+ switch (codec) {
+ case QMediaFormat::VideoCodec::MPEG1:
+ return MFVideoFormat_MPG1;
+ case QMediaFormat::VideoCodec::MPEG2:
+ return MFVideoFormat_MPEG2;
+ case QMediaFormat::VideoCodec::MPEG4:
+ return MFVideoFormat_MP4V;
+ case QMediaFormat::VideoCodec::H264:
+ return MFVideoFormat_H264;
+ case QMediaFormat::VideoCodec::H265:
+ return MFVideoFormat_H265;
+ case QMediaFormat::VideoCodec::VP8:
+ return MFVideoFormat_VP80;
+ case QMediaFormat::VideoCodec::VP9:
+ return MFVideoFormat_VP90;
+ case QMediaFormat::VideoCodec::AV1:
+ return MFVideoFormat_AV1;
+ case QMediaFormat::VideoCodec::WMV:
+ return MFVideoFormat_WMV3;
+ case QMediaFormat::VideoCodec::MotionJPEG:
+ return MFVideoFormat_MJPG;
+ default:
+ return MFVideoFormat_H264;
+ }
+}
+
+QMediaFormat::VideoCodec QWindowsMultimediaUtils::codecForVideoFormat(GUID format)
+{
+ if (format == MFVideoFormat_MPG1)
+ return QMediaFormat::VideoCodec::MPEG1;
+ if (format == MFVideoFormat_MPEG2)
+ return QMediaFormat::VideoCodec::MPEG2;
+ if (format == MFVideoFormat_MP4V
+ || format == MFVideoFormat_M4S2
+ || format == MFVideoFormat_MP4S
+ || format == MFVideoFormat_MP43)
+ return QMediaFormat::VideoCodec::MPEG4;
+ if (format == MFVideoFormat_H264)
+ return QMediaFormat::VideoCodec::H264;
+ if (format == MFVideoFormat_H265)
+ return QMediaFormat::VideoCodec::H265;
+ if (format == MFVideoFormat_VP80)
+ return QMediaFormat::VideoCodec::VP8;
+ if (format == MFVideoFormat_VP90)
+ return QMediaFormat::VideoCodec::VP9;
+ if (format == MFVideoFormat_AV1)
+ return QMediaFormat::VideoCodec::AV1;
+ if (format == MFVideoFormat_WMV1
+ || format == MFVideoFormat_WMV2
+ || format == MFVideoFormat_WMV3)
+ return QMediaFormat::VideoCodec::WMV;
+ if (format == MFVideoFormat_MJPG)
+ return QMediaFormat::VideoCodec::MotionJPEG;
+ return QMediaFormat::VideoCodec::Unspecified;
+}
+
+GUID QWindowsMultimediaUtils::audioFormatForCodec(QMediaFormat::AudioCodec codec)
+{
+ switch (codec) {
+ case QMediaFormat::AudioCodec::MP3:
+ return MFAudioFormat_MP3;
+ case QMediaFormat::AudioCodec::AAC:
+ return MFAudioFormat_AAC;
+ case QMediaFormat::AudioCodec::ALAC:
+ return MFAudioFormat_ALAC;
+ case QMediaFormat::AudioCodec::FLAC:
+ return MFAudioFormat_FLAC;
+ case QMediaFormat::AudioCodec::Vorbis:
+ return MFAudioFormat_Vorbis;
+ case QMediaFormat::AudioCodec::Wave:
+ return MFAudioFormat_PCM;
+ case QMediaFormat::AudioCodec::Opus:
+ return MFAudioFormat_Opus;
+ case QMediaFormat::AudioCodec::AC3:
+ return MFAudioFormat_Dolby_AC3;
+ case QMediaFormat::AudioCodec::EAC3:
+ return MFAudioFormat_Dolby_DDPlus;
+ case QMediaFormat::AudioCodec::WMA:
+ return MFAudioFormat_WMAudioV9;
+ default:
+ return MFAudioFormat_AAC;
+ }
+}
+
+QMediaFormat::AudioCodec QWindowsMultimediaUtils::codecForAudioFormat(GUID format)
+{
+ if (format == MFAudioFormat_MP3)
+ return QMediaFormat::AudioCodec::MP3;
+ if (format == MFAudioFormat_AAC)
+ return QMediaFormat::AudioCodec::AAC;
+ if (format == MFAudioFormat_ALAC)
+ return QMediaFormat::AudioCodec::ALAC;
+ if (format == MFAudioFormat_FLAC)
+ return QMediaFormat::AudioCodec::FLAC;
+ if (format == MFAudioFormat_Vorbis)
+ return QMediaFormat::AudioCodec::Vorbis;
+ if (format == MFAudioFormat_PCM)
+ return QMediaFormat::AudioCodec::Wave;
+ if (format == MFAudioFormat_Opus)
+ return QMediaFormat::AudioCodec::Opus;
+ if (format == MFAudioFormat_Dolby_AC3)
+ return QMediaFormat::AudioCodec::AC3;
+ if (format == MFAudioFormat_Dolby_DDPlus)
+ return QMediaFormat::AudioCodec::EAC3;
+ if (format == MFAudioFormat_WMAudioV8
+ || format == MFAudioFormat_WMAudioV9
+ || format == MFAudioFormat_WMAudio_Lossless)
+ return QMediaFormat::AudioCodec::WMA;
+ return QMediaFormat::AudioCodec::Unspecified;
+}
+
+GUID QWindowsMultimediaUtils::containerForVideoFileFormat(QMediaFormat::FileFormat format)
+{
+ switch (format) {
+ case QMediaFormat::FileFormat::MPEG4:
+ return QMM_MFTranscodeContainerType_MPEG4;
+ case QMediaFormat::FileFormat::WMV:
+ return QMM_MFTranscodeContainerType_ASF;
+ case QMediaFormat::FileFormat::AVI:
+ return QMM_MFTranscodeContainerType_AVI;
+ default:
+ return QMM_MFTranscodeContainerType_MPEG4;
+ }
+}
+
+GUID QWindowsMultimediaUtils::containerForAudioFileFormat(QMediaFormat::FileFormat format)
+{
+ switch (format) {
+ case QMediaFormat::FileFormat::MP3:
+ return QMM_MFTranscodeContainerType_MP3;
+ case QMediaFormat::FileFormat::AAC:
+ return QMM_MFTranscodeContainerType_ADTS;
+ case QMediaFormat::FileFormat::Mpeg4Audio:
+ return QMM_MFTranscodeContainerType_MPEG4;
+ case QMediaFormat::FileFormat::WMA:
+ return QMM_MFTranscodeContainerType_ASF;
+ case QMediaFormat::FileFormat::FLAC:
+ return QMM_MFTranscodeContainerType_FLAC;
+ case QMediaFormat::FileFormat::Wave:
+ return QMM_MFTranscodeContainerType_WAVE;
+ default:
+ 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