summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--config.tests/wmp/wmp.pro7
-rw-r--r--[-rwxr-xr-x]examples/multimedia/audiooutput/doc/images/audiooutput-example.pngbin11966 -> 11966 bytes
-rw-r--r--examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectBillboard.qml8
-rw-r--r--examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectBlackAndWhite.qml7
-rw-r--r--examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectGaussianBlur.qml24
-rw-r--r--examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectIsolate.qml11
-rw-r--r--examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectMagnify.qml11
-rw-r--r--examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectPageCurl.qml8
-rw-r--r--examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectPixelate.qml8
-rw-r--r--examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectPosterize.qml8
-rw-r--r--examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectRipple.qml11
-rw-r--r--examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectSharpen.qml8
-rw-r--r--examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectShockwave.qml11
-rw-r--r--examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectSobelEdgeDetection1.qml8
-rw-r--r--qtmultimedia.pro3
-rw-r--r--src/imports/audioengine/audioengine.cpp4
-rw-r--r--src/imports/audioengine/plugins.qmltypes42
-rw-r--r--src/imports/audioengine/qaudioengine_openal_p.h11
-rw-r--r--src/imports/audioengine/qaudioengine_p.h11
-rw-r--r--src/imports/audioengine/qdeclarative_attenuationmodel_p.cpp48
-rw-r--r--src/imports/audioengine/qdeclarative_attenuationmodel_p.h32
-rw-r--r--src/imports/audioengine/qdeclarative_audiocategory_p.cpp24
-rw-r--r--src/imports/audioengine/qdeclarative_audiocategory_p.h24
-rw-r--r--src/imports/audioengine/qdeclarative_audioengine_p.cpp296
-rw-r--r--src/imports/audioengine/qdeclarative_audioengine_p.h19
-rw-r--r--src/imports/audioengine/qdeclarative_audiolistener_p.h11
-rw-r--r--src/imports/audioengine/qdeclarative_audiosample_p.cpp50
-rw-r--r--src/imports/audioengine/qdeclarative_audiosample_p.h25
-rw-r--r--src/imports/audioengine/qdeclarative_playvariation_p.cpp30
-rw-r--r--src/imports/audioengine/qdeclarative_playvariation_p.h23
-rw-r--r--src/imports/audioengine/qdeclarative_sound_p.cpp116
-rw-r--r--src/imports/audioengine/qdeclarative_sound_p.h29
-rw-r--r--src/imports/audioengine/qdeclarative_soundinstance_p.h11
-rw-r--r--src/imports/audioengine/qsoundbuffer_p.h11
-rw-r--r--src/imports/audioengine/qsoundinstance_p.h11
-rw-r--r--src/imports/audioengine/qsoundsource_p.h11
-rw-r--r--src/imports/multimedia/Video.qml58
-rw-r--r--src/imports/multimedia/multimedia.cpp7
-rw-r--r--src/imports/multimedia/multimedia.pro2
-rw-r--r--src/imports/multimedia/plugins.qmltypes162
-rw-r--r--src/imports/multimedia/qdeclarativeaudio.cpp204
-rw-r--r--src/imports/multimedia/qdeclarativeaudio_p.h34
-rw-r--r--src/imports/multimedia/qdeclarativeplaylist.cpp583
-rw-r--r--src/imports/multimedia/qdeclarativeplaylist_p.h199
-rw-r--r--src/imports/multimedia/qdeclarativetorch_p.h11
-rw-r--r--src/multimedia/audio/qaudio.cpp61
-rw-r--r--src/multimedia/audio/qaudio.h15
-rw-r--r--src/multimedia/audio/qaudiobuffer_p.h11
-rw-r--r--src/multimedia/camera/qcamera.cpp2
-rw-r--r--src/multimedia/controls/controls.pri6
-rw-r--r--src/multimedia/controls/qaudiorolecontrol.cpp111
-rw-r--r--src/multimedia/controls/qaudiorolecontrol.h69
-rw-r--r--src/multimedia/controls/qmediaplayercontrol.cpp1
-rw-r--r--src/multimedia/doc/qtmultimedia-dita.qdocconf32
-rw-r--r--src/multimedia/doc/qtmultimedia.qdocconf16
-rw-r--r--src/multimedia/doc/src/multimediabackend.qdoc5
-rw-r--r--src/multimedia/doc/src/qtmultimedia-cpp.qdoc19
-rw-r--r--src/multimedia/doc/src/qtmultimedia-index.qdoc23
-rw-r--r--src/multimedia/gsttools_headers/gstvideoconnector_p.h11
-rw-r--r--src/multimedia/gsttools_headers/qgstappsrc_p.h11
-rw-r--r--src/multimedia/gsttools_headers/qgstcodecsinfo_p.h11
-rw-r--r--src/multimedia/gsttools_headers/qgstreameraudioinputselector_p.h11
-rw-r--r--src/multimedia/gsttools_headers/qgstreameraudioprobecontrol_p.h11
-rw-r--r--src/multimedia/gsttools_headers/qgstreamerbufferprobe_p.h11
-rw-r--r--src/multimedia/gsttools_headers/qgstreamergltexturerenderer_p.h11
-rw-r--r--src/multimedia/gsttools_headers/qgstreamermirtexturerenderer_p.h11
-rw-r--r--src/multimedia/gsttools_headers/qgstreamervideoinputdevicecontrol_p.h11
-rw-r--r--src/multimedia/gsttools_headers/qgstreamervideooverlay_p.h11
-rw-r--r--src/multimedia/gsttools_headers/qgstreamervideoprobecontrol_p.h11
-rw-r--r--src/multimedia/gsttools_headers/qgstreamervideorenderer_p.h11
-rw-r--r--src/multimedia/gsttools_headers/qgstreamervideorendererinterface_p.h11
-rw-r--r--src/multimedia/gsttools_headers/qgstreamervideowidget_p.h11
-rw-r--r--src/multimedia/gsttools_headers/qgstreamervideowindow_p.h11
-rw-r--r--src/multimedia/multimedia.pro5
-rw-r--r--src/multimedia/playback/playlistfileparser.cpp7
-rw-r--r--src/multimedia/playback/qmediaplayer.cpp67
-rw-r--r--src/multimedia/playback/qmediaplayer.h8
-rw-r--r--src/multimedia/playback/qmediaplaylist.cpp72
-rw-r--r--src/multimedia/playback/qmediaplaylist_p.h4
-rw-r--r--src/multimedia/qmediametadata.cpp1
-rw-r--r--src/multimedia/qmediaresourcepolicy_p.h11
-rw-r--r--src/multimedia/qmediaresourcepolicyplugin_p.h11
-rw-r--r--src/multimedia/qmediaresourceset_p.h11
-rw-r--r--src/multimedia/qmediaserviceprovider_p.h11
-rw-r--r--src/multimedia/qmediastoragelocation_p.h11
-rw-r--r--src/multimedia/qmultimedia.cpp1
-rw-r--r--src/multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_backend_p.h11
-rw-r--r--src/multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_p.h11
-rw-r--r--src/multimedia/qtmultimediaquicktools_headers/qsgvideonode_p.h13
-rw-r--r--src/multimedia/recording/qmediarecorder_p.h11
-rw-r--r--src/multimedia/video/qvideoframe.cpp126
-rw-r--r--src/multimedia/video/qvideoframe.h3
-rw-r--r--src/multimedia/video/qvideoframe_p.h57
-rw-r--r--src/multimedia/video/qvideoframeconversionhelper.cpp348
-rw-r--r--src/multimedia/video/qvideoframeconversionhelper_avx2.cpp83
-rw-r--r--src/multimedia/video/qvideoframeconversionhelper_p.h117
-rw-r--r--src/multimedia/video/qvideoframeconversionhelper_sse2.cpp83
-rw-r--r--src/multimedia/video/qvideoframeconversionhelper_ssse3.cpp82
-rw-r--r--src/multimedia/video/qvideooutputorientationhandler_p.h11
-rw-r--r--src/multimedia/video/qvideosurfaceoutput_p.h11
-rw-r--r--src/multimedia/video/video.pri11
-rw-r--r--src/multimediawidgets/doc/qtmultimediawidgets.qdocconf44
-rw-r--r--src/multimediawidgets/multimediawidgets.pro2
-rw-r--r--src/multimediawidgets/qvideowidget.cpp2
-rw-r--r--src/plugins/android/jar/jar.pri3
-rw-r--r--src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCameraListener.java56
-rw-r--r--src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceHolderCallback.java67
-rw-r--r--src/plugins/android/src/common/common.pri3
-rw-r--r--src/plugins/android/src/common/qandroidmultimediautils.cpp586
-rw-r--r--src/plugins/android/src/common/qandroidmultimediautils.h4
-rw-r--r--src/plugins/android/src/common/qandroidvideooutput.cpp (renamed from src/plugins/android/src/common/qandroidvideorendercontrol.cpp)83
-rw-r--r--src/plugins/android/src/common/qandroidvideooutput.h64
-rw-r--r--src/plugins/android/src/common/qandroidvideorendercontrol.h118
-rw-r--r--src/plugins/android/src/mediacapture/mediacapture.pri6
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcamerasession.cpp143
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcamerasession.h20
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcameravideorenderercontrol.cpp275
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcameravideorenderercontrol.h66
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcaptureservice.cpp6
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcaptureservice.h4
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcapturesession.cpp27
-rw-r--r--src/plugins/android/src/mediaplayer/mediaplayer.pri6
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp4
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h2
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaplayervideorenderercontrol.cpp70
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaplayervideorenderercontrol.h62
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp10
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaservice.h3
-rw-r--r--src/plugins/android/src/qandroidmediaserviceplugin.cpp4
-rw-r--r--src/plugins/android/src/wrappers/jni/androidcamera.cpp168
-rw-r--r--src/plugins/android/src/wrappers/jni/androidcamera.h12
-rw-r--r--src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp37
-rw-r--r--src/plugins/android/src/wrappers/jni/androidmediarecorder.h5
-rw-r--r--src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp20
-rw-r--r--src/plugins/android/src/wrappers/jni/androidsurfacetexture.h4
-rw-r--r--src/plugins/android/src/wrappers/jni/androidsurfaceview.cpp204
-rw-r--r--src/plugins/android/src/wrappers/jni/androidsurfaceview.h101
-rw-r--r--src/plugins/android/src/wrappers/jni/jni.pri8
-rw-r--r--src/plugins/audiocapture/audiocapturesession.cpp51
-rw-r--r--src/plugins/audiocapture/audiocapturesession.h12
-rw-r--r--src/plugins/audiocapture/audiomediarecordercontrol.cpp15
-rw-r--r--src/plugins/avfoundation/camera/avfcameraservice.mm11
-rw-r--r--src/plugins/avfoundation/camera/avfcamerasession.h4
-rw-r--r--src/plugins/avfoundation/camera/avfcamerasession.mm6
-rw-r--r--src/plugins/avfoundation/camera/avfimagecapturecontrol.h20
-rw-r--r--src/plugins/avfoundation/camera/avfimagecapturecontrol.mm84
-rw-r--r--src/plugins/common/evr.pri8
-rw-r--r--src/plugins/common/evr/evrdefs.h127
-rw-r--r--src/plugins/common/evr/evrvideowindowcontrol.cpp (renamed from src/plugins/wmf/player/evr9videowindowcontrol.cpp)148
-rw-r--r--src/plugins/common/evr/evrvideowindowcontrol.h (renamed from src/plugins/wmf/player/evr9videowindowcontrol.h)23
-rw-r--r--src/plugins/directshow/camera/camera.pri6
-rw-r--r--src/plugins/directshow/camera/dscameraimageprocessingcontrol.cpp74
-rw-r--r--src/plugins/directshow/camera/dscameraimageprocessingcontrol.h63
-rw-r--r--src/plugins/directshow/camera/dscameraservice.cpp6
-rw-r--r--src/plugins/directshow/camera/dscameraservice.h2
-rw-r--r--src/plugins/directshow/camera/dscamerasession.cpp312
-rw-r--r--src/plugins/directshow/camera/dscamerasession.h45
-rw-r--r--src/plugins/directshow/directshow.pro5
-rw-r--r--src/plugins/directshow/player/directshowaudioendpointcontrol.cpp2
-rw-r--r--src/plugins/directshow/player/directshowevrvideowindowcontrol.cpp63
-rw-r--r--src/plugins/directshow/player/directshowevrvideowindowcontrol.h (renamed from config.tests/wmp/main.cpp)31
-rw-r--r--src/plugins/directshow/player/directshowglobal.h12
-rw-r--r--src/plugins/directshow/player/directshowioreader.cpp2
-rw-r--r--src/plugins/directshow/player/directshowiosource.cpp2
-rw-r--r--src/plugins/directshow/player/directshowmetadatacontrol.cpp27
-rw-r--r--src/plugins/directshow/player/directshowmetadatacontrol.h7
-rw-r--r--src/plugins/directshow/player/directshowplayercontrol.cpp126
-rw-r--r--src/plugins/directshow/player/directshowplayercontrol.h8
-rw-r--r--src/plugins/directshow/player/directshowplayerservice.cpp93
-rw-r--r--src/plugins/directshow/player/directshowplayerservice.h10
-rw-r--r--src/plugins/directshow/player/directshowvideorenderercontrol.cpp6
-rw-r--r--src/plugins/directshow/player/player.pri24
-rw-r--r--src/plugins/directshow/player/videosurfacefilter.cpp36
-rw-r--r--src/plugins/directshow/player/vmr9videowindowcontrol.cpp7
-rw-r--r--src/plugins/gstreamer/camerabin/camerabin.pro11
-rw-r--r--src/plugins/gstreamer/camerabin/camerabinimageprocessing.cpp166
-rw-r--r--src/plugins/gstreamer/camerabin/camerabinimageprocessing.h10
-rw-r--r--src/plugins/gstreamer/camerabin/camerabinsession.h2
-rw-r--r--src/plugins/gstreamer/camerabin/camerabinv4limageprocessing.cpp304
-rw-r--r--src/plugins/gstreamer/camerabin/camerabinv4limageprocessing.h84
-rw-r--r--src/plugins/gstreamer/mediacapture/qgstreamercaptureserviceplugin.cpp2
-rw-r--r--src/plugins/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp4
-rw-r--r--src/plugins/pulseaudio/qaudioinput_pulse.h2
-rw-r--r--src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp112
-rw-r--r--src/plugins/winrt/qwinrtabstractvideorenderercontrol.h28
-rw-r--r--src/plugins/winrt/qwinrtcameracontrol.cpp680
-rw-r--r--src/plugins/winrt/qwinrtcameracontrol.h16
-rw-r--r--src/plugins/winrt/qwinrtcamerafocuscontrol.cpp273
-rw-r--r--src/plugins/winrt/qwinrtcamerafocuscontrol.h77
-rw-r--r--src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp4
-rw-r--r--src/plugins/winrt/qwinrtcameraimagecapturecontrol.h3
-rw-r--r--src/plugins/winrt/qwinrtcameralockscontrol.cpp125
-rw-r--r--src/plugins/winrt/qwinrtcameralockscontrol.h66
-rw-r--r--src/plugins/winrt/qwinrtcameraservice.cpp52
-rw-r--r--src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp260
-rw-r--r--src/plugins/winrt/qwinrtcameravideorenderercontrol.h7
-rw-r--r--src/plugins/winrt/qwinrtimageencodercontrol.cpp20
-rw-r--r--src/plugins/winrt/qwinrtimageencodercontrol.h1
-rw-r--r--src/plugins/winrt/qwinrtmediaplayercontrol.cpp1
-rw-r--r--src/plugins/winrt/qwinrtvideoprobecontrol.cpp55
-rw-r--r--src/plugins/winrt/qwinrtvideoprobecontrol.h54
-rw-r--r--src/plugins/winrt/winrt.pro14
-rw-r--r--src/plugins/wmf/mftvideo.cpp225
-rw-r--r--src/plugins/wmf/mftvideo.h4
-rw-r--r--src/plugins/wmf/player/mfevrvideowindowcontrol.cpp85
-rw-r--r--src/plugins/wmf/player/mfevrvideowindowcontrol.h57
-rw-r--r--src/plugins/wmf/player/mfplayerservice.cpp22
-rw-r--r--src/plugins/wmf/player/mfplayerservice.h12
-rw-r--r--src/plugins/wmf/player/mfplayersession.cpp193
-rw-r--r--src/plugins/wmf/player/mfplayersession.h5
-rw-r--r--src/plugins/wmf/player/player.pri11
-rw-r--r--src/plugins/wmf/wmf.pro14
-rw-r--r--src/qtmultimediaquicktools/qdeclarativevideooutput_render_p.h19
-rw-r--r--src/qtmultimediaquicktools/qdeclarativevideooutput_window_p.h13
-rw-r--r--src/qtmultimediaquicktools/qsgvideonode_p.cpp4
-rw-r--r--src/qtmultimediaquicktools/qsgvideonode_rgb.cpp2
-rw-r--r--src/qtmultimediaquicktools/qsgvideonode_rgb_p.h (renamed from src/qtmultimediaquicktools/qsgvideonode_rgb.h)11
-rw-r--r--src/qtmultimediaquicktools/qsgvideonode_texture.cpp2
-rw-r--r--src/qtmultimediaquicktools/qsgvideonode_texture_p.h (renamed from src/qtmultimediaquicktools/qsgvideonode_texture.h)11
-rw-r--r--src/qtmultimediaquicktools/qsgvideonode_yuv.cpp2
-rw-r--r--src/qtmultimediaquicktools/qsgvideonode_yuv_p.h (renamed from src/qtmultimediaquicktools/qsgvideonode_yuv.h)11
-rw-r--r--src/qtmultimediaquicktools/qtmultimediaquicktools.pro25
-rw-r--r--src/src.pro3
-rw-r--r--tests/auto/integration/qaudiodecoderbackend/BLACKLIST41
-rw-r--r--tests/auto/integration/qaudiodecoderbackend/qaudiodecoderbackend.pro2
-rw-r--r--tests/auto/integration/qaudiodeviceinfo/BLACKLIST4
-rw-r--r--tests/auto/integration/qaudiodeviceinfo/qaudiodeviceinfo.pro2
-rw-r--r--[-rwxr-xr-x]tests/auto/integration/qaudioinput/tst_qaudioinput.cpp0
-rw-r--r--[-rwxr-xr-x]tests/auto/integration/qaudioinput/wavheader.cpp0
-rw-r--r--[-rwxr-xr-x]tests/auto/integration/qaudioinput/wavheader.h0
-rw-r--r--tests/auto/integration/qaudiooutput/BLACKLIST4
-rw-r--r--[-rwxr-xr-x]tests/auto/integration/qaudiooutput/tst_qaudiooutput.cpp0
-rw-r--r--[-rwxr-xr-x]tests/auto/integration/qaudiooutput/wavheader.cpp0
-rw-r--r--[-rwxr-xr-x]tests/auto/integration/qaudiooutput/wavheader.h0
-rw-r--r--tests/auto/integration/qmediaplayerbackend/BLACKLIST62
-rw-r--r--tests/auto/integration/qmediaplayerbackend/qmediaplayerbackend.pro2
-rw-r--r--tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp11
-rw-r--r--tests/auto/integration/qsoundeffect/BLACKLIST6
-rw-r--r--tests/auto/integration/qsoundeffect/qsoundeffect.pro4
-rw-r--r--tests/auto/unit/qaudiodecoder/tst_qaudiodecoder.cpp8
-rw-r--r--tests/auto/unit/qdeclarativeaudio/qdeclarativeaudio.pro4
-rw-r--r--tests/auto/unit/qdeclarativeaudio/tst_qdeclarativeaudio.cpp49
-rw-r--r--tests/auto/unit/qmediaplayer/tst_qmediaplayer.cpp41
-rw-r--r--tests/auto/unit/qmediaplaylist/tst_qmediaplaylist.cpp304
-rw-r--r--tests/auto/unit/qmultimedia_common/mockaudiorolecontrol.h72
-rw-r--r--tests/auto/unit/qmultimedia_common/mockmediaplayerservice.h13
-rw-r--r--tests/auto/unit/qmultimedia_common/mockmediaplaylistcontrol.h46
-rw-r--r--tests/auto/unit/qmultimedia_common/mockplayer.pri3
-rw-r--r--tests/auto/unit/qmultimedia_common/mockplaylistservice.h2
-rw-r--r--tests/auto/unit/qmultimedia_common/mockreadonlyplaylistprovider.h1
251 files changed, 9460 insertions, 2130 deletions
diff --git a/.qmake.conf b/.qmake.conf
index fd7c2fa95..a9b6a3290 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -1,4 +1,4 @@
load(qt_build_config)
CONFIG += qt_example_installs
-MODULE_VERSION = 5.5.1
+MODULE_VERSION = 5.6.0
diff --git a/config.tests/wmp/wmp.pro b/config.tests/wmp/wmp.pro
deleted file mode 100644
index 563de1453..000000000
--- a/config.tests/wmp/wmp.pro
+++ /dev/null
@@ -1,7 +0,0 @@
-CONFIG -= qt
-CONFIG += console
-
-SOURCES += main.cpp
-
-LIBS += -lstrmiids -lole32 -lOleaut32
-!wince*:LIBS += -luser32 -lgdi32
diff --git a/examples/multimedia/audiooutput/doc/images/audiooutput-example.png b/examples/multimedia/audiooutput/doc/images/audiooutput-example.png
index 5588fbb57..5588fbb57 100755..100644
--- a/examples/multimedia/audiooutput/doc/images/audiooutput-example.png
+++ b/examples/multimedia/audiooutput/doc/images/audiooutput-example.png
Binary files differ
diff --git a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectBillboard.qml b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectBillboard.qml
index 021b8d778..c4e1b204e 100644
--- a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectBillboard.qml
+++ b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectBillboard.qml
@@ -39,10 +39,16 @@ Effect {
name: "Grid Spacing"
value: 0.5
}
+ onDataChanged: updateGrid()
+ }
+
+ function updateGrid()
+ {
+ grid = parameters.get(0).value * 10;
}
// Transform slider values, and bind result to shader uniforms
- property real grid: parameters.get(0).value * 10
+ property real grid: 5.0
property real step_x: 0.0015625
property real step_y: targetHeight ? (step_x * targetWidth / targetHeight) : 0.0
diff --git a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectBlackAndWhite.qml b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectBlackAndWhite.qml
index 8cfe5a78a..f1e53e005 100644
--- a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectBlackAndWhite.qml
+++ b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectBlackAndWhite.qml
@@ -39,10 +39,15 @@ Effect {
name: "Threshold"
value: 0.5
}
+ onDataChanged: updateThreshold()
}
+ function updateThreshold()
+ {
+ threshold = parameters.get(0).value;
+ }
// Transform slider values, and bind result to shader uniforms
- property real threshold: parameters.get(0).value
+ property real threshold: 0.5
fragmentShaderFilename: "blackandwhite.fsh"
}
diff --git a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectGaussianBlur.qml b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectGaussianBlur.qml
index 3ccf1c678..7941eac63 100644
--- a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectGaussianBlur.qml
+++ b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectGaussianBlur.qml
@@ -44,17 +44,37 @@ Item {
name: "Radius"
value: 0.5
}
+ onDataChanged: updateBlurSize()
+ }
+
+ function updateBlurSize()
+ {
+ if ((targetHeight > 0) && (targetWidth > 0))
+ {
+ verticalBlurSize = 4.0 * parameters.get(0).value / targetHeight;
+ horizontalBlurSize = 4.0 * parameters.get(0).value / targetWidth;
+ }
}
property alias targetWidth: verticalShader.targetWidth
property alias targetHeight: verticalShader.targetHeight
property alias source: verticalShader.source
+ property alias horizontalBlurSize: horizontalShader.blurSize
+ property alias verticalBlurSize: verticalShader.blurSize
+
Effect {
id: verticalShader
anchors.fill: parent
dividerValue: parent.dividerValue
- property real blurSize: 4.0 * parent.parameters.get(0).value / targetHeight
+ property real blurSize: 0.0
+
+ onTargetHeightChanged: {
+ updateBlurSize()
+ }
+ onTargetWidthChanged: {
+ updateBlurSize()
+ }
fragmentShaderFilename: "gaussianblur_v.fsh"
}
@@ -62,7 +82,7 @@ Item {
id: horizontalShader
anchors.fill: parent
dividerValue: parent.dividerValue
- property real blurSize: 4.0 * parent.parameters.get(0).value / parent.targetWidth
+ property real blurSize: 0.0
fragmentShaderFilename: "gaussianblur_h.fsh"
source: horizontalShaderSource
diff --git a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectIsolate.qml b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectIsolate.qml
index 24a281db6..5af8b6fd6 100644
--- a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectIsolate.qml
+++ b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectIsolate.qml
@@ -43,11 +43,18 @@ Effect {
name: "Width"
value: 0.5
}
+ onDataChanged: updateParameters()
+ }
+
+ function updateParameters()
+ {
+ targetHue = parameters.get(0).value * 360
+ windowWidth = parameters.get(1).value * 60
}
// Transform slider values, and bind result to shader uniforms
- property real targetHue: parameters.get(0).value * 360
- property real windowWidth: parameters.get(1).value * 60
+ property real targetHue: 0.5 * 360
+ property real windowWidth: 0.5 * 60
fragmentShaderFilename: "isolate.fsh"
}
diff --git a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectMagnify.qml b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectMagnify.qml
index 5e8c9e0ef..76535ea7e 100644
--- a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectMagnify.qml
+++ b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectMagnify.qml
@@ -46,6 +46,13 @@ Effect {
name: "Diffraction"
value: 0.5
}
+ onDataChanged: updateParameters()
+ }
+
+ function updateParameters()
+ {
+ radius = parameters.get(0).value * 100;
+ diffractionIndex = parameters.get(1).value;
}
property real posX: -1
@@ -59,8 +66,8 @@ Effect {
}
// Transform slider values, and bind result to shader uniforms
- property real radius: parameters.get(0).value * 100
- property real diffractionIndex: parameters.get(1).value
+ property real radius: 0.5 * 100
+ property real diffractionIndex: 0.5
onTargetWidthChanged: {
if (posX == -1)
diff --git a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectPageCurl.qml b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectPageCurl.qml
index 4ccad8b58..4980b1ddf 100644
--- a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectPageCurl.qml
+++ b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectPageCurl.qml
@@ -40,10 +40,16 @@ Effect {
name: "Extent"
value: 0.5
}
+ onDataChanged: updateParameters()
+ }
+
+ function updateParameters()
+ {
+ curlExtent = 1.0 - parameters.get(0).value;
}
// Transform slider values, and bind result to shader uniforms
- property real curlExtent: 1.0 - parameters.get(0).value
+ property real curlExtent: 0.5
fragmentShaderFilename: "pagecurl.fsh"
}
diff --git a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectPixelate.qml b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectPixelate.qml
index cea15c285..40453f93f 100644
--- a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectPixelate.qml
+++ b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectPixelate.qml
@@ -39,10 +39,16 @@ Effect {
name: "Granularity"
value: 0.5
}
+ onDataChanged: updateParameters()
+ }
+
+ function updateParameters()
+ {
+ granularity = parameters.get(0).value * 20.0;
}
// Transform slider values, and bind result to shader uniforms
- property real granularity: parameters.get(0).value * 20
+ property real granularity: 0.5 * 20
fragmentShaderFilename: "pixelate.fsh"
}
diff --git a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectPosterize.qml b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectPosterize.qml
index bba48dcd8..c8b1893d1 100644
--- a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectPosterize.qml
+++ b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectPosterize.qml
@@ -39,10 +39,16 @@ Effect {
name: "Gamma"
value: 0.5
}
+ onDataChanged: updateParameters()
+ }
+
+ function updateParameters()
+ {
+ gamma = parameters.get(0).value;
}
// Transform slider values, and bind result to shader uniforms
- property real gamma: parameters.get(0).value
+ property real gamma: 0.5
property real numColors: 8.0
diff --git a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectRipple.qml b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectRipple.qml
index e47eadfb4..67eae30ea 100644
--- a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectRipple.qml
+++ b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectRipple.qml
@@ -44,11 +44,18 @@ Effect {
name: "Frequency"
value: 0.5
}
+ onDataChanged: updateParameters()
+ }
+
+ function updateParameters()
+ {
+ amplitude = parameters.get(0).value * 0.03;
+ n = parameters.get(1).value * 7;
}
// Transform slider values, and bind result to shader uniforms
- property real amplitude: parameters.get(0).value * 0.03
- property real n: parameters.get(1).value * 7
+ property real amplitude: 0.5 * 0.03
+ property real n: 0.5 * 7
property real pixDens: Screen.pixelDensity
property real time: 0
diff --git a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectSharpen.qml b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectSharpen.qml
index 9b80dd4b2..094270c01 100644
--- a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectSharpen.qml
+++ b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectSharpen.qml
@@ -39,10 +39,16 @@ Effect {
name: "Sharpness"
value: 0.5
}
+ onDataChanged: updateParameters()
+ }
+
+ function updateParameters()
+ {
+ amount = parameters.get(0).value * 18;
}
// Transform slider values, and bind result to shader uniforms
- property real amount: parameters.get(0).value * 18
+ property real amount: 0.5 * 18
fragmentShaderFilename: "sharpen.fsh"
}
diff --git a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectShockwave.qml b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectShockwave.qml
index 0e0520c29..a20f2445e 100644
--- a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectShockwave.qml
+++ b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectShockwave.qml
@@ -40,11 +40,18 @@ Effect {
name: "Amplitude"
value: 0.5
}
+ onDataChanged: updateParameters()
+ }
+
+ function updateParameters()
+ {
+ granularity = parameters.get(0).value * 20;
+ weight = parameters.get(0).value;
}
// Transform slider values, and bind result to shader uniforms
- property real granularity: parameters.get(0).value * 20
- property real weight: parameters.get(0).value
+ property real granularity: 0.5 * 20
+ property real weight: 0.5
property real centerX
property real centerY
diff --git a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectSobelEdgeDetection1.qml b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectSobelEdgeDetection1.qml
index 8da5c26be..936571c89 100644
--- a/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectSobelEdgeDetection1.qml
+++ b/examples/multimedia/video/qmlvideofx/qml/qmlvideofx/EffectSobelEdgeDetection1.qml
@@ -39,10 +39,16 @@ Effect {
name: "Threshold"
value: 0.5
}
+ onDataChanged: updateMixLevel()
+ }
+
+ function updateMixLevel()
+ {
+ mixLevel = parameters.get(0).value;
}
// Transform slider values, and bind result to shader uniforms
- property real mixLevel: parameters.get(0).value
+ property real mixLevel: 0.5
property real targetSize: 250 - (200 * mixLevel) // TODO: fix ...
property real resS: targetSize
property real resT: targetSize
diff --git a/qtmultimedia.pro b/qtmultimedia.pro
index 1225ffb61..98bb3152f 100644
--- a/qtmultimedia.pro
+++ b/qtmultimedia.pro
@@ -6,10 +6,9 @@ win32 {
qtCompileTest(directshow) {
qtCompileTest(wshellitem)
}
+ qtCompileTest(evr)
qtCompileTest(wmsdk)
- qtCompileTest(wmp)
contains(QT_CONFIG, wmf-backend): qtCompileTest(wmf)
- qtCompileTest(evr)
} else:mac {
qtCompileTest(avfoundation)
} else:qnx {
diff --git a/src/imports/audioengine/audioengine.cpp b/src/imports/audioengine/audioengine.cpp
index 612524447..aa2d195c5 100644
--- a/src/imports/audioengine/audioengine.cpp
+++ b/src/imports/audioengine/audioengine.cpp
@@ -68,6 +68,10 @@ public:
qmlRegisterType<QDeclarativeAttenuationModelLinear>(uri, 1, 0, "AttenuationModelLinear");
qmlRegisterType<QDeclarativeAttenuationModelInverse>(uri, 1, 0, "AttenuationModelInverse");
+
+ // Dynamically adding audio engine related objects is only supported through revision 1
+ qmlRegisterType<QDeclarativeAudioEngine, 1>(uri, 1, 1, "AudioEngine");
+ qmlRegisterType<QDeclarativeSound, 1>(uri, 1, 1, "Sound");
}
};
diff --git a/src/imports/audioengine/plugins.qmltypes b/src/imports/audioengine/plugins.qmltypes
index 8c6267bda..22fad073a 100644
--- a/src/imports/audioengine/plugins.qmltypes
+++ b/src/imports/audioengine/plugins.qmltypes
@@ -1,11 +1,13 @@
-import QtQuick.tooling 1.1
+import QtQuick.tooling 1.2
// This file describes the plugin-supplied types contained in the library.
// It is used for QML tooling purposes only.
//
-// This file was auto-generated with the command 'qmlplugindump -notrelocatable QtAudioEngine 1.0'.
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable QtAudioEngine 1.0'
Module {
+ dependencies: []
Component {
name: "QDeclarativeAttenuationModel"
prototype: "QObject"
@@ -50,8 +52,11 @@ Module {
name: "QDeclarativeAudioEngine"
defaultProperty: "bank"
prototype: "QObject"
- exports: ["QtAudioEngine/AudioEngine 1.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtAudioEngine/AudioEngine 1.0",
+ "QtAudioEngine/AudioEngine 1.1"
+ ]
+ exportMetaObjectRevisions: [0, 1]
Property { name: "bank"; type: "QObject"; isList: true; isReadonly: true }
Property { name: "categories"; type: "QObject"; isReadonly: true; isPointer: true }
Property { name: "samples"; type: "QObject"; isReadonly: true; isPointer: true }
@@ -70,6 +75,26 @@ Module {
Signal { name: "liveInstanceCountChanged" }
Signal { name: "isLoadingChanged" }
Signal { name: "finishedLoading" }
+ Method {
+ name: "addAudioSample"
+ revision: 1
+ Parameter { type: "QDeclarativeAudioSample"; isPointer: true }
+ }
+ Method {
+ name: "addSound"
+ revision: 1
+ Parameter { type: "QDeclarativeSound"; isPointer: true }
+ }
+ Method {
+ name: "addAudioCategory"
+ revision: 1
+ Parameter { type: "QDeclarativeAudioCategory"; isPointer: true }
+ }
+ Method {
+ name: "addAttenuationModel"
+ revision: 1
+ Parameter { type: "QDeclarativeAttenuationModel"; isPointer: true }
+ }
}
Component {
name: "QDeclarativeAudioListener"
@@ -111,8 +136,8 @@ Module {
name: "QDeclarativeSound"
defaultProperty: "playVariationlist"
prototype: "QObject"
- exports: ["QtAudioEngine/Sound 1.0"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtAudioEngine/Sound 1.0", "QtAudioEngine/Sound 1.1"]
+ exportMetaObjectRevisions: [0, 1]
Enum {
name: "PlayType"
values: {
@@ -196,6 +221,11 @@ Module {
Parameter { name: "pitch"; type: "double" }
}
Method { name: "newInstance"; type: "QDeclarativeSoundInstance*" }
+ Method {
+ name: "addPlayVariation"
+ revision: 1
+ Parameter { type: "QDeclarativePlayVariation"; isPointer: true }
+ }
}
Component {
name: "QDeclarativeSoundCone"
diff --git a/src/imports/audioengine/qaudioengine_openal_p.h b/src/imports/audioengine/qaudioengine_openal_p.h
index f534ab8c4..c2cecff40 100644
--- a/src/imports/audioengine/qaudioengine_openal_p.h
+++ b/src/imports/audioengine/qaudioengine_openal_p.h
@@ -34,6 +34,17 @@
#ifndef QAUDIOENGINE_OPENAL_P_H
#define QAUDIOENGINE_OPENAL_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 <QList>
#include <QMap>
diff --git a/src/imports/audioengine/qaudioengine_p.h b/src/imports/audioengine/qaudioengine_p.h
index d62e4de48..dccce09ed 100644
--- a/src/imports/audioengine/qaudioengine_p.h
+++ b/src/imports/audioengine/qaudioengine_p.h
@@ -34,6 +34,17 @@
#ifndef QAUDIOENGINE_P_H
#define QAUDIOENGINE_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>
#include <QtCore/QMap>
#include <QtCore/QUrl>
diff --git a/src/imports/audioengine/qdeclarative_attenuationmodel_p.cpp b/src/imports/audioengine/qdeclarative_attenuationmodel_p.cpp
index 0814e9d62..7ecdb41ae 100644
--- a/src/imports/audioengine/qdeclarative_attenuationmodel_p.cpp
+++ b/src/imports/audioengine/qdeclarative_attenuationmodel_p.cpp
@@ -32,6 +32,7 @@
****************************************************************************/
#include "qdeclarative_attenuationmodel_p.h"
+#include "qdeclarative_audioengine_p.h"
#include "qdebug.h"
#define DEBUG_AUDIOENGINE
@@ -40,7 +41,7 @@ QT_USE_NAMESPACE
QDeclarativeAttenuationModel::QDeclarativeAttenuationModel(QObject *parent)
: QObject(parent)
- , m_complete(false)
+ , m_engine(0)
{
}
@@ -48,22 +49,9 @@ QDeclarativeAttenuationModel::~QDeclarativeAttenuationModel()
{
}
-void QDeclarativeAttenuationModel::classBegin()
+void QDeclarativeAttenuationModel::setEngine(QDeclarativeAudioEngine *engine)
{
- if (!parent() || !parent()->inherits("QDeclarativeAudioEngine")) {
- qWarning("AttenuationModel must be defined inside AudioEngine!");
- //TODO: COMPILE_EXCEPTION ?
- return;
- }
-}
-
-void QDeclarativeAttenuationModel::componentComplete()
-{
- if (m_name.isEmpty()) {
- qWarning("AttenuationModel must have a name!");
- return;
- }
- m_complete = true;
+ m_engine = engine;
}
QString QDeclarativeAttenuationModel::name() const
@@ -73,7 +61,7 @@ QString QDeclarativeAttenuationModel::name() const
void QDeclarativeAttenuationModel::setName(const QString& name)
{
- if (m_complete) {
+ if (m_engine) {
qWarning("AttenuationModel: you can not change name after initialization.");
return;
}
@@ -93,7 +81,9 @@ void QDeclarativeAttenuationModel::setName(const QString& name)
This type is part of the \b{QtAudioEngine 1.0} module.
- AttenuationModelLinear must be defined inside \l AudioEngine.
+ AttenuationModelLinear must be defined inside \l AudioEngine or be added to it using
+ \l{QtAudioEngine::AudioEngine::addAttenuationModel()}{AudioEngine.addAttenuationModel()}
+ if AttenuationModelLinear is created dynamically.
\qml
import QtQuick 2.0
@@ -144,13 +134,13 @@ QDeclarativeAttenuationModelLinear::QDeclarativeAttenuationModelLinear(QObject *
{
}
-void QDeclarativeAttenuationModelLinear::componentComplete()
+void QDeclarativeAttenuationModelLinear::setEngine(QDeclarativeAudioEngine *engine)
{
if (m_start > m_end) {
qSwap(m_start, m_end);
qWarning() << "AttenuationModelLinear[" << m_name << "]: start must be less or equal than end.";
}
- QDeclarativeAttenuationModel::componentComplete();
+ QDeclarativeAttenuationModel::setEngine(engine);
}
/*!
@@ -167,7 +157,7 @@ qreal QDeclarativeAttenuationModelLinear::startDistance() const
void QDeclarativeAttenuationModelLinear::setStartDistance(qreal startDist)
{
- if (m_complete) {
+ if (m_engine) {
qWarning() << "AttenuationModelLinear[" << m_name << "]: you can not change properties after initialization.";
return;
}
@@ -192,7 +182,7 @@ qreal QDeclarativeAttenuationModelLinear::endDistance() const
void QDeclarativeAttenuationModelLinear::setEndDistance(qreal endDist)
{
- if (m_complete) {
+ if (m_engine) {
qWarning() << "AttenuationModelLinear[" << m_name << "]: you can not change properties after initialization.";
return;
}
@@ -226,7 +216,9 @@ qreal QDeclarativeAttenuationModelLinear::calculateGain(const QVector3D &listene
This type is part of the \b{QtAudioEngine 1.0} module.
- AttenuationModelInverse must be defined inside AudioEngine.
+ AttenuationModelInverse must be defined inside \l AudioEngine or be added to it using
+ \l{QtAudioEngine::AudioEngine::addAttenuationModel()}{AudioEngine.addAttenuationModel()}
+ if AttenuationModelInverse is created dynamically.
\qml
import QtQuick 2.0
@@ -309,13 +301,13 @@ QDeclarativeAttenuationModelInverse::QDeclarativeAttenuationModelInverse(QObject
{
}
-void QDeclarativeAttenuationModelInverse::componentComplete()
+void QDeclarativeAttenuationModelInverse::setEngine(QDeclarativeAudioEngine *engine)
{
if (m_ref > m_max) {
qSwap(m_ref, m_max);
qWarning() << "AttenuationModelInverse[" << m_name << "]: referenceDistance must be less or equal than maxDistance.";
}
- QDeclarativeAttenuationModel::componentComplete();
+ QDeclarativeAttenuationModel::setEngine(engine);
}
qreal QDeclarativeAttenuationModelInverse::referenceDistance() const
@@ -325,7 +317,7 @@ qreal QDeclarativeAttenuationModelInverse::referenceDistance() const
void QDeclarativeAttenuationModelInverse::setReferenceDistance(qreal referenceDistance)
{
- if (m_complete) {
+ if (m_engine) {
qWarning() << "AttenuationModelInverse[" << m_name << "]: you can not change properties after initialization.";
return;
}
@@ -343,7 +335,7 @@ qreal QDeclarativeAttenuationModelInverse::maxDistance() const
void QDeclarativeAttenuationModelInverse::setMaxDistance(qreal maxDistance)
{
- if (m_complete) {
+ if (m_engine) {
qWarning() << "AttenuationModelInverse[" << m_name << "]: you can not change properties after initialization.";
return;
}
@@ -361,7 +353,7 @@ qreal QDeclarativeAttenuationModelInverse::rolloffFactor() const
void QDeclarativeAttenuationModelInverse::setRolloffFactor(qreal rolloffFactor)
{
- if (m_complete) {
+ if (m_engine) {
qWarning() << "AttenuationModelInverse[" << m_name << "]: you can not change properties after initialization.";
return;
}
diff --git a/src/imports/audioengine/qdeclarative_attenuationmodel_p.h b/src/imports/audioengine/qdeclarative_attenuationmodel_p.h
index dc8bff36f..d4d12df04 100644
--- a/src/imports/audioengine/qdeclarative_attenuationmodel_p.h
+++ b/src/imports/audioengine/qdeclarative_attenuationmodel_p.h
@@ -34,33 +34,43 @@
#ifndef QDECLARATIVEATTENUATIONMODEL_P_H
#define QDECLARATIVEATTENUATIONMODEL_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 <QtQml/qqml.h>
-#include <QtQml/qqmlcomponent.h>
#include <QVector3D>
QT_BEGIN_NAMESPACE
-class QDeclarativeAttenuationModel : public QObject, public QQmlParserStatus
+class QDeclarativeAudioEngine;
+
+class QDeclarativeAttenuationModel : public QObject
{
Q_OBJECT
- Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QString name READ name WRITE setName)
public:
QDeclarativeAttenuationModel(QObject *parent = 0);
~QDeclarativeAttenuationModel();
- void classBegin();
- void componentComplete();
-
QString name() const;
void setName(const QString& name);
virtual qreal calculateGain(const QVector3D &listenerPosition, const QVector3D &sourcePosition) const = 0;
+ virtual void setEngine(QDeclarativeAudioEngine *engine);
+
protected:
- bool m_complete;
QString m_name;
+ QDeclarativeAudioEngine *m_engine;
private:
Q_DISABLE_COPY(QDeclarativeAttenuationModel);
@@ -75,8 +85,6 @@ class QDeclarativeAttenuationModelLinear : public QDeclarativeAttenuationModel
public:
QDeclarativeAttenuationModelLinear(QObject *parent = 0);
- void componentComplete();
-
qreal startDistance() const;
void setStartDistance(qreal startDist);
@@ -85,6 +93,8 @@ public:
qreal calculateGain(const QVector3D &listenerPosition, const QVector3D &sourcePosition) const;
+ void setEngine(QDeclarativeAudioEngine *engine);
+
private:
Q_DISABLE_COPY(QDeclarativeAttenuationModelLinear);
qreal m_start;
@@ -101,8 +111,6 @@ class QDeclarativeAttenuationModelInverse : public QDeclarativeAttenuationModel
public:
QDeclarativeAttenuationModelInverse(QObject *parent = 0);
- void componentComplete();
-
qreal referenceDistance() const;
void setReferenceDistance(qreal referenceDistance);
@@ -114,6 +122,8 @@ public:
qreal calculateGain(const QVector3D &listenerPosition, const QVector3D &sourcePosition) const;
+ void setEngine(QDeclarativeAudioEngine *engine);
+
private:
Q_DISABLE_COPY(QDeclarativeAttenuationModelInverse);
qreal m_ref;
diff --git a/src/imports/audioengine/qdeclarative_audiocategory_p.cpp b/src/imports/audioengine/qdeclarative_audiocategory_p.cpp
index df1a3cec9..847941ca9 100644
--- a/src/imports/audioengine/qdeclarative_audiocategory_p.cpp
+++ b/src/imports/audioengine/qdeclarative_audiocategory_p.cpp
@@ -51,7 +51,9 @@ QT_USE_NAMESPACE
This type is part of the \b{QtAudioEngine 1.0} module.
An instance of AudioCategory can be accessed through \l {QtAudioEngine::AudioEngine::categories}
- {AudioEngine.categories} with its unique name and must be defined inside AudioEngine.
+ {AudioEngine.categories} with its unique name and must be defined inside AudioEngine or be added
+ to it using \l{QtAudioEngine::AudioEngine::addAudioCategory()}{AudioEngine.addAudioCategory()} if
+ AudioCategory is created dynamically.
\qml
import QtQuick 2.0
@@ -103,8 +105,8 @@ QT_USE_NAMESPACE
*/
QDeclarativeAudioCategory::QDeclarativeAudioCategory(QObject *parent)
: QObject(parent)
- , m_complete(false)
, m_volume(1)
+ , m_engine(0)
{
}
@@ -112,21 +114,9 @@ QDeclarativeAudioCategory::~QDeclarativeAudioCategory()
{
}
-void QDeclarativeAudioCategory::classBegin()
+void QDeclarativeAudioCategory::setEngine(QDeclarativeAudioEngine *engine)
{
- if (!parent() || !parent()->inherits("QDeclarativeAudioEngine")) {
- qWarning("AudioCategory must be defined inside AudioEngine!");
- return;
- }
-}
-
-void QDeclarativeAudioCategory::componentComplete()
-{
- if (m_name.isEmpty()) {
- qWarning("AudioCategory must have a name!");
- return;
- }
- m_complete = true;
+ m_engine = engine;
}
/*!
@@ -159,7 +149,7 @@ void QDeclarativeAudioCategory::setVolume(qreal volume)
*/
void QDeclarativeAudioCategory::setName(const QString& name)
{
- if (m_complete) {
+ if (m_engine) {
qWarning("AudioCategory: you can not change name after initialization.");
return;
}
diff --git a/src/imports/audioengine/qdeclarative_audiocategory_p.h b/src/imports/audioengine/qdeclarative_audiocategory_p.h
index a797b2698..cdcd7351c 100644
--- a/src/imports/audioengine/qdeclarative_audiocategory_p.h
+++ b/src/imports/audioengine/qdeclarative_audiocategory_p.h
@@ -34,15 +34,26 @@
#ifndef QDECLARATIVEAUDIOCATEGORY_P_H
#define QDECLARATIVEAUDIOCATEGORY_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 <QtQml/qqml.h>
-#include <QtQml/qqmlcomponent.h>
QT_BEGIN_NAMESPACE
-class QDeclarativeAudioCategory : public QObject, public QQmlParserStatus
+class QDeclarativeAudioEngine;
+
+class QDeclarativeAudioCategory : public QObject
{
Q_OBJECT
- Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged)
Q_PROPERTY(QString name READ name WRITE setName)
@@ -50,15 +61,14 @@ public:
QDeclarativeAudioCategory(QObject *parent = 0);
~QDeclarativeAudioCategory();
- void classBegin();
- void componentComplete();
-
qreal volume() const;
void setVolume(qreal volume);
QString name() const;
void setName(const QString& name);
+ void setEngine(QDeclarativeAudioEngine *engine);
+
Q_SIGNALS:
void volumeChanged(qreal newVolume);
void stopped();
@@ -72,9 +82,9 @@ public Q_SLOTS:
private:
Q_DISABLE_COPY(QDeclarativeAudioCategory);
- bool m_complete;
QString m_name;
qreal m_volume;
+ QDeclarativeAudioEngine *m_engine;
};
QT_END_NAMESPACE
diff --git a/src/imports/audioengine/qdeclarative_audioengine_p.cpp b/src/imports/audioengine/qdeclarative_audioengine_p.cpp
index cf0a22644..dd80c698d 100644
--- a/src/imports/audioengine/qdeclarative_audioengine_p.cpp
+++ b/src/imports/audioengine/qdeclarative_audioengine_p.cpp
@@ -221,6 +221,222 @@ void QDeclarativeAudioEngine::releaseSoundInstance(QSoundInstance* instance)
emit liveInstanceCountChanged();
}
+void QDeclarativeAudioEngine::initAudioSample(QDeclarativeAudioSample *sample)
+{
+ sample->init();
+}
+
+void QDeclarativeAudioEngine::initSound(QDeclarativeSound *sound)
+{
+ QDeclarativeAudioCategory *category = m_defaultCategory;
+ if (m_categories.contains(sound->category())) {
+ category = qobject_cast<QDeclarativeAudioCategory*>(
+ qvariant_cast<QObject*>(m_categories[sound->category()]));
+ }
+ sound->setCategoryObject(category);
+
+ QDeclarativeAttenuationModel *attenuationModel = 0;
+ if (sound->attenuationModel().isEmpty()) {
+ if (m_defaultAttenuationModel)
+ attenuationModel = m_defaultAttenuationModel;
+ } else if (m_attenuationModels.contains(sound->attenuationModel())){
+ attenuationModel = m_attenuationModels[sound->attenuationModel()];
+ } else {
+ qWarning() << "Sound[" << sound->name() << "] contains invalid attenuationModel["
+ << sound->attenuationModel() << "]";
+ }
+ sound->setAttenuationModelObject(attenuationModel);
+
+ foreach (QDeclarativePlayVariation *playVariation, sound->playlist()) {
+ if (m_samples.contains(playVariation->sample())) {
+ playVariation->setSampleObject(
+ qobject_cast<QDeclarativeAudioSample*>(
+ qvariant_cast<QObject*>(m_samples[playVariation->sample()])));
+ } else {
+ qWarning() << "Sound[" << sound->name() << "] contains invalid sample["
+ << playVariation->sample() << "] for its playVarations";
+ }
+ }
+}
+
+/*!
+ \qmlmethod QtAudioEngine::AudioEngine::addAudioSample(AudioSample sample)
+
+ Adds the given \a sample to the engine.
+ This can be used when the AudioSample is created dynamically:
+
+ \qml
+ import QtAudioEngine 1.1
+
+ AudioEngine {
+ id: engine
+
+ Component.onCompleted: {
+ var sample = Qt.createQmlObject('import QtAudioEngine 1.1; AudioSample {}', engine);
+ sample.name = "example";
+ sample.source = "example.wav";
+ engine.addAudioSample(sample);
+ }
+ }
+ \endqml
+*/
+void QDeclarativeAudioEngine::addAudioSample(QDeclarativeAudioSample *sample)
+{
+#ifdef DEBUG_AUDIOENGINE
+ qDebug() << "add QDeclarativeAudioSample[" << sample->name() << "]";
+#endif
+ if (sample->name().isEmpty()) {
+ qWarning("AudioSample must have a name!");
+ return;
+ }
+
+ if (m_samples.contains(sample->name())) {
+ qWarning() << "Failed to add AudioSample[" << sample->name() << "], already exists!";
+ return;
+ }
+ m_samples.insert(sample->name(), QVariant::fromValue(sample));
+ sample->setEngine(this);
+
+ if (m_complete) { initAudioSample(sample); }
+}
+
+/*!
+ \qmlmethod QtAudioEngine::AudioEngine::addSound(Sound sound)
+
+ Adds the given \a sound to the engine.
+ This can be used when the Sound is created dynamically:
+
+ \qml
+ import QtAudioEngine 1.1
+
+ AudioEngine {
+ id: engine
+
+ Component.onCompleted: {
+ var sound = Qt.createQmlObject('import QtAudioEngine 1.1; Sound {}', engine);
+ sound.name = "example";
+ engine.addSound(sound);
+ }
+ }
+ \endqml
+*/
+void QDeclarativeAudioEngine::addSound(QDeclarativeSound *sound)
+{
+#ifdef DEBUG_AUDIOENGINE
+ qDebug() << "add QDeclarativeSound[" << sound->name() << "]";
+#endif
+ if (sound->name().isEmpty()) {
+ qWarning("Sound must have a name!");
+ return;
+ }
+
+ if (m_sounds.contains(sound->name())) {
+ qWarning() << "Failed to add Sound[" << sound->name() << "], already exists!";
+ return;
+ }
+ m_sounds.insert(sound->name(), QVariant::fromValue(sound));
+ sound->setEngine(this);
+
+ if (m_complete) { initSound(sound); }
+
+}
+
+/*!
+ \qmlmethod QtAudioEngine::AudioEngine::addAudioCategory(AudioCategory category)
+
+ Adds the given \a category to the engine.
+ This can be used when the AudioCategory is created dynamically:
+
+ \qml
+ import QtAudioEngine 1.1
+
+ AudioEngine {
+ id: engine
+
+ Component.onCompleted: {
+ var category = Qt.createQmlObject('import QtAudioEngine 1.1; AudioCategory {}', engine);
+ category.name = "sample";
+ category.volume = 0.9;
+ engine.addAudioCategory(category);
+ }
+ }
+ \endqml
+*/
+void QDeclarativeAudioEngine::addAudioCategory(QDeclarativeAudioCategory *category)
+{
+#ifdef DEBUG_AUDIOENGINE
+ qDebug() << "add QDeclarativeAudioCategory[" << category->name() << "]";
+#endif
+ if (category->name().isEmpty()) {
+ qWarning("AudioCategory must have a name!");
+ return;
+ }
+
+ if (m_categories.contains(category->name())) {
+ qWarning() << "Failed to add AudioCategory[" << category->name() << "], already exists!";
+ return;
+ }
+ m_categories.insert(category->name(), QVariant::fromValue(category));
+ if (category->name() == QLatin1String("default")) {
+ if (!m_complete) {
+ m_defaultCategory = category;
+ } else {
+ qWarning() << "Can not change default category after initializing engine";
+ }
+ }
+
+ category->setEngine(this);
+}
+
+/*!
+ \qmlmethod QtAudioEngine::AudioEngine::addAttenuationModel(AttenuationModel attenuationModel)
+
+ Adds the given \a attenuationModel to the engine.
+ This can be used when the AttenuationModelLinear / AttenuationModelInverse is created dynamically:
+
+ \qml
+ import QtAudioEngine 1.1
+
+ AudioEngine {
+ id: engine
+
+ Component.onCompleted: {
+ var attenuationModel = Qt.createQmlObject('import QtAudioEngine 1.1; AttenuationModelLinear {}', engine);
+ attenuationModel.name ="linear"
+ attenuationModel.start = 20
+ attenuationModel.end = 180
+ engine.addAttenuationModel(attenuationModel);
+ }
+ }
+ \endqml
+*/
+void QDeclarativeAudioEngine::addAttenuationModel(QDeclarativeAttenuationModel *attenModel)
+{
+#ifdef DEBUG_AUDIOENGINE
+ qDebug() << "add AttenuationModel[" << attenModel->name() << "]";
+#endif
+ if (attenModel->name().isEmpty()) {
+ qWarning("AttenuationModel must have a name!");
+ return;
+ }
+
+ if (m_attenuationModels.contains(attenModel->name())) {
+ qWarning() << "Failed to add AttenuationModel[" << attenModel->name() << "], already exists!";
+ return;
+ }
+ m_attenuationModels.insert(attenModel->name(), attenModel);
+
+ if (attenModel->name() == QLatin1String("default")) {
+ if (!m_complete) {
+ m_defaultAttenuationModel = attenModel;
+ } else {
+ qWarning() << "Can not change default attenuation model after initializing engine";
+ }
+ }
+
+ attenModel->setEngine(this);
+}
+
void QDeclarativeAudioEngine::componentComplete()
{
#ifdef DEBUG_AUDIOENGINE
@@ -231,10 +447,9 @@ void QDeclarativeAudioEngine::componentComplete()
qDebug() << "creating default category";
#endif
m_defaultCategory = new QDeclarativeAudioCategory(this);
- m_defaultCategory->classBegin();
m_defaultCategory->setName(QString::fromLatin1("default"));
m_defaultCategory->setVolume(1);
- m_defaultCategory->componentComplete();
+ m_defaultCategory->setEngine(this);
}
#ifdef DEBUG_AUDIOENGINE
qDebug() << "init samples" << m_samples.keys().count();
@@ -246,7 +461,8 @@ void QDeclarativeAudioEngine::componentComplete()
qWarning() << "accessing invalid sample[" << key << "]";
continue;
}
- sample->init();
+
+ initAudioSample(sample);
}
#ifdef DEBUG_AUDIOENGINE
@@ -260,35 +476,8 @@ void QDeclarativeAudioEngine::componentComplete()
qWarning() << "accessing invalid sound[" << key << "]";
continue;
}
- QDeclarativeAudioCategory *category = m_defaultCategory;
- if (m_categories.contains(sound->category())) {
- category = qobject_cast<QDeclarativeAudioCategory*>(
- qvariant_cast<QObject*>(m_categories[sound->category()]));
- }
- sound->setCategoryObject(category);
-
- QDeclarativeAttenuationModel *attenuationModel = 0;
- if (sound->attenuationModel().isEmpty()) {
- if (m_defaultAttenuationModel)
- attenuationModel = m_defaultAttenuationModel;
- } else if (m_attenuationModels.contains(sound->attenuationModel())){
- attenuationModel = m_attenuationModels[sound->attenuationModel()];
- } else {
- qWarning() << "Sound[" << sound->name() << "] contains invalid attenuationModel["
- << sound->attenuationModel() << "]";
- }
- sound->setAttenuationModelObject(attenuationModel);
-
- foreach (QDeclarativePlayVariation* playVariation, sound->playlist()) {
- if (m_samples.contains(playVariation->sample())) {
- playVariation->setSampleObject(
- qobject_cast<QDeclarativeAudioSample*>(
- qvariant_cast<QObject*>(m_samples[playVariation->sample()])));
- } else {
- qWarning() << "Sound[" << sound->name() << "] contains invalid sample["
- << playVariation->sample() << "] for its playVarations";
- }
- }
+
+ initSound(sound);
}
m_complete = true;
#ifdef DEBUG_AUDIOENGINE
@@ -330,65 +519,30 @@ void QDeclarativeAudioEngine::appendFunction(QQmlListProperty<QObject> *property
{
QDeclarativeAudioEngine* engine = static_cast<QDeclarativeAudioEngine*>(property->object);
if (engine->m_complete) {
- qWarning("AudioEngine: cannot add child after initialization!");
return;
}
QDeclarativeSound *sound = qobject_cast<QDeclarativeSound*>(value);
if (sound) {
-#ifdef DEBUG_AUDIOENGINE
- qDebug() << "add QDeclarativeSound[" << sound->name() << "]";
-#endif
- if (engine->m_sounds.contains(sound->name())) {
- qWarning() << "Failed to add Sound[" << sound->name() << "], already exists!";
- return;
- }
- engine->m_sounds.insert(sound->name(), QVariant::fromValue(value));
+ engine->addSound(sound);
return;
}
QDeclarativeAudioSample *sample = qobject_cast<QDeclarativeAudioSample*>(value);
if (sample) {
-#ifdef DEBUG_AUDIOENGINE
- qDebug() << "add QDeclarativeAudioSample[" << sample->name() << "]";
-#endif
- if (engine->m_samples.contains(sample->name())) {
- qWarning() << "Failed to add AudioSample[" << sample->name() << "], already exists!";
- return;
- }
- engine->m_samples.insert(sample->name(), QVariant::fromValue(value));
+ engine->addAudioSample(sample);
return;
}
QDeclarativeAudioCategory *category = qobject_cast<QDeclarativeAudioCategory*>(value);
if (category) {
-#ifdef DEBUG_AUDIOENGINE
- qDebug() << "add QDeclarativeAudioCategory[" << category->name() << "]";
-#endif
- if (engine->m_categories.contains(category->name())) {
- qWarning() << "Failed to add AudioCategory[" << category->name() << "], already exists!";
- return;
- }
- engine->m_categories.insert(category->name(), QVariant::fromValue(value));
- if (category->name() == QLatin1String("default")) {
- engine->m_defaultCategory = category;
- }
+ engine->addAudioCategory(category);
return;
}
QDeclarativeAttenuationModel *attenModel = qobject_cast<QDeclarativeAttenuationModel*>(value);
if (attenModel) {
-#ifdef DEBUG_AUDIOENGINE
- qDebug() << "add AttenuationModel[" << attenModel->name() << "]";
-#endif
- if (attenModel->name() == QLatin1String("default")) {
- engine->m_defaultAttenuationModel = attenModel;
- }
- if (engine->m_attenuationModels.contains(attenModel->name())) {
- qWarning() << "Failed to add AttenuationModel[" << attenModel->name() << "], already exists!";
- return;
- }
- engine->m_attenuationModels.insert(attenModel->name(), attenModel);
+ engine->addAttenuationModel(attenModel);
return;
}
diff --git a/src/imports/audioengine/qdeclarative_audioengine_p.h b/src/imports/audioengine/qdeclarative_audioengine_p.h
index 51090b5dc..497fdecac 100644
--- a/src/imports/audioengine/qdeclarative_audioengine_p.h
+++ b/src/imports/audioengine/qdeclarative_audioengine_p.h
@@ -34,6 +34,17 @@
#ifndef QDECLARATIVEAUDIOENGINE_P_H
#define QDECLARATIVEAUDIOENGINE_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 <QtQml/qqml.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlpropertymap.h>
@@ -111,6 +122,11 @@ public:
QSoundInstance* newSoundInstance(const QString &name);
void releaseSoundInstance(QSoundInstance* instance);
+ Q_REVISION(1) Q_INVOKABLE void addAudioSample(QDeclarativeAudioSample *);
+ Q_REVISION(1) Q_INVOKABLE void addSound(QDeclarativeSound *);
+ Q_REVISION(1) Q_INVOKABLE void addAudioCategory(QDeclarativeAudioCategory *);
+ Q_REVISION(1) Q_INVOKABLE void addAttenuationModel(QDeclarativeAttenuationModel *);
+
Q_SIGNALS:
void ready();
void liveInstanceCountChanged();
@@ -149,6 +165,9 @@ private:
QList<QDeclarativeSoundInstance*> m_managedDeclSoundInstances;
QList<QDeclarativeSoundInstance*> m_managedDeclSndInstancePool;
void releaseManagedDeclarativeSoundInstance(QDeclarativeSoundInstance* declSndInstance);
+
+ void initAudioSample(QDeclarativeAudioSample *);
+ void initSound(QDeclarativeSound *);
};
QT_END_NAMESPACE
diff --git a/src/imports/audioengine/qdeclarative_audiolistener_p.h b/src/imports/audioengine/qdeclarative_audiolistener_p.h
index 057e4c492..907333b83 100644
--- a/src/imports/audioengine/qdeclarative_audiolistener_p.h
+++ b/src/imports/audioengine/qdeclarative_audiolistener_p.h
@@ -34,6 +34,17 @@
#ifndef QDECLARATIVEAUDIOLISTENER_P_H
#define QDECLARATIVEAUDIOLISTENER_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>
#include <QtGui/qvector3d.h>
diff --git a/src/imports/audioengine/qdeclarative_audiosample_p.cpp b/src/imports/audioengine/qdeclarative_audiosample_p.cpp
index 5a9a67b71..297af3b31 100644
--- a/src/imports/audioengine/qdeclarative_audiosample_p.cpp
+++ b/src/imports/audioengine/qdeclarative_audiosample_p.cpp
@@ -54,7 +54,9 @@ QT_USE_NAMESPACE
\c AudioSample is part of the \b{QtAudioEngine 1.0} module.
It can be accessed through QtAudioEngine::AudioEngine::samples with its unique
- name and must be defined inside AudioEngine.
+ name and must be defined inside AudioEngine or be added to it using
+ \l{QtAudioEngine::AudioEngine::addAudioSample()}{AudioEngine.addAudioSample()}
+ if AudioSample is created dynamically.
\qml
import QtQuick 2.0
@@ -78,10 +80,10 @@ QT_USE_NAMESPACE
*/
QDeclarativeAudioSample::QDeclarativeAudioSample(QObject *parent)
: QObject(parent)
- , m_complete(false)
, m_streaming(false)
, m_preloaded(false)
, m_soundBuffer(0)
+ , m_engine(0)
{
}
@@ -89,23 +91,6 @@ QDeclarativeAudioSample::~QDeclarativeAudioSample()
{
}
-void QDeclarativeAudioSample::classBegin()
-{
- if (!parent() || !parent()->inherits("QDeclarativeAudioEngine")) {
- qWarning("AudioSample must be defined inside AudioEngine!");
- return;
- }
-}
-
-void QDeclarativeAudioSample::componentComplete()
-{
- if (m_name.isEmpty()) {
- qWarning("AudioSample must have a name!");
- return;
- }
- m_complete = true;
-}
-
/*!
\qmlproperty url QtAudioEngine::AudioSample::source
@@ -118,7 +103,7 @@ QUrl QDeclarativeAudioSample::source() const
void QDeclarativeAudioSample::setSource(const QUrl& url)
{
- if (m_complete) {
+ if (m_engine) {
qWarning("AudioSample: source not changeable after initialization.");
return;
}
@@ -130,6 +115,11 @@ bool QDeclarativeAudioSample::isStreaming() const
return m_streaming;
}
+QDeclarativeAudioEngine *QDeclarativeAudioSample::engine() const
+{
+ return m_engine;
+}
+
/*!
\qmlproperty bool QtAudioEngine::AudioSample::preloaded
@@ -173,7 +163,7 @@ void QDeclarativeAudioSample::load()
void QDeclarativeAudioSample::setPreloaded(bool preloaded)
{
- if (m_complete) {
+ if (m_engine) {
qWarning("AudioSample: preloaded not changeable after initialization.");
return;
}
@@ -182,13 +172,22 @@ void QDeclarativeAudioSample::setPreloaded(bool preloaded)
void QDeclarativeAudioSample::setStreaming(bool streaming)
{
- if (m_complete) {
+ if (m_engine) {
qWarning("AudioSample: streaming not changeable after initialization.");
return;
}
m_streaming = streaming;
}
+void QDeclarativeAudioSample::setEngine(QDeclarativeAudioEngine *engine)
+{
+ if (m_engine) {
+ qWarning("AudioSample: engine not changeable after initialization.");
+ return;
+ }
+ m_engine = engine;
+}
+
/*!
\qmlproperty string QtAudioEngine::AudioSample::name
@@ -202,7 +201,7 @@ QString QDeclarativeAudioSample::name() const
void QDeclarativeAudioSample::setName(const QString& name)
{
- if (m_complete) {
+ if (m_engine) {
qWarning("AudioSample: name not changeable after initialization.");
return;
}
@@ -211,12 +210,13 @@ void QDeclarativeAudioSample::setName(const QString& name)
void QDeclarativeAudioSample::init()
{
+ Q_ASSERT(m_engine != 0);
+
if (m_streaming) {
//TODO
} else {
- m_soundBuffer =
- qobject_cast<QDeclarativeAudioEngine*>(parent())->engine()->getStaticSoundBuffer(m_url);
+ m_soundBuffer = m_engine->engine()->getStaticSoundBuffer(m_url);
if (m_soundBuffer->state() == QSoundBuffer::Ready) {
emit loadedChanged();
} else {
diff --git a/src/imports/audioengine/qdeclarative_audiosample_p.h b/src/imports/audioengine/qdeclarative_audiosample_p.h
index 94e1c7e27..2b8d9f8da 100644
--- a/src/imports/audioengine/qdeclarative_audiosample_p.h
+++ b/src/imports/audioengine/qdeclarative_audiosample_p.h
@@ -34,17 +34,27 @@
#ifndef QDECLARATIVEAUDIOSAMPLE_P_H
#define QDECLARATIVEAUDIOSAMPLE_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 <QtQml/qqml.h>
-#include <QtQml/qqmlcomponent.h>
QT_BEGIN_NAMESPACE
class QSoundBuffer;
+class QDeclarativeAudioEngine;
-class QDeclarativeAudioSample : public QObject, public QQmlParserStatus
+class QDeclarativeAudioSample : public QObject
{
Q_OBJECT
- Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(QUrl source READ source WRITE setSource)
Q_PROPERTY(bool preloaded READ isPreloaded WRITE setPreloaded)
@@ -55,9 +65,6 @@ public:
QDeclarativeAudioSample(QObject *parent = 0);
~QDeclarativeAudioSample();
- void classBegin();
- void componentComplete();
-
QString name() const;
void setName(const QString& name);
@@ -70,6 +77,9 @@ public:
bool isPreloaded() const;
void setPreloaded(bool preloaded);
+ QDeclarativeAudioEngine *engine() const;
+ void setEngine(QDeclarativeAudioEngine *);
+
bool isLoaded() const;
QSoundBuffer* soundBuffer() const;
@@ -85,13 +95,12 @@ public Q_SLOTS:
private:
Q_DISABLE_COPY(QDeclarativeAudioSample);
- bool m_complete;
QString m_name;
QUrl m_url;
bool m_streaming;
bool m_preloaded;
-
QSoundBuffer *m_soundBuffer;
+ QDeclarativeAudioEngine *m_engine;
};
QT_END_NAMESPACE
diff --git a/src/imports/audioengine/qdeclarative_playvariation_p.cpp b/src/imports/audioengine/qdeclarative_playvariation_p.cpp
index 38876c227..156f83f68 100644
--- a/src/imports/audioengine/qdeclarative_playvariation_p.cpp
+++ b/src/imports/audioengine/qdeclarative_playvariation_p.cpp
@@ -55,7 +55,9 @@ QT_USE_NAMESPACE
This type is part of the \b{QtAudioEngine 1.0} module.
- PlayVariation must be defined inside a \l Sound.
+ PlayVariation must be defined inside a \l Sound or be added to it using
+ \l{QtAudioEngine::Sound::addPlayVariation()}{Sound.addPlayVariation()}
+ if PlayVariation is created dynamically.
\qml
import QtQuick 2.0
@@ -100,13 +102,13 @@ QT_USE_NAMESPACE
*/
QDeclarativePlayVariation::QDeclarativePlayVariation(QObject *parent)
: QObject(parent)
- , m_complete(false)
, m_looping(false)
, m_maxGain(1)
, m_minGain(1)
, m_maxPitch(1)
, m_minPitch(1)
, m_sampleObject(0)
+ , m_engine(0)
{
}
@@ -114,15 +116,7 @@ QDeclarativePlayVariation::~QDeclarativePlayVariation()
{
}
-void QDeclarativePlayVariation::classBegin()
-{
- if (!parent() || !parent()->inherits("QDeclarativeSound")) {
- qWarning("PlayVariation must be defined inside Sound!");
- return;
- }
-}
-
-void QDeclarativePlayVariation::componentComplete()
+void QDeclarativePlayVariation::setEngine(QDeclarativeAudioEngine *engine)
{
if (m_maxGain < m_minGain) {
qWarning("PlayVariation: maxGain must be no less than minGain");
@@ -132,7 +126,7 @@ void QDeclarativePlayVariation::componentComplete()
qWarning("PlayVariation: maxPitch must be no less than minPitch");
qSwap(m_minPitch, m_maxPitch);
}
- m_complete = true;
+ m_engine = engine;
}
/*!
@@ -147,7 +141,7 @@ QString QDeclarativePlayVariation::sample() const
void QDeclarativePlayVariation::setSample(const QString& sample)
{
- if (m_complete) {
+ if (m_engine) {
qWarning("PlayVariation: cannot change properties after initialization.");
return;
}
@@ -166,7 +160,7 @@ bool QDeclarativePlayVariation::isLooping() const
void QDeclarativePlayVariation::setLooping(bool looping)
{
- if (m_complete) {
+ if (m_engine) {
qWarning("PlayVariation: cannot change properties after initialization.");
return;
}
@@ -185,7 +179,7 @@ qreal QDeclarativePlayVariation::maxGain() const
void QDeclarativePlayVariation::setMaxGain(qreal maxGain)
{
- if (m_complete) {
+ if (m_engine) {
qWarning("PlayVariation: cannot change properties after initialization.");
return;
}
@@ -208,7 +202,7 @@ qreal QDeclarativePlayVariation::minGain() const
void QDeclarativePlayVariation::setMinGain(qreal minGain)
{
- if (m_complete) {
+ if (m_engine) {
qWarning("PlayVariation: cannot change properties after initialization.");
return;
}
@@ -231,7 +225,7 @@ qreal QDeclarativePlayVariation::maxPitch() const
void QDeclarativePlayVariation::setMaxPitch(qreal maxPitch)
{
- if (m_complete) {
+ if (m_engine) {
qWarning("PlayVariation: cannot change properties after initialization.");
return;
}
@@ -254,7 +248,7 @@ qreal QDeclarativePlayVariation::minPitch() const
void QDeclarativePlayVariation::setMinPitch(qreal minPitch)
{
- if (m_complete) {
+ if (m_engine) {
qWarning("PlayVariation: cannot change properties after initialization.");
return;
}
diff --git a/src/imports/audioengine/qdeclarative_playvariation_p.h b/src/imports/audioengine/qdeclarative_playvariation_p.h
index dfe690cef..4a8306d72 100644
--- a/src/imports/audioengine/qdeclarative_playvariation_p.h
+++ b/src/imports/audioengine/qdeclarative_playvariation_p.h
@@ -34,18 +34,28 @@
#ifndef QDECLARATIVEPLAYVARIATION_P_H
#define QDECLARATIVEPLAYVARIATION_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 <QtQml/qqml.h>
-#include <QtQml/qqmlcomponent.h>
QT_BEGIN_NAMESPACE
class QDeclarativeAudioSample;
class QSoundInstance;
+class QDeclarativeAudioEngine;
-class QDeclarativePlayVariation : public QObject, public QQmlParserStatus
+class QDeclarativePlayVariation : public QObject
{
Q_OBJECT
- Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QString sample READ sample WRITE setSample)
Q_PROPERTY(bool looping READ isLooping WRITE setLooping)
Q_PROPERTY(qreal maxGain READ maxGain WRITE setMaxGain)
@@ -57,9 +67,6 @@ public:
QDeclarativePlayVariation(QObject *parent = 0);
~QDeclarativePlayVariation();
- void classBegin();
- void componentComplete();
-
QString sample() const;
void setSample(const QString& sample);
@@ -82,9 +89,10 @@ public:
void applyParameters(QSoundInstance *soundInstance);
+ void setEngine(QDeclarativeAudioEngine *engine);
+
private:
Q_DISABLE_COPY(QDeclarativePlayVariation);
- bool m_complete;
QString m_sample;
bool m_looping;
qreal m_maxGain;
@@ -92,6 +100,7 @@ private:
qreal m_maxPitch;
qreal m_minPitch;
QDeclarativeAudioSample *m_sampleObject;
+ QDeclarativeAudioEngine *m_engine;
};
QT_END_NAMESPACE
diff --git a/src/imports/audioengine/qdeclarative_sound_p.cpp b/src/imports/audioengine/qdeclarative_sound_p.cpp
index fcbd76f71..f19b8dbb3 100644
--- a/src/imports/audioengine/qdeclarative_sound_p.cpp
+++ b/src/imports/audioengine/qdeclarative_sound_p.cpp
@@ -64,8 +64,12 @@ qreal QDeclarativeSoundCone::innerAngle() const
void QDeclarativeSoundCone::setInnerAngle(qreal innerAngle)
{
QDeclarativeSound *s = qobject_cast<QDeclarativeSound*>(parent());
- if (s && s->m_complete)
+
+ if (s && s->m_engine) {
+ qWarning("SoundCone: innerAngle not changeable after initialization.");
return;
+ }
+
if (innerAngle < 0 || innerAngle > 360) {
qWarning() << "innerAngle should be within[0, 360] degrees";
return;
@@ -88,8 +92,12 @@ qreal QDeclarativeSoundCone::outerAngle() const
void QDeclarativeSoundCone::setOuterAngle(qreal outerAngle)
{
QDeclarativeSound *s = qobject_cast<QDeclarativeSound*>(parent());
- if (s && s->m_complete)
+
+ if (s && s->m_engine) {
+ qWarning("SoundCone: outerAngle not changeable after initialization.");
return;
+ }
+
if (outerAngle < 0 || outerAngle > 360) {
qWarning() << "outerAngle should be within[0, 360] degrees";
return;
@@ -112,8 +120,12 @@ qreal QDeclarativeSoundCone::outerGain() const
void QDeclarativeSoundCone::setOuterGain(qreal outerGain)
{
QDeclarativeSound *s = qobject_cast<QDeclarativeSound*>(parent());
- if (s && s->m_complete)
+
+ if (s && s->m_engine) {
+ qWarning("SoundCone: outerGain not changeable after initialization.");
return;
+ }
+
if (outerGain < 0 || outerGain > 1) {
qWarning() << "outerGain should no less than 0 and no more than 1";
return;
@@ -121,11 +133,18 @@ void QDeclarativeSoundCone::setOuterGain(qreal outerGain)
m_outerGain = outerGain;
}
-void QDeclarativeSoundCone::componentComplete()
+void QDeclarativeSoundCone::setEngine(QDeclarativeAudioEngine *engine)
{
+ if (m_engine) {
+ qWarning("SoundCone: engine not changeable after initialization.");
+ return;
+ }
+
if (m_outerAngle < m_innerAngle) {
m_outerAngle = m_innerAngle;
}
+
+ m_engine = engine;
}
////////////////////////////////////////////////////////////
@@ -143,7 +162,9 @@ void QDeclarativeSoundCone::componentComplete()
This type is part of the \b{QtAudioEngine 1.0} module.
Sound can be accessed through QtAudioEngine::AudioEngine::sounds with its unique name
- and must be defined inside AudioEngine.
+ and must be defined inside AudioEngine or be added to it using
+ \l{QtAudioEngine::AudioEngine::addSound()}{AudioEngine.addSound()}
+ if \l Sound is created dynamically.
\qml
import QtQuick 2.0
@@ -194,10 +215,10 @@ void QDeclarativeSoundCone::componentComplete()
QDeclarativeSound::QDeclarativeSound(QObject *parent)
: QObject(parent)
- , m_complete(false)
, m_playType(Random)
, m_attenuationModelObject(0)
, m_categoryObject(0)
+ , m_engine(0)
{
m_cone = new QDeclarativeSoundCone(this);
}
@@ -206,20 +227,6 @@ QDeclarativeSound::~QDeclarativeSound()
{
}
-void QDeclarativeSound::classBegin()
-{
- if (!parent() || !parent()->inherits("QDeclarativeAudioEngine")) {
- qWarning("Sound must be defined inside AudioEngine!");
- return;
- }
-}
-
-void QDeclarativeSound::componentComplete()
-{
- m_complete = true;
- m_cone->componentComplete();
-}
-
/*!
\qmlproperty enumeration QtAudioEngine::Sound::playType
@@ -239,7 +246,7 @@ QDeclarativeSound::PlayType QDeclarativeSound::playType() const
void QDeclarativeSound::setPlayType(PlayType playType)
{
- if (m_complete) {
+ if (m_engine) {
qWarning("Sound: playType not changeable after initialization.");
return;
}
@@ -258,7 +265,7 @@ QString QDeclarativeSound::category() const
void QDeclarativeSound::setCategory(const QString& category)
{
- if (m_complete) {
+ if (m_engine) {
qWarning("Sound: category not changeable after initialization.");
return;
}
@@ -278,7 +285,7 @@ QString QDeclarativeSound::name() const
void QDeclarativeSound::setName(const QString& name)
{
- if (m_complete) {
+ if (m_engine) {
qWarning("Sound: category not changeable after initialization.");
return;
}
@@ -322,13 +329,28 @@ QDeclarativePlayVariation* QDeclarativeSound::getVariation(int index)
void QDeclarativeSound::setAttenuationModel(const QString &attenuationModel)
{
- if (m_complete) {
+ if (m_engine) {
qWarning("Sound: attenuationModel not changeable after initialization.");
return;
}
m_attenuationModel = attenuationModel;
}
+void QDeclarativeSound::setEngine(QDeclarativeAudioEngine *engine)
+{
+ if (m_engine) {
+ qWarning("Sound: engine not changeable after initialization.");
+ return;
+ }
+ m_cone->setEngine(engine);
+ m_engine = engine;
+}
+
+QDeclarativeAudioEngine *QDeclarativeSound::engine() const
+{
+ return m_engine;
+}
+
QDeclarativeSoundCone* QDeclarativeSound::cone() const
{
return m_cone;
@@ -367,11 +389,42 @@ QList<QDeclarativePlayVariation*>& QDeclarativeSound::playlist()
void QDeclarativeSound::appendFunction(QQmlListProperty<QDeclarativePlayVariation> *property, QDeclarativePlayVariation *value)
{
QDeclarativeSound *sound = static_cast<QDeclarativeSound*>(property->object);
- if (sound->m_complete) {
- qWarning("Sound: PlayVariation not addable after initialization.");
+ if (sound->m_engine) {
return;
}
- sound->m_playlist.append(value);
+ sound->addPlayVariation(value);
+}
+
+/*!
+ \qmlmethod QtAudioEngine::Sound::addPlayVariation(PlayVariation playVariation)
+
+ Adds the given \a playVariation to sound.
+ This can be used when the PlayVariation is created dynamically:
+
+ \qml
+ import QtAudioEngine 1.1
+
+ AudioEngine {
+ id: engine
+
+ Component.onCompleted: {
+ var playVariation = Qt.createQmlObject('import QtAudioEngine 1.1; PlayVariation {}', engine);
+ playVariation.sample = "sample";
+ playVariation.minPitch = 0.8
+ playVariation.maxPitch = 1.1
+
+ var sound = Qt.createQmlObject('import QtAudioEngine 1.1; Sound {}', engine);
+ sound.name = "example";
+ sound.addPlayVariation(playVariation);
+ engine.addSound(sound);
+ }
+ }
+ \endqml
+*/
+void QDeclarativeSound::addPlayVariation(QDeclarativePlayVariation *value)
+{
+ m_playlist.append(value);
+ value->setEngine(m_engine);
}
/*!
@@ -507,7 +560,7 @@ void QDeclarativeSound::play(const QVector3D& position, const QVector3D& velocit
*/
void QDeclarativeSound::play(const QVector3D& position, const QVector3D& velocity, const QVector3D& direction, qreal gain, qreal pitch)
{
- if (!m_complete) {
+ if (!m_engine) {
qWarning() << "AudioEngine::play not ready!";
return;
}
@@ -546,8 +599,13 @@ QDeclarativeSoundInstance* QDeclarativeSound::newInstance()
QDeclarativeSoundInstance* QDeclarativeSound::newInstance(bool managed)
{
+ if (!m_engine) {
+ qWarning("engine attrbiute must be set for Sound object!");
+ return NULL;
+ }
+
QDeclarativeSoundInstance *instance =
- qobject_cast<QDeclarativeAudioEngine*>(this->parent())->newDeclarativeSoundInstance(managed);
+ m_engine->newDeclarativeSoundInstance(managed);
instance->setSound(m_name);
return instance;
}
diff --git a/src/imports/audioengine/qdeclarative_sound_p.h b/src/imports/audioengine/qdeclarative_sound_p.h
index 14ebd1039..494fe2e34 100644
--- a/src/imports/audioengine/qdeclarative_sound_p.h
+++ b/src/imports/audioengine/qdeclarative_sound_p.h
@@ -34,8 +34,18 @@
#ifndef QDECLARATIVESOUND_P_H
#define QDECLARATIVESOUND_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 <QtQml/qqml.h>
-#include <QtQml/qqmlcomponent.h>
#include <QtCore/qlist.h>
#include "qdeclarative_playvariation_p.h"
@@ -44,6 +54,7 @@ QT_BEGIN_NAMESPACE
class QDeclarativeAudioCategory;
class QDeclarativeAttenuationModel;
class QDeclarativeSoundInstance;
+class QDeclarativeAudioEngine;
class QDeclarativeSoundCone : public QObject
{
@@ -65,21 +76,21 @@ public:
qreal outerGain() const;
void setOuterGain(qreal outerGain);
- void componentComplete();
+ void setEngine(QDeclarativeAudioEngine *engine);
private:
Q_DISABLE_COPY(QDeclarativeSoundCone)
qreal m_innerAngle;
qreal m_outerAngle;
qreal m_outerGain;
+ QDeclarativeAudioEngine *m_engine;
};
-class QDeclarativeSound : public QObject, public QQmlParserStatus
+class QDeclarativeSound : public QObject
{
friend class QDeclarativeSoundCone;
Q_OBJECT
- Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(PlayType playType READ playType WRITE setPlayType)
Q_PROPERTY(QString category READ category WRITE setCategory)
@@ -99,9 +110,6 @@ public:
QDeclarativeSound(QObject *parent = 0);
~QDeclarativeSound();
- void classBegin();
- void componentComplete();
-
PlayType playType() const;
void setPlayType(PlayType playType);
@@ -114,6 +122,9 @@ public:
QString attenuationModel() const;
void setAttenuationModel(const QString &attenuationModel);
+ QDeclarativeAudioEngine *engine() const;
+ void setEngine(QDeclarativeAudioEngine *);
+
QDeclarativeSoundCone* cone() const;
QDeclarativeAttenuationModel* attenuationModelObject() const;
@@ -128,6 +139,8 @@ public:
QQmlListProperty<QDeclarativePlayVariation> playVariationlist();
QList<QDeclarativePlayVariation*>& playlist();
+ Q_INVOKABLE Q_REVISION(1) void addPlayVariation(QDeclarativePlayVariation*);
+
public Q_SLOTS:
void play();
void play(qreal gain);
@@ -147,7 +160,6 @@ private:
Q_DISABLE_COPY(QDeclarativeSound)
QDeclarativeSoundInstance* newInstance(bool managed);
static void appendFunction(QQmlListProperty<QDeclarativePlayVariation> *property, QDeclarativePlayVariation *value);
- bool m_complete;
PlayType m_playType;
QString m_name;
QString m_category;
@@ -157,6 +169,7 @@ private:
QDeclarativeAttenuationModel *m_attenuationModelObject;
QDeclarativeAudioCategory *m_categoryObject;
+ QDeclarativeAudioEngine *m_engine;
};
QT_END_NAMESPACE
diff --git a/src/imports/audioengine/qdeclarative_soundinstance_p.h b/src/imports/audioengine/qdeclarative_soundinstance_p.h
index 55310a3ae..80fe82e47 100644
--- a/src/imports/audioengine/qdeclarative_soundinstance_p.h
+++ b/src/imports/audioengine/qdeclarative_soundinstance_p.h
@@ -34,6 +34,17 @@
#ifndef QDECLARATIVE_SOUNDINSTANCE_P_H
#define QDECLARATIVE_SOUNDINSTANCE_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>
#include <QtGui/qvector3d.h>
#include "qsoundinstance_p.h"
diff --git a/src/imports/audioengine/qsoundbuffer_p.h b/src/imports/audioengine/qsoundbuffer_p.h
index 9a98b59ba..9f7af625a 100644
--- a/src/imports/audioengine/qsoundbuffer_p.h
+++ b/src/imports/audioengine/qsoundbuffer_p.h
@@ -34,6 +34,17 @@
#ifndef QSOUNDBUFFER_P_H
#define QSOUNDBUFFER_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>
QT_BEGIN_NAMESPACE
diff --git a/src/imports/audioengine/qsoundinstance_p.h b/src/imports/audioengine/qsoundinstance_p.h
index 37b252b98..39bab3231 100644
--- a/src/imports/audioengine/qsoundinstance_p.h
+++ b/src/imports/audioengine/qsoundinstance_p.h
@@ -34,6 +34,17 @@
#ifndef QSOUNDINSTANCE_P_H
#define QSOUNDINSTANCE_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 <QVector3D>
#include <QObject>
#include "qsoundsource_p.h"
diff --git a/src/imports/audioengine/qsoundsource_p.h b/src/imports/audioengine/qsoundsource_p.h
index b9f68ff98..dfe8d0851 100644
--- a/src/imports/audioengine/qsoundsource_p.h
+++ b/src/imports/audioengine/qsoundsource_p.h
@@ -34,6 +34,17 @@
#ifndef QSOUNDSOURCE_P_H
#define QSOUNDSOURCE_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 <QVector3D>
#include <QObject>
diff --git a/src/imports/multimedia/Video.qml b/src/imports/multimedia/Video.qml
index 2312924d9..1ce3065e9 100644
--- a/src/imports/multimedia/Video.qml
+++ b/src/imports/multimedia/Video.qml
@@ -32,7 +32,7 @@
****************************************************************************/
import QtQuick 2.0
-import QtMultimedia 5.0
+import QtMultimedia 5.6
/*!
\qmltype Video
@@ -274,6 +274,35 @@ Item {
property alias position: player.position
/*!
+ \qmlproperty enumeration Video::audioRole
+
+ This property holds the role of the audio stream. 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 setting the source property.
+
+ Supported values can be retrieved with supportedAudioRoles().
+
+ The value can be one of:
+ \list
+ \li MediaPlayer.UnknownRole - the role is unknown or undefined.
+ \li MediaPlayer.MusicRole - music.
+ \li MediaPlayer.VideoRole - soundtrack from a movie or a video.
+ \li MediaPlayer.VoiceCommunicationRole - voice communications, such as telephony.
+ \li MediaPlayer.AlarmRole - alarm.
+ \li MediaPlayer.NotificationRole - notification, such as an incoming e-mail or a chat request.
+ \li MediaPlayer.RingtoneRole - ringtone.
+ \li MediaPlayer.AccessibilityRole - for accessibility, such as with a screen reader.
+ \li MediaPlayer.SonificationRole - sonification, such as with user interface sounds.
+ \li MediaPlayer.GameRole - game audio.
+ \endlist
+
+ \since 5.6
+ */
+ property alias audioRole: player.audioRole
+
+ /*!
\qmlproperty bool Video::seekable
This property holds whether the playback position of the video can be
@@ -287,10 +316,23 @@ Item {
\qmlproperty url Video::source
This property holds the source URL of the media.
+
+ Setting the \l source property clears the current \l playlist, if any.
*/
property alias source: player.source
/*!
+ \qmlproperty Playlist Video::playlist
+
+ This property holds the playlist used by the media player.
+
+ Setting the \l playlist property resets the \l source to an empty string.
+
+ \since 5.6
+ */
+ property alias playlist: player.playlist
+
+ /*!
\qmlproperty enumeration Video::status
This property holds the status of media loading. It can be one of:
@@ -407,4 +449,18 @@ Item {
player.seek(offset);
}
+ /*!
+ \qmlmethod list<int> Video::supportedAudioRoles()
+
+ Returns a list of supported audio roles.
+
+ If setting the audio role is not supported, an empty list is returned.
+
+ \since 5.6
+ \sa audioRole
+ */
+ function supportedAudioRoles() {
+ return player.supportedAudioRoles();
+ }
+
}
diff --git a/src/imports/multimedia/multimedia.cpp b/src/imports/multimedia/multimedia.cpp
index 4b31068ea..7d34672a1 100644
--- a/src/imports/multimedia/multimedia.cpp
+++ b/src/imports/multimedia/multimedia.cpp
@@ -45,6 +45,7 @@
#include "qdeclarativeaudio_p.h"
#include "qdeclarativeradio_p.h"
#include "qdeclarativeradiodata_p.h"
+#include "qdeclarativeplaylist_p.h"
#include "qdeclarativecamera_p.h"
#include "qdeclarativecamerapreviewprovider_p.h"
#include "qdeclarativecameraexposure_p.h"
@@ -114,6 +115,12 @@ public:
qmlRegisterUncreatableType<QDeclarativeCameraImageProcessing, 1>(uri, 5, 5, "CameraImageProcessing", trUtf8("CameraImageProcessing is provided by Camera"));
qmlRegisterType<QDeclarativeCamera, 2>(uri, 5, 5, "Camera");
+ // 5.6 types
+ qmlRegisterType<QDeclarativeAudio, 1>(uri, 5, 6, "Audio");
+ qmlRegisterType<QDeclarativeAudio, 1>(uri, 5, 6, "MediaPlayer");
+ qmlRegisterType<QDeclarativePlaylist>(uri, 5, 6, "Playlist");
+ qmlRegisterType<QDeclarativePlaylistItem>(uri, 5, 6, "PlaylistItem");
+
qmlRegisterType<QDeclarativeMediaMetaData>();
qmlRegisterType<QAbstractVideoFilter>();
}
diff --git a/src/imports/multimedia/multimedia.pro b/src/imports/multimedia/multimedia.pro
index 71358caed..606fb3966 100644
--- a/src/imports/multimedia/multimedia.pro
+++ b/src/imports/multimedia/multimedia.pro
@@ -3,6 +3,7 @@ QT += qml quick network multimedia-private qtmultimediaquicktools-private
HEADERS += \
qdeclarativeaudio_p.h \
qdeclarativemediametadata_p.h \
+ qdeclarativeplaylist_p.h \
qdeclarativeradio_p.h \
qdeclarativeradiodata_p.h \
qdeclarativecamera_p.h \
@@ -20,6 +21,7 @@ HEADERS += \
SOURCES += \
multimedia.cpp \
qdeclarativeaudio.cpp \
+ qdeclarativeplaylist.cpp \
qdeclarativeradio.cpp \
qdeclarativeradiodata.cpp \
qdeclarativecamera.cpp \
diff --git a/src/imports/multimedia/plugins.qmltypes b/src/imports/multimedia/plugins.qmltypes
index 53d7cb435..fe1c68af2 100644
--- a/src/imports/multimedia/plugins.qmltypes
+++ b/src/imports/multimedia/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable QtMultimedia 5.5'
+// 'qmlplugindump -nonrelocatable QtMultimedia 5.6'
Module {
dependencies: ["QtQuick 2.0"]
@@ -146,8 +146,13 @@ Module {
Component {
name: "QDeclarativeAudio"
prototype: "QObject"
- exports: ["QtMultimedia/Audio 5.0", "QtMultimedia/MediaPlayer 5.0"]
- exportMetaObjectRevisions: [0, 0]
+ exports: [
+ "QtMultimedia/Audio 5.0",
+ "QtMultimedia/Audio 5.6",
+ "QtMultimedia/MediaPlayer 5.0",
+ "QtMultimedia/MediaPlayer 5.6"
+ ]
+ exportMetaObjectRevisions: [0, 1, 0, 1]
Enum {
name: "Status"
values: {
@@ -196,7 +201,23 @@ Module {
"ResourceMissing": 3
}
}
+ Enum {
+ name: "AudioRole"
+ values: {
+ "UnknownRole": 0,
+ "AccessibilityRole": 7,
+ "AlarmRole": 4,
+ "GameRole": 9,
+ "MusicRole": 1,
+ "NotificationRole": 5,
+ "RingtoneRole": 6,
+ "SonificationRole": 8,
+ "VideoRole": 2,
+ "VoiceCommunicationRole": 3
+ }
+ }
Property { name: "source"; type: "QUrl" }
+ Property { name: "playlist"; revision: 1; type: "QDeclarativePlaylist"; isPointer: true }
Property { name: "loops"; type: "int" }
Property { name: "playbackState"; type: "PlaybackState"; isReadonly: true }
Property { name: "autoPlay"; type: "bool" }
@@ -221,10 +242,13 @@ Module {
}
Property { name: "mediaObject"; type: "QObject"; isReadonly: true; isPointer: true }
Property { name: "availability"; type: "Availability"; isReadonly: true }
+ Property { name: "audioRole"; revision: 1; type: "AudioRole" }
+ Signal { name: "playlistChanged"; revision: 1 }
Signal { name: "loopCountChanged" }
Signal { name: "paused" }
Signal { name: "stopped" }
Signal { name: "playing" }
+ Signal { name: "audioRoleChanged"; revision: 1 }
Signal {
name: "availabilityChanged"
Parameter { name: "availability"; type: "Availability" }
@@ -241,6 +265,7 @@ Module {
name: "seek"
Parameter { name: "position"; type: "int" }
}
+ Method { name: "supportedAudioRoles"; revision: 1; type: "QJSValue" }
}
Component {
name: "QDeclarativeCamera"
@@ -1215,6 +1240,137 @@ Module {
Property { name: "availableCameras"; type: "QJSValue"; isReadonly: true }
}
Component {
+ name: "QDeclarativePlaylist"
+ defaultProperty: "items"
+ prototype: "QAbstractListModel"
+ exports: ["QtMultimedia/Playlist 5.6"]
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "PlaybackMode"
+ values: {
+ "CurrentItemOnce": 0,
+ "CurrentItemInLoop": 1,
+ "Sequential": 2,
+ "Loop": 3,
+ "Random": 4
+ }
+ }
+ Enum {
+ name: "Error"
+ values: {
+ "NoError": 0,
+ "FormatError": 1,
+ "FormatNotSupportedError": 2,
+ "NetworkError": 3,
+ "AccessDeniedError": 4
+ }
+ }
+ Property { name: "playbackMode"; type: "PlaybackMode" }
+ Property { name: "currentItemSource"; type: "QUrl"; isReadonly: true }
+ Property { name: "currentIndex"; type: "int" }
+ Property { name: "itemCount"; type: "int"; isReadonly: true }
+ Property { name: "readOnly"; type: "bool"; isReadonly: true }
+ Property { name: "error"; type: "Error"; isReadonly: true }
+ Property { name: "errorString"; type: "string"; isReadonly: true }
+ Property { name: "items"; type: "QDeclarativePlaylistItem"; isList: true; isReadonly: true }
+ Signal {
+ name: "itemAboutToBeInserted"
+ Parameter { name: "start"; type: "int" }
+ Parameter { name: "end"; type: "int" }
+ }
+ Signal {
+ name: "itemInserted"
+ Parameter { name: "start"; type: "int" }
+ Parameter { name: "end"; type: "int" }
+ }
+ Signal {
+ name: "itemAboutToBeRemoved"
+ Parameter { name: "start"; type: "int" }
+ Parameter { name: "end"; type: "int" }
+ }
+ Signal {
+ name: "itemRemoved"
+ Parameter { name: "start"; type: "int" }
+ Parameter { name: "end"; type: "int" }
+ }
+ Signal {
+ name: "itemChanged"
+ Parameter { name: "start"; type: "int" }
+ Parameter { name: "end"; type: "int" }
+ }
+ Signal { name: "loaded" }
+ Signal { name: "loadFailed" }
+ Signal {
+ name: "error"
+ Parameter { name: "error"; type: "QDeclarativePlaylist::Error" }
+ Parameter { name: "errorString"; type: "string" }
+ }
+ Method {
+ name: "itemSource"
+ type: "QUrl"
+ Parameter { name: "index"; type: "int" }
+ }
+ Method {
+ name: "nextIndex"
+ type: "int"
+ Parameter { name: "steps"; type: "int" }
+ }
+ Method { name: "nextIndex"; type: "int" }
+ Method {
+ name: "previousIndex"
+ type: "int"
+ Parameter { name: "steps"; type: "int" }
+ }
+ Method { name: "previousIndex"; type: "int" }
+ Method { name: "next" }
+ Method { name: "previous" }
+ Method { name: "shuffle" }
+ Method {
+ name: "load"
+ Parameter { name: "location"; type: "QUrl" }
+ Parameter { name: "format"; type: "string" }
+ }
+ Method {
+ name: "load"
+ Parameter { name: "location"; type: "QUrl" }
+ }
+ Method {
+ name: "save"
+ type: "bool"
+ Parameter { name: "location"; type: "QUrl" }
+ Parameter { name: "format"; type: "string" }
+ }
+ Method {
+ name: "save"
+ type: "bool"
+ Parameter { name: "location"; type: "QUrl" }
+ }
+ Method {
+ name: "addItem"
+ type: "bool"
+ Parameter { name: "source"; type: "QUrl" }
+ }
+ Method {
+ name: "insertItem"
+ type: "bool"
+ Parameter { name: "index"; type: "int" }
+ Parameter { name: "source"; type: "QUrl" }
+ }
+ Method {
+ name: "removeItem"
+ type: "bool"
+ Parameter { name: "index"; type: "int" }
+ }
+ Method { name: "clear"; type: "bool" }
+ }
+ Component {
+ name: "QDeclarativePlaylistItem"
+ prototype: "QObject"
+ exports: ["QtMultimedia/PlaylistItem 5.6"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "source"; type: "QUrl" }
+ }
+ Component {
name: "QDeclarativeRadio"
prototype: "QObject"
exports: ["QtMultimedia/Radio 5.0"]
diff --git a/src/imports/multimedia/qdeclarativeaudio.cpp b/src/imports/multimedia/qdeclarativeaudio.cpp
index 540ed6464..7decc4f19 100644
--- a/src/imports/multimedia/qdeclarativeaudio.cpp
+++ b/src/imports/multimedia/qdeclarativeaudio.cpp
@@ -42,9 +42,11 @@
#include <qmetadatareadercontrol.h>
#include <qmediaavailabilitycontrol.h>
+#include "qdeclarativeplaylist_p.h"
#include "qdeclarativemediametadata_p.h"
#include <QTimerEvent>
+#include <QtQml/qqmlengine.h>
QT_BEGIN_NAMESPACE
@@ -94,16 +96,19 @@ void QDeclarativeAudio::_q_availabilityChanged(QMultimedia::AvailabilityStatus)
QDeclarativeAudio::QDeclarativeAudio(QObject *parent)
: QObject(parent)
+ , m_playlist(0)
, m_autoPlay(false)
, m_autoLoad(true)
, m_loaded(false)
, m_muted(false)
, m_complete(false)
+ , m_emitPlaylistChanged(false)
, m_loopCount(1)
, m_runningCount(0)
, m_position(0)
, m_vol(1.0)
, m_playbackRate(1.0)
+ , m_audioRole(UnknownRole)
, m_playbackState(QMediaPlayer::StoppedState)
, m_status(QMediaPlayer::NoMedia)
, m_error(QMediaPlayer::ServiceMissingError)
@@ -144,11 +149,122 @@ QDeclarativeAudio::Availability QDeclarativeAudio::availability() const
return Availability(m_player->availability());
}
+/*!
+ \qmlproperty enumeration QtMultimedia::Audio::audioRole
+
+ This property holds the role of the audio stream. 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 setting the source property.
+
+ Supported values can be retrieved with supportedAudioRoles().
+
+ The value can be one of:
+ \list
+ \li UnknownRole - the role is unknown or undefined.
+ \li MusicRole - music.
+ \li VideoRole - soundtrack from a movie or a video.
+ \li VoiceCommunicationRole - voice communications, such as telephony.
+ \li AlarmRole - alarm.
+ \li NotificationRole - notification, such as an incoming e-mail or a chat request.
+ \li RingtoneRole - ringtone.
+ \li AccessibilityRole - for accessibility, such as with a screen reader.
+ \li SonificationRole - sonification, such as with user interface sounds.
+ \li GameRole - game audio.
+ \endlist
+
+ \since 5.6
+*/
+QDeclarativeAudio::AudioRole QDeclarativeAudio::audioRole() const
+{
+ return !m_complete ? m_audioRole : AudioRole(m_player->audioRole());
+}
+
+void QDeclarativeAudio::setAudioRole(QDeclarativeAudio::AudioRole audioRole)
+{
+ if (this->audioRole() == audioRole)
+ return;
+
+ if (m_complete) {
+ m_player->setAudioRole(QAudio::Role(audioRole));
+ } else {
+ m_audioRole = audioRole;
+ emit audioRoleChanged();
+ }
+}
+
+/*!
+ \qmlmethod list<int> QtMultimedia::Audio::supportedAudioRoles()
+
+ Returns a list of supported audio roles.
+
+ If setting the audio role is not supported, an empty list is returned.
+
+ \since 5.6
+ \sa audioRole
+*/
+QJSValue QDeclarativeAudio::supportedAudioRoles() const
+{
+ QJSEngine *engine = qmlEngine(this);
+
+ if (!m_complete)
+ return engine->newArray();
+
+ QList<QAudio::Role> roles = m_player->supportedAudioRoles();
+ int size = roles.size();
+
+ QJSValue result = engine->newArray(size);
+ for (int i = 0; i < size; ++i)
+ result.setProperty(i, roles.at(i));
+
+ return result;
+}
+
QUrl QDeclarativeAudio::source() const
{
return m_source;
}
+QDeclarativePlaylist *QDeclarativeAudio::playlist() const
+{
+ return m_playlist;
+}
+
+void QDeclarativeAudio::setPlaylist(QDeclarativePlaylist *playlist)
+{
+ if (playlist == m_playlist && m_source.isEmpty())
+ return;
+
+ if (!m_source.isEmpty()) {
+ m_source.clear();
+ emit sourceChanged();
+ }
+
+ m_playlist = playlist;
+ m_content = m_playlist ?
+ QMediaContent(m_playlist->mediaPlaylist(), QUrl(), false) : QMediaContent();
+ m_loaded = false;
+ if (m_complete && (m_autoLoad || m_content.isNull() || m_autoPlay)) {
+ if (m_error != QMediaPlayer::ServiceMissingError && m_error != QMediaPlayer::NoError) {
+ m_error = QMediaPlayer::NoError;
+ m_errorString = QString();
+
+ emit errorChanged();
+ }
+
+ if (!playlist)
+ m_emitPlaylistChanged = true;
+ m_player->setMedia(m_content, 0);
+ m_loaded = true;
+ }
+ else
+ emit playlistChanged();
+
+ if (m_autoPlay)
+ m_player->play();
+}
+
bool QDeclarativeAudio::autoPlay() const
{
return m_autoPlay;
@@ -166,9 +282,14 @@ void QDeclarativeAudio::setAutoPlay(bool autoplay)
void QDeclarativeAudio::setSource(const QUrl &url)
{
- if (url == m_source)
+ if (url == m_source && m_playlist == NULL)
return;
+ if (m_playlist) {
+ m_playlist = NULL;
+ emit playlistChanged();
+ }
+
m_source = url;
m_content = m_source.isEmpty() ? QMediaContent() : m_source;
m_loaded = false;
@@ -425,6 +546,18 @@ void QDeclarativeAudio::seek(int position)
\qmlproperty url QtMultimedia::Audio::source
This property holds the source URL of the media.
+
+ Setting the \l source property clears the current \l playlist, if any.
+*/
+
+/*!
+ \qmlproperty Playlist QtMultimedia::Audio::playlist
+
+ This property holds the playlist used by the media player.
+
+ Setting the \l playlist property resets the \l source to an empty string.
+
+ \since 5.6
*/
/*!
@@ -650,8 +783,8 @@ void QDeclarativeAudio::classBegin()
this, SLOT(_q_statusChanged()));
connect(m_player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
this, SLOT(_q_statusChanged()));
- connect(m_player, SIGNAL(mediaChanged(QMediaContent)),
- this, SIGNAL(sourceChanged()));
+ connect(m_player, SIGNAL(mediaChanged(const QMediaContent&)),
+ this, SLOT(_q_mediaChanged(const QMediaContent&)));
connect(m_player, SIGNAL(durationChanged(qint64)),
this, SIGNAL(durationChanged()));
connect(m_player, SIGNAL(positionChanged(qint64)),
@@ -672,6 +805,8 @@ void QDeclarativeAudio::classBegin()
this, SIGNAL(hasAudioChanged()));
connect(m_player, SIGNAL(videoAvailableChanged(bool)),
this, SIGNAL(hasVideoChanged()));
+ connect(m_player, SIGNAL(audioRoleChanged(QAudio::Role)),
+ this, SIGNAL(audioRoleChanged()));
m_error = m_player->availability() == QMultimedia::ServiceMissing ? QMediaPlayer::ServiceMissingError : QMediaPlayer::NoError;
@@ -694,6 +829,8 @@ void QDeclarativeAudio::componentComplete()
m_player->setMuted(m_muted);
if (!qFuzzyCompare(m_playbackRate, qreal(1.0)))
m_player->setPlaybackRate(m_playbackRate);
+ if (m_audioRole != UnknownRole)
+ m_player->setAudioRole(QAudio::Role(m_audioRole));
if (!m_content.isNull() && (m_autoLoad || m_autoPlay)) {
m_player->setMedia(m_content, 0);
@@ -752,6 +889,16 @@ void QDeclarativeAudio::_q_statusChanged()
}
}
+void QDeclarativeAudio::_q_mediaChanged(const QMediaContent &media)
+{
+ if (!media.playlist() && !m_emitPlaylistChanged) {
+ emit sourceChanged();
+ } else {
+ m_emitPlaylistChanged = false;
+ emit playlistChanged();
+ }
+}
+
/*!
\qmlproperty string QtMultimedia::Audio::errorString
@@ -965,6 +1112,45 @@ void QDeclarativeAudio::_q_statusChanged()
*/
/*!
+ \qmlproperty enumeration QtMultimedia::MediaPlayer::audioRole
+
+ This property holds the role of the audio stream. 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 setting the source property.
+
+ Supported values can be retrieved with supportedAudioRoles().
+
+ The value can be one of:
+ \list
+ \li UnknownRole - the role is unknown or undefined.
+ \li MusicRole - music.
+ \li VideoRole - soundtrack from a movie or a video.
+ \li VoiceCommunicationRole - voice communications, such as telephony.
+ \li AlarmRole - alarm.
+ \li NotificationRole - notification, such as an incoming e-mail or a chat request.
+ \li RingtoneRole - ringtone.
+ \li AccessibilityRole - for accessibility, such as with a screen reader.
+ \li SonificationRole - sonification, such as with user interface sounds.
+ \li GameRole - game audio.
+ \endlist
+
+ \since 5.6
+*/
+
+/*!
+ \qmlmethod list<int> QtMultimedia::MediaPlayer::supportedAudioRoles()
+
+ Returns a list of supported audio roles.
+
+ If setting the audio role is not supported, an empty list is returned.
+
+ \since 5.6
+ \sa audioRole
+*/
+
+/*!
\qmlmethod QtMultimedia::MediaPlayer::play()
Starts playback of the media.
@@ -992,6 +1178,18 @@ void QDeclarativeAudio::_q_statusChanged()
\qmlproperty url QtMultimedia::MediaPlayer::source
This property holds the source URL of the media.
+
+ Setting the \l source property clears the current \l playlist, if any.
+*/
+
+/*!
+ \qmlproperty Playlist QtMultimedia::MediaPlayer::playlist
+
+ This property holds the playlist used by the media player.
+
+ Setting the \l playlist property resets the \l source to an empty string.
+
+ \since 5.6
*/
/*!
diff --git a/src/imports/multimedia/qdeclarativeaudio_p.h b/src/imports/multimedia/qdeclarativeaudio_p.h
index d4840f207..d8363969d 100644
--- a/src/imports/multimedia/qdeclarativeaudio_p.h
+++ b/src/imports/multimedia/qdeclarativeaudio_p.h
@@ -48,6 +48,7 @@
#include <QtCore/qbasictimer.h>
#include <QtQml/qqmlparserstatus.h>
#include <QtQml/qqml.h>
+#include <QtQml/qjsvalue.h>
#include <qmediaplayer.h>
@@ -58,6 +59,7 @@ class QMediaPlayerControl;
class QMediaService;
class QMediaServiceProvider;
class QMetaDataReaderControl;
+class QDeclarativePlaylist;
class QDeclarativeMediaBaseAnimation;
class QDeclarativeMediaMetaData;
class QMediaAvailabilityControl;
@@ -66,6 +68,7 @@ class QDeclarativeAudio : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(QDeclarativePlaylist *playlist READ playlist WRITE setPlaylist NOTIFY playlistChanged REVISION 1)
Q_PROPERTY(int loops READ loopCount WRITE setLoopCount NOTIFY loopCountChanged)
Q_PROPERTY(PlaybackState playbackState READ playbackState NOTIFY playbackStateChanged)
Q_PROPERTY(bool autoPlay READ autoPlay WRITE setAutoPlay NOTIFY autoPlayChanged)
@@ -85,11 +88,13 @@ class QDeclarativeAudio : public QObject, public QQmlParserStatus
Q_PROPERTY(QDeclarativeMediaMetaData *metaData READ metaData CONSTANT)
Q_PROPERTY(QObject *mediaObject READ mediaObject NOTIFY mediaObjectChanged SCRIPTABLE false DESIGNABLE false)
Q_PROPERTY(Availability availability READ availability NOTIFY availabilityChanged)
+ Q_PROPERTY(AudioRole audioRole READ audioRole WRITE setAudioRole NOTIFY audioRoleChanged REVISION 1)
Q_ENUMS(Status)
Q_ENUMS(Error)
Q_ENUMS(Loop)
Q_ENUMS(PlaybackState)
Q_ENUMS(Availability)
+ Q_ENUMS(AudioRole)
Q_INTERFACES(QQmlParserStatus)
public:
enum Status
@@ -134,6 +139,19 @@ public:
ResourceMissing = QMultimedia::ResourceError
};
+ enum AudioRole {
+ UnknownRole = QAudio::UnknownRole,
+ AccessibilityRole = QAudio::AccessibilityRole,
+ AlarmRole = QAudio::AlarmRole,
+ GameRole = QAudio::GameRole,
+ MusicRole = QAudio::MusicRole,
+ NotificationRole = QAudio::NotificationRole,
+ RingtoneRole = QAudio::RingtoneRole,
+ SonificationRole = QAudio::SonificationRole,
+ VideoRole = QAudio::VideoRole,
+ VoiceCommunicationRole = QAudio::VoiceCommunicationRole
+ };
+
QDeclarativeAudio(QObject *parent = 0);
~QDeclarativeAudio();
@@ -152,9 +170,15 @@ public:
Availability availability() const;
+ AudioRole audioRole() const;
+ void setAudioRole(AudioRole audioRole);
+
QUrl source() const;
void setSource(const QUrl &url);
+ QDeclarativePlaylist *playlist() const;
+ void setPlaylist(QDeclarativePlaylist *playlist);
+
int loopCount() const;
void setLoopCount(int loopCount);
@@ -191,7 +215,11 @@ public Q_SLOTS:
void stop();
void seek(int position);
+ Q_REVISION(1) QJSValue supportedAudioRoles() const;
+
Q_SIGNALS:
+ Q_REVISION(1) void playlistChanged();
+
void sourceChanged();
void autoLoadChanged();
void loopCountChanged();
@@ -218,6 +246,8 @@ Q_SIGNALS:
void seekableChanged();
void playbackRateChanged();
+ Q_REVISION(1) void audioRoleChanged();
+
void availabilityChanged(Availability availability);
void errorChanged();
@@ -229,20 +259,24 @@ private Q_SLOTS:
void _q_error(QMediaPlayer::Error);
void _q_availabilityChanged(QMultimedia::AvailabilityStatus);
void _q_statusChanged();
+ void _q_mediaChanged(const QMediaContent&);
private:
Q_DISABLE_COPY(QDeclarativeAudio)
+ QDeclarativePlaylist *m_playlist;
bool m_autoPlay;
bool m_autoLoad;
bool m_loaded;
bool m_muted;
bool m_complete;
+ bool m_emitPlaylistChanged;
int m_loopCount;
int m_runningCount;
int m_position;
qreal m_vol;
qreal m_playbackRate;
+ AudioRole m_audioRole;
QMediaPlayer::State m_playbackState;
QMediaPlayer::MediaStatus m_status;
diff --git a/src/imports/multimedia/qdeclarativeplaylist.cpp b/src/imports/multimedia/qdeclarativeplaylist.cpp
new file mode 100644
index 000000000..bb785aa98
--- /dev/null
+++ b/src/imports/multimedia/qdeclarativeplaylist.cpp
@@ -0,0 +1,583 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativeplaylist_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype PlaylistItem
+ \instantiates QDeclarativePlaylistItem
+ \since 5.6
+
+ \inqmlmodule QtMultimedia
+ \ingroup multimedia_qml
+ \ingroup multimedia_audio_qml
+ \ingroup multimedia_video_qml
+ \brief Defines an item in a Playlist.
+
+ \sa Playlist
+*/
+
+/*!
+ \qmlproperty url QtMultimedia::PlaylistItem::source
+
+ This property holds the source URL of the item.
+
+ \sa Playlist
+*/
+QDeclarativePlaylistItem::QDeclarativePlaylistItem(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QUrl QDeclarativePlaylistItem::source() const
+{
+ return m_source;
+}
+
+void QDeclarativePlaylistItem::setSource(const QUrl &source)
+{
+ m_source = source;
+}
+
+/*!
+ \qmltype Playlist
+ \instantiates QDeclarativePlaylist
+ \since 5.6
+ \brief For specifying a list of media to be played.
+
+ \inqmlmodule QtMultimedia
+ \ingroup multimedia_qml
+ \ingroup multimedia_audio_qml
+ \ingroup multimedia_video_qml
+
+ The Playlist type provides a way to play a list of media with the MediaPlayer, Audio and Video
+ types. It can be used as a data source for view elements (such as ListView) and other elements
+ that interact with model data (such as Repeater). When used as a data model, each playlist
+ item's source URL can be accessed using the \c source role.
+
+ \qml
+ import QtQuick 2.0
+ import QtMultimedia 5.6
+
+ Item {
+ width: 400;
+ height: 300;
+
+ Audio {
+ id: player;
+ playlist: Playlist {
+ id: playlist
+ PlaylistItem { source: "song1.ogg"; }
+ PlaylistItem { source: "song2.ogg"; }
+ PlaylistItem { source: "song3.ogg"; }
+ }
+ }
+
+ ListView {
+ model: playlist;
+ delegate: Text {
+ font.pixelSize: 16;
+ text: source;
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent;
+ onPressed: {
+ if (player.playbackState != Audio.PlayingState) {
+ player.play();
+ } else {
+ player.pause();
+ }
+ }
+ }
+ }
+ \endqml
+
+ \sa MediaPlayer, Audio, Video
+*/
+
+void QDeclarativePlaylist::_q_mediaAboutToBeInserted(int start, int end)
+{
+ emit itemAboutToBeInserted(start, end);
+
+ beginInsertRows(QModelIndex(), start, end);
+}
+
+void QDeclarativePlaylist::_q_mediaInserted(int start, int end)
+{
+ endInsertRows();
+
+ emit itemCountChanged();
+ emit itemInserted(start, end);
+}
+
+void QDeclarativePlaylist::_q_mediaAboutToBeRemoved(int start, int end)
+{
+ emit itemAboutToBeRemoved(start, end);
+
+ beginRemoveRows(QModelIndex(), start, end);
+}
+
+void QDeclarativePlaylist::_q_mediaRemoved(int start, int end)
+{
+ endRemoveRows();
+
+ emit itemCountChanged();
+ emit itemRemoved(start, end);
+}
+
+void QDeclarativePlaylist::_q_mediaChanged(int start, int end)
+{
+ emit dataChanged(createIndex(start, 0), createIndex(end, 0));
+ emit itemChanged(start, end);
+}
+
+void QDeclarativePlaylist::_q_loadFailed()
+{
+ m_error = m_playlist->error();
+ m_errorString = m_playlist->errorString();
+
+ emit error(Error(m_error), m_errorString);
+ emit errorChanged();
+ emit loadFailed();
+}
+
+QDeclarativePlaylist::QDeclarativePlaylist(QObject *parent)
+ : QAbstractListModel(parent)
+ , m_playlist(0)
+ , m_error(QMediaPlaylist::NoError)
+ , m_readOnly(false)
+{
+}
+
+QDeclarativePlaylist::~QDeclarativePlaylist()
+{
+ delete m_playlist;
+}
+
+/*!
+ \qmlproperty enumeration QtMultimedia::Playlist::playbackMode
+
+ This property holds the order in which items in the playlist are played.
+
+ \table
+ \header \li Value \li Description
+ \row \li CurrentItemOnce
+ \li The current item is played only once.
+ \row \li CurrentItemInLoop
+ \li The current item is played repeatedly in a loop.
+ \row \li Sequential
+ \li 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.
+ \row \li Loop
+ \li Playback restarts at the first item after the last has finished playing.
+ \row \li Random
+ \li Play items in random order.
+ \endtable
+ */
+QDeclarativePlaylist::PlaybackMode QDeclarativePlaylist::playbackMode() const
+{
+ return PlaybackMode(m_playlist->playbackMode());
+}
+
+void QDeclarativePlaylist::setPlaybackMode(PlaybackMode mode)
+{
+ if (playbackMode() == mode)
+ return;
+
+ m_playlist->setPlaybackMode(QMediaPlaylist::PlaybackMode(mode));
+}
+
+/*!
+ \qmlproperty url QtMultimedia::Playlist::currentItemsource
+
+ This property holds the source URL of the current item in the playlist.
+ */
+QUrl QDeclarativePlaylist::currentItemSource() const
+{
+ return m_playlist->currentMedia().canonicalUrl();
+}
+
+/*!
+ \qmlproperty int QtMultimedia::Playlist::currentIndex
+
+ This property holds the position of the current item in the playlist.
+ */
+int QDeclarativePlaylist::currentIndex() const
+{
+ return m_playlist->currentIndex();
+}
+
+void QDeclarativePlaylist::setCurrentIndex(int index)
+{
+ if (currentIndex() == index)
+ return;
+
+ m_playlist->setCurrentIndex(index);
+}
+
+/*!
+ \qmlproperty int QtMultimedia::Playlist::itemCount
+
+ This property holds the number of items in the playlist.
+ */
+int QDeclarativePlaylist::itemCount() const
+{
+ return m_playlist->mediaCount();
+}
+
+/*!
+ \qmlproperty bool QtMultimedia::Playlist::readOnly
+
+ This property indicates if the playlist can be modified.
+ */
+bool QDeclarativePlaylist::readOnly() const
+{
+ // There's no signal to tell whether or not the read only state changed, so we consider it fixed
+ // after its initial retrieval in componentComplete().
+ return m_readOnly;
+}
+
+/*!
+ \qmlproperty enumeration QtMultimedia::Playlist::error
+
+ This property holds the error condition of the playlist.
+
+ \table
+ \header \li Value \li Description
+ \row \li NoError
+ \li No errors
+ \row \li FormatError
+ \li Format error.
+ \row \li FormatNotSupportedError
+ \li Format not supported.
+ \row \li NetworkError
+ \li Network error.
+ \row \li AccessDeniedError
+ \li Access denied error.
+ \endtable
+ */
+QDeclarativePlaylist::Error QDeclarativePlaylist::error() const
+{
+ return Error(m_error);
+}
+
+/*!
+ \qmlproperty string QtMultimedia::Playlist::errorString
+
+ This property holds a string describing the current error condition of the playlist.
+*/
+QString QDeclarativePlaylist::errorString() const
+{
+ return m_errorString;
+}
+
+/*!
+ \qmlmethod url QtMultimedia::Playlist::itemSource(index)
+
+ Returns the source URL of the item at the given \a index in the playlist.
+*/
+QUrl QDeclarativePlaylist::itemSource(int index)
+{
+ return m_playlist->media(index).canonicalUrl();
+}
+
+/*!
+ \qmlmethod int QtMultimedia::Playlist::nextIndex(steps)
+
+ Returns the index of the item in the playlist which would be current after calling next()
+ \a steps times.
+
+ Returned value depends on the size of the playlist, the current position and the playback mode.
+
+ \sa playbackMode, previousIndex()
+*/
+int QDeclarativePlaylist::nextIndex(int steps)
+{
+ return m_playlist->nextIndex(steps);
+}
+
+/*!
+ \qmlmethod int QtMultimedia::Playlist::previousIndex(steps)
+
+ Returns the index of the item in the playlist which would be current after calling previous()
+ \a steps times.
+
+ Returned value depends on the size of the playlist, the current position and the playback mode.
+
+ \sa playbackMode, nextIndex()
+*/
+int QDeclarativePlaylist::previousIndex(int steps)
+{
+ return m_playlist->previousIndex(steps);
+}
+
+/*!
+ \qmlmethod QtMultimedia::Playlist::next()
+
+ Advances to the next item in the playlist.
+*/
+void QDeclarativePlaylist::next()
+{
+ m_playlist->next();
+}
+
+/*!
+ \qmlmethod QtMultimedia::Playlist::previous()
+
+ Returns to the previous item in the playlist.
+*/
+void QDeclarativePlaylist::previous()
+{
+ m_playlist->previous();
+}
+
+/*!
+ \qmlmethod QtMultimedia::Playlist::shuffle()
+
+ Shuffles items in the playlist.
+*/
+void QDeclarativePlaylist::shuffle()
+{
+ m_playlist->shuffle();
+}
+
+/*!
+ \qmlmethod QtMultimedia::Playlist::load(location, format)
+
+ Loads a playlist from the given \a location. If \a format is specified, it is used, otherwise
+ the format is guessed from the location name and the data.
+
+ New items are appended to the playlist.
+
+ \c onloaded() is emitted if the playlist loads successfully, otherwise \c onLoadFailed() is
+ emitted with \l error and \l errorString defined accordingly.
+*/
+void QDeclarativePlaylist::load(const QUrl &location, const QString &format)
+{
+ m_error = QMediaPlaylist::NoError;
+ m_errorString = QString();
+ emit errorChanged();
+ m_playlist->load(location, format.toLatin1().constData());
+}
+
+/*!
+ \qmlmethod bool QtMultimedia::Playlist::save(location, format)
+
+ Saves the playlist to the given \a location. If \a format is specified, it is used, otherwise
+ the format is guessed from the location name.
+
+ Returns true if the playlist is saved successfully.
+*/
+bool QDeclarativePlaylist::save(const QUrl &location, const QString &format)
+{
+ return m_playlist->save(location, format.toLatin1().constData());
+}
+
+/*!
+ \qmlmethod bool QtMultimedia::Playlist::addItem(source)
+
+ Appends the \a source URL to the playlist.
+
+ Returns true if the \a source is added successfully.
+*/
+bool QDeclarativePlaylist::addItem(const QUrl &source)
+{
+ return m_playlist->addMedia(QMediaContent(source));
+}
+
+/*!
+ \qmlmethod bool QtMultimedia::Playlist::insertItem(index, source)
+
+ Inserts the \a source URL to the playlist at the given \a index.
+
+ Returns true if the \a source is added successfully.
+*/
+bool QDeclarativePlaylist::insertItem(int index, const QUrl &source)
+{
+ return m_playlist->insertMedia(index, QMediaContent(source));
+}
+
+/*!
+ \qmlmethod bool QtMultimedia::Playlist::removeItem(index)
+
+ Removed the item at the given \a index from the playlist.
+
+ Returns true if the \a source is removed successfully.
+*/
+bool QDeclarativePlaylist::removeItem(int index)
+{
+ return m_playlist->removeMedia(index);
+}
+
+/*!
+ \qmlmethod bool QtMultimedia::Playlist::clear()
+
+ Removes all the items from the playlist.
+
+ Returns true if the operation is successful.
+*/
+bool QDeclarativePlaylist::clear()
+{
+ return m_playlist->clear();
+}
+
+int QDeclarativePlaylist::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+
+ return m_playlist->mediaCount();
+}
+
+QVariant QDeclarativePlaylist::data(const QModelIndex &index, int role) const
+{
+ Q_UNUSED(role);
+
+ if (!index.isValid())
+ return QVariant();
+
+ return m_playlist->media(index.row()).canonicalUrl();
+}
+
+QHash<int, QByteArray> QDeclarativePlaylist::roleNames() const
+{
+ QHash<int, QByteArray> roleNames;
+ roleNames[SourceRole] = "source";
+ return roleNames;
+}
+
+void QDeclarativePlaylist::classBegin()
+{
+ m_playlist = new QMediaPlaylist(this);
+
+ connect(m_playlist, SIGNAL(currentIndexChanged(int)),
+ this, SIGNAL(currentIndexChanged()));
+ connect(m_playlist, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)),
+ this, SIGNAL(playbackModeChanged()));
+ connect(m_playlist, SIGNAL(currentMediaChanged(QMediaContent)),
+ this, SIGNAL(currentItemSourceChanged()));
+ connect(m_playlist, SIGNAL(mediaAboutToBeInserted(int,int)),
+ this, SLOT(_q_mediaAboutToBeInserted(int,int)));
+ connect(m_playlist, SIGNAL(mediaInserted(int,int)),
+ this, SLOT(_q_mediaInserted(int,int)));
+ connect(m_playlist, SIGNAL(mediaAboutToBeRemoved(int,int)),
+ this, SLOT(_q_mediaAboutToBeRemoved(int,int)));
+ connect(m_playlist, SIGNAL(mediaRemoved(int,int)),
+ this, SLOT(_q_mediaRemoved(int,int)));
+ connect(m_playlist, SIGNAL(mediaChanged(int,int)),
+ this, SLOT(_q_mediaChanged(int,int)));
+ connect(m_playlist, SIGNAL(loaded()),
+ this, SIGNAL(loaded()));
+ connect(m_playlist, SIGNAL(loadFailed()),
+ this, SLOT(_q_loadFailed()));
+
+ if (m_playlist->isReadOnly()) {
+ m_readOnly = true;
+ emit readOnlyChanged();
+ }
+}
+
+void QDeclarativePlaylist::componentComplete()
+{
+}
+
+/*!
+ \qmlsignal QtMultimedia::Audio::itemAboutToBeInserted(start, end)
+
+ This signal is emitted when items are to be inserted into the playlist at \a start and ending at
+ \a end.
+
+ The corresponding handler is \c onItemAboutToBeInserted.
+*/
+
+/*!
+ \qmlsignal QtMultimedia::Audio::itemInserted(start, end)
+
+ This signal is emitted after items have been inserted into the playlist. The new items are those
+ between \a start and \a end inclusive.
+
+ The corresponding handler is \c onItemInserted.
+*/
+
+/*!
+ \qmlsignal QtMultimedia::Audio::itemAboutToBeRemoved(start, end)
+
+ This signal emitted when items are to be deleted from the playlist at \a start and ending at
+ \a end.
+
+ The corresponding handler is \c onItemAboutToBeRemoved.
+*/
+
+/*!
+ \qmlsignal QtMultimedia::Audio::itemRemoved(start, end)
+
+ This signal is emitted after items have been removed from the playlist. The removed items are
+ those between \a start and \a end inclusive.
+
+ The corresponding handler is \c onMediaRemoved.
+*/
+
+/*!
+ \qmlsignal QtMultimedia::Audio::itemChanged(start, end)
+
+ This signal is emitted after items have been changed in the playlist between \a start and
+ \a end positions inclusive.
+
+ The corresponding handler is \c onItemChanged.
+*/
+
+/*!
+ \qmlsignal QtMultimedia::Audio::loaded()
+
+ This signal is emitted when the playlist loading succeeded.
+
+ The corresponding handler is \c onLoaded.
+*/
+
+/*!
+ \qmlsignal QtMultimedia::Audio::loadFailed()
+
+ This signal is emitted when the playlist loading failed. \l error and \l errorString can be
+ checked for more information on the failure.
+
+ The corresponding handler is \c onLoadFailed.
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qdeclarativeplaylist_p.cpp"
diff --git a/src/imports/multimedia/qdeclarativeplaylist_p.h b/src/imports/multimedia/qdeclarativeplaylist_p.h
new file mode 100644
index 000000000..fd94135e6
--- /dev/null
+++ b/src/imports/multimedia/qdeclarativeplaylist_p.h
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEPLAYLIST_P_H
+#define QDECLARATIVEPLAYLIST_P_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/QAbstractListModel>
+#include <QtQml/qqmlparserstatus.h>
+#include <QtQml/qqml.h>
+
+#include <qmediaplaylist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativePlaylistItem : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl source READ source WRITE setSource)
+
+public:
+ QDeclarativePlaylistItem(QObject *parent = 0);
+
+ QUrl source() const;
+ void setSource(const QUrl &source);
+
+private:
+ QUrl m_source;
+};
+
+class QDeclarativePlaylist : public QAbstractListModel, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_PROPERTY(PlaybackMode playbackMode READ playbackMode WRITE setPlaybackMode NOTIFY playbackModeChanged)
+ Q_PROPERTY(QUrl currentItemSource READ currentItemSource NOTIFY currentItemSourceChanged)
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
+ Q_PROPERTY(int itemCount READ itemCount NOTIFY itemCountChanged)
+ Q_PROPERTY(bool readOnly READ readOnly NOTIFY readOnlyChanged)
+ Q_PROPERTY(Error error READ error NOTIFY errorChanged)
+ Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged)
+ Q_PROPERTY(QQmlListProperty<QDeclarativePlaylistItem> items READ items DESIGNABLE false)
+ Q_ENUMS(PlaybackMode)
+ Q_ENUMS(Error)
+ Q_INTERFACES(QQmlParserStatus)
+ Q_CLASSINFO("DefaultProperty", "items")
+
+public:
+ enum PlaybackMode
+ {
+ CurrentItemOnce = QMediaPlaylist::CurrentItemOnce,
+ CurrentItemInLoop = QMediaPlaylist::CurrentItemInLoop,
+ Sequential = QMediaPlaylist::Sequential,
+ Loop = QMediaPlaylist::Loop,
+ Random = QMediaPlaylist::Random
+ };
+ enum Error
+ {
+ NoError = QMediaPlaylist::NoError,
+ FormatError = QMediaPlaylist::FormatError,
+ FormatNotSupportedError = QMediaPlaylist::FormatNotSupportedError,
+ NetworkError = QMediaPlaylist::NetworkError,
+ AccessDeniedError = QMediaPlaylist::AccessDeniedError
+ };
+ enum Roles
+ {
+ SourceRole = Qt::UserRole + 1
+ };
+
+ QDeclarativePlaylist(QObject *parent = 0);
+ ~QDeclarativePlaylist();
+
+ PlaybackMode playbackMode() const;
+ void setPlaybackMode(PlaybackMode playbackMode);
+ QUrl currentItemSource() const;
+ int currentIndex() const;
+ void setCurrentIndex(int currentIndex);
+ int itemCount() const;
+ bool readOnly() const;
+ Error error() const;
+ QString errorString() const;
+ QMediaPlaylist *mediaPlaylist() const { return m_playlist; }
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ QHash<int, QByteArray> roleNames() const;
+
+ void classBegin();
+ void componentComplete();
+
+ QQmlListProperty<QDeclarativePlaylistItem> items() {
+ return QQmlListProperty<QDeclarativePlaylistItem>(
+ this, 0, item_append, item_count, 0, item_clear);
+ }
+ static void item_append(QQmlListProperty<QDeclarativePlaylistItem> *list,
+ QDeclarativePlaylistItem* item) {
+ static_cast<QDeclarativePlaylist*>(list->object)->addItem(item->source());
+ }
+ static int item_count(QQmlListProperty<QDeclarativePlaylistItem> *list) {
+ return static_cast<QDeclarativePlaylist*>(list->object)->itemCount();
+ }
+ static void item_clear(QQmlListProperty<QDeclarativePlaylistItem> *list) {
+ static_cast<QDeclarativePlaylist*>(list->object)->clear();
+ }
+
+public Q_SLOTS:
+ QUrl itemSource(int index);
+ int nextIndex(int steps = 1);
+ int previousIndex(int steps = 1);
+ void next();
+ void previous();
+ void shuffle();
+ void load(const QUrl &location, const QString &format = QString());
+ bool save(const QUrl &location, const QString &format = QString());
+ bool addItem(const QUrl &source);
+ bool insertItem(int index, const QUrl &source);
+ bool removeItem(int index);
+ bool clear();
+
+Q_SIGNALS:
+ void playbackModeChanged();
+ void currentItemSourceChanged();
+ void currentIndexChanged();
+ void itemCountChanged();
+ void readOnlyChanged();
+ void errorChanged();
+
+ void itemAboutToBeInserted(int start, int end);
+ void itemInserted(int start, int end);
+ void itemAboutToBeRemoved(int start, int end);
+ void itemRemoved(int start, int end);
+ void itemChanged(int start, int end);
+ void loaded();
+ void loadFailed();
+
+ void error(QDeclarativePlaylist::Error error, const QString &errorString);
+
+private Q_SLOTS:
+ void _q_mediaAboutToBeInserted(int start, int end);
+ void _q_mediaInserted(int start, int end);
+ void _q_mediaAboutToBeRemoved(int start, int end);
+ void _q_mediaRemoved(int start, int end);
+ void _q_mediaChanged(int start, int end);
+ void _q_loadFailed();
+
+private:
+ Q_DISABLE_COPY(QDeclarativePlaylist)
+
+ QMediaPlaylist *m_playlist;
+ QString m_errorString;
+ QMediaPlaylist::Error m_error;
+ bool m_readOnly;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QT_PREPEND_NAMESPACE(QDeclarativePlaylistItem))
+QML_DECLARE_TYPE(QT_PREPEND_NAMESPACE(QDeclarativePlaylist))
+
+#endif
diff --git a/src/imports/multimedia/qdeclarativetorch_p.h b/src/imports/multimedia/qdeclarativetorch_p.h
index b7ef55755..db7f99ed5 100644
--- a/src/imports/multimedia/qdeclarativetorch_p.h
+++ b/src/imports/multimedia/qdeclarativetorch_p.h
@@ -35,6 +35,17 @@
#ifndef QDECLARATIVETORCH_P_H
#define QDECLARATIVETORCH_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>
#include <QtQml/qqml.h>
#include <qcamera.h>
diff --git a/src/multimedia/audio/qaudio.cpp b/src/multimedia/audio/qaudio.cpp
index 8b452a118..45540a2b9 100644
--- a/src/multimedia/audio/qaudio.cpp
+++ b/src/multimedia/audio/qaudio.cpp
@@ -42,12 +42,14 @@ static void qRegisterAudioMetaTypes()
qRegisterMetaType<QAudio::Error>();
qRegisterMetaType<QAudio::State>();
qRegisterMetaType<QAudio::Mode>();
+ qRegisterMetaType<QAudio::Role>();
}
Q_CONSTRUCTOR_FUNCTION(qRegisterAudioMetaTypes)
/*!
\namespace QAudio
+ \ingroup multimedia-namespaces
\brief The QAudio namespace contains enums used by the audio classes.
\inmodule QtMultimedia
\ingroup multimedia
@@ -83,6 +85,26 @@ Q_CONSTRUCTOR_FUNCTION(qRegisterAudioMetaTypes)
\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
+
+ \since 5.6
+ \sa QMediaPlayer::setAudioRole()
+*/
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, QAudio::Error error)
{
@@ -143,6 +165,45 @@ QDebug operator<<(QDebug dbg, QAudio::Mode mode)
}
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;
+ }
+ return dbg;
+}
#endif
diff --git a/src/multimedia/audio/qaudio.h b/src/multimedia/audio/qaudio.h
index 63953145c..2ee66bcc1 100644
--- a/src/multimedia/audio/qaudio.h
+++ b/src/multimedia/audio/qaudio.h
@@ -51,12 +51,26 @@ namespace QAudio
enum Error { NoError, OpenError, IOError, UnderrunError, FatalError };
enum State { ActiveState, SuspendedState, StoppedState, IdleState };
enum Mode { AudioInput, AudioOutput };
+
+ enum Role {
+ UnknownRole,
+ MusicRole,
+ VideoRole,
+ VoiceCommunicationRole,
+ AlarmRole,
+ NotificationRole,
+ RingtoneRole,
+ AccessibilityRole,
+ SonificationRole,
+ GameRole
+ };
}
#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);
#endif
QT_END_NAMESPACE
@@ -64,5 +78,6 @@ QT_END_NAMESPACE
Q_DECLARE_METATYPE(QAudio::Error)
Q_DECLARE_METATYPE(QAudio::State)
Q_DECLARE_METATYPE(QAudio::Mode)
+Q_DECLARE_METATYPE(QAudio::Role)
#endif // QAUDIO_H
diff --git a/src/multimedia/audio/qaudiobuffer_p.h b/src/multimedia/audio/qaudiobuffer_p.h
index 98e2a1868..a98d6d3bf 100644
--- a/src/multimedia/audio/qaudiobuffer_p.h
+++ b/src/multimedia/audio/qaudiobuffer_p.h
@@ -34,6 +34,17 @@
#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 <qtmultimediadefs.h>
#include <qmultimedia.h>
diff --git a/src/multimedia/camera/qcamera.cpp b/src/multimedia/camera/qcamera.cpp
index ea1b6beb6..bec894b75 100644
--- a/src/multimedia/camera/qcamera.cpp
+++ b/src/multimedia/camera/qcamera.cpp
@@ -931,7 +931,7 @@ QCamera::LockStatus QCamera::lockStatus() const
}
/*!
- Returns the status of camera settings \a lock.
+ Returns the lock status for a given \a lockType.
*/
QCamera::LockStatus QCamera::lockStatus(QCamera::LockType lockType) const
{
diff --git a/src/multimedia/controls/controls.pri b/src/multimedia/controls/controls.pri
index b19532fdc..7ab2e51c4 100644
--- a/src/multimedia/controls/controls.pri
+++ b/src/multimedia/controls/controls.pri
@@ -36,7 +36,8 @@ PUBLIC_HEADERS += \
controls/qvideowindowcontrol.h \
controls/qmediaaudioprobecontrol.h \
controls/qmediavideoprobecontrol.h \
- controls/qmediaavailabilitycontrol.h
+ controls/qmediaavailabilitycontrol.h \
+ controls/qaudiorolecontrol.h
PRIVATE_HEADERS += \
controls/qmediaplaylistcontrol_p.h \
@@ -79,5 +80,6 @@ SOURCES += \
controls/qaudioencodersettingscontrol.cpp \
controls/qaudioinputselectorcontrol.cpp \
controls/qaudiooutputselectorcontrol.cpp \
- controls/qvideodeviceselectorcontrol.cpp
+ controls/qvideodeviceselectorcontrol.cpp \
+ controls/qaudiorolecontrol.cpp
diff --git a/src/multimedia/controls/qaudiorolecontrol.cpp b/src/multimedia/controls/qaudiorolecontrol.cpp
new file mode 100644
index 000000000..62696f013
--- /dev/null
+++ b/src/multimedia/controls/qaudiorolecontrol.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmediacontrol_p.h"
+#include "qaudiorolecontrol.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAudioRoleControl
+ \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.
+ */
+
+
+#include "moc_qaudiorolecontrol.cpp"
+QT_END_NAMESPACE
diff --git a/src/multimedia/controls/qaudiorolecontrol.h b/src/multimedia/controls/qaudiorolecontrol.h
new file mode 100644
index 000000000..983b2aed0
--- /dev/null
+++ b/src/multimedia/controls/qaudiorolecontrol.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $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 = 0);
+};
+
+#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/qmediaplayercontrol.cpp b/src/multimedia/controls/qmediaplayercontrol.cpp
index 9ea6fde82..0c891a1d4 100644
--- a/src/multimedia/controls/qmediaplayercontrol.cpp
+++ b/src/multimedia/controls/qmediaplayercontrol.cpp
@@ -111,6 +111,7 @@ QMediaPlayerControl::QMediaPlayerControl(QObject *parent):
Returns the status of the current media.
*/
+
/*!
\fn QMediaPlayerControl::mediaStatusChanged(QMediaPlayer::MediaStatus status)
diff --git a/src/multimedia/doc/qtmultimedia-dita.qdocconf b/src/multimedia/doc/qtmultimedia-dita.qdocconf
deleted file mode 100644
index cb8a73c4f..000000000
--- a/src/multimedia/doc/qtmultimedia-dita.qdocconf
+++ /dev/null
@@ -1,32 +0,0 @@
-# Name of the project.
-project = Qt Multimedia
-
-# Directories in which to search for files to document and images.
-# By default set to the root directory of the project for sources
-# and headers and qdoc will therefore generate output for each file.
-# Images should be placed in <rootdir>/dic/images and examples in
-# <rootdir>/examples.
-# Paths are relative to the location of this file.
-exampledirs += ../src/examples \
- ../.. \
- ../../examples
-
-headerdirs += ../src \
- ../../src
-
-imagedirs += ../src/images \
-
-sourcedirs += ../src \
- ../../src
-
-excludedirs +=
-
-#Do not change the variables after this line unless you know what you are doing.
-
-outputdir = ../ditaxml
-outputformats = DITAXML
-
-examples.fileextensions = "*.cpp *.h *.js *.svg *.xml *.ui *.qml"
-examples.imageextensions = "*.png *.jpeg *.jpg *.gif *.mng"
-headers.fileextensions = "*.h *.ch *.h++ *.hh *.hpp *.hxx"
-sources.fileextensions = "*.cpp *.qdoc *.mm *.qml"
diff --git a/src/multimedia/doc/qtmultimedia.qdocconf b/src/multimedia/doc/qtmultimedia.qdocconf
index d917062a2..cd16a3f5d 100644
--- a/src/multimedia/doc/qtmultimedia.qdocconf
+++ b/src/multimedia/doc/qtmultimedia.qdocconf
@@ -18,21 +18,27 @@ qhp.QtMultimedia.indexTitle = Qt Multimedia
qhp.QtMultimedia.virtualFolder = qtmultimedia
# For listing child nodes in Qt Creator or Assistant.
-qhp.QtMultimedia.subprojects = classes qmltypes
+qhp.QtMultimedia.subprojects = classes qmltypes examples
qhp.QtMultimedia.subprojects.classes.title = C++ Classes
qhp.QtMultimedia.subprojects.classes.indexTitle = Qt Multimedia C++ Classes
qhp.QtMultimedia.subprojects.classes.selectors = class fake:headerfile
qhp.QtMultimedia.subprojects.classes.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.sortPages = true
-exampledirs += ../../../examples/multimedia \
+qhp.QtMultimedia.subprojects.examples.title = Examples
+qhp.QtMultimedia.subprojects.examples.indexTitle = Qt Multimedia Examples
+qhp.QtMultimedia.subprojects.examples.selectors = doc:example
+qhp.QtMultimedia.subprojects.examples.sortPages = true
+
+exampledirs += ../../../examples \
snippets
# Specify example install dir under QT_INSTALL_EXAMPLES
-examplesinstallpath = multimedia
+examplesinstallpath = qtmultimedia/multimedia
headerdirs += ../..
@@ -40,9 +46,9 @@ imagedirs += src/images \
sourcedirs += ../..
-excludedirs += ../../multimediawidgets
+#excludedirs += ../../multimediawidgets
-depends += qtcore qtdoc qtgui qtquick qtqml qtmultimediawidgets qtwidgets
+depends += qtcore qtdoc qtgui qtquick qtqml qtwidgets
navigation.landingpage = "Qt Multimedia"
navigation.cppclassespage = "Qt Multimedia C++ Classes"
diff --git a/src/multimedia/doc/src/multimediabackend.qdoc b/src/multimedia/doc/src/multimediabackend.qdoc
index b56f1040d..0622f5f09 100644
--- a/src/multimedia/doc/src/multimediabackend.qdoc
+++ b/src/multimedia/doc/src/multimediabackend.qdoc
@@ -37,14 +37,14 @@
\section1 Overview
-A multimedia backend provides the glue between platform specific libraries, and
+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.
@@ -94,7 +94,6 @@ In general, adding a new media service provider is outside the scope of this doc
For best results, consult the existing provider source code, and seek assistance on the relevant
mailing lists and IRC channels.
-\omit
The base class for creating new service providers is \l{QMediaServiceProvider}.
The user must implement the \l{QMediaServiceProvider::requestService()}{requestService()}
function
diff --git a/src/multimedia/doc/src/qtmultimedia-cpp.qdoc b/src/multimedia/doc/src/qtmultimedia-cpp.qdoc
index 8460238e7..44623beca 100644
--- a/src/multimedia/doc/src/qtmultimedia-cpp.qdoc
+++ b/src/multimedia/doc/src/qtmultimedia-cpp.qdoc
@@ -27,16 +27,33 @@
/*!
\module QtMultimedia
- \title Qt Multimedia C++ Classes
+ \title Qt Multimedia Module C++ Classes
\ingroup modules
\qtvariable multimedia
\brief The \l {Qt Multimedia} module provides audio, video, radio and camera
functionality.
+*/
+
+/*!
+ \page qtmultimedia-modules.html
+ \title Qt Multimedia C++ Classes
+ \brief Provides C++ class for multimedia use cases.
The C++ classes provide more control over the multimedia content than the
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}.
+
+ \section1 Namespaces
+ \annotatedlist multimedia-namespaces
+
+ \section1 Classes
+
+ \section2 Qt Multimedia Module
+ \generatelist {classesbymodule QtMultimedia}
+
+ \section2 Qt Multimedia Widgets Module
+ \generatelist {classesbymodule QtMultimediaWidgets}
*/
diff --git a/src/multimedia/doc/src/qtmultimedia-index.qdoc b/src/multimedia/doc/src/qtmultimedia-index.qdoc
index 65fcb210b..e51ec97e0 100644
--- a/src/multimedia/doc/src/qtmultimedia-index.qdoc
+++ b/src/multimedia/doc/src/qtmultimedia-index.qdoc
@@ -35,10 +35,18 @@
and C++ classes to handle multimedia content. It also provides necessary
APIs to access the camera and radio functionality. The included
\l{Qt Audio Engine QML Types}{Qt Audio Engine} provides types for
- 3D positional audio playback and management.
+ 3D positional audio playback and content management.
- The \l{Qt Multimedia Widgets} module provides widget based multimedia
- classes.
+ 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.
+ \row
+ \li \l{QtMultimediaWidgets}{Qt Multimedia Widgets}
+ \li Provides the widget-based multimedia API.
+ \endtable
\section1 Getting Started
@@ -54,6 +62,7 @@
\code
#include <QtMultimedia>
+ #include <QtMultimediaWidgets>
\endcode
\note If you are using a few classes from this module, we recommend
@@ -63,7 +72,7 @@
\c {qmake} project file:
\code
- QT += multimedia
+ QT += multimedia multimediawidgets
\endcode
\section1 QML Types and C++ Classes
@@ -79,6 +88,9 @@
\li \l {QtMultimedia::Audio}{Audio}
\li Add audio playback functionality to a scene
\row
+ \li \l {QtMultimedia::Playlist}{Playlist}
+ \li For specifying a list of media to be played.
+ \row
\li \l {QtMultimedia::Camera}{Camera}
\li Access camera viewfinder frames
\row
@@ -117,6 +129,9 @@
\li QMediaPlayer
\li Playback media from a source.
\row
+ \li QMediaPlaylist
+ \li List of media to be played.
+ \row
\li QRadioTuner
\li Access radio device.
\row
diff --git a/src/multimedia/gsttools_headers/gstvideoconnector_p.h b/src/multimedia/gsttools_headers/gstvideoconnector_p.h
index 43a56f5d8..1407dcd17 100644
--- a/src/multimedia/gsttools_headers/gstvideoconnector_p.h
+++ b/src/multimedia/gsttools_headers/gstvideoconnector_p.h
@@ -34,6 +34,17 @@
#ifndef QGSTVIDEOCONNECTOR_H
#define QGSTVIDEOCONNECTOR_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <gst/gst.h>
G_BEGIN_DECLS
diff --git a/src/multimedia/gsttools_headers/qgstappsrc_p.h b/src/multimedia/gsttools_headers/qgstappsrc_p.h
index ec54af0d1..5b32911e4 100644
--- a/src/multimedia/gsttools_headers/qgstappsrc_p.h
+++ b/src/multimedia/gsttools_headers/qgstappsrc_p.h
@@ -34,6 +34,17 @@
#ifndef QGSTAPPSRC_H
#define QGSTAPPSRC_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <QtCore/qobject.h>
#include <QtCore/qiodevice.h>
diff --git a/src/multimedia/gsttools_headers/qgstcodecsinfo_p.h b/src/multimedia/gsttools_headers/qgstcodecsinfo_p.h
index 8e5867c16..183768a66 100644
--- a/src/multimedia/gsttools_headers/qgstcodecsinfo_p.h
+++ b/src/multimedia/gsttools_headers/qgstcodecsinfo_p.h
@@ -34,6 +34,17 @@
#ifndef QGSTCODECSINFO_H
#define QGSTCODECSINFO_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists 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/qstringlist.h>
diff --git a/src/multimedia/gsttools_headers/qgstreameraudioinputselector_p.h b/src/multimedia/gsttools_headers/qgstreameraudioinputselector_p.h
index 20259f411..75ce9f5ea 100644
--- a/src/multimedia/gsttools_headers/qgstreameraudioinputselector_p.h
+++ b/src/multimedia/gsttools_headers/qgstreameraudioinputselector_p.h
@@ -34,6 +34,17 @@
#ifndef QGSTREAMERAUDIOINPUTSELECTOR_H
#define QGSTREAMERAUDIOINPUTSELECTOR_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <qaudioinputselectorcontrol.h>
#include <QtCore/qstringlist.h>
diff --git a/src/multimedia/gsttools_headers/qgstreameraudioprobecontrol_p.h b/src/multimedia/gsttools_headers/qgstreameraudioprobecontrol_p.h
index 3246ac2f6..9c25a53a4 100644
--- a/src/multimedia/gsttools_headers/qgstreameraudioprobecontrol_p.h
+++ b/src/multimedia/gsttools_headers/qgstreameraudioprobecontrol_p.h
@@ -34,6 +34,17 @@
#ifndef QGSTREAMERAUDIOPROBECONTROL_H
#define QGSTREAMERAUDIOPROBECONTROL_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <gst/gst.h>
#include <qmediaaudioprobecontrol.h>
#include <QtCore/qmutex.h>
diff --git a/src/multimedia/gsttools_headers/qgstreamerbufferprobe_p.h b/src/multimedia/gsttools_headers/qgstreamerbufferprobe_p.h
index ca1547a87..307d68ea7 100644
--- a/src/multimedia/gsttools_headers/qgstreamerbufferprobe_p.h
+++ b/src/multimedia/gsttools_headers/qgstreamerbufferprobe_p.h
@@ -34,6 +34,17 @@
#ifndef QGSTREAMERBUFFERPROBE_H
#define QGSTREAMERBUFFERPROBE_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <gst/gst.h>
#include <QtCore/qglobal.h>
diff --git a/src/multimedia/gsttools_headers/qgstreamergltexturerenderer_p.h b/src/multimedia/gsttools_headers/qgstreamergltexturerenderer_p.h
index 5c90fc588..64aaed909 100644
--- a/src/multimedia/gsttools_headers/qgstreamergltexturerenderer_p.h
+++ b/src/multimedia/gsttools_headers/qgstreamergltexturerenderer_p.h
@@ -34,6 +34,17 @@
#ifndef QGSTREAMERGLTEXTURERENDERER_H
#define QGSTREAMERGLTEXTURERENDERER_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <qvideorenderercontrol.h>
#include <private/qvideosurfacegstsink_p.h>
#include <private/qgstreamerbushelper_p.h>
diff --git a/src/multimedia/gsttools_headers/qgstreamermirtexturerenderer_p.h b/src/multimedia/gsttools_headers/qgstreamermirtexturerenderer_p.h
index e1be653cc..a794258c7 100644
--- a/src/multimedia/gsttools_headers/qgstreamermirtexturerenderer_p.h
+++ b/src/multimedia/gsttools_headers/qgstreamermirtexturerenderer_p.h
@@ -34,6 +34,17 @@
#ifndef QGSTREAMERMIRTEXTURERENDERER_H
#define QGSTREAMERMIRTEXTURERENDERER_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists 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 <qvideorenderercontrol.h>
#include <private/qvideosurfacegstsink_p.h>
diff --git a/src/multimedia/gsttools_headers/qgstreamervideoinputdevicecontrol_p.h b/src/multimedia/gsttools_headers/qgstreamervideoinputdevicecontrol_p.h
index cd03d3257..597567c52 100644
--- a/src/multimedia/gsttools_headers/qgstreamervideoinputdevicecontrol_p.h
+++ b/src/multimedia/gsttools_headers/qgstreamervideoinputdevicecontrol_p.h
@@ -34,6 +34,17 @@
#ifndef QGSTREAMERVIDEOINPUTDEVICECONTROL_H
#define QGSTREAMERVIDEOINPUTDEVICECONTROL_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <qvideodeviceselectorcontrol.h>
#include <QtCore/qstringlist.h>
diff --git a/src/multimedia/gsttools_headers/qgstreamervideooverlay_p.h b/src/multimedia/gsttools_headers/qgstreamervideooverlay_p.h
index e18a1b5ca..cad04510f 100644
--- a/src/multimedia/gsttools_headers/qgstreamervideooverlay_p.h
+++ b/src/multimedia/gsttools_headers/qgstreamervideooverlay_p.h
@@ -34,6 +34,17 @@
#ifndef QGSTREAMERVIDEOOVERLAY_P_H
#define QGSTREAMERVIDEOOVERLAY_P_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <private/qgstreamerbushelper_p.h>
#include <private/qgstreamerbufferprobe_p.h>
#include <QtGui/qwindowdefs.h>
diff --git a/src/multimedia/gsttools_headers/qgstreamervideoprobecontrol_p.h b/src/multimedia/gsttools_headers/qgstreamervideoprobecontrol_p.h
index c77dae7a2..4b399f59d 100644
--- a/src/multimedia/gsttools_headers/qgstreamervideoprobecontrol_p.h
+++ b/src/multimedia/gsttools_headers/qgstreamervideoprobecontrol_p.h
@@ -34,6 +34,17 @@
#ifndef QGSTREAMERVIDEOPROBECONTROL_H
#define QGSTREAMERVIDEOPROBECONTROL_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <gst/gst.h>
#include <gst/video/video.h>
#include <qmediavideoprobecontrol.h>
diff --git a/src/multimedia/gsttools_headers/qgstreamervideorenderer_p.h b/src/multimedia/gsttools_headers/qgstreamervideorenderer_p.h
index a4cf72a56..f828e14a6 100644
--- a/src/multimedia/gsttools_headers/qgstreamervideorenderer_p.h
+++ b/src/multimedia/gsttools_headers/qgstreamervideorenderer_p.h
@@ -34,6 +34,17 @@
#ifndef QGSTREAMERVIDEORENDERER_H
#define QGSTREAMERVIDEORENDERER_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <qvideorenderercontrol.h>
#include <private/qvideosurfacegstsink_p.h>
#include <qabstractvideosurface.h>
diff --git a/src/multimedia/gsttools_headers/qgstreamervideorendererinterface_p.h b/src/multimedia/gsttools_headers/qgstreamervideorendererinterface_p.h
index cb6ccb15f..3f68fb7d3 100644
--- a/src/multimedia/gsttools_headers/qgstreamervideorendererinterface_p.h
+++ b/src/multimedia/gsttools_headers/qgstreamervideorendererinterface_p.h
@@ -34,6 +34,17 @@
#ifndef QGSTREAMERVIDEOOUTPUTCONTROL_H
#define QGSTREAMERVIDEOOUTPUTCONTROL_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <gst/gst.h>
#include <QtCore/qobject.h>
diff --git a/src/multimedia/gsttools_headers/qgstreamervideowidget_p.h b/src/multimedia/gsttools_headers/qgstreamervideowidget_p.h
index 4526a8ac9..724c88d16 100644
--- a/src/multimedia/gsttools_headers/qgstreamervideowidget_p.h
+++ b/src/multimedia/gsttools_headers/qgstreamervideowidget_p.h
@@ -34,6 +34,17 @@
#ifndef QGSTREAMERVIDEOWIDGET_H
#define QGSTREAMERVIDEOWIDGET_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <qvideowidgetcontrol.h>
#include "qgstreamervideorendererinterface_p.h"
diff --git a/src/multimedia/gsttools_headers/qgstreamervideowindow_p.h b/src/multimedia/gsttools_headers/qgstreamervideowindow_p.h
index 8884aa2c0..bf115f48f 100644
--- a/src/multimedia/gsttools_headers/qgstreamervideowindow_p.h
+++ b/src/multimedia/gsttools_headers/qgstreamervideowindow_p.h
@@ -34,6 +34,17 @@
#ifndef QGSTREAMERVIDEOWINDOW_H
#define QGSTREAMERVIDEOWINDOW_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <qvideowindowcontrol.h>
#include "qgstreamervideorendererinterface_p.h"
diff --git a/src/multimedia/multimedia.pro b/src/multimedia/multimedia.pro
index 524952470..b16a792fb 100644
--- a/src/multimedia/multimedia.pro
+++ b/src/multimedia/multimedia.pro
@@ -7,7 +7,8 @@ MODULE_PLUGIN_TYPES = \
video/bufferpool \
video/gstvideorenderer \
video/videonode \
- playlistformats
+ playlistformats \
+ resourcepolicy
QMAKE_DOCS = $$PWD/doc/qtmultimedia.qdocconf
@@ -56,6 +57,8 @@ SOURCES += \
qmultimedia.cpp \
qmultimediautils.cpp
+CONFIG += simd optimize_full
+
include(audio/audio.pri)
include(camera/camera.pri)
include(controls/controls.pri)
diff --git a/src/multimedia/playback/playlistfileparser.cpp b/src/multimedia/playback/playlistfileparser.cpp
index edaf98c52..c7553e16b 100644
--- a/src/multimedia/playback/playlistfileparser.cpp
+++ b/src/multimedia/playback/playlistfileparser.cpp
@@ -290,7 +290,8 @@ void QPlaylistFileParserPrivate::processLine(int startIndex, int length)
switch (m_type) {
case QPlaylistFileParser::UNKNOWN:
- emit q->error(QPlaylistFileParser::FormatError, QString(QObject::tr("%1 playlist type is unknown")).arg(m_root.toString()));
+ emit q->error(QPlaylistFileParser::FormatError,
+ QPlaylistFileParser::tr("%1 playlist type is unknown").arg(m_root.toString()));
q->stop();
return;
case QPlaylistFileParser::M3U:
@@ -350,7 +351,7 @@ void QPlaylistFileParserPrivate::_q_handleData()
if (m_buffer.length() - processedBytes >= LINE_LIMIT) {
qWarning() << "error parsing playlist["<< m_root << "] with line content >= 4096 bytes.";
- emit q->error(QPlaylistFileParser::FormatError, QObject::tr("invalid line in playlist file"));
+ emit q->error(QPlaylistFileParser::FormatError, QPlaylistFileParser::tr("invalid line in playlist file"));
q->stop();
return;
}
@@ -398,7 +399,7 @@ void QPlaylistFileParserPrivate::_q_handleParserFinished()
Q_Q(QPlaylistFileParser);
bool isParserValid = (m_currentParser != 0);
if (!isParserValid)
- emit q->error(QPlaylistFileParser::FormatNotSupportedError, QObject::tr("Empty file provided"));
+ emit q->error(QPlaylistFileParser::FormatNotSupportedError, QPlaylistFileParser::tr("Empty file provided"));
q->stop();
diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp
index 51be94c43..c1636e8e8 100644
--- a/src/multimedia/playback/qmediaplayer.cpp
+++ b/src/multimedia/playback/qmediaplayer.cpp
@@ -42,6 +42,7 @@
#include <qmediaplaylistcontrol_p.h>
#include <qmediaplaylistsourcecontrol_p.h>
#include <qmedianetworkaccesscontrol.h>
+#include <qaudiorolecontrol.h>
#include <QtCore/qcoreevent.h>
#include <QtCore/qmetaobject.h>
@@ -104,6 +105,7 @@ public:
QMediaPlayerPrivate()
: provider(0)
, control(0)
+ , audioRoleControl(0)
, state(QMediaPlayer::StoppedState)
, status(QMediaPlayer::UnknownMediaStatus)
, error(QMediaPlayer::NoError)
@@ -116,6 +118,7 @@ public:
QMediaServiceProvider *provider;
QMediaPlayerControl* control;
+ QAudioRoleControl *audioRoleControl;
QMediaPlayer::State state;
QMediaPlayer::MediaStatus status;
QMediaPlayer::Error error;
@@ -598,6 +601,12 @@ QMediaPlayer::QMediaPlayer(QObject *parent, QMediaPlayer::Flags flags):
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);
+ }
}
if (d->networkAccessControl != 0) {
connect(d->networkAccessControl, SIGNAL(configurationChanged(QNetworkConfiguration)),
@@ -620,6 +629,8 @@ QMediaPlayer::~QMediaPlayer()
if (d->service) {
if (d->control)
d->service->releaseControl(d->control);
+ if (d->audioRoleControl)
+ d->service->releaseControl(d->audioRoleControl);
d->provider->releaseService(d->service);
}
@@ -1113,6 +1124,41 @@ QMultimedia::AvailabilityStatus QMediaPlayer::availability() const
return QMediaObject::availability();
}
+QAudio::Role QMediaPlayer::audioRole() const
+{
+ Q_D(const QMediaPlayer);
+
+ if (d->audioRoleControl != NULL)
+ return d->audioRoleControl->audioRole();
+
+ return QAudio::UnknownRole;
+}
+
+void QMediaPlayer::setAudioRole(QAudio::Role audioRole)
+{
+ Q_D(QMediaPlayer);
+
+ if (d->audioRoleControl)
+ d->audioRoleControl->setAudioRole(audioRole);
+}
+
+/*!
+ Returns a list of supported audio roles.
+
+ If setting the audio role is not supported, an empty list is returned.
+
+ \since 5.6
+ \sa audioRole
+*/
+QList<QAudio::Role> QMediaPlayer::supportedAudioRoles() const
+{
+ Q_D(const QMediaPlayer);
+
+ if (d->audioRoleControl)
+ return d->audioRoleControl->supportedAudioRoles();
+
+ return QList<QAudio::Role>();
+}
// Enums
/*!
@@ -1213,6 +1259,14 @@ QMultimedia::AvailabilityStatus QMediaPlayer::availability() 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
+*/
+
// Properties
/*!
\property QMediaPlayer::state
@@ -1381,6 +1435,19 @@ QMultimedia::AvailabilityStatus QMediaPlayer::availability() const
*/
/*!
+ \property QMediaPlayer::audioRole
+ \brief the role of the audio stream played by the media player.
+
+ 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().
+
+ \since 5.6
+ \sa supportedAudioRoles()
+*/
+
+/*!
\fn void QMediaPlayer::durationChanged(qint64 duration)
Signal the duration of the content has changed to \a duration, expressed in milliseconds.
diff --git a/src/multimedia/playback/qmediaplayer.h b/src/multimedia/playback/qmediaplayer.h
index 735f11130..437bf58ad 100644
--- a/src/multimedia/playback/qmediaplayer.h
+++ b/src/multimedia/playback/qmediaplayer.h
@@ -37,6 +37,7 @@
#include <QtMultimedia/qmediaobject.h>
#include <QtMultimedia/qmediacontent.h>
#include <QtMultimedia/qmediaenumdebug.h>
+#include <QtMultimedia/qaudio.h>
#include <QtNetwork/qnetworkconfiguration.h>
@@ -66,6 +67,7 @@ class Q_MULTIMEDIA_EXPORT QMediaPlayer : public QMediaObject
Q_PROPERTY(qreal playbackRate READ playbackRate WRITE setPlaybackRate NOTIFY playbackRateChanged)
Q_PROPERTY(State state READ state NOTIFY stateChanged)
Q_PROPERTY(MediaStatus mediaStatus READ mediaStatus NOTIFY mediaStatusChanged)
+ Q_PROPERTY(QAudio::Role audioRole READ audioRole WRITE setAudioRole)
Q_PROPERTY(QString error READ errorString)
Q_ENUMS(State)
Q_ENUMS(MediaStatus)
@@ -151,6 +153,10 @@ public:
QMultimedia::AvailabilityStatus availability() const;
+ QAudio::Role audioRole() const;
+ void setAudioRole(QAudio::Role audioRole);
+ QList<QAudio::Role> supportedAudioRoles() const;
+
public Q_SLOTS:
void play();
void pause();
@@ -187,6 +193,8 @@ Q_SIGNALS:
void seekableChanged(bool seekable);
void playbackRateChanged(qreal rate);
+ void audioRoleChanged(QAudio::Role role);
+
void error(QMediaPlayer::Error error);
void networkConfigurationChanged(const QNetworkConfiguration &configuration);
diff --git a/src/multimedia/playback/qmediaplaylist.cpp b/src/multimedia/playback/qmediaplaylist.cpp
index 06813592e..c63340637 100644
--- a/src/multimedia/playback/qmediaplaylist.cpp
+++ b/src/multimedia/playback/qmediaplaylist.cpp
@@ -168,10 +168,13 @@ bool QMediaPlaylist::setMediaObject(QMediaObject *mediaObject)
newControl = d->networkPlaylistControl;
if (d->control != newControl) {
- int oldSize = 0;
+ int removedStart = -1;
+ int removedEnd = -1;
+ int insertedStart = -1;
+ int insertedEnd = -1;
+
if (d->control) {
QMediaPlaylistProvider *playlist = d->control->playlistProvider();
- oldSize = playlist->mediaCount();
disconnect(playlist, SIGNAL(loadFailed(QMediaPlaylist::Error,QString)),
this, SLOT(_q_loadFailed(QMediaPlaylist::Error,QString)));
@@ -190,6 +193,12 @@ bool QMediaPlaylist::setMediaObject(QMediaObject *mediaObject)
disconnect(d->control, SIGNAL(currentMediaChanged(QMediaContent)),
this, SIGNAL(currentMediaChanged(QMediaContent)));
+ // 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);
}
@@ -214,14 +223,14 @@ bool QMediaPlaylist::setMediaObject(QMediaObject *mediaObject)
connect(d->control, SIGNAL(currentMediaChanged(QMediaContent)),
this, SIGNAL(currentMediaChanged(QMediaContent)));
- if (oldSize) {
- emit mediaAboutToBeRemoved(0, oldSize-1);
- emit mediaRemoved(0, oldSize-1);
+ if (removedStart != -1 && removedEnd != -1) {
+ emit mediaAboutToBeRemoved(removedStart, removedEnd);
+ emit mediaRemoved(removedStart, removedEnd);
}
- if (playlist->mediaCount()) {
- emit mediaAboutToBeInserted(0,playlist->mediaCount()-1);
- emit mediaInserted(0,playlist->mediaCount()-1);
+ if (insertedStart != -1 && insertedEnd != -1) {
+ emit mediaAboutToBeInserted(insertedStart, insertedEnd);
+ emit mediaInserted(insertedStart, insertedEnd);
}
}
@@ -436,6 +445,53 @@ bool QMediaPlaylistPrivate::writeItems(QMediaPlaylistWriter *writer)
}
/*!
+ * \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.
diff --git a/src/multimedia/playback/qmediaplaylist_p.h b/src/multimedia/playback/qmediaplaylist_p.h
index 25571378f..1440362df 100644
--- a/src/multimedia/playback/qmediaplaylist_p.h
+++ b/src/multimedia/playback/qmediaplaylist_p.h
@@ -108,6 +108,10 @@ public:
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;
diff --git a/src/multimedia/qmediametadata.cpp b/src/multimedia/qmediametadata.cpp
index f07c0936b..9ffd2a727 100644
--- a/src/multimedia/qmediametadata.cpp
+++ b/src/multimedia/qmediametadata.cpp
@@ -160,6 +160,7 @@ Q_DEFINE_METADATA(ThumbnailImage);
/*!
\namespace QMediaMetaData
+ \ingroup multimedia-namespaces
\ingroup multimedia
\inmodule QtMultimedia
diff --git a/src/multimedia/qmediaresourcepolicy_p.h b/src/multimedia/qmediaresourcepolicy_p.h
index ee07c87e3..9877a628e 100644
--- a/src/multimedia/qmediaresourcepolicy_p.h
+++ b/src/multimedia/qmediaresourcepolicy_p.h
@@ -34,6 +34,17 @@
#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 "qtmultimediadefs.h"
diff --git a/src/multimedia/qmediaresourcepolicyplugin_p.h b/src/multimedia/qmediaresourcepolicyplugin_p.h
index 938ea9d5d..47596352c 100644
--- a/src/multimedia/qmediaresourcepolicyplugin_p.h
+++ b/src/multimedia/qmediaresourcepolicyplugin_p.h
@@ -34,6 +34,17 @@
#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 <qtmultimediadefs.h>
diff --git a/src/multimedia/qmediaresourceset_p.h b/src/multimedia/qmediaresourceset_p.h
index cddb380da..ccfa55954 100644
--- a/src/multimedia/qmediaresourceset_p.h
+++ b/src/multimedia/qmediaresourceset_p.h
@@ -33,6 +33,17 @@
#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 <qtmultimediadefs.h>
diff --git a/src/multimedia/qmediaserviceprovider_p.h b/src/multimedia/qmediaserviceprovider_p.h
index 4230c427d..e2b02c8b9 100644
--- a/src/multimedia/qmediaserviceprovider_p.h
+++ b/src/multimedia/qmediaserviceprovider_p.h
@@ -34,6 +34,17 @@
#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 <qtmultimediadefs.h>
diff --git a/src/multimedia/qmediastoragelocation_p.h b/src/multimedia/qmediastoragelocation_p.h
index c934089d6..56995026a 100644
--- a/src/multimedia/qmediastoragelocation_p.h
+++ b/src/multimedia/qmediastoragelocation_p.h
@@ -34,6 +34,17 @@
#ifndef QMEDIASTORAGELOCATION_H
#define QMEDIASTORAGELOCATION_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <qtmultimediadefs.h>
#include <QDir>
#include <QMap>
diff --git a/src/multimedia/qmultimedia.cpp b/src/multimedia/qmultimedia.cpp
index 2641cae44..f1673871f 100644
--- a/src/multimedia/qmultimedia.cpp
+++ b/src/multimedia/qmultimedia.cpp
@@ -31,6 +31,7 @@ QT_BEGIN_NAMESPACE
/*!
\namespace QMultimedia
+ \ingroup multimedia-namespaces
\ingroup multimedia
\inmodule QtMultimedia
diff --git a/src/multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_backend_p.h b/src/multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_backend_p.h
index 450c0cff5..94d7d15cd 100644
--- a/src/multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_backend_p.h
+++ b/src/multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_backend_p.h
@@ -35,6 +35,17 @@
#ifndef QDECLARATIVEVIDEOOUTPUT_BACKEND_P_H
#define QDECLARATIVEVIDEOOUTPUT_BACKEND_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/qpointer.h>
#include <QtCore/qsize.h>
#include <QtQuick/qquickitem.h>
diff --git a/src/multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_p.h b/src/multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_p.h
index 87565b91b..0f34cc036 100644
--- a/src/multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_p.h
+++ b/src/multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_p.h
@@ -35,6 +35,17 @@
#ifndef QDECLARATIVEVIDEOOUTPUT_P_H
#define QDECLARATIVEVIDEOOUTPUT_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/qrect.h>
#include <QtCore/qsharedpointer.h>
#include <QtQuick/qquickitem.h>
diff --git a/src/multimedia/qtmultimediaquicktools_headers/qsgvideonode_p.h b/src/multimedia/qtmultimediaquicktools_headers/qsgvideonode_p.h
index 11d76f6b4..3024d1316 100644
--- a/src/multimedia/qtmultimediaquicktools_headers/qsgvideonode_p.h
+++ b/src/multimedia/qtmultimediaquicktools_headers/qsgvideonode_p.h
@@ -34,6 +34,17 @@
#ifndef QSGVIDEONODE_P_H
#define QSGVIDEONODE_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 <QtQuick/qsgnode.h>
#include <private/qtmultimediaquickdefs_p.h>
@@ -70,6 +81,8 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QSGVideoNode::FrameFlags)
class Q_MULTIMEDIAQUICK_EXPORT QSGVideoNodeFactoryInterface
{
public:
+ virtual ~QSGVideoNodeFactoryInterface();
+
virtual QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const = 0;
virtual QSGVideoNode *createNode(const QVideoSurfaceFormat &format) = 0;
};
diff --git a/src/multimedia/recording/qmediarecorder_p.h b/src/multimedia/recording/qmediarecorder_p.h
index 9510d2406..598e833ad 100644
--- a/src/multimedia/recording/qmediarecorder_p.h
+++ b/src/multimedia/recording/qmediarecorder_p.h
@@ -34,6 +34,17 @@
#ifndef QMEDIARECORDER_P_H
#define QMEDIARECORDER_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 "qmediarecorder.h"
#include "qmediaobject_p.h"
#include <QtCore/qurl.h>
diff --git a/src/multimedia/video/qvideoframe.cpp b/src/multimedia/video/qvideoframe.cpp
index 4e9e28a4d..f0495577c 100644
--- a/src/multimedia/video/qvideoframe.cpp
+++ b/src/multimedia/video/qvideoframe.cpp
@@ -33,8 +33,10 @@
#include "qvideoframe.h"
+#include "qvideoframe_p.h"
#include "qimagevideobuffer_p.h"
#include "qmemoryvideobuffer_p.h"
+#include "qvideoframeconversionhelper_p.h"
#include <qimage.h>
#include <qpair.h>
@@ -654,6 +656,8 @@ bool QVideoFrame::map(QAbstractVideoBuffer::MapMode mode)
d->data[2] = d->data[1] + (d->bytesPerLine[1] * d->size.height() / 2);
break;
}
+ default:
+ break;
}
d->mappedCount++;
@@ -994,11 +998,133 @@ QImage::Format QVideoFrame::imageFormatFromPixelFormat(PixelFormat format)
case Format_AdobeDng:
return QImage::Format_Invalid;
case Format_User:
+ default:
return QImage::Format_Invalid;
}
return QImage::Format_Invalid;
}
+
+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 */ Q_NULLPTR, // Not needed
+ /* Format_ARGB32 */ Q_NULLPTR, // Not needed
+ /* Format_ARGB32_Premultiplied */ Q_NULLPTR, // Not needed
+ /* Format_RGB32 */ Q_NULLPTR, // Not needed
+ /* Format_RGB24 */ Q_NULLPTR, // Not needed
+ /* Format_RGB565 */ Q_NULLPTR, // Not needed
+ /* Format_RGB555 */ Q_NULLPTR, // Not needed
+ /* Format_ARGB8565_Premultiplied */ Q_NULLPTR, // Not needed
+ /* Format_BGRA32 */ qt_convert_BGRA32_to_ARGB32,
+ /* Format_BGRA32_Premultiplied */ qt_convert_BGRA32_to_ARGB32,
+ /* 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 */ Q_NULLPTR,
+ /* Format_AYUV444 */ qt_convert_AYUV444_to_ARGB32,
+ /* Format_AYUV444_Premultiplied */ Q_NULLPTR,
+ /* Format_YUV444 */ qt_convert_YUV444_to_ARGB32,
+ /* Format_YUV420P */ qt_convert_YUV420P_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 */ Q_NULLPTR,
+ /* Format_IMC2 */ Q_NULLPTR,
+ /* Format_IMC3 */ Q_NULLPTR,
+ /* Format_IMC4 */ Q_NULLPTR,
+ /* Format_Y8 */ Q_NULLPTR,
+ /* Format_Y16 */ Q_NULLPTR,
+ /* Format_Jpeg */ Q_NULLPTR, // Not needed
+ /* Format_CameraRaw */ Q_NULLPTR,
+ /* Format_AdobeDng */ Q_NULLPTR
+};
+
+static void qInitConvertFuncsAsm()
+{
+#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
+}
+
+/*!
+ \internal
+*/
+QImage qt_imageFromVideoFrame(const QVideoFrame &f)
+{
+ QVideoFrame &frame = const_cast<QVideoFrame&>(f);
+ 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(), imageFormat).copy();
+ }
+
+ // Load from JPG
+ else if (frame.pixelFormat() == QVideoFrame::Format_Jpeg) {
+ result.loadFromData(frame.bits(), frame.mappedBytes(), "JPG");
+ }
+
+ // 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());
+ }
+ }
+
+ frame.unmap();
+
+ return result;
+}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, QVideoFrame::PixelFormat pf)
{
diff --git a/src/multimedia/video/qvideoframe.h b/src/multimedia/video/qvideoframe.h
index a273b7f73..633604ebb 100644
--- a/src/multimedia/video/qvideoframe.h
+++ b/src/multimedia/video/qvideoframe.h
@@ -96,6 +96,9 @@ public:
Format_CameraRaw,
Format_AdobeDng,
+#ifndef Q_QDOC
+ NPixelFormats,
+#endif
Format_User = 1000
};
diff --git a/src/multimedia/video/qvideoframe_p.h b/src/multimedia/video/qvideoframe_p.h
new file mode 100644
index 000000000..15260c26f
--- /dev/null
+++ b/src/multimedia/video/qvideoframe_p.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QVIDEOFRAME_P_H
+#define QVIDEOFRAME_P_H
+
+#include <QtMultimedia/qvideoframe.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It 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
+
+Q_MULTIMEDIA_EXPORT QImage qt_imageFromVideoFrame(const QVideoFrame &frame);
+
+QT_END_NAMESPACE
+
+#endif // QVIDEOFRAME_P_H
+
diff --git a/src/multimedia/video/qvideoframeconversionhelper.cpp b/src/multimedia/video/qvideoframeconversionhelper.cpp
new file mode 100644
index 000000000..9599b1947
--- /dev/null
+++ b/src/multimedia/video/qvideoframeconversionhelper.cpp
@@ -0,0 +1,348 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qvideoframeconversionhelper_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#define CLAMP(n) (n > 255 ? 255 : (n < 0 ? 0 : n))
+
+#define EXPAND_UV(u, v) \
+ int uu = u - 128; \
+ int vv = v - 128; \
+ int rv = 409 * vv + 128; \
+ int guv = 100 * uu + 208 * vv + 128; \
+ int bu = 516 * uu + 128; \
+
+static inline quint32 qYUVToARGB32(int y, int rv, int guv, int bu, int a = 0xff)
+{
+ int yy = (y - 16) * 298;
+ return (a << 24)
+ | CLAMP((yy + rv) >> 8) << 16
+ | CLAMP((yy - guv) >> 8) << 8
+ | CLAMP((yy + bu) >> 8);
+}
+
+static inline void planarYUV420_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)
+{
+ quint32 *rgb0 = rgb;
+ quint32 *rgb1 = rgb + width;
+
+ for (int j = 0; j < 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) {
+ 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);
+ }
+
+ y += yStride << 1; // stride * 2
+ u += uStride;
+ v += vStride;
+ rgb0 += width;
+ rgb1 += width;
+ }
+}
+
+
+
+void QT_FASTCALL qt_convert_YUV420P_to_ARGB32(const QVideoFrame &frame, uchar *output)
+{
+ FETCH_INFO_TRIPLANAR(frame)
+ planarYUV420_to_ARGB32(plane1, plane1Stride,
+ plane2, plane2Stride,
+ plane3, plane3Stride,
+ 1,
+ reinterpret_cast<quint32*>(output),
+ width, height);
+}
+
+void QT_FASTCALL qt_convert_YV12_to_ARGB32(const QVideoFrame &frame, uchar *output)
+{
+ FETCH_INFO_TRIPLANAR(frame)
+ planarYUV420_to_ARGB32(plane1, plane1Stride,
+ plane3, plane3Stride,
+ plane2, plane2Stride,
+ 1,
+ reinterpret_cast<quint32*>(output),
+ width, height);
+}
+
+void QT_FASTCALL qt_convert_AYUV444_to_ARGB32(const QVideoFrame &frame, uchar *output)
+{
+ FETCH_INFO_PACKED(frame)
+ MERGE_LOOPS(width, height, stride, 4)
+
+ quint32 *rgb = reinterpret_cast<quint32*>(output);
+
+ for (int i = 0; i < height; ++i) {
+ 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, a);
+ }
+
+ src += stride;
+ }
+}
+
+void QT_FASTCALL qt_convert_YUV444_to_ARGB32(const QVideoFrame &frame, uchar *output)
+{
+ FETCH_INFO_PACKED(frame)
+ MERGE_LOOPS(width, height, stride, 3)
+
+ quint32 *rgb = reinterpret_cast<quint32*>(output);
+
+ for (int i = 0; i < height; ++i) {
+ const uchar *lineSrc = src;
+
+ for (int j = 0; j < width; ++j) {
+ int y = *lineSrc++;
+ int u = *lineSrc++;
+ int v = *lineSrc++;
+
+ EXPAND_UV(u, v);
+
+ *rgb++ = qYUVToARGB32(y, rv, guv, bu);
+ }
+
+ src += stride;
+ }
+}
+
+void QT_FASTCALL qt_convert_UYVY_to_ARGB32(const QVideoFrame &frame, uchar *output)
+{
+ FETCH_INFO_PACKED(frame)
+ MERGE_LOOPS(width, height, stride, 2)
+
+ quint32 *rgb = reinterpret_cast<quint32*>(output);
+
+ for (int i = 0; i < height; ++i) {
+ const uchar *lineSrc = src;
+
+ for (int j = 0; j < width; j += 2) {
+ int u = *lineSrc++;
+ int y0 = *lineSrc++;
+ int v = *lineSrc++;
+ int y1 = *lineSrc++;
+
+ EXPAND_UV(u, v);
+
+ *rgb++ = qYUVToARGB32(y0, rv, guv, bu);
+ *rgb++ = qYUVToARGB32(y1, rv, guv, bu);
+ }
+
+ src += stride;
+ }
+}
+
+void QT_FASTCALL qt_convert_YUYV_to_ARGB32(const QVideoFrame &frame, uchar *output)
+{
+ FETCH_INFO_PACKED(frame)
+ MERGE_LOOPS(width, height, stride, 2)
+
+ quint32 *rgb = reinterpret_cast<quint32*>(output);
+
+ for (int i = 0; i < height; ++i) {
+ const uchar *lineSrc = src;
+
+ for (int j = 0; j < width; j += 2) {
+ int y0 = *lineSrc++;
+ int u = *lineSrc++;
+ int y1 = *lineSrc++;
+ int v = *lineSrc++;
+
+ EXPAND_UV(u, v);
+
+ *rgb++ = qYUVToARGB32(y0, rv, guv, bu);
+ *rgb++ = qYUVToARGB32(y1, rv, guv, bu);
+ }
+
+ src += stride;
+ }
+}
+
+void QT_FASTCALL qt_convert_NV12_to_ARGB32(const QVideoFrame &frame, uchar *output)
+{
+ FETCH_INFO_BIPLANAR(frame)
+ planarYUV420_to_ARGB32(plane1, plane1Stride,
+ plane2, plane2Stride,
+ plane2 + 1, plane2Stride,
+ 2,
+ reinterpret_cast<quint32*>(output),
+ width, height);
+}
+
+void QT_FASTCALL qt_convert_NV21_to_ARGB32(const QVideoFrame &frame, uchar *output)
+{
+ FETCH_INFO_BIPLANAR(frame)
+ planarYUV420_to_ARGB32(plane1, plane1Stride,
+ plane2 + 1, plane2Stride,
+ plane2, plane2Stride,
+ 2,
+ reinterpret_cast<quint32*>(output),
+ width, height);
+}
+
+void QT_FASTCALL qt_convert_BGRA32_to_ARGB32(const QVideoFrame &frame, uchar *output)
+{
+ FETCH_INFO_PACKED(frame)
+ MERGE_LOOPS(width, height, stride, 4)
+
+ quint32 *argb = reinterpret_cast<quint32*>(output);
+
+ for (int y = 0; y < height; ++y) {
+ const quint32 *bgra = reinterpret_cast<const quint32*>(src);
+
+ int x = 0;
+ for (; x < width - 3; x += 4) {
+ *argb++ = qConvertBGRA32ToARGB32(*bgra++);
+ *argb++ = qConvertBGRA32ToARGB32(*bgra++);
+ *argb++ = qConvertBGRA32ToARGB32(*bgra++);
+ *argb++ = qConvertBGRA32ToARGB32(*bgra++);
+ }
+
+ // leftovers
+ for (; x < width; ++x)
+ *argb++ = qConvertBGRA32ToARGB32(*bgra++);
+
+ src += stride;
+ }
+}
+
+void QT_FASTCALL qt_convert_BGR24_to_ARGB32(const QVideoFrame &frame, uchar *output)
+{
+ FETCH_INFO_PACKED(frame)
+ MERGE_LOOPS(width, height, stride, 3)
+
+ quint32 *argb = reinterpret_cast<quint32*>(output);
+
+ for (int y = 0; y < height; ++y) {
+ const uchar *bgr = 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;
+ }
+
+ // leftovers
+ for (; x < width; ++x) {
+ *argb++ = qConvertBGR24ToARGB32(bgr);
+ bgr += 3;
+ }
+
+ src += stride;
+ }
+}
+
+void QT_FASTCALL qt_convert_BGR565_to_ARGB32(const QVideoFrame &frame, uchar *output)
+{
+ FETCH_INFO_PACKED(frame)
+ MERGE_LOOPS(width, height, stride, 2)
+
+ quint32 *argb = reinterpret_cast<quint32*>(output);
+
+ for (int y = 0; y < height; ++y) {
+ const quint16 *bgr = reinterpret_cast<const quint16*>(src);
+
+ int x = 0;
+ for (; x < width - 3; x += 4) {
+ *argb++ = qConvertBGR565ToARGB32(*bgr++);
+ *argb++ = qConvertBGR565ToARGB32(*bgr++);
+ *argb++ = qConvertBGR565ToARGB32(*bgr++);
+ *argb++ = qConvertBGR565ToARGB32(*bgr++);
+ }
+
+ // leftovers
+ for (; x < width; ++x)
+ *argb++ = qConvertBGR565ToARGB32(*bgr++);
+
+ src += stride;
+ }
+}
+
+void QT_FASTCALL qt_convert_BGR555_to_ARGB32(const QVideoFrame &frame, uchar *output)
+{
+ FETCH_INFO_PACKED(frame)
+ MERGE_LOOPS(width, height, stride, 2)
+
+ quint32 *argb = reinterpret_cast<quint32*>(output);
+
+ for (int y = 0; y < height; ++y) {
+ const quint16 *bgr = reinterpret_cast<const quint16*>(src);
+
+ int x = 0;
+ for (; x < width - 3; x += 4) {
+ *argb++ = qConvertBGR555ToARGB32(*bgr++);
+ *argb++ = qConvertBGR555ToARGB32(*bgr++);
+ *argb++ = qConvertBGR555ToARGB32(*bgr++);
+ *argb++ = qConvertBGR555ToARGB32(*bgr++);
+ }
+
+ // leftovers
+ for (; x < width; ++x)
+ *argb++ = qConvertBGR555ToARGB32(*bgr++);
+
+ src += stride;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/video/qvideoframeconversionhelper_avx2.cpp b/src/multimedia/video/qvideoframeconversionhelper_avx2.cpp
new file mode 100644
index 000000000..c769c8868
--- /dev/null
+++ b/src/multimedia/video/qvideoframeconversionhelper_avx2.cpp
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qvideoframeconversionhelper_p.h"
+
+#ifdef QT_COMPILER_SUPPORTS_AVX2
+
+QT_BEGIN_NAMESPACE
+
+void QT_FASTCALL qt_convert_BGRA32_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);
+
+ for (int y = 0; y < height; ++y) {
+ const quint32 *bgra = reinterpret_cast<const quint32*>(src);
+
+ int x = 0;
+ ALIGN(32, argb, x, width) {
+ *argb = qConvertBGRA32ToARGB32(*bgra);
+ ++bgra;
+ ++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;
+ pixelData = _mm256_shuffle_epi8(pixelData, shuffleMask);
+ pixelData2 = _mm256_shuffle_epi8(pixelData2, shuffleMask);
+ _mm256_store_si256(reinterpret_cast<__m256i*>(argb), pixelData);
+ _mm256_store_si256(reinterpret_cast<__m256i*>(argb + 8), pixelData2);
+ argb += 16;
+ }
+
+ // leftovers
+ for (; x < width; ++x) {
+ *argb = qConvertBGRA32ToARGB32(*bgra);
+ ++bgra;
+ ++argb;
+ }
+
+ src += stride;
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/video/qvideoframeconversionhelper_p.h b/src/multimedia/video/qvideoframeconversionhelper_p.h
new file mode 100644
index 000000000..10e9d3ab3
--- /dev/null
+++ b/src/multimedia/video/qvideoframeconversionhelper_p.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QVIDEOFRAMECONVERSIONHELPER_P_H
+#define QVIDEOFRAMECONVERSIONHELPER_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 <private/qsimd_p.h>
+
+typedef void (QT_FASTCALL *VideoFrameConvertFunc)(const QVideoFrame &frame, uchar *output);
+
+inline quint32 qConvertBGRA32ToARGB32(quint32 bgra)
+{
+ return (((bgra & 0xFF000000) >> 24)
+ | ((bgra & 0x00FF0000) >> 8)
+ | ((bgra & 0x0000FF00) << 8)
+ | ((bgra & 0x000000FF) << 24));
+}
+
+inline quint32 qConvertBGR24ToARGB32(const uchar *bgr)
+{
+ return 0xFF000000 | bgr[0] | bgr[1] << 8 | bgr[2] << 16;
+}
+
+inline quint32 qConvertBGR565ToARGB32(quint16 bgr)
+{
+ return 0xff000000
+ | ((((bgr) >> 8) & 0xf8) | (((bgr) >> 13) & 0x7))
+ | ((((bgr) << 5) & 0xfc00) | (((bgr) >> 1) & 0x300))
+ | ((((bgr) << 19) & 0xf80000) | (((bgr) << 14) & 0x70000));
+}
+
+inline quint32 qConvertBGR555ToARGB32(quint16 bgr)
+{
+ return 0xff000000
+ | ((((bgr) >> 7) & 0xf8) | (((bgr) >> 12) & 0x7))
+ | ((((bgr) << 6) & 0xf800) | (((bgr) << 1) & 0x700))
+ | ((((bgr) << 19) & 0xf80000) | (((bgr) << 11) & 0x70000));
+}
+
+#define FETCH_INFO_PACKED(frame) \
+ const uchar *src = frame.bits(); \
+ int stride = frame.bytesPerLine(); \
+ int width = frame.width(); \
+ int height = frame.height();
+
+#define FETCH_INFO_BIPLANAR(frame) \
+ const uchar *plane1 = frame.bits(0); \
+ const uchar *plane2 = frame.bits(1); \
+ int plane1Stride = frame.bytesPerLine(0); \
+ int plane2Stride = frame.bytesPerLine(1); \
+ int width = frame.width(); \
+ int height = frame.height();
+
+#define FETCH_INFO_TRIPLANAR(frame) \
+ const uchar *plane1 = frame.bits(0); \
+ const uchar *plane2 = frame.bits(1); \
+ const uchar *plane3 = frame.bits(2); \
+ int plane1Stride = frame.bytesPerLine(0); \
+ int plane2Stride = frame.bytesPerLine(1); \
+ int plane3Stride = frame.bytesPerLine(2); \
+ int width = frame.width(); \
+ int height = frame.height(); \
+
+#define MERGE_LOOPS(width, height, stride, bpp) \
+ if (stride == width * bpp) { \
+ width *= height; \
+ height = 1; \
+ stride = 0; \
+ }
+
+#define ALIGN(boundary, ptr, x, length) \
+ for (; ((reinterpret_cast<qintptr>(ptr) & (boundary - 1)) != 0) && x < length; ++x)
+
+#endif // QVIDEOFRAMECONVERSIONHELPER_P_H
+
diff --git a/src/multimedia/video/qvideoframeconversionhelper_sse2.cpp b/src/multimedia/video/qvideoframeconversionhelper_sse2.cpp
new file mode 100644
index 000000000..27689e5bb
--- /dev/null
+++ b/src/multimedia/video/qvideoframeconversionhelper_sse2.cpp
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qvideoframeconversionhelper_p.h"
+
+#ifdef QT_COMPILER_SUPPORTS_SSE2
+
+QT_BEGIN_NAMESPACE
+
+void QT_FASTCALL qt_convert_BGRA32_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();
+
+ for (int y = 0; y < height; ++y) {
+ const quint32 *bgra = reinterpret_cast<const quint32*>(src);
+
+ int x = 0;
+ ALIGN(16, argb, x, width) {
+ *argb = qConvertBGRA32ToARGB32(*bgra);
+ ++bgra;
+ ++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);
+ _mm_store_si128(reinterpret_cast<__m128i*>(argb), pixelData);
+ argb += 4;
+ }
+
+ // leftovers
+ for (; x < width; ++x) {
+ *argb = qConvertBGRA32ToARGB32(*bgra);
+ ++bgra;
+ ++argb;
+ }
+
+ src += stride;
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/video/qvideoframeconversionhelper_ssse3.cpp b/src/multimedia/video/qvideoframeconversionhelper_ssse3.cpp
new file mode 100644
index 000000000..b15617cef
--- /dev/null
+++ b/src/multimedia/video/qvideoframeconversionhelper_ssse3.cpp
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qvideoframeconversionhelper_p.h"
+
+#ifdef QT_COMPILER_SUPPORTS_SSSE3
+
+QT_BEGIN_NAMESPACE
+
+void QT_FASTCALL qt_convert_BGRA32_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);
+
+ for (int y = 0; y < height; ++y) {
+ const quint32 *bgra = reinterpret_cast<const quint32*>(src);
+
+ int x = 0;
+ ALIGN(16, argb, x, width) {
+ *argb = qConvertBGRA32ToARGB32(*bgra);
+ ++bgra;
+ ++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;
+ pixelData = _mm_shuffle_epi8(pixelData, shuffleMask);
+ pixelData2 = _mm_shuffle_epi8(pixelData2, shuffleMask);
+ _mm_store_si128(reinterpret_cast<__m128i*>(argb), pixelData);
+ _mm_store_si128(reinterpret_cast<__m128i*>(argb + 4), pixelData2);
+ argb += 8;
+ }
+
+ // leftovers
+ for (; x < width; ++x) {
+ *argb = qConvertBGRA32ToARGB32(*bgra);
+ ++bgra;
+ ++argb;
+ }
+
+ src += stride;
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/multimedia/video/qvideooutputorientationhandler_p.h b/src/multimedia/video/qvideooutputorientationhandler_p.h
index 28629adce..c690cafae 100644
--- a/src/multimedia/video/qvideooutputorientationhandler_p.h
+++ b/src/multimedia/video/qvideooutputorientationhandler_p.h
@@ -34,6 +34,17 @@
#ifndef QVIDEOOUTPUTORIENTATIONHANDLER_P_H
#define QVIDEOOUTPUTORIENTATIONHANDLER_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 <qtmultimediadefs.h>
#include <QObject>
diff --git a/src/multimedia/video/qvideosurfaceoutput_p.h b/src/multimedia/video/qvideosurfaceoutput_p.h
index 2356a6b44..b9e3960f4 100644
--- a/src/multimedia/video/qvideosurfaceoutput_p.h
+++ b/src/multimedia/video/qvideosurfaceoutput_p.h
@@ -34,6 +34,17 @@
#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>
diff --git a/src/multimedia/video/video.pri b/src/multimedia/video/video.pri
index 3e39d9d18..e5fa697ce 100644
--- a/src/multimedia/video/video.pri
+++ b/src/multimedia/video/video.pri
@@ -14,7 +14,9 @@ PRIVATE_HEADERS += \
video/qimagevideobuffer_p.h \
video/qmemoryvideobuffer_p.h \
video/qvideooutputorientationhandler_p.h \
- video/qvideosurfaceoutput_p.h
+ video/qvideosurfaceoutput_p.h \
+ video/qvideoframe_p.h \
+ video/qvideoframeconversionhelper_p.h
SOURCES += \
video/qabstractvideobuffer.cpp \
@@ -26,4 +28,9 @@ SOURCES += \
video/qvideosurfaceformat.cpp \
video/qvideosurfaceoutput.cpp \
video/qvideoprobe.cpp \
- video/qabstractvideofilter.cpp
+ video/qabstractvideofilter.cpp \
+ video/qvideoframeconversionhelper.cpp
+
+SSE2_SOURCES += video/qvideoframeconversionhelper_sse2.cpp
+SSSE3_SOURCES += video/qvideoframeconversionhelper_ssse3.cpp
+AVX2_SOURCES += video/qvideoframeconversionhelper_avx2.cpp
diff --git a/src/multimediawidgets/doc/qtmultimediawidgets.qdocconf b/src/multimediawidgets/doc/qtmultimediawidgets.qdocconf
deleted file mode 100644
index 19e956a0e..000000000
--- a/src/multimediawidgets/doc/qtmultimediawidgets.qdocconf
+++ /dev/null
@@ -1,44 +0,0 @@
-include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
-
-project = QtMultimediaWidgets
-description = Qt Multimedia Widgets Documentation
-version = $QT_VERSION
-
-# The following parameters are for creating a qhp file, the qhelpgenerator
-# program can convert the qhp file into a qch file which can be opened in
-# Qt Assistant and/or Qt Creator.
-
-# Defines the name of the project. You cannot use operators (+, =, -) in
-# the name. Properties for this project are set using a qhp.<projectname>.property
-# format.
-qhp.projects = QtMultimediaWidgets
-qhp.QtMultimediaWidgets.file = qtmultimediawidgets.qhp
-qhp.QtMultimediaWidgets.namespace = org.qt-project.qtmultimediawidgets.$QT_VERSION_TAG
-qhp.QtMultimediaWidgets.indexTitle = Qt Multimedia Widgets
-qhp.QtMultimediaWidgets.virtualFolder = qtmultimediawidgets
-
-# For listing child nodes in Qt Creator or Assistant.
-qhp.QtMultimediaWidgets.subprojects = classes
-qhp.QtMultimediaWidgets.subprojects.classes.title = C++ Classes
-qhp.QtMultimediaWidgets.subprojects.classes.indexTitle = Qt Multimedia Widgets C++ Classes
-qhp.QtMultimediaWidgets.subprojects.classes.selectors = class fake:headerfile
-qhp.QtMultimediaWidgets.subprojects.classes.sortPages = true
-
-exampledirs += ../../../examples/multimediawidgets \
- snippets
-
-# Specify example install dir under QT_INSTALL_EXAMPLES
-examplesinstallpath = multimediawidgets
-
-headerdirs += ../
-
-imagedirs += \
-
-sourcedirs += ../
-
-excludedirs +=
-
-depends += qtcore qtdoc qtquick qtqml qtmultimedia qtwidgets qtgui
-
-navigation.landingpage = "Qt Multimedia Widgets"
-navigation.cppclassespage = "Qt Multimedia Widgets C++ Classes"
diff --git a/src/multimediawidgets/multimediawidgets.pro b/src/multimediawidgets/multimediawidgets.pro
index 1cf35986f..ec96be57c 100644
--- a/src/multimediawidgets/multimediawidgets.pro
+++ b/src/multimediawidgets/multimediawidgets.pro
@@ -7,8 +7,6 @@ qtHaveModule(opengl):!contains(QT_CONFIG, opengles1) {
DEFINES += QT_NO_OPENGL
}
-QMAKE_DOCS = $$PWD/doc/qtmultimediawidgets.qdocconf
-
load(qt_module)
PRIVATE_HEADERS += \
diff --git a/src/multimediawidgets/qvideowidget.cpp b/src/multimediawidgets/qvideowidget.cpp
index 24184e32d..d14a70475 100644
--- a/src/multimediawidgets/qvideowidget.cpp
+++ b/src/multimediawidgets/qvideowidget.cpp
@@ -734,7 +734,7 @@ void QVideoWidget::setFullScreen(bool fullScreen)
Signals that the \a fullScreen mode of a video widget has changed.
- \sa fullScreen()
+ \sa isFullScreen()
*/
/*!
diff --git a/src/plugins/android/jar/jar.pri b/src/plugins/android/jar/jar.pri
index d31839c61..713123baf 100644
--- a/src/plugins/android/jar/jar.pri
+++ b/src/plugins/android/jar/jar.pri
@@ -10,7 +10,8 @@ JAVASOURCES += $$PWD/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlay
$$PWD/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureListener.java \
$$PWD/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder.java \
$$PWD/src/org/qtproject/qt5/android/multimedia/QtMultimediaUtils.java \
- $$PWD/src/org/qtproject/qt5/android/multimedia/QtMediaRecorderListener.java
+ $$PWD/src/org/qtproject/qt5/android/multimedia/QtMediaRecorderListener.java \
+ $$PWD/src/org/qtproject/qt5/android/multimedia/QtSurfaceHolderCallback.java
# install
target.path = $$[QT_INSTALL_PREFIX]/jar
diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCameraListener.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCameraListener.java
index 974489c19..8724eeba4 100644
--- a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCameraListener.java
+++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCameraListener.java
@@ -54,6 +54,8 @@ public class QtCameraListener implements Camera.ShutterCallback,
private byte[][] m_previewBuffers = null;
private byte[] m_lastPreviewBuffer = null;
private Camera.Size m_previewSize = null;
+ private int m_previewFormat = ImageFormat.NV21; // Default preview format on all devices
+ private int m_previewBytesPerLine = -1;
private QtCameraListener(int id)
{
@@ -86,6 +88,16 @@ public class QtCameraListener implements Camera.ShutterCallback,
return m_previewSize.height;
}
+ public int previewFormat()
+ {
+ return m_previewFormat;
+ }
+
+ public int previewBytesPerLine()
+ {
+ return m_previewBytesPerLine;
+ }
+
public void setupPreviewCallback(Camera camera)
{
// Clear previous callback (also clears added buffers)
@@ -94,8 +106,37 @@ public class QtCameraListener implements Camera.ShutterCallback,
final Camera.Parameters params = camera.getParameters();
m_previewSize = params.getPreviewSize();
- double bytesPerPixel = ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8.0;
- int bufferSizeNeeded = (int) Math.ceil(bytesPerPixel * m_previewSize.width * m_previewSize.height);
+ m_previewFormat = params.getPreviewFormat();
+
+ int bufferSizeNeeded = 0;
+ if (m_previewFormat == ImageFormat.YV12) {
+ // For YV12, bytes per line must be a multiple of 16
+ final int yStride = (int) Math.ceil(m_previewSize.width / 16.0) * 16;
+ final int uvStride = (int) Math.ceil((yStride / 2) / 16.0) * 16;
+ final int ySize = yStride * m_previewSize.height;
+ final int uvSize = uvStride * m_previewSize.height / 2;
+ bufferSizeNeeded = ySize + uvSize * 2;
+
+ m_previewBytesPerLine = yStride;
+
+ } else {
+ double bytesPerPixel = ImageFormat.getBitsPerPixel(m_previewFormat) / 8.0;
+ bufferSizeNeeded = (int) Math.ceil(bytesPerPixel * m_previewSize.width * m_previewSize.height);
+
+ // bytes per line are calculated only for the first plane
+ switch (m_previewFormat) {
+ case ImageFormat.NV21:
+ m_previewBytesPerLine = m_previewSize.width; // 1 byte per sample and tightly packed
+ break;
+ case ImageFormat.RGB_565:
+ case ImageFormat.YUY2:
+ m_previewBytesPerLine = m_previewSize.width * 2; // 2 bytes per pixel
+ break;
+ default:
+ m_previewBytesPerLine = -1;
+ break;
+ }
+ }
// We could keep the same buffers when they are already bigger than the required size
// but the Android doc says the size must match, so in doubt just replace them.
@@ -117,8 +158,12 @@ public class QtCameraListener implements Camera.ShutterCallback,
m_lastPreviewBuffer = data;
- if (data != null && m_notifyNewFrames)
- notifyNewPreviewFrame(m_cameraId, data, m_previewSize.width, m_previewSize.height);
+ if (data != null && m_notifyNewFrames) {
+ notifyNewPreviewFrame(m_cameraId, data,
+ m_previewSize.width, m_previewSize.height,
+ m_previewFormat,
+ m_previewBytesPerLine);
+ }
}
@Override
@@ -142,5 +187,6 @@ public class QtCameraListener implements Camera.ShutterCallback,
private static native void notifyAutoFocusComplete(int id, boolean success);
private static native void notifyPictureExposed(int id);
private static native void notifyPictureCaptured(int id, byte[] data);
- private static native void notifyNewPreviewFrame(int id, byte[] data, int width, int height);
+ private static native void notifyNewPreviewFrame(int id, byte[] data, int width, int height,
+ int pixelFormat, int bytesPerLine);
}
diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceHolderCallback.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceHolderCallback.java
new file mode 100644
index 000000000..266d8a150
--- /dev/null
+++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceHolderCallback.java
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtMultimedia of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+package org.qtproject.qt5.android.multimedia;
+
+import android.view.SurfaceHolder;
+
+public class QtSurfaceHolderCallback implements SurfaceHolder.Callback
+{
+ private long m_id = -1;
+
+ public QtSurfaceHolderCallback(long id)
+ {
+ m_id = id;
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
+ {
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder)
+ {
+ notifySurfaceCreated(m_id);
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder)
+ {
+ notifySurfaceDestroyed(m_id);
+ }
+
+
+ private static native void notifySurfaceCreated(long id);
+ private static native void notifySurfaceDestroyed(long id);
+}
diff --git a/src/plugins/android/src/common/common.pri b/src/plugins/android/src/common/common.pri
index f99dad507..9c741bd94 100644
--- a/src/plugins/android/src/common/common.pri
+++ b/src/plugins/android/src/common/common.pri
@@ -2,9 +2,8 @@ INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/qandroidvideooutput.h \
- $$PWD/qandroidvideorendercontrol.h \
$$PWD/qandroidmultimediautils.h
SOURCES += \
- $$PWD/qandroidvideorendercontrol.cpp \
+ $$PWD/qandroidvideooutput.cpp \
$$PWD/qandroidmultimediautils.cpp
diff --git a/src/plugins/android/src/common/qandroidmultimediautils.cpp b/src/plugins/android/src/common/qandroidmultimediautils.cpp
index a41cc0e1b..6b6ca3255 100644
--- a/src/plugins/android/src/common/qandroidmultimediautils.cpp
+++ b/src/plugins/android/src/common/qandroidmultimediautils.cpp
@@ -68,563 +68,39 @@ bool qt_sizeLessThan(const QSize &s1, const QSize &s2)
return s1.width() * s1.height() < s2.width() * s2.height();
}
-// Pre-computed Y coefficients for all possible y values (0-255). Stored as fixed-point (16:16)
-// Y = 1.164 * (y - 16)
-static const int coefficientsY[256] = {
- -593888, -555746, -517604, -479462, -441320, -403178, -365036, -326894, -288752, -250610,
- -212468, -174326, -136184, -98042, -59900, -21758, 16384, 54526, 92668, 130810,
- 168952, 207094, 245236, 283378, 321520, 359662, 397804, 435946, 474088, 512230,
- 550372, 588514, 626656, 664798, 702940, 741082, 779224, 817366, 855508, 893650,
- 931792, 969934, 1008076, 1046218, 1084360, 1122502, 1160644, 1198786, 1236928, 1275070,
- 1313212, 1351354, 1389496, 1427638, 1465780, 1503922, 1542064, 1580206, 1618348, 1656490,
- 1694632, 1732774, 1770916, 1809058, 1847200, 1885342, 1923484, 1961626, 1999768, 2037910,
- 2076052, 2114194, 2152336, 2190478, 2228620, 2266762, 2304904, 2343046, 2381188, 2419330,
- 2457472, 2495614, 2533756, 2571898, 2610040, 2648182, 2686324, 2724466, 2762608, 2800750,
- 2838892, 2877034, 2915176, 2953318, 2991460, 3029602, 3067744, 3105886, 3144028, 3182170,
- 3220312, 3258454, 3296596, 3334738, 3372880, 3411022, 3449164, 3487306, 3525448, 3563590,
- 3601732, 3639874, 3678016, 3716158, 3754300, 3792442, 3830584, 3868726, 3906868, 3945010,
- 3983152, 4021294, 4059436, 4097578, 4135720, 4173862, 4212004, 4250146, 4288288, 4326430,
- 4364572, 4402714, 4440856, 4478998, 4517140, 4555282, 4593424, 4631566, 4669708, 4707850,
- 4745992, 4784134, 4822276, 4860418, 4898560, 4936702, 4974844, 5012986, 5051128, 5089270,
- 5127412, 5165554, 5203696, 5241838, 5279980, 5318122, 5356264, 5394406, 5432548, 5470690,
- 5508832, 5546974, 5585116, 5623258, 5661400, 5699542, 5737684, 5775826, 5813968, 5852110,
- 5890252, 5928394, 5966536, 6004678, 6042820, 6080962, 6119104, 6157246, 6195388, 6233530,
- 6271672, 6309814, 6347956, 6386098, 6424240, 6462382, 6500524, 6538666, 6576808, 6614950,
- 6653092, 6691234, 6729376, 6767518, 6805660, 6843802, 6881944, 6920086, 6958228, 6996370,
- 7034512, 7072654, 7110796, 7148938, 7187080, 7225222, 7263364, 7301506, 7339648, 7377790,
- 7415932, 7454074, 7492216, 7530358, 7568500, 7606642, 7644784, 7682926, 7721068, 7759210,
- 7797352, 7835494, 7873636, 7911778, 7949920, 7988062, 8026204, 8064346, 8102488, 8140630,
- 8178772, 8216914, 8255056, 8293198, 8331340, 8369482, 8407624, 8445766, 8483908, 8522050,
- 8560192, 8598334, 8636476, 8674618, 8712760, 8750902, 8789044, 8827186, 8865328, 8903470,
- 8941612, 8979754, 9017896, 9056038, 9094180, 9132322
-};
-
-// V lookup table for the Red component. Stored as fixed-point (16:16).
-// V = 1.596 * (v - 128)
-static const int coefficientsRV[256] = {
- -6694144, -6641846, -6589548, -6537250, -6484952, -6432654, -6380356, -6328058, -6275760,
- -6223462, -6171164, -6118866, -6066568, -6014270, -5961972, -5909674, -5857376, -5805078,
- -5752780, -5700482, -5648184, -5595886, -5543588, -5491290, -5438992, -5386694, -5334396,
- -5282098, -5229800, -5177502, -5125204, -5072906, -5020608, -4968310, -4916012, -4863714,
- -4811416, -4759118, -4706820, -4654522, -4602224, -4549926, -4497628, -4445330, -4393032,
- -4340734, -4288436, -4236138, -4183840, -4131542, -4079244, -4026946, -3974648, -3922350,
- -3870052, -3817754, -3765456, -3713158, -3660860, -3608562, -3556264, -3503966, -3451668,
- -3399370, -3347072, -3294774, -3242476, -3190178, -3137880, -3085582, -3033284, -2980986,
- -2928688, -2876390, -2824092, -2771794, -2719496, -2667198, -2614900, -2562602, -2510304,
- -2458006, -2405708, -2353410, -2301112, -2248814, -2196516, -2144218, -2091920, -2039622,
- -1987324, -1935026, -1882728, -1830430, -1778132, -1725834, -1673536, -1621238, -1568940,
- -1516642, -1464344, -1412046, -1359748, -1307450, -1255152, -1202854, -1150556, -1098258,
- -1045960, -993662, -941364, -889066, -836768, -784470, -732172, -679874, -627576,
- -575278, -522980, -470682, -418384, -366086, -313788, -261490, -209192, -156894,
- -104596, -52298, 0, 52298, 104596, 156894, 209192, 261490, 313788,
- 366086, 418384, 470682, 522980, 575278, 627576, 679874, 732172, 784470,
- 836768, 889066, 941364, 993662, 1045960, 1098258, 1150556, 1202854, 1255152,
- 1307450, 1359748, 1412046, 1464344, 1516642, 1568940, 1621238, 1673536, 1725834,
- 1778132, 1830430, 1882728, 1935026, 1987324, 2039622, 2091920, 2144218, 2196516,
- 2248814, 2301112, 2353410, 2405708, 2458006, 2510304, 2562602, 2614900, 2667198,
- 2719496, 2771794, 2824092, 2876390, 2928688, 2980986, 3033284, 3085582, 3137880,
- 3190178, 3242476, 3294774, 3347072, 3399370, 3451668, 3503966, 3556264, 3608562,
- 3660860, 3713158, 3765456, 3817754, 3870052, 3922350, 3974648, 4026946, 4079244,
- 4131542, 4183840, 4236138, 4288436, 4340734, 4393032, 4445330, 4497628, 4549926,
- 4602224, 4654522, 4706820, 4759118, 4811416, 4863714, 4916012, 4968310, 5020608,
- 5072906, 5125204, 5177502, 5229800, 5282098, 5334396, 5386694, 5438992, 5491290,
- 5543588, 5595886, 5648184, 5700482, 5752780, 5805078, 5857376, 5909674, 5961972,
- 6014270, 6066568, 6118866, 6171164, 6223462, 6275760, 6328058, 6380356, 6432654,
- 6484952, 6537250, 6589548, 6641846
-};
-
-// U lookup table for the Green component. Stored as fixed-point (16:16).
-// U = 0.391 * (u - 128)
-static const int coefficientsGU[256] = {
- 1639936, 1627124, 1614312, 1601500, 1588688, 1575876, 1563064, 1550252, 1537440,
- 1524628, 1511816, 1499004, 1486192, 1473380, 1460568, 1447756, 1434944, 1422132,
- 1409320, 1396508, 1383696, 1370884, 1358072, 1345260, 1332448, 1319636, 1306824,
- 1294012, 1281200, 1268388, 1255576, 1242764, 1229952, 1217140, 1204328, 1191516,
- 1178704, 1165892, 1153080, 1140268, 1127456, 1114644, 1101832, 1089020, 1076208,
- 1063396, 1050584, 1037772, 1024960, 1012148, 999336, 986524, 973712, 960900,
- 948088, 935276, 922464, 909652, 896840, 884028, 871216, 858404, 845592,
- 832780, 819968, 807156, 794344, 781532, 768720, 755908, 743096, 730284,
- 717472, 704660, 691848, 679036, 666224, 653412, 640600, 627788, 614976,
- 602164, 589352, 576540, 563728, 550916, 538104, 525292, 512480, 499668,
- 486856, 474044, 461232, 448420, 435608, 422796, 409984, 397172, 384360,
- 371548, 358736, 345924, 333112, 320300, 307488, 294676, 281864, 269052,
- 256240, 243428, 230616, 217804, 204992, 192180, 179368, 166556, 153744,
- 140932, 128120, 115308, 102496, 89684, 76872, 64060, 51248, 38436,
- 25624, 12812, 0, -12812, -25624, -38436, -51248, -64060, -76872,
- -89684, -102496, -115308, -128120, -140932, -153744, -166556, -179368, -192180,
- -204992, -217804, -230616, -243428, -256240, -269052, -281864, -294676, -307488,
- -320300, -333112, -345924, -358736, -371548, -384360, -397172, -409984, -422796,
- -435608, -448420, -461232, -474044, -486856, -499668, -512480, -525292, -538104,
- -550916, -563728, -576540, -589352, -602164, -614976, -627788, -640600, -653412,
- -666224, -679036, -691848, -704660, -717472, -730284, -743096, -755908, -768720,
- -781532, -794344, -807156, -819968, -832780, -845592, -858404, -871216, -884028,
- -896840, -909652, -922464, -935276, -948088, -960900, -973712, -986524, -999336,
- -1012148, -1024960, -1037772, -1050584, -1063396, -1076208, -1089020, -1101832, -1114644,
- -1127456, -1140268, -1153080, -1165892, -1178704, -1191516, -1204328, -1217140, -1229952,
- -1242764, -1255576, -1268388, -1281200, -1294012, -1306824, -1319636, -1332448, -1345260,
- -1358072, -1370884, -1383696, -1396508, -1409320, -1422132, -1434944, -1447756, -1460568,
- -1473380, -1486192, -1499004, -1511816, -1524628, -1537440, -1550252, -1563064, -1575876,
- -1588688, -1601500, -1614312, -1627124
-};
-
-// V lookup table for the Green component. Stored as fixed-point (16:16).
-// V = 0.813 * (v - 128)
-static const int coefficientsGV[256] = {
- 3409920, 3383280, 3356640, 3330000, 3303360, 3276720, 3250080, 3223440, 3196800,
- 3170160, 3143520, 3116880, 3090240, 3063600, 3036960, 3010320, 2983680, 2957040,
- 2930400, 2903760, 2877120, 2850480, 2823840, 2797200, 2770560, 2743920, 2717280,
- 2690640, 2664000, 2637360, 2610720, 2584080, 2557440, 2530800, 2504160, 2477520,
- 2450880, 2424240, 2397600, 2370960, 2344320, 2317680, 2291040, 2264400, 2237760,
- 2211120, 2184480, 2157840, 2131200, 2104560, 2077920, 2051280, 2024640, 1998000,
- 1971360, 1944720, 1918080, 1891440, 1864800, 1838160, 1811520, 1784880, 1758240,
- 1731600, 1704960, 1678320, 1651680, 1625040, 1598400, 1571760, 1545120, 1518480,
- 1491840, 1465200, 1438560, 1411920, 1385280, 1358640, 1332000, 1305360, 1278720,
- 1252080, 1225440, 1198800, 1172160, 1145520, 1118880, 1092240, 1065600, 1038960,
- 1012320, 985680, 959040, 932400, 905760, 879120, 852480, 825840, 799200,
- 772560, 745920, 719280, 692640, 666000, 639360, 612720, 586080, 559440,
- 532800, 506160, 479520, 452880, 426240, 399600, 372960, 346320, 319680,
- 293040, 266400, 239760, 213120, 186480, 159840, 133200, 106560, 79920,
- 53280, 26640, 0, -26640, -53280, -79920, -106560, -133200, -159840,
- -186480, -213120, -239760, -266400, -293040, -319680, -346320, -372960, -399600,
- -426240, -452880, -479520, -506160, -532800, -559440, -586080, -612720, -639360,
- -666000, -692640, -719280, -745920, -772560, -799200, -825840, -852480, -879120,
- -905760, -932400, -959040, -985680, -1012320, -1038960, -1065600, -1092240, -1118880,
- -1145520, -1172160, -1198800, -1225440, -1252080, -1278720, -1305360, -1332000, -1358640,
- -1385280, -1411920, -1438560, -1465200, -1491840, -1518480, -1545120, -1571760, -1598400,
- -1625040, -1651680, -1678320, -1704960, -1731600, -1758240, -1784880, -1811520, -1838160,
- -1864800, -1891440, -1918080, -1944720, -1971360, -1998000, -2024640, -2051280, -2077920,
- -2104560, -2131200, -2157840, -2184480, -2211120, -2237760, -2264400, -2291040, -2317680,
- -2344320, -2370960, -2397600, -2424240, -2450880, -2477520, -2504160, -2530800, -2557440,
- -2584080, -2610720, -2637360, -2664000, -2690640, -2717280, -2743920, -2770560, -2797200,
- -2823840, -2850480, -2877120, -2903760, -2930400, -2957040, -2983680, -3010320, -3036960,
- -3063600, -3090240, -3116880, -3143520, -3170160, -3196800, -3223440, -3250080, -3276720,
- -3303360, -3330000, -3356640, -3383280
-};
-
-// U lookup table for the Blue component. Stored as fixed-point (16:16).
-// U = 2.018 * (u - 128)
-static const int coefficientsBU[256] = {
- -8464128, -8398002, -8331876, -8265750, -8199624, -8133498, -8067372, -8001246, -7935120,
- -7868994, -7802868, -7736742, -7670616, -7604490, -7538364, -7472238, -7406112, -7339986,
- -7273860, -7207734, -7141608, -7075482, -7009356, -6943230, -6877104, -6810978, -6744852,
- -6678726, -6612600, -6546474, -6480348, -6414222, -6348096, -6281970, -6215844, -6149718,
- -6083592, -6017466, -5951340, -5885214, -5819088, -5752962, -5686836, -5620710, -5554584,
- -5488458, -5422332, -5356206, -5290080, -5223954, -5157828, -5091702, -5025576, -4959450,
- -4893324, -4827198, -4761072, -4694946, -4628820, -4562694, -4496568, -4430442, -4364316,
- -4298190, -4232064, -4165938, -4099812, -4033686, -3967560, -3901434, -3835308, -3769182,
- -3703056, -3636930, -3570804, -3504678, -3438552, -3372426, -3306300, -3240174, -3174048,
- -3107922, -3041796, -2975670, -2909544, -2843418, -2777292, -2711166, -2645040, -2578914,
- -2512788, -2446662, -2380536, -2314410, -2248284, -2182158, -2116032, -2049906, -1983780,
- -1917654, -1851528, -1785402, -1719276, -1653150, -1587024, -1520898, -1454772, -1388646,
- -1322520, -1256394, -1190268, -1124142, -1058016, -991890, -925764, -859638, -793512,
- -727386, -661260, -595134, -529008, -462882, -396756, -330630, -264504, -198378,
- -132252, -66126, 0, 66126, 132252, 198378, 264504, 330630, 396756,
- 462882, 529008, 595134, 661260, 727386, 793512, 859638, 925764, 991890,
- 1058016, 1124142, 1190268, 1256394, 1322520, 1388646, 1454772, 1520898, 1587024,
- 1653150, 1719276, 1785402, 1851528, 1917654, 1983780, 2049906, 2116032, 2182158,
- 2248284, 2314410, 2380536, 2446662, 2512788, 2578914, 2645040, 2711166, 2777292,
- 2843418, 2909544, 2975670, 3041796, 3107922, 3174048, 3240174, 3306300, 3372426,
- 3438552, 3504678, 3570804, 3636930, 3703056, 3769182, 3835308, 3901434, 3967560,
- 4033686, 4099812, 4165938, 4232064, 4298190, 4364316, 4430442, 4496568, 4562694,
- 4628820, 4694946, 4761072, 4827198, 4893324, 4959450, 5025576, 5091702, 5157828,
- 5223954, 5290080, 5356206, 5422332, 5488458, 5554584, 5620710, 5686836, 5752962,
- 5819088, 5885214, 5951340, 6017466, 6083592, 6149718, 6215844, 6281970, 6348096,
- 6414222, 6480348, 6546474, 6612600, 6678726, 6744852, 6810978, 6877104, 6943230,
- 7009356, 7075482, 7141608, 7207734, 7273860, 7339986, 7406112, 7472238, 7538364,
- 7604490, 7670616, 7736742, 7802868, 7868994, 7935120, 8001246, 8067372, 8133498,
- 8199624, 8265750, 8331876, 8398002
-};
-
-// R = min(max(r, 0), 255) << 16
-// where 'r' is the converted red component from YUV, which is always in the range -320 <= r < 704
-// and needs to be clamped to 0-255. It also precomputes the bitshift needed to create an RGB value.
-static const quint32 _clampedR[1024] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 65536, 131072, 196608, 262144, 327680, 393216, 458752,
- 524288, 589824, 655360, 720896, 786432, 851968, 917504, 983040,
- 1048576, 1114112, 1179648, 1245184, 1310720, 1376256, 1441792, 1507328,
- 1572864, 1638400, 1703936, 1769472, 1835008, 1900544, 1966080, 2031616,
- 2097152, 2162688, 2228224, 2293760, 2359296, 2424832, 2490368, 2555904,
- 2621440, 2686976, 2752512, 2818048, 2883584, 2949120, 3014656, 3080192,
- 3145728, 3211264, 3276800, 3342336, 3407872, 3473408, 3538944, 3604480,
- 3670016, 3735552, 3801088, 3866624, 3932160, 3997696, 4063232, 4128768,
- 4194304, 4259840, 4325376, 4390912, 4456448, 4521984, 4587520, 4653056,
- 4718592, 4784128, 4849664, 4915200, 4980736, 5046272, 5111808, 5177344,
- 5242880, 5308416, 5373952, 5439488, 5505024, 5570560, 5636096, 5701632,
- 5767168, 5832704, 5898240, 5963776, 6029312, 6094848, 6160384, 6225920,
- 6291456, 6356992, 6422528, 6488064, 6553600, 6619136, 6684672, 6750208,
- 6815744, 6881280, 6946816, 7012352, 7077888, 7143424, 7208960, 7274496,
- 7340032, 7405568, 7471104, 7536640, 7602176, 7667712, 7733248, 7798784,
- 7864320, 7929856, 7995392, 8060928, 8126464, 8192000, 8257536, 8323072,
- 8388608, 8454144, 8519680, 8585216, 8650752, 8716288, 8781824, 8847360,
- 8912896, 8978432, 9043968, 9109504, 9175040, 9240576, 9306112, 9371648,
- 9437184, 9502720, 9568256, 9633792, 9699328, 9764864, 9830400, 9895936,
- 9961472, 10027008, 10092544, 10158080, 10223616, 10289152, 10354688, 10420224,
- 10485760, 10551296, 10616832, 10682368, 10747904, 10813440, 10878976, 10944512,
- 11010048, 11075584, 11141120, 11206656, 11272192, 11337728, 11403264, 11468800,
- 11534336, 11599872, 11665408, 11730944, 11796480, 11862016, 11927552, 11993088,
- 12058624, 12124160, 12189696, 12255232, 12320768, 12386304, 12451840, 12517376,
- 12582912, 12648448, 12713984, 12779520, 12845056, 12910592, 12976128, 13041664,
- 13107200, 13172736, 13238272, 13303808, 13369344, 13434880, 13500416, 13565952,
- 13631488, 13697024, 13762560, 13828096, 13893632, 13959168, 14024704, 14090240,
- 14155776, 14221312, 14286848, 14352384, 14417920, 14483456, 14548992, 14614528,
- 14680064, 14745600, 14811136, 14876672, 14942208, 15007744, 15073280, 15138816,
- 15204352, 15269888, 15335424, 15400960, 15466496, 15532032, 15597568, 15663104,
- 15728640, 15794176, 15859712, 15925248, 15990784, 16056320, 16121856, 16187392,
- 16252928, 16318464, 16384000, 16449536, 16515072, 16580608, 16646144, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680
-};
-
-// G = min(max(g, 0), 255) << 8
-// where 'g' is the converted green component from YUV, which is always in the range -320 <= r < 704
-// and needs to be clamped to 0-255. It also precomputes the bitshift needed to create an RGB value.
-static const quint32 _clampedG[1024] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 256, 512, 768, 1024, 1280, 1536, 1792,
- 2048, 2304, 2560, 2816, 3072, 3328, 3584, 3840,
- 4096, 4352, 4608, 4864, 5120, 5376, 5632, 5888,
- 6144, 6400, 6656, 6912, 7168, 7424, 7680, 7936,
- 8192, 8448, 8704, 8960, 9216, 9472, 9728, 9984,
- 10240, 10496, 10752, 11008, 11264, 11520, 11776, 12032,
- 12288, 12544, 12800, 13056, 13312, 13568, 13824, 14080,
- 14336, 14592, 14848, 15104, 15360, 15616, 15872, 16128,
- 16384, 16640, 16896, 17152, 17408, 17664, 17920, 18176,
- 18432, 18688, 18944, 19200, 19456, 19712, 19968, 20224,
- 20480, 20736, 20992, 21248, 21504, 21760, 22016, 22272,
- 22528, 22784, 23040, 23296, 23552, 23808, 24064, 24320,
- 24576, 24832, 25088, 25344, 25600, 25856, 26112, 26368,
- 26624, 26880, 27136, 27392, 27648, 27904, 28160, 28416,
- 28672, 28928, 29184, 29440, 29696, 29952, 30208, 30464,
- 30720, 30976, 31232, 31488, 31744, 32000, 32256, 32512,
- 32768, 33024, 33280, 33536, 33792, 34048, 34304, 34560,
- 34816, 35072, 35328, 35584, 35840, 36096, 36352, 36608,
- 36864, 37120, 37376, 37632, 37888, 38144, 38400, 38656,
- 38912, 39168, 39424, 39680, 39936, 40192, 40448, 40704,
- 40960, 41216, 41472, 41728, 41984, 42240, 42496, 42752,
- 43008, 43264, 43520, 43776, 44032, 44288, 44544, 44800,
- 45056, 45312, 45568, 45824, 46080, 46336, 46592, 46848,
- 47104, 47360, 47616, 47872, 48128, 48384, 48640, 48896,
- 49152, 49408, 49664, 49920, 50176, 50432, 50688, 50944,
- 51200, 51456, 51712, 51968, 52224, 52480, 52736, 52992,
- 53248, 53504, 53760, 54016, 54272, 54528, 54784, 55040,
- 55296, 55552, 55808, 56064, 56320, 56576, 56832, 57088,
- 57344, 57600, 57856, 58112, 58368, 58624, 58880, 59136,
- 59392, 59648, 59904, 60160, 60416, 60672, 60928, 61184,
- 61440, 61696, 61952, 62208, 62464, 62720, 62976, 63232,
- 63488, 63744, 64000, 64256, 64512, 64768, 65024, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280
-};
-
-// B = min(max(b, 0), 255)
-// where 'b' is the converted blue component from YUV, which is always in the range -320 <= r < 704
-static const quint32 _clampedB[1024] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
- 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
- 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
- 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
- 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
- 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
- 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
- 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
- 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
- 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
- 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
- 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
-};
-
-static const quint32 *clampedR = _clampedR + 320;
-static const quint32 *clampedG = _clampedG + 320;
-static const quint32 *clampedB = _clampedB + 320;
-
-#define MAKE_RGB(r, g, b) 0xff000000 | clampedR[r] | clampedG[g] | clampedB[b]
-
-void qt_convert_NV21_to_ARGB32(const uchar *yuv, quint32 *rgb, int width, int height)
+QVideoFrame::PixelFormat qt_pixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat f)
{
- const uchar *y0 = yuv;
- const uchar *y1 = yuv + width;
- const uchar *vu = yuv + width * height;
-
- quint32 *rgb0 = rgb;
- quint32 *rgb1 = rgb + width;
-
- for (int i = 0; i < height; i += 2) {
- for (int j = 0; j < width; j += 2) {
- int v = *vu++;
- int u = *vu++;
-
- int ruv = coefficientsRV[v] >> 15;
- int guv = (coefficientsGU[u] + coefficientsGV[v]) >> 15;
- int buv = coefficientsBU[u] >> 15;
-
- int y = coefficientsY[*y0++] >> 15;
- int r = y + ruv;
- int g = y + guv;
- int b = y + buv;
- *rgb0++ = MAKE_RGB(r, g, b);
-
- y = coefficientsY[*y0++] >> 15;
- r = y + ruv;
- g = y + guv;
- b = y + buv;
- *rgb0++ = MAKE_RGB(r, g, b);
-
- y = coefficientsY[*y1++] >> 15;
- r = y + ruv;
- g = y + guv;
- b = y + buv;
- *rgb1++ = MAKE_RGB(r, g, b);
-
- y = coefficientsY[*y1++] >> 15;
- r = y + ruv;
- g = y + guv;
- b = y + buv;
- *rgb1++ = MAKE_RGB(r, g, b);
- }
+ switch (f) {
+ case AndroidCamera::NV21:
+ return QVideoFrame::Format_NV21;
+ case AndroidCamera::YV12:
+ return QVideoFrame::Format_YV12;
+ case AndroidCamera::RGB565:
+ return QVideoFrame::Format_RGB565;
+ case AndroidCamera::YUY2:
+ return QVideoFrame::Format_YUYV;
+ case AndroidCamera::JPEG:
+ return QVideoFrame::Format_Jpeg;
+ default:
+ return QVideoFrame::Format_Invalid;
+ }
+}
- rgb0 += width;
- rgb1 += width;
- y0 += width;
- y1 += width;
+AndroidCamera::ImageFormat qt_androidImageFormatFromPixelFormat(QVideoFrame::PixelFormat f)
+{
+ switch (f) {
+ case QVideoFrame::Format_NV21:
+ return AndroidCamera::NV21;
+ case QVideoFrame::Format_YV12:
+ return AndroidCamera::YV12;
+ case QVideoFrame::Format_RGB565:
+ return AndroidCamera::RGB565;
+ case QVideoFrame::Format_YUYV:
+ return AndroidCamera::YUY2;
+ case QVideoFrame::Format_Jpeg:
+ return AndroidCamera::JPEG;
+ default:
+ return AndroidCamera::UnknownImageFormat;
}
}
diff --git a/src/plugins/android/src/common/qandroidmultimediautils.h b/src/plugins/android/src/common/qandroidmultimediautils.h
index ea6a322e7..622f343f5 100644
--- a/src/plugins/android/src/common/qandroidmultimediautils.h
+++ b/src/plugins/android/src/common/qandroidmultimediautils.h
@@ -36,6 +36,7 @@
#include <qglobal.h>
#include <qsize.h>
+#include "androidcamera.h"
QT_BEGIN_NAMESPACE
@@ -45,7 +46,8 @@ int qt_findClosestValue(const QList<int> &list, int value);
bool qt_sizeLessThan(const QSize &s1, const QSize &s2);
-void qt_convert_NV21_to_ARGB32(const uchar *yuv, quint32 *rgb, int width, int height);
+QVideoFrame::PixelFormat qt_pixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat f);
+AndroidCamera::ImageFormat qt_androidImageFormatFromPixelFormat(QVideoFrame::PixelFormat f);
QT_END_NAMESPACE
diff --git a/src/plugins/android/src/common/qandroidvideorendercontrol.cpp b/src/plugins/android/src/common/qandroidvideooutput.cpp
index cd9c9d1d6..82c27035d 100644
--- a/src/plugins/android/src/common/qandroidvideorendercontrol.cpp
+++ b/src/plugins/android/src/common/qandroidvideooutput.cpp
@@ -31,9 +31,9 @@
**
****************************************************************************/
-#include "qandroidvideorendercontrol.h"
-#include "androidsurfacetexture.h"
+#include "qandroidvideooutput.h"
+#include "androidsurfacetexture.h"
#include <QAbstractVideoSurface>
#include <QVideoSurfaceFormat>
#include <qevent.h>
@@ -59,19 +59,13 @@ static const GLfloat g_texture_data[] = {
0.f, 1.f
};
-OpenGLResourcesDeleter::~OpenGLResourcesDeleter()
-{
- glDeleteTextures(1, &m_textureID);
- delete m_fbo;
- delete m_program;
-}
class AndroidTextureVideoBuffer : public QAbstractVideoBuffer
{
public:
- AndroidTextureVideoBuffer(QAndroidVideoRendererControl *control)
+ AndroidTextureVideoBuffer(QAndroidTextureVideoOutput *output)
: QAbstractVideoBuffer(GLTextureHandle)
- , m_control(control)
+ , m_output(output)
, m_textureUpdated(false)
, m_mapMode(NotMapped)
{
@@ -86,7 +80,7 @@ public:
if (m_mapMode == NotMapped && mode == ReadOnly) {
updateFrame();
m_mapMode = mode;
- m_image = m_control->m_fbo->toImage();
+ m_image = m_output->m_fbo->toImage();
if (numBytes)
*numBytes = m_image.byteCount();
@@ -110,7 +104,7 @@ public:
{
AndroidTextureVideoBuffer *that = const_cast<AndroidTextureVideoBuffer*>(this);
that->updateFrame();
- return m_control->m_fbo->texture();
+ return m_output->m_fbo->texture();
}
private:
@@ -118,19 +112,47 @@ private:
{
if (!m_textureUpdated) {
// update the video texture (called from the render thread)
- m_control->renderFrameToFbo();
+ m_output->renderFrameToFbo();
m_textureUpdated = true;
}
}
- QAndroidVideoRendererControl *m_control;
+ QAndroidTextureVideoOutput *m_output;
bool m_textureUpdated;
MapMode m_mapMode;
QImage m_image;
};
-QAndroidVideoRendererControl::QAndroidVideoRendererControl(QObject *parent)
- : QVideoRendererControl(parent)
+
+class OpenGLResourcesDeleter : public QObject
+{
+public:
+ OpenGLResourcesDeleter()
+ : m_textureID(0)
+ , m_fbo(0)
+ , m_program(0)
+ { }
+
+ ~OpenGLResourcesDeleter()
+ {
+ glDeleteTextures(1, &m_textureID);
+ delete m_fbo;
+ delete m_program;
+ }
+
+ void setTexture(quint32 id) { m_textureID = id; }
+ void setFbo(QOpenGLFramebufferObject *fbo) { m_fbo = fbo; }
+ void setShaderProgram(QOpenGLShaderProgram *prog) { m_program = prog; }
+
+private:
+ quint32 m_textureID;
+ QOpenGLFramebufferObject *m_fbo;
+ QOpenGLShaderProgram *m_program;
+};
+
+
+QAndroidTextureVideoOutput::QAndroidTextureVideoOutput(QObject *parent)
+ : QAndroidVideoOutput(parent)
, m_surface(0)
, m_surfaceTexture(0)
, m_externalTex(0)
@@ -138,9 +160,10 @@ QAndroidVideoRendererControl::QAndroidVideoRendererControl(QObject *parent)
, m_program(0)
, m_glDeleter(0)
{
+
}
-QAndroidVideoRendererControl::~QAndroidVideoRendererControl()
+QAndroidTextureVideoOutput::~QAndroidTextureVideoOutput()
{
clearSurfaceTexture();
@@ -148,12 +171,12 @@ QAndroidVideoRendererControl::~QAndroidVideoRendererControl()
m_glDeleter->deleteLater();
}
-QAbstractVideoSurface *QAndroidVideoRendererControl::surface() const
+QAbstractVideoSurface *QAndroidTextureVideoOutput::surface() const
{
return m_surface;
}
-void QAndroidVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
+void QAndroidTextureVideoOutput::setSurface(QAbstractVideoSurface *surface)
{
if (surface == m_surface)
return;
@@ -172,12 +195,12 @@ void QAndroidVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
}
}
-bool QAndroidVideoRendererControl::isReady()
+bool QAndroidTextureVideoOutput::isReady()
{
return QOpenGLContext::currentContext() || m_externalTex;
}
-bool QAndroidVideoRendererControl::initSurfaceTexture()
+bool QAndroidTextureVideoOutput::initSurfaceTexture()
{
if (m_surfaceTexture)
return true;
@@ -210,7 +233,7 @@ bool QAndroidVideoRendererControl::initSurfaceTexture()
return m_surfaceTexture != 0;
}
-void QAndroidVideoRendererControl::clearSurfaceTexture()
+void QAndroidTextureVideoOutput::clearSurfaceTexture()
{
if (m_surfaceTexture) {
delete m_surfaceTexture;
@@ -218,7 +241,7 @@ void QAndroidVideoRendererControl::clearSurfaceTexture()
}
}
-AndroidSurfaceTexture *QAndroidVideoRendererControl::surfaceTexture()
+AndroidSurfaceTexture *QAndroidTextureVideoOutput::surfaceTexture()
{
if (!initSurfaceTexture())
return 0;
@@ -226,7 +249,7 @@ AndroidSurfaceTexture *QAndroidVideoRendererControl::surfaceTexture()
return m_surfaceTexture;
}
-void QAndroidVideoRendererControl::setVideoSize(const QSize &size)
+void QAndroidTextureVideoOutput::setVideoSize(const QSize &size)
{
QMutexLocker locker(&m_mutex);
@@ -238,19 +261,19 @@ void QAndroidVideoRendererControl::setVideoSize(const QSize &size)
m_nativeSize = size;
}
-void QAndroidVideoRendererControl::stop()
+void QAndroidTextureVideoOutput::stop()
{
if (m_surface && m_surface->isActive())
m_surface->stop();
m_nativeSize = QSize();
}
-void QAndroidVideoRendererControl::reset()
+void QAndroidTextureVideoOutput::reset()
{
clearSurfaceTexture();
}
-void QAndroidVideoRendererControl::onFrameAvailable()
+void QAndroidTextureVideoOutput::onFrameAvailable()
{
if (!m_nativeSize.isValid() || !m_surface)
return;
@@ -274,7 +297,7 @@ void QAndroidVideoRendererControl::onFrameAvailable()
m_surface->present(frame);
}
-void QAndroidVideoRendererControl::renderFrameToFbo()
+void QAndroidTextureVideoOutput::renderFrameToFbo()
{
QMutexLocker locker(&m_mutex);
@@ -333,7 +356,7 @@ void QAndroidVideoRendererControl::renderFrameToFbo()
glEnable(GL_BLEND);
}
-void QAndroidVideoRendererControl::createGLResources()
+void QAndroidTextureVideoOutput::createGLResources()
{
if (!m_fbo || m_fbo->size() != m_nativeSize) {
delete m_fbo;
@@ -374,7 +397,7 @@ void QAndroidVideoRendererControl::createGLResources()
}
}
-void QAndroidVideoRendererControl::customEvent(QEvent *e)
+void QAndroidTextureVideoOutput::customEvent(QEvent *e)
{
if (e->type() == QEvent::User) {
// This is running in the render thread (OpenGL enabled)
diff --git a/src/plugins/android/src/common/qandroidvideooutput.h b/src/plugins/android/src/common/qandroidvideooutput.h
index d45779d12..f4401fa1d 100644
--- a/src/plugins/android/src/common/qandroidvideooutput.h
+++ b/src/plugins/android/src/common/qandroidvideooutput.h
@@ -34,19 +34,27 @@
#ifndef QANDROIDVIDEOOUTPUT_H
#define QANDROIDVIDEOOUTPUT_H
-#include <qglobal.h>
+#include <qobject.h>
#include <qsize.h>
+#include <qmutex.h>
QT_BEGIN_NAMESPACE
class AndroidSurfaceTexture;
+class AndroidSurfaceHolder;
+class QOpenGLFramebufferObject;
+class QOpenGLShaderProgram;
+class OpenGLResourcesDeleter;
+class QAbstractVideoSurface;
-class QAndroidVideoOutput
+class QAndroidVideoOutput : public QObject
{
+ Q_OBJECT
public:
virtual ~QAndroidVideoOutput() { }
virtual AndroidSurfaceTexture *surfaceTexture() { return 0; }
+ virtual AndroidSurfaceHolder *surfaceHolder() { return 0; }
virtual bool isReady() { return true; }
@@ -54,12 +62,56 @@ public:
virtual void stop() { }
virtual void reset() { }
- // signals:
- // void readyChanged(bool);
+Q_SIGNALS:
+ void readyChanged(bool);
+
+protected:
+ QAndroidVideoOutput(QObject *parent) : QObject(parent) { }
};
-#define QAndroidVideoOutput_iid "org.qt-project.qt.qandroidvideooutput/5.0"
-Q_DECLARE_INTERFACE(QAndroidVideoOutput, QAndroidVideoOutput_iid)
+
+class QAndroidTextureVideoOutput : public QAndroidVideoOutput
+{
+ Q_OBJECT
+public:
+ explicit QAndroidTextureVideoOutput(QObject *parent = 0);
+ ~QAndroidTextureVideoOutput() Q_DECL_OVERRIDE;
+
+ QAbstractVideoSurface *surface() const;
+ void setSurface(QAbstractVideoSurface *surface);
+
+ AndroidSurfaceTexture *surfaceTexture() Q_DECL_OVERRIDE;
+
+ bool isReady() Q_DECL_OVERRIDE;
+ void setVideoSize(const QSize &) Q_DECL_OVERRIDE;
+ void stop() Q_DECL_OVERRIDE;
+ void reset() Q_DECL_OVERRIDE;
+
+ void customEvent(QEvent *) Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+ void onFrameAvailable();
+
+private:
+ bool initSurfaceTexture();
+ void renderFrameToFbo();
+ void createGLResources();
+
+ QMutex m_mutex;
+ void clearSurfaceTexture();
+
+ QAbstractVideoSurface *m_surface;
+ QSize m_nativeSize;
+
+ AndroidSurfaceTexture *m_surfaceTexture;
+
+ quint32 m_externalTex;
+ QOpenGLFramebufferObject *m_fbo;
+ QOpenGLShaderProgram *m_program;
+ OpenGLResourcesDeleter *m_glDeleter;
+
+ friend class AndroidTextureVideoBuffer;
+};
QT_END_NAMESPACE
diff --git a/src/plugins/android/src/common/qandroidvideorendercontrol.h b/src/plugins/android/src/common/qandroidvideorendercontrol.h
deleted file mode 100644
index c660758fb..000000000
--- a/src/plugins/android/src/common/qandroidvideorendercontrol.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL21$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QANDROIDVIDEORENDERCONTROL_H
-#define QANDROIDVIDEORENDERCONTROL_H
-
-#include <qvideorenderercontrol.h>
-#include <qmutex.h>
-#include "qandroidvideooutput.h"
-
-QT_BEGIN_NAMESPACE
-
-class QOpenGLTexture;
-class QOpenGLFramebufferObject;
-class QOpenGLShaderProgram;
-class AndroidSurfaceTexture;
-
-class OpenGLResourcesDeleter : public QObject
-{
- Q_OBJECT
-public:
- OpenGLResourcesDeleter()
- : m_textureID(0)
- , m_fbo(0)
- , m_program(0)
- { }
-
- ~OpenGLResourcesDeleter();
-
- void setTexture(quint32 id) { m_textureID = id; }
- void setFbo(QOpenGLFramebufferObject *fbo) { m_fbo = fbo; }
- void setShaderProgram(QOpenGLShaderProgram *prog) { m_program = prog; }
-
-private:
- quint32 m_textureID;
- QOpenGLFramebufferObject *m_fbo;
- QOpenGLShaderProgram *m_program;
-};
-
-class QAndroidVideoRendererControl : public QVideoRendererControl, public QAndroidVideoOutput
-{
- Q_OBJECT
- Q_INTERFACES(QAndroidVideoOutput)
-public:
- explicit QAndroidVideoRendererControl(QObject *parent = 0);
- ~QAndroidVideoRendererControl() Q_DECL_OVERRIDE;
-
- QAbstractVideoSurface *surface() const Q_DECL_OVERRIDE;
- void setSurface(QAbstractVideoSurface *surface) Q_DECL_OVERRIDE;
-
- AndroidSurfaceTexture *surfaceTexture() Q_DECL_OVERRIDE;
- bool isReady() Q_DECL_OVERRIDE;
- void setVideoSize(const QSize &size) Q_DECL_OVERRIDE;
- void stop() Q_DECL_OVERRIDE;
- void reset() Q_DECL_OVERRIDE;
-
- void customEvent(QEvent *) Q_DECL_OVERRIDE;
-
-Q_SIGNALS:
- void readyChanged(bool);
-
-private Q_SLOTS:
- void onFrameAvailable();
-
-private:
- bool initSurfaceTexture();
- void renderFrameToFbo();
- void createGLResources();
-
- QMutex m_mutex;
- void clearSurfaceTexture();
-
- QAbstractVideoSurface *m_surface;
- QSize m_nativeSize;
-
- AndroidSurfaceTexture *m_surfaceTexture;
-
- quint32 m_externalTex;
- QOpenGLFramebufferObject *m_fbo;
- QOpenGLShaderProgram *m_program;
- OpenGLResourcesDeleter *m_glDeleter;
-
- friend class AndroidTextureVideoBuffer;
-};
-
-QT_END_NAMESPACE
-
-#endif // QANDROIDVIDEORENDERCONTROL_H
diff --git a/src/plugins/android/src/mediacapture/mediacapture.pri b/src/plugins/android/src/mediacapture/mediacapture.pri
index fde0e3d6f..2811f0371 100644
--- a/src/plugins/android/src/mediacapture/mediacapture.pri
+++ b/src/plugins/android/src/mediacapture/mediacapture.pri
@@ -22,7 +22,8 @@ SOURCES += \
$$PWD/qandroidvideoencodersettingscontrol.cpp \
$$PWD/qandroidaudioinputselectorcontrol.cpp \
$$PWD/qandroidmediavideoprobecontrol.cpp \
- $$PWD/qandroidcamerainfocontrol.cpp
+ $$PWD/qandroidcamerainfocontrol.cpp \
+ $$PWD/qandroidcameravideorenderercontrol.cpp
HEADERS += \
$$PWD/qandroidcaptureservice.h \
@@ -46,4 +47,5 @@ HEADERS += \
$$PWD/qandroidvideoencodersettingscontrol.h \
$$PWD/qandroidaudioinputselectorcontrol.h \
$$PWD/qandroidmediavideoprobecontrol.h \
- $$PWD/qandroidcamerainfocontrol.h
+ $$PWD/qandroidcamerainfocontrol.h \
+ $$PWD/qandroidcameravideorenderercontrol.h
diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
index 743764cb0..7b065c8c4 100644
--- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
+++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
@@ -43,45 +43,11 @@
#include <qguiapplication.h>
#include <qdebug.h>
#include <qvideoframe.h>
+#include <private/qmemoryvideobuffer_p.h>
+#include <private/qvideoframe_p.h>
QT_BEGIN_NAMESPACE
-class DataVideoBuffer : public QAbstractVideoBuffer
-{
-public:
- DataVideoBuffer(const QByteArray &d, int bpl = -1)
- : QAbstractVideoBuffer(NoHandle)
- , data(d)
- , mode(NotMapped)
- , bytesPerLine(bpl)
- { }
-
- MapMode mapMode() const { return mode; }
-
- uchar *map(MapMode m, int *numBytes, int *bpl)
- {
- if (mode != NotMapped || m == NotMapped)
- return 0;
-
- mode = m;
-
- if (numBytes)
- *numBytes = data.size();
-
- if (bpl)
- *bpl = bytesPerLine;
-
- return reinterpret_cast<uchar *>(data.data());
- }
-
- void unmap() { mode = NotMapped; }
-
-private:
- QByteArray data;
- MapMode mode;
- int bytesPerLine;
-};
-
Q_GLOBAL_STATIC(QList<AndroidCameraInfo>, g_availableCameras)
QAndroidCameraSession::QAndroidCameraSession(QObject *parent)
@@ -102,6 +68,7 @@ QAndroidCameraSession::QAndroidCameraSession(QObject *parent)
, m_readyForCapture(false)
, m_captureCanceled(false)
, m_currentImageCaptureId(-1)
+ , m_previewCallback(0)
{
m_mediaStorageLocation.addStorageLocation(
QMediaStorageLocation::Pictures,
@@ -206,10 +173,11 @@ bool QAndroidCameraSession::open()
if (m_camera) {
connect(m_camera, SIGNAL(pictureExposed()), this, SLOT(onCameraPictureExposed()));
- connect(m_camera, SIGNAL(lastPreviewFrameFetched(QByteArray,int,int)),
- this, SLOT(onLastPreviewFrameFetched(QByteArray,int,int)));
- connect(m_camera, SIGNAL(newPreviewFrame(QByteArray,int,int)),
- this, SLOT(onNewPreviewFrame(QByteArray,int,int)),
+ connect(m_camera, SIGNAL(lastPreviewFrameFetched(QVideoFrame)),
+ this, SLOT(onLastPreviewFrameFetched(QVideoFrame)),
+ Qt::DirectConnection);
+ connect(m_camera, SIGNAL(newPreviewFrame(QVideoFrame)),
+ this, SLOT(onNewPreviewFrame(QVideoFrame)),
Qt::DirectConnection);
connect(m_camera, SIGNAL(pictureCaptured(QByteArray)), this, SLOT(onCameraPictureCaptured(QByteArray)));
connect(m_camera, SIGNAL(previewStarted()), this, SLOT(onCameraPreviewStarted()));
@@ -224,7 +192,7 @@ bool QAndroidCameraSession::open()
if (m_camera->getPreviewFormat() != AndroidCamera::NV21)
m_camera->setPreviewFormat(AndroidCamera::NV21);
- m_camera->notifyNewFrames(m_videoProbes.count());
+ m_camera->notifyNewFrames(m_videoProbes.count() || m_previewCallback);
emit opened();
} else {
@@ -259,16 +227,19 @@ void QAndroidCameraSession::close()
emit statusChanged(m_status);
}
-void QAndroidCameraSession::setVideoPreview(QObject *videoOutput)
+void QAndroidCameraSession::setVideoOutput(QAndroidVideoOutput *output)
{
if (m_videoOutput) {
m_videoOutput->stop();
m_videoOutput->reset();
}
- if (videoOutput) {
- connect(videoOutput, SIGNAL(readyChanged(bool)), this, SLOT(onVideoOutputReady(bool)));
- m_videoOutput = qobject_cast<QAndroidVideoOutput *>(videoOutput);
+ if (output) {
+ m_videoOutput = output;
+ if (m_videoOutput->isReady())
+ onVideoOutputReady(true);
+ else
+ connect(m_videoOutput, SIGNAL(readyChanged(bool)), this, SLOT(onVideoOutputReady(bool)));
} else {
m_videoOutput = 0;
}
@@ -336,7 +307,10 @@ bool QAndroidCameraSession::startPreview()
if (!m_videoOutput->isReady())
return true; // delay starting until the video output is ready
- if (!m_camera->setPreviewTexture(m_videoOutput->surfaceTexture()))
+ Q_ASSERT(m_videoOutput->surfaceTexture() || m_videoOutput->surfaceHolder());
+
+ if ((m_videoOutput->surfaceTexture() && !m_camera->setPreviewTexture(m_videoOutput->surfaceTexture()))
+ || (m_videoOutput->surfaceHolder() && !m_camera->setPreviewDisplay(m_videoOutput->surfaceHolder())))
return false;
m_status = QCamera::StartingStatus;
@@ -366,6 +340,7 @@ void QAndroidCameraSession::stopPreview()
m_camera->stopPreview();
m_camera->setPreviewSize(QSize());
m_camera->setPreviewTexture(0);
+ m_camera->setPreviewDisplay(0);
if (m_videoOutput) {
m_videoOutput->stop();
@@ -413,7 +388,7 @@ void QAndroidCameraSession::addProbe(QAndroidMediaVideoProbeControl *probe)
if (probe)
m_videoProbes << probe;
if (m_camera)
- m_camera->notifyNewFrames(m_videoProbes.count());
+ m_camera->notifyNewFrames(m_videoProbes.count() || m_previewCallback);
m_videoProbesMutex.unlock();
}
@@ -422,7 +397,24 @@ void QAndroidCameraSession::removeProbe(QAndroidMediaVideoProbeControl *probe)
m_videoProbesMutex.lock();
m_videoProbes.remove(probe);
if (m_camera)
- m_camera->notifyNewFrames(m_videoProbes.count());
+ m_camera->notifyNewFrames(m_videoProbes.count() || m_previewCallback);
+ m_videoProbesMutex.unlock();
+}
+
+void QAndroidCameraSession::setPreviewFormat(AndroidCamera::ImageFormat format)
+{
+ if (format == AndroidCamera::UnknownImageFormat)
+ return;
+
+ m_camera->setPreviewFormat(format);
+}
+
+void QAndroidCameraSession::setPreviewCallback(PreviewCallback *callback)
+{
+ m_videoProbesMutex.lock();
+ m_previewCallback = callback;
+ if (m_camera)
+ m_camera->notifyNewFrames(m_videoProbes.count() || m_previewCallback);
m_videoProbesMutex.unlock();
}
@@ -571,58 +563,37 @@ void QAndroidCameraSession::onCameraPictureExposed()
m_camera->fetchLastPreviewFrame();
}
-void QAndroidCameraSession::onLastPreviewFrameFetched(const QByteArray &preview, int width, int height)
-{
- if (preview.size()) {
- QtConcurrent::run(this, &QAndroidCameraSession::processPreviewImage,
- m_currentImageCaptureId,
- preview,
- width,
- height,
- m_camera->getRotation());
- }
-}
-
-void QAndroidCameraSession::processPreviewImage(int id, const QByteArray &data, int width, int height, int rotation)
+void QAndroidCameraSession::onLastPreviewFrameFetched(const QVideoFrame &frame)
{
- emit imageCaptured(id, prepareImageFromPreviewData(data, width, height, rotation));
+ QtConcurrent::run(this, &QAndroidCameraSession::processPreviewImage,
+ m_currentImageCaptureId,
+ frame,
+ m_camera->getRotation());
}
-QImage QAndroidCameraSession::prepareImageFromPreviewData(const QByteArray &data, int width, int height, int rotation)
+void QAndroidCameraSession::processPreviewImage(int id, const QVideoFrame &frame, int rotation)
{
- QImage result(width, height, QImage::Format_ARGB32);
- qt_convert_NV21_to_ARGB32((const uchar *)data.constData(),
- (quint32 *)result.bits(),
- width,
- height);
-
- QTransform transform;
-
// Preview display of front-facing cameras is flipped horizontally, but the frame data
// we get here is not. Flip it ourselves if the camera is front-facing to match what the user
// sees on the viewfinder.
+ QTransform transform;
if (m_camera->getFacing() == AndroidCamera::CameraFacingFront)
transform.scale(-1, 1);
-
transform.rotate(rotation);
- result = result.transformed(transform);
-
- return result;
+ emit imageCaptured(id, qt_imageFromVideoFrame(frame).transformed(transform));
}
-void QAndroidCameraSession::onNewPreviewFrame(const QByteArray &frame, int width, int height)
+void QAndroidCameraSession::onNewPreviewFrame(const QVideoFrame &frame)
{
m_videoProbesMutex.lock();
- if (frame.size() && m_videoProbes.count()) {
- // Bytes per line should be only for the first plane. For NV21, the Y plane has 8 bits
- // per sample, so bpl == width
- QVideoFrame videoFrame(new DataVideoBuffer(frame, width),
- QSize(width, height),
- QVideoFrame::Format_NV21);
- foreach (QAndroidMediaVideoProbeControl *probe, m_videoProbes)
- probe->newFrameProbed(videoFrame);
- }
+
+ foreach (QAndroidMediaVideoProbeControl *probe, m_videoProbes)
+ probe->newFrameProbed(frame);
+
+ if (m_previewCallback)
+ m_previewCallback->onFrameAvailable(frame);
+
m_videoProbesMutex.unlock();
}
@@ -720,7 +691,7 @@ void QAndroidCameraSession::processCapturedImage(int id,
}
if (dest & QCameraImageCapture::CaptureToBuffer) {
- QVideoFrame frame(new DataVideoBuffer(data), resolution, QVideoFrame::Format_Jpeg);
+ QVideoFrame frame(new QMemoryVideoBuffer(data, -1), resolution, QVideoFrame::Format_Jpeg);
emit imageAvailable(id, frame);
}
}
diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.h b/src/plugins/android/src/mediacapture/qandroidcamerasession.h
index c1772053d..d15509fe8 100644
--- a/src/plugins/android/src/mediacapture/qandroidcamerasession.h
+++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.h
@@ -68,7 +68,8 @@ public:
void setCaptureMode(QCamera::CaptureModes mode);
bool isCaptureModeSupported(QCamera::CaptureModes mode) const;
- void setVideoPreview(QObject *videoOutput);
+ QAndroidVideoOutput *videoOutput() const { return m_videoOutput; }
+ void setVideoOutput(QAndroidVideoOutput *output);
void adjustViewfinderSize(const QSize &captureSize, bool restartPreview = true);
QImageEncoderSettings imageSettings() const { return m_imageSettings; }
@@ -90,6 +91,14 @@ public:
void addProbe(QAndroidMediaVideoProbeControl *probe);
void removeProbe(QAndroidMediaVideoProbeControl *probe);
+ void setPreviewFormat(AndroidCamera::ImageFormat format);
+
+ struct PreviewCallback
+ {
+ virtual void onFrameAvailable(const QVideoFrame &frame) = 0;
+ };
+ void setPreviewCallback(PreviewCallback *callback);
+
Q_SIGNALS:
void statusChanged(QCamera::Status status);
void stateChanged(QCamera::State);
@@ -115,8 +124,8 @@ private Q_SLOTS:
void onCameraTakePictureFailed();
void onCameraPictureExposed();
void onCameraPictureCaptured(const QByteArray &data);
- void onLastPreviewFrameFetched(const QByteArray &preview, int width, int height);
- void onNewPreviewFrame(const QByteArray &frame, int width, int height);
+ void onLastPreviewFrameFetched(const QVideoFrame &frame);
+ void onNewPreviewFrame(const QVideoFrame &frame);
void onCameraPreviewStarted();
void onCameraPreviewFailedToStart();
void onCameraPreviewStopped();
@@ -131,8 +140,8 @@ private:
void stopPreview();
void applyImageSettings();
- void processPreviewImage(int id, const QByteArray &data, int width, int height, int rotation);
- QImage prepareImageFromPreviewData(const QByteArray &data, int width, int height, int rotation);
+
+ void processPreviewImage(int id, const QVideoFrame &frame, int rotation);
void processCapturedImage(int id,
const QByteArray &data,
const QSize &resolution,
@@ -164,6 +173,7 @@ private:
QSet<QAndroidMediaVideoProbeControl *> m_videoProbes;
QMutex m_videoProbesMutex;
+ PreviewCallback *m_previewCallback;
};
QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidcameravideorenderercontrol.cpp b/src/plugins/android/src/mediacapture/qandroidcameravideorenderercontrol.cpp
new file mode 100644
index 000000000..1d5b521b8
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcameravideorenderercontrol.cpp
@@ -0,0 +1,275 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidcameravideorenderercontrol.h"
+
+#include "qandroidcamerasession.h"
+#include "qandroidvideooutput.h"
+#include "androidsurfaceview.h"
+#include "qandroidmultimediautils.h"
+#include <qabstractvideosurface.h>
+#include <qvideosurfaceformat.h>
+#include <qcoreapplication.h>
+#include <qthread.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCameraDataVideoOutput : public QAndroidVideoOutput
+ , public QAndroidCameraSession::PreviewCallback
+{
+ Q_OBJECT
+public:
+ explicit QAndroidCameraDataVideoOutput(QAndroidCameraVideoRendererControl *control);
+ ~QAndroidCameraDataVideoOutput() Q_DECL_OVERRIDE;
+
+ AndroidSurfaceHolder *surfaceHolder() Q_DECL_OVERRIDE;
+
+ bool isReady() Q_DECL_OVERRIDE;
+
+ void stop() Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+ void onSurfaceCreated();
+ void configureFormat();
+
+private:
+ void onFrameAvailable(const QVideoFrame &frame);
+ void presentFrame();
+ bool event(QEvent *);
+
+ QAndroidCameraVideoRendererControl *m_control;
+ AndroidSurfaceView *m_surfaceView;
+ QMutex m_mutex;
+ QVideoFrame::PixelFormat m_pixelFormat;
+ QVideoFrame m_lastFrame;
+};
+
+QAndroidCameraDataVideoOutput::QAndroidCameraDataVideoOutput(QAndroidCameraVideoRendererControl *control)
+ : QAndroidVideoOutput(control)
+ , m_control(control)
+ , m_pixelFormat(QVideoFrame::Format_Invalid)
+{
+ // The camera preview cannot be started unless we set a SurfaceTexture or a
+ // SurfaceHolder. In this case we don't actually care about either of these, but since
+ // we need to, we setup an offscreen dummy SurfaceView in order to be able to start
+ // the camera preview. We'll then be able to use setPreviewCallbackWithBuffer() to
+ // get the raw data.
+
+ m_surfaceView = new AndroidSurfaceView;
+
+ connect(m_surfaceView, &AndroidSurfaceView::surfaceCreated,
+ this, &QAndroidCameraDataVideoOutput::onSurfaceCreated);
+
+ m_surfaceView->setGeometry(-1, -1, 1, 1);
+ m_surfaceView->setVisible(true);
+
+ connect(m_control->cameraSession(), &QAndroidCameraSession::opened,
+ this, &QAndroidCameraDataVideoOutput::configureFormat);
+ connect(m_control->surface(), &QAbstractVideoSurface::supportedFormatsChanged,
+ this, &QAndroidCameraDataVideoOutput::configureFormat);
+ configureFormat();
+}
+
+QAndroidCameraDataVideoOutput::~QAndroidCameraDataVideoOutput()
+{
+ m_control->cameraSession()->setPreviewCallback(Q_NULLPTR);
+ delete m_surfaceView;
+}
+
+AndroidSurfaceHolder *QAndroidCameraDataVideoOutput::surfaceHolder()
+{
+ return m_surfaceView->holder();
+}
+
+bool QAndroidCameraDataVideoOutput::isReady()
+{
+ return m_surfaceView->holder() && m_surfaceView->holder()->isSurfaceCreated();
+}
+
+void QAndroidCameraDataVideoOutput::onSurfaceCreated()
+{
+ emit readyChanged(true);
+}
+
+void QAndroidCameraDataVideoOutput::configureFormat()
+{
+ m_pixelFormat = QVideoFrame::Format_Invalid;
+
+ if (!m_control->cameraSession()->camera())
+ return;
+
+ QList<QVideoFrame::PixelFormat> surfaceFormats = m_control->surface()->supportedPixelFormats();
+ QList<AndroidCamera::ImageFormat> previewFormats = m_control->cameraSession()->camera()->getSupportedPreviewFormats();
+ for (int i = 0; i < surfaceFormats.size(); ++i) {
+ QVideoFrame::PixelFormat pixFormat = surfaceFormats.at(i);
+ AndroidCamera::ImageFormat f = qt_androidImageFormatFromPixelFormat(pixFormat);
+ if (previewFormats.contains(f)) {
+ m_pixelFormat = pixFormat;
+ break;
+ }
+ }
+
+ if (m_pixelFormat == QVideoFrame::Format_Invalid) {
+ m_control->cameraSession()->setPreviewCallback(Q_NULLPTR);
+ qWarning("The video surface is not compatible with any format supported by the camera");
+ } else {
+ m_control->cameraSession()->setPreviewCallback(this);
+
+ if (m_control->cameraSession()->status() > QCamera::LoadedStatus)
+ m_control->cameraSession()->camera()->stopPreview();
+
+ m_control->cameraSession()->setPreviewFormat(qt_androidImageFormatFromPixelFormat(m_pixelFormat));
+
+ if (m_control->cameraSession()->status() > QCamera::LoadedStatus)
+ m_control->cameraSession()->camera()->startPreview();
+ }
+}
+
+void QAndroidCameraDataVideoOutput::stop()
+{
+ m_mutex.lock();
+ m_lastFrame = QVideoFrame();
+ m_mutex.unlock();
+
+ if (m_control->surface() && m_control->surface()->isActive())
+ m_control->surface()->stop();
+}
+
+void QAndroidCameraDataVideoOutput::onFrameAvailable(const QVideoFrame &frame)
+{
+ m_mutex.lock();
+ m_lastFrame = frame;
+ m_mutex.unlock();
+
+ if (thread() == QThread::currentThread())
+ presentFrame();
+ else
+ QCoreApplication::postEvent(this, new QEvent(QEvent::User), Qt::HighEventPriority);
+}
+
+bool QAndroidCameraDataVideoOutput::event(QEvent *e)
+{
+ if (e->type() == QEvent::User) {
+ presentFrame();
+ return true;
+ }
+
+ return QObject::event(e);
+}
+
+void QAndroidCameraDataVideoOutput::presentFrame()
+{
+ Q_ASSERT(thread() == QThread::currentThread());
+
+ QMutexLocker locker(&m_mutex);
+
+ if (m_control->surface() && m_lastFrame.isValid() && m_lastFrame.pixelFormat() == m_pixelFormat) {
+
+ if (m_control->surface()->isActive() && (m_control->surface()->surfaceFormat().pixelFormat() != m_lastFrame.pixelFormat()
+ || m_control->surface()->surfaceFormat().frameSize() != m_lastFrame.size())) {
+ m_control->surface()->stop();
+ }
+
+ if (!m_control->surface()->isActive()) {
+ QVideoSurfaceFormat format(m_lastFrame.size(), m_lastFrame.pixelFormat(), m_lastFrame.handleType());
+ // Front camera frames are automatically mirrored when using SurfaceTexture or SurfaceView,
+ // but the buffers we get from the data callback are not. Tell the QAbstractVideoSurface
+ // that it needs to mirror the frames.
+ if (m_control->cameraSession()->camera()->getFacing() == AndroidCamera::CameraFacingFront)
+ format.setProperty("mirrored", true);
+
+ m_control->surface()->start(format);
+ }
+
+ if (m_control->surface()->isActive())
+ m_control->surface()->present(m_lastFrame);
+ }
+
+ m_lastFrame = QVideoFrame();
+}
+
+
+QAndroidCameraVideoRendererControl::QAndroidCameraVideoRendererControl(QAndroidCameraSession *session, QObject *parent)
+ : QVideoRendererControl(parent)
+ , m_cameraSession(session)
+ , m_surface(0)
+ , m_textureOutput(0)
+ , m_dataOutput(0)
+{
+}
+
+QAndroidCameraVideoRendererControl::~QAndroidCameraVideoRendererControl()
+{
+ m_cameraSession->setVideoOutput(0);
+}
+
+QAbstractVideoSurface *QAndroidCameraVideoRendererControl::surface() const
+{
+ return m_surface;
+}
+
+void QAndroidCameraVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
+{
+ if (m_surface == surface)
+ return;
+
+ m_surface = surface;
+ QAndroidVideoOutput *oldOutput = m_textureOutput ? static_cast<QAndroidVideoOutput*>(m_textureOutput)
+ : static_cast<QAndroidVideoOutput*>(m_dataOutput);
+ QAndroidVideoOutput *newOutput = 0;
+
+ if (m_surface) {
+ if (!m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).isEmpty()) {
+ if (!m_textureOutput) {
+ m_dataOutput = 0;
+ newOutput = m_textureOutput = new QAndroidTextureVideoOutput(this);
+ }
+ } else if (!m_dataOutput) {
+ m_textureOutput = 0;
+ newOutput = m_dataOutput = new QAndroidCameraDataVideoOutput(this);
+ }
+
+ if (m_textureOutput)
+ m_textureOutput->setSurface(m_surface);
+ }
+
+ if (newOutput != oldOutput) {
+ m_cameraSession->setVideoOutput(newOutput);
+ delete oldOutput;
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "qandroidcameravideorenderercontrol.moc"
+
diff --git a/src/plugins/android/src/mediacapture/qandroidcameravideorenderercontrol.h b/src/plugins/android/src/mediacapture/qandroidcameravideorenderercontrol.h
new file mode 100644
index 000000000..4b6428ba0
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcameravideorenderercontrol.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDCAMERAVIDEORENDERERCONTROL_H
+#define QANDROIDCAMERAVIDEORENDERERCONTROL_H
+
+#include <qvideorenderercontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCameraSession;
+class QAndroidTextureVideoOutput;
+class QAndroidCameraDataVideoOutput;
+
+class QAndroidCameraVideoRendererControl : public QVideoRendererControl
+{
+ Q_OBJECT
+public:
+ QAndroidCameraVideoRendererControl(QAndroidCameraSession *session, QObject *parent = 0);
+ ~QAndroidCameraVideoRendererControl() Q_DECL_OVERRIDE;
+
+ QAbstractVideoSurface *surface() const Q_DECL_OVERRIDE;
+ void setSurface(QAbstractVideoSurface *surface) Q_DECL_OVERRIDE;
+
+ QAndroidCameraSession *cameraSession() const { return m_cameraSession; }
+
+private:
+ QAndroidCameraSession *m_cameraSession;
+ QAbstractVideoSurface *m_surface;
+ QAndroidTextureVideoOutput *m_textureOutput;
+ QAndroidCameraDataVideoOutput *m_dataOutput;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDCAMERAVIDEORENDERERCONTROL_H
diff --git a/src/plugins/android/src/mediacapture/qandroidcaptureservice.cpp b/src/plugins/android/src/mediacapture/qandroidcaptureservice.cpp
index e9cdb1e78..d2107e8a5 100644
--- a/src/plugins/android/src/mediacapture/qandroidcaptureservice.cpp
+++ b/src/plugins/android/src/mediacapture/qandroidcaptureservice.cpp
@@ -40,7 +40,7 @@
#include "qandroidvideodeviceselectorcontrol.h"
#include "qandroidaudioinputselectorcontrol.h"
#include "qandroidcamerasession.h"
-#include "qandroidvideorendercontrol.h"
+#include "qandroidcameravideorenderercontrol.h"
#include "qandroidcamerazoomcontrol.h"
#include "qandroidcameraexposurecontrol.h"
#include "qandroidcameraflashcontrol.h"
@@ -196,8 +196,7 @@ QMediaControl *QAndroidCaptureService::requestControl(const char *name)
if (qstrcmp(name, QVideoRendererControl_iid) == 0
&& m_service == QLatin1String(Q_MEDIASERVICE_CAMERA)
&& !m_videoRendererControl) {
- m_videoRendererControl = new QAndroidVideoRendererControl;
- m_cameraSession->setVideoPreview(m_videoRendererControl);
+ m_videoRendererControl = new QAndroidCameraVideoRendererControl(m_cameraSession);
return m_videoRendererControl;
}
@@ -217,7 +216,6 @@ void QAndroidCaptureService::releaseControl(QMediaControl *control)
{
if (control) {
if (control == m_videoRendererControl) {
- m_cameraSession->setVideoPreview(0);
delete m_videoRendererControl;
m_videoRendererControl = 0;
return;
diff --git a/src/plugins/android/src/mediacapture/qandroidcaptureservice.h b/src/plugins/android/src/mediacapture/qandroidcaptureservice.h
index fc84ac124..02f063444 100644
--- a/src/plugins/android/src/mediacapture/qandroidcaptureservice.h
+++ b/src/plugins/android/src/mediacapture/qandroidcaptureservice.h
@@ -46,7 +46,7 @@ class QAndroidCameraInfoControl;
class QAndroidVideoDeviceSelectorControl;
class QAndroidAudioInputSelectorControl;
class QAndroidCameraSession;
-class QAndroidVideoRendererControl;
+class QAndroidCameraVideoRendererControl;
class QAndroidCameraZoomControl;
class QAndroidCameraExposureControl;
class QAndroidCameraFlashControl;
@@ -82,7 +82,7 @@ private:
QAndroidVideoDeviceSelectorControl *m_videoInputControl;
QAndroidAudioInputSelectorControl *m_audioInputControl;
QAndroidCameraSession *m_cameraSession;
- QMediaControl *m_videoRendererControl;
+ QAndroidCameraVideoRendererControl *m_videoRendererControl;
QAndroidCameraZoomControl *m_cameraZoomControl;
QAndroidCameraExposureControl *m_cameraExposureControl;
QAndroidCameraFlashControl *m_cameraFlashControl;
diff --git a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
index f2ea1b9d7..d25438ec7 100644
--- a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
+++ b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
@@ -37,6 +37,7 @@
#include "qandroidcamerasession.h"
#include "androidmultimediautils.h"
#include "qandroidmultimediautils.h"
+#include "qandroidvideooutput.h"
QT_BEGIN_NAMESPACE
@@ -217,6 +218,20 @@ void QAndroidCaptureSession::start()
m_usedOutputLocation = QUrl::fromLocalFile(filePath);
m_mediaRecorder->setOutputFile(filePath);
+ // Even though the Android doc explicitly says that calling MediaRecorder.setPreviewDisplay()
+ // is not necessary when the Camera already has a Surface, it doesn't actually work on some
+ // devices. For example on the Samsung Galaxy Tab 2, the camera server dies after prepare()
+ // and start() if MediaRecorder.setPreviewDispaly() is not called.
+ if (m_cameraSession) {
+ // When using a SurfaceTexture, we need to pass a new one to the MediaRecorder, not the same
+ // one that is set on the Camera or it will crash, hence the reset().
+ m_cameraSession->videoOutput()->reset();
+ if (m_cameraSession->videoOutput()->surfaceTexture())
+ m_mediaRecorder->setSurfaceTexture(m_cameraSession->videoOutput()->surfaceTexture());
+ else if (m_cameraSession->videoOutput()->surfaceHolder())
+ m_mediaRecorder->setSurfaceHolder(m_cameraSession->videoOutput()->surfaceHolder());
+ }
+
if (!m_mediaRecorder->prepare()) {
emit error(QMediaRecorder::FormatError, QLatin1String("Unable to prepare the media recorder."));
restartViewfinder();
@@ -412,13 +427,23 @@ void QAndroidCaptureSession::applySettings()
void QAndroidCaptureSession::updateViewfinder()
{
- m_cameraSession->camera()->stopPreview();
+ m_cameraSession->camera()->stopPreviewSynchronous();
m_cameraSession->adjustViewfinderSize(m_videoSettings.resolution(), false);
}
void QAndroidCaptureSession::restartViewfinder()
{
m_cameraSession->camera()->reconnect();
+
+ // This is not necessary on most devices, but it crashes on some if we don't stop the
+ // preview and reset the preview display on the camera when recording is over.
+ m_cameraSession->camera()->stopPreviewSynchronous();
+ m_cameraSession->videoOutput()->reset();
+ if (m_cameraSession->videoOutput()->surfaceTexture())
+ m_cameraSession->camera()->setPreviewTexture(m_cameraSession->videoOutput()->surfaceTexture());
+ else if (m_cameraSession->videoOutput()->surfaceHolder())
+ m_cameraSession->camera()->setPreviewDisplay(m_cameraSession->videoOutput()->surfaceHolder());
+
m_cameraSession->camera()->startPreview();
m_cameraSession->setReadyForCapture(true);
}
diff --git a/src/plugins/android/src/mediaplayer/mediaplayer.pri b/src/plugins/android/src/mediaplayer/mediaplayer.pri
index c386d996b..9f758a993 100644
--- a/src/plugins/android/src/mediaplayer/mediaplayer.pri
+++ b/src/plugins/android/src/mediaplayer/mediaplayer.pri
@@ -3,9 +3,11 @@ INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/qandroidmediaplayercontrol.h \
$$PWD/qandroidmediaservice.h \
- $$PWD/qandroidmetadatareadercontrol.h
+ $$PWD/qandroidmetadatareadercontrol.h \
+ $$PWD/qandroidmediaplayervideorenderercontrol.h
SOURCES += \
$$PWD/qandroidmediaplayercontrol.cpp \
$$PWD/qandroidmediaservice.cpp \
- $$PWD/qandroidmetadatareadercontrol.cpp
+ $$PWD/qandroidmetadatareadercontrol.cpp \
+ $$PWD/qandroidmediaplayervideorenderercontrol.cpp
diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp
index 9a050e7ad..90beeabe7 100644
--- a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp
@@ -345,7 +345,7 @@ void QAndroidMediaPlayerControl::setMedia(const QMediaContent &mediaContent,
mReloadingMedia = false;
}
-void QAndroidMediaPlayerControl::setVideoOutput(QObject *videoOutput)
+void QAndroidMediaPlayerControl::setVideoOutput(QAndroidVideoOutput *videoOutput)
{
if (mVideoOutput) {
mMediaPlayer->setDisplay(0);
@@ -353,7 +353,7 @@ void QAndroidMediaPlayerControl::setVideoOutput(QObject *videoOutput)
mVideoOutput->reset();
}
- mVideoOutput = qobject_cast<QAndroidVideoOutput *>(videoOutput);
+ mVideoOutput = videoOutput;
if (!mVideoOutput)
return;
diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h
index 3f92d809c..a015a6809 100644
--- a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h
@@ -67,7 +67,7 @@ public:
const QIODevice *mediaStream() const Q_DECL_OVERRIDE;
void setMedia(const QMediaContent &mediaContent, QIODevice *stream) Q_DECL_OVERRIDE;
- void setVideoOutput(QObject *videoOutput);
+ void setVideoOutput(QAndroidVideoOutput *videoOutput);
Q_SIGNALS:
void metaDataUpdated();
diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayervideorenderercontrol.cpp b/src/plugins/android/src/mediaplayer/qandroidmediaplayervideorenderercontrol.cpp
new file mode 100644
index 000000000..5dd51c395
--- /dev/null
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayervideorenderercontrol.cpp
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidmediaplayervideorenderercontrol.h"
+
+#include "qandroidmediaplayercontrol.h"
+#include "qandroidvideooutput.h"
+#include <qabstractvideosurface.h>
+
+QT_BEGIN_NAMESPACE
+
+QAndroidMediaPlayerVideoRendererControl::QAndroidMediaPlayerVideoRendererControl(QAndroidMediaPlayerControl *mediaPlayer, QObject *parent)
+ : QVideoRendererControl(parent)
+ , m_mediaPlayerControl(mediaPlayer)
+ , m_surface(0)
+ , m_textureOutput(new QAndroidTextureVideoOutput(this))
+{
+ m_mediaPlayerControl->setVideoOutput(m_textureOutput);
+}
+
+QAndroidMediaPlayerVideoRendererControl::~QAndroidMediaPlayerVideoRendererControl()
+{
+ m_mediaPlayerControl->setVideoOutput(0);
+}
+
+QAbstractVideoSurface *QAndroidMediaPlayerVideoRendererControl::surface() const
+{
+ return m_surface;
+}
+
+void QAndroidMediaPlayerVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
+{
+ if (m_surface == surface)
+ return;
+
+ m_surface = surface;
+ m_textureOutput->setSurface(m_surface);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayervideorenderercontrol.h b/src/plugins/android/src/mediaplayer/qandroidmediaplayervideorenderercontrol.h
new file mode 100644
index 000000000..cfa41980d
--- /dev/null
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayervideorenderercontrol.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDMEDIAPLAYERVIDEORENDERERCONTROL_H
+#define QANDROIDMEDIAPLAYERVIDEORENDERERCONTROL_H
+
+#include <qvideorenderercontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidMediaPlayerControl;
+class QAndroidTextureVideoOutput;
+
+class QAndroidMediaPlayerVideoRendererControl : public QVideoRendererControl
+{
+ Q_OBJECT
+public:
+ QAndroidMediaPlayerVideoRendererControl(QAndroidMediaPlayerControl *mediaPlayer, QObject *parent = 0);
+ ~QAndroidMediaPlayerVideoRendererControl() Q_DECL_OVERRIDE;
+
+ QAbstractVideoSurface *surface() const Q_DECL_OVERRIDE;
+ void setSurface(QAbstractVideoSurface *surface) Q_DECL_OVERRIDE;
+
+private:
+ QAndroidMediaPlayerControl *m_mediaPlayerControl;
+ QAbstractVideoSurface *m_surface;
+ QAndroidTextureVideoOutput *m_textureOutput;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDMEDIAPLAYERVIDEORENDERERCONTROL_H
diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp b/src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp
index 74943ca64..992bcead2 100644
--- a/src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp
@@ -35,7 +35,7 @@
#include "qandroidmediaplayercontrol.h"
#include "qandroidmetadatareadercontrol.h"
-#include "qandroidvideorendercontrol.h"
+#include "qandroidmediaplayervideorenderercontrol.h"
QT_BEGIN_NAMESPACE
@@ -53,9 +53,9 @@ QAndroidMediaService::QAndroidMediaService(QObject *parent)
QAndroidMediaService::~QAndroidMediaService()
{
- delete mMediaControl;
- delete mMetadataControl;
delete mVideoRendererControl;
+ delete mMetadataControl;
+ delete mMediaControl;
}
QMediaControl *QAndroidMediaService::requestControl(const char *name)
@@ -68,8 +68,7 @@ QMediaControl *QAndroidMediaService::requestControl(const char *name)
if (qstrcmp(name, QVideoRendererControl_iid) == 0) {
if (!mVideoRendererControl) {
- mVideoRendererControl = new QAndroidVideoRendererControl;
- mMediaControl->setVideoOutput(mVideoRendererControl);
+ mVideoRendererControl = new QAndroidMediaPlayerVideoRendererControl(mMediaControl);
return mVideoRendererControl;
}
}
@@ -80,7 +79,6 @@ QMediaControl *QAndroidMediaService::requestControl(const char *name)
void QAndroidMediaService::releaseControl(QMediaControl *control)
{
if (control == mVideoRendererControl) {
- mMediaControl->setVideoOutput(0);
delete mVideoRendererControl;
mVideoRendererControl = 0;
}
diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaservice.h b/src/plugins/android/src/mediaplayer/qandroidmediaservice.h
index 6babbb15f..798d6ef39 100644
--- a/src/plugins/android/src/mediaplayer/qandroidmediaservice.h
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaservice.h
@@ -40,6 +40,7 @@ QT_BEGIN_NAMESPACE
class QAndroidMediaPlayerControl;
class QAndroidMetaDataReaderControl;
+class QAndroidMediaPlayerVideoRendererControl;
class QAndroidMediaService : public QMediaService
{
@@ -54,7 +55,7 @@ public:
private:
QAndroidMediaPlayerControl *mMediaControl;
QAndroidMetaDataReaderControl *mMetadataControl;
- QMediaControl *mVideoRendererControl;
+ QAndroidMediaPlayerVideoRendererControl *mVideoRendererControl;
};
QT_END_NAMESPACE
diff --git a/src/plugins/android/src/qandroidmediaserviceplugin.cpp b/src/plugins/android/src/qandroidmediaserviceplugin.cpp
index 5d35ddf51..bf89badb3 100644
--- a/src/plugins/android/src/qandroidmediaserviceplugin.cpp
+++ b/src/plugins/android/src/qandroidmediaserviceplugin.cpp
@@ -43,6 +43,7 @@
#include "androidcamera.h"
#include "androidmultimediautils.h"
#include "androidmediarecorder.h"
+#include "androidsurfaceview.h"
#include <qdebug.h>
QT_BEGIN_NAMESPACE
@@ -160,7 +161,8 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void * /*reserved*/)
if (!AndroidMediaPlayer::initJNI(jniEnv) ||
!AndroidCamera::initJNI(jniEnv) ||
- !AndroidMediaRecorder::initJNI(jniEnv)) {
+ !AndroidMediaRecorder::initJNI(jniEnv) ||
+ !AndroidSurfaceHolder::initJNI(jniEnv)) {
return JNI_ERR;
}
diff --git a/src/plugins/android/src/wrappers/jni/androidcamera.cpp b/src/plugins/android/src/wrappers/jni/androidcamera.cpp
index 7d8e4532d..23200462e 100644
--- a/src/plugins/android/src/wrappers/jni/androidcamera.cpp
+++ b/src/plugins/android/src/wrappers/jni/androidcamera.cpp
@@ -33,20 +33,24 @@
#include "androidcamera.h"
#include "androidsurfacetexture.h"
+#include "androidsurfaceview.h"
#include "qandroidmultimediautils.h"
#include <qstringlist.h>
#include <qdebug.h>
-#include <qmutex.h>
#include <QtCore/private/qjnihelpers_p.h>
#include <QtCore/qthread.h>
+#include <QtCore/qreadwritelock.h>
+#include <QtCore/qmutex.h>
+#include <QtMultimedia/private/qmemoryvideobuffer_p.h>
QT_BEGIN_NAMESPACE
static const char QtCameraListenerClassName[] = "org/qtproject/qt5/android/multimedia/QtCameraListener";
-static QMutex g_cameraMapMutex;
-typedef QMap<int, AndroidCamera *> CameraMap;
-Q_GLOBAL_STATIC(CameraMap, g_cameraMap)
+
+typedef QHash<int, AndroidCamera *> CameraMap;
+Q_GLOBAL_STATIC(CameraMap, cameras)
+Q_GLOBAL_STATIC(QReadWriteLock, rwLock)
static inline bool exceptionCheckAndClear(JNIEnv *env)
{
@@ -88,43 +92,57 @@ static QJNIObjectPrivate rectToArea(const QRect &rect)
// native method for QtCameraLisener.java
static void notifyAutoFocusComplete(JNIEnv* , jobject, int id, jboolean success)
{
- QMutexLocker locker(&g_cameraMapMutex);
- AndroidCamera *obj = g_cameraMap->value(id, 0);
- if (obj)
- Q_EMIT obj->autoFocusComplete(success);
+ QReadLocker locker(rwLock);
+ const auto it = cameras->constFind(id);
+ if (Q_UNLIKELY(it == cameras->cend()))
+ return;
+
+ Q_EMIT (*it)->autoFocusComplete(success);
}
static void notifyPictureExposed(JNIEnv* , jobject, int id)
{
- QMutexLocker locker(&g_cameraMapMutex);
- AndroidCamera *obj = g_cameraMap->value(id, 0);
- if (obj)
- Q_EMIT obj->pictureExposed();
+ QReadLocker locker(rwLock);
+ const auto it = cameras->constFind(id);
+ if (Q_UNLIKELY(it == cameras->cend()))
+ return;
+
+ Q_EMIT (*it)->pictureExposed();
}
static void notifyPictureCaptured(JNIEnv *env, jobject, int id, jbyteArray data)
{
- QMutexLocker locker(&g_cameraMapMutex);
- AndroidCamera *obj = g_cameraMap->value(id, 0);
- if (obj) {
- const int arrayLength = env->GetArrayLength(data);
- QByteArray bytes(arrayLength, Qt::Uninitialized);
- env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
- Q_EMIT obj->pictureCaptured(bytes);
- }
+ QReadLocker locker(rwLock);
+ const auto it = cameras->constFind(id);
+ if (Q_UNLIKELY(it == cameras->cend()))
+ return;
+
+ const int arrayLength = env->GetArrayLength(data);
+ QByteArray bytes(arrayLength, Qt::Uninitialized);
+ env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
+ Q_EMIT (*it)->pictureCaptured(bytes);
}
-static void notifyNewPreviewFrame(JNIEnv *env, jobject, int id, jbyteArray data, int width, int height)
+static void notifyNewPreviewFrame(JNIEnv *env, jobject, int id, jbyteArray data,
+ int width, int height, int format, int bpl)
{
- QMutexLocker locker(&g_cameraMapMutex);
- AndroidCamera *obj = g_cameraMap->value(id, 0);
- if (obj) {
- const int arrayLength = env->GetArrayLength(data);
- QByteArray bytes(arrayLength, Qt::Uninitialized);
- env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
+ QReadLocker locker(rwLock);
+ const auto it = cameras->constFind(id);
+ if (Q_UNLIKELY(it == cameras->cend()))
+ return;
- Q_EMIT obj->newPreviewFrame(bytes, width, height);
- }
+ const int arrayLength = env->GetArrayLength(data);
+ if (arrayLength == 0)
+ return;
+
+ QByteArray bytes(arrayLength, Qt::Uninitialized);
+ env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
+
+ QVideoFrame frame(new QMemoryVideoBuffer(bytes, bpl),
+ QSize(width, height),
+ qt_pixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat(format)));
+
+ Q_EMIT (*it)->newPreviewFrame(frame);
}
class AndroidCameraPrivate : public QObject
@@ -149,10 +167,12 @@ public:
Q_INVOKABLE AndroidCamera::ImageFormat getPreviewFormat();
Q_INVOKABLE void setPreviewFormat(AndroidCamera::ImageFormat fmt);
+ Q_INVOKABLE QList<AndroidCamera::ImageFormat> getSupportedPreviewFormats();
Q_INVOKABLE QSize previewSize() const { return m_previewSize; }
Q_INVOKABLE void updatePreviewSize();
Q_INVOKABLE bool setPreviewTexture(void *surfaceTexture);
+ Q_INVOKABLE bool setPreviewDisplay(void *surfaceHolder);
Q_INVOKABLE bool isZoomSupported();
Q_INVOKABLE int getMaxZoom();
@@ -233,7 +253,7 @@ Q_SIGNALS:
void takePictureFailed();
- void lastPreviewFrameFetched(const QByteArray &preview, int width, int height);
+ void lastPreviewFrameFetched(const QVideoFrame &frame);
};
AndroidCamera::AndroidCamera(AndroidCameraPrivate *d, QThread *worker)
@@ -245,6 +265,7 @@ AndroidCamera::AndroidCamera(AndroidCameraPrivate *d, QThread *worker)
qRegisterMetaType<QList<int> >();
qRegisterMetaType<QList<QSize> >();
qRegisterMetaType<QList<QRect> >();
+ qRegisterMetaType<ImageFormat>();
connect(d, &AndroidCameraPrivate::previewSizeChanged, this, &AndroidCamera::previewSizeChanged);
connect(d, &AndroidCameraPrivate::previewStarted, this, &AndroidCamera::previewStarted);
@@ -260,12 +281,11 @@ AndroidCamera::~AndroidCamera()
{
Q_D(AndroidCamera);
if (d->m_camera.isValid()) {
- g_cameraMapMutex.lock();
- g_cameraMap->remove(d->m_cameraId);
- g_cameraMapMutex.unlock();
+ release();
+ QWriteLocker locker(rwLock);
+ cameras->remove(cameraId());
}
- release();
m_worker->exit();
m_worker->wait(5000);
}
@@ -288,9 +308,9 @@ AndroidCamera *AndroidCamera::open(int cameraId)
}
AndroidCamera *q = new AndroidCamera(d, worker);
- g_cameraMapMutex.lock();
- g_cameraMap->insert(cameraId, q);
- g_cameraMapMutex.unlock();
+ QWriteLocker locker(rwLock);
+ cameras->insert(cameraId, q);
+
return q;
}
@@ -366,6 +386,12 @@ void AndroidCamera::setPreviewFormat(ImageFormat fmt)
QMetaObject::invokeMethod(d, "setPreviewFormat", Q_ARG(AndroidCamera::ImageFormat, fmt));
}
+QList<AndroidCamera::ImageFormat> AndroidCamera::getSupportedPreviewFormats()
+{
+ Q_D(AndroidCamera);
+ return d->getSupportedPreviewFormats();
+}
+
QSize AndroidCamera::previewSize() const
{
Q_D(const AndroidCamera);
@@ -397,6 +423,18 @@ bool AndroidCamera::setPreviewTexture(AndroidSurfaceTexture *surfaceTexture)
return ok;
}
+bool AndroidCamera::setPreviewDisplay(AndroidSurfaceHolder *surfaceHolder)
+{
+ Q_D(AndroidCamera);
+ bool ok = true;
+ QMetaObject::invokeMethod(d,
+ "setPreviewDisplay",
+ Qt::BlockingQueuedConnection,
+ Q_RETURN_ARG(bool, ok),
+ Q_ARG(void *, surfaceHolder ? surfaceHolder->surfaceHolder() : 0));
+ return ok;
+}
+
bool AndroidCamera::isZoomSupported()
{
Q_D(AndroidCamera);
@@ -711,6 +749,12 @@ void AndroidCamera::stopPreview()
QMetaObject::invokeMethod(d, "stopPreview");
}
+void AndroidCamera::stopPreviewSynchronous()
+{
+ Q_D(AndroidCamera);
+ QMetaObject::invokeMethod(d, "stopPreview", Qt::BlockingQueuedConnection);
+}
+
AndroidCameraPrivate::AndroidCameraPrivate()
: QObject(),
m_parametersMutex(QMutex::Recursive)
@@ -832,7 +876,7 @@ AndroidCamera::ImageFormat AndroidCameraPrivate::getPreviewFormat()
QMutexLocker parametersLocker(&m_parametersMutex);
if (!m_parameters.isValid())
- return AndroidCamera::Unknown;
+ return AndroidCamera::UnknownImageFormat;
return AndroidCamera::ImageFormat(m_parameters.callMethod<jint>("getPreviewFormat"));
}
@@ -848,6 +892,27 @@ void AndroidCameraPrivate::setPreviewFormat(AndroidCamera::ImageFormat fmt)
applyParameters();
}
+QList<AndroidCamera::ImageFormat> AndroidCameraPrivate::getSupportedPreviewFormats()
+{
+ QList<AndroidCamera::ImageFormat> list;
+
+ QMutexLocker parametersLocker(&m_parametersMutex);
+
+ if (m_parameters.isValid()) {
+ QJNIObjectPrivate formatList = m_parameters.callObjectMethod("getSupportedPreviewFormats",
+ "()Ljava/util/List;");
+ int count = formatList.callMethod<jint>("size");
+ for (int i = 0; i < count; ++i) {
+ QJNIObjectPrivate format = formatList.callObjectMethod("get",
+ "(I)Ljava/lang/Object;",
+ i);
+ list.append(AndroidCamera::ImageFormat(format.callMethod<jint>("intValue")));
+ }
+ }
+
+ return list;
+}
+
void AndroidCameraPrivate::updatePreviewSize()
{
QMutexLocker parametersLocker(&m_parametersMutex);
@@ -869,6 +934,15 @@ bool AndroidCameraPrivate::setPreviewTexture(void *surfaceTexture)
return !exceptionCheckAndClear(env);
}
+bool AndroidCameraPrivate::setPreviewDisplay(void *surfaceHolder)
+{
+ QJNIEnvironmentPrivate env;
+ m_camera.callMethod<void>("setPreviewDisplay",
+ "(Landroid/view/SurfaceHolder;)V",
+ static_cast<jobject>(surfaceHolder));
+ return !exceptionCheckAndClear(env);
+}
+
bool AndroidCameraPrivate::isZoomSupported()
{
QMutexLocker parametersLocker(&m_parametersMutex);
@@ -1380,15 +1454,25 @@ void AndroidCameraPrivate::fetchLastPreviewFrame()
return;
const int arrayLength = env->GetArrayLength(static_cast<jbyteArray>(data.object()));
+ if (arrayLength == 0)
+ return;
+
QByteArray bytes(arrayLength, Qt::Uninitialized);
env->GetByteArrayRegion(static_cast<jbyteArray>(data.object()),
0,
arrayLength,
reinterpret_cast<jbyte *>(bytes.data()));
- emit lastPreviewFrameFetched(bytes,
- m_cameraListener.callMethod<jint>("previewWidth"),
- m_cameraListener.callMethod<jint>("previewHeight"));
+ const int width = m_cameraListener.callMethod<jint>("previewWidth");
+ const int height = m_cameraListener.callMethod<jint>("previewHeight");
+ const int format = m_cameraListener.callMethod<jint>("previewFormat");
+ const int bpl = m_cameraListener.callMethod<jint>("previewBytesPerLine");
+
+ QVideoFrame frame(new QMemoryVideoBuffer(bytes, bpl),
+ QSize(width, height),
+ qt_pixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat(format)));
+
+ emit lastPreviewFrameFetched(frame);
}
void AndroidCameraPrivate::applyParameters()
@@ -1433,7 +1517,7 @@ bool AndroidCamera::initJNI(JNIEnv *env)
{"notifyAutoFocusComplete", "(IZ)V", (void *)notifyAutoFocusComplete},
{"notifyPictureExposed", "(I)V", (void *)notifyPictureExposed},
{"notifyPictureCaptured", "(I[B)V", (void *)notifyPictureCaptured},
- {"notifyNewPreviewFrame", "(I[BII)V", (void *)notifyNewPreviewFrame}
+ {"notifyNewPreviewFrame", "(I[BIIII)V", (void *)notifyNewPreviewFrame}
};
if (clazz && env->RegisterNatives(clazz,
diff --git a/src/plugins/android/src/wrappers/jni/androidcamera.h b/src/plugins/android/src/wrappers/jni/androidcamera.h
index b5903688d..a5e0294c0 100644
--- a/src/plugins/android/src/wrappers/jni/androidcamera.h
+++ b/src/plugins/android/src/wrappers/jni/androidcamera.h
@@ -46,6 +46,7 @@ class QThread;
class AndroidCameraPrivate;
class AndroidSurfaceTexture;
+class AndroidSurfaceHolder;
struct AndroidCameraInfo
{
@@ -67,7 +68,7 @@ public:
};
enum ImageFormat { // same values as in android.graphics.ImageFormat Java class
- Unknown = 0,
+ UnknownImageFormat = 0,
RGB565 = 4,
NV16 = 16,
NV21 = 17,
@@ -95,10 +96,12 @@ public:
ImageFormat getPreviewFormat();
void setPreviewFormat(ImageFormat fmt);
+ QList<ImageFormat> getSupportedPreviewFormats();
QSize previewSize() const;
void setPreviewSize(const QSize &size);
bool setPreviewTexture(AndroidSurfaceTexture *surfaceTexture);
+ bool setPreviewDisplay(AndroidSurfaceHolder *surfaceHolder);
bool isZoomSupported();
int getMaxZoom();
@@ -152,6 +155,7 @@ public:
void startPreview();
void stopPreview();
+ void stopPreviewSynchronous();
void takePicture();
@@ -179,8 +183,8 @@ Q_SIGNALS:
void takePictureFailed();
void pictureExposed();
void pictureCaptured(const QByteArray &data);
- void lastPreviewFrameFetched(const QByteArray &preview, int width, int height);
- void newPreviewFrame(const QByteArray &frame, int width, int height);
+ void lastPreviewFrameFetched(const QVideoFrame &frame);
+ void newPreviewFrame(const QVideoFrame &frame);
private:
AndroidCamera(AndroidCameraPrivate *d, QThread *worker);
@@ -190,6 +194,8 @@ private:
QScopedPointer<QThread> m_worker;
};
+Q_DECLARE_METATYPE(AndroidCamera::ImageFormat)
+
QT_END_NAMESPACE
#endif // ANDROIDCAMERA_H
diff --git a/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp b/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp
index fa32f31ef..34063056f 100644
--- a/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp
+++ b/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp
@@ -34,6 +34,8 @@
#include "androidmediarecorder.h"
#include "androidcamera.h"
+#include "androidsurfacetexture.h"
+#include "androidsurfaceview.h"
#include <QtCore/private/qjni_p.h>
#include <qmap.h>
@@ -339,6 +341,41 @@ void AndroidMediaRecorder::setOutputFile(const QString &path)
}
}
+void AndroidMediaRecorder::setSurfaceTexture(AndroidSurfaceTexture *texture)
+{
+ QJNIEnvironmentPrivate env;
+ m_mediaRecorder.callMethod<void>("setPreviewDisplay",
+ "(Landroid/view/Surface;)V",
+ texture->surface());
+ if (env->ExceptionCheck()) {
+#ifdef QT_DEBUG
+ env->ExceptionDescribe();
+#endif
+ env->ExceptionClear();
+ }
+}
+
+void AndroidMediaRecorder::setSurfaceHolder(AndroidSurfaceHolder *holder)
+{
+ QJNIEnvironmentPrivate env;
+ QJNIObjectPrivate surfaceHolder(holder->surfaceHolder());
+ QJNIObjectPrivate surface = surfaceHolder.callObjectMethod("getSurface",
+ "()Landroid/view/Surface;");
+ if (!surface.isValid())
+ return;
+
+ m_mediaRecorder.callMethod<void>("setPreviewDisplay",
+ "(Landroid/view/Surface;)V",
+ surface.object());
+ if (env->ExceptionCheck()) {
+#ifdef QT_DEBUG
+ env->ExceptionDescribe();
+#endif
+ env->ExceptionClear();
+ }
+}
+
+
bool AndroidMediaRecorder::initJNI(JNIEnv *env)
{
jclass clazz = QJNIEnvironmentPrivate::findClass(QtMediaRecorderListenerClassName,
diff --git a/src/plugins/android/src/wrappers/jni/androidmediarecorder.h b/src/plugins/android/src/wrappers/jni/androidmediarecorder.h
index 1aa83a201..95b48ed47 100644
--- a/src/plugins/android/src/wrappers/jni/androidmediarecorder.h
+++ b/src/plugins/android/src/wrappers/jni/androidmediarecorder.h
@@ -41,6 +41,8 @@
QT_BEGIN_NAMESPACE
class AndroidCamera;
+class AndroidSurfaceTexture;
+class AndroidSurfaceHolder;
class AndroidCamcorderProfile
{
@@ -149,6 +151,9 @@ public:
void setOutputFormat(OutputFormat format);
void setOutputFile(const QString &path);
+ void setSurfaceTexture(AndroidSurfaceTexture *texture);
+ void setSurfaceHolder(AndroidSurfaceHolder *holder);
+
static bool initJNI(JNIEnv *env);
Q_SIGNALS:
diff --git a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp
index ffa37d7d4..9a25b7e28 100644
--- a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp
+++ b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp
@@ -78,8 +78,8 @@ AndroidSurfaceTexture::AndroidSurfaceTexture(unsigned int texName)
AndroidSurfaceTexture::~AndroidSurfaceTexture()
{
- if (QtAndroidPrivate::androidSdkVersion() > 13 && m_surfaceView.isValid())
- m_surfaceView.callMethod<void>("release");
+ if (QtAndroidPrivate::androidSdkVersion() > 13 && m_surface.isValid())
+ m_surface.callMethod<void>("release");
if (m_surfaceTexture.isValid()) {
release();
@@ -124,21 +124,23 @@ jobject AndroidSurfaceTexture::surfaceTexture()
return m_surfaceTexture.object();
}
-jobject AndroidSurfaceTexture::surfaceView()
+jobject AndroidSurfaceTexture::surface()
{
- return m_surfaceView.object();
+ if (!m_surface.isValid()) {
+ m_surface = QJNIObjectPrivate("android/view/Surface",
+ "(Landroid/graphics/SurfaceTexture;)V",
+ m_surfaceTexture.object());
+ }
+
+ return m_surface.object();
}
jobject AndroidSurfaceTexture::surfaceHolder()
{
if (!m_surfaceHolder.isValid()) {
- m_surfaceView = QJNIObjectPrivate("android/view/Surface",
- "(Landroid/graphics/SurfaceTexture;)V",
- m_surfaceTexture.object());
-
m_surfaceHolder = QJNIObjectPrivate("org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder",
"(Landroid/view/Surface;)V",
- m_surfaceView.object());
+ surface());
}
return m_surfaceHolder.object();
diff --git a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h
index 2618ed6c9..ac2af694e 100644
--- a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h
+++ b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h
@@ -50,7 +50,7 @@ public:
int textureID() const { return m_texID; }
jobject surfaceTexture();
- jobject surfaceView();
+ jobject surface();
jobject surfaceHolder();
inline bool isValid() const { return m_surfaceTexture.isValid(); }
@@ -66,7 +66,7 @@ Q_SIGNALS:
private:
int m_texID;
QJNIObjectPrivate m_surfaceTexture;
- QJNIObjectPrivate m_surfaceView;
+ QJNIObjectPrivate m_surface;
QJNIObjectPrivate m_surfaceHolder;
};
diff --git a/src/plugins/android/src/wrappers/jni/androidsurfaceview.cpp b/src/plugins/android/src/wrappers/jni/androidsurfaceview.cpp
new file mode 100644
index 000000000..67560baf4
--- /dev/null
+++ b/src/plugins/android/src/wrappers/jni/androidsurfaceview.cpp
@@ -0,0 +1,204 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "androidsurfaceview.h"
+
+#include <QtCore/private/qjnihelpers_p.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qmutex.h>
+#include <QtGui/qwindow.h>
+
+QT_BEGIN_NAMESPACE
+
+static const char QtSurfaceHolderCallbackClassName[] = "org/qtproject/qt5/android/multimedia/QtSurfaceHolderCallback";
+typedef QVector<AndroidSurfaceHolder *> SurfaceHolders;
+Q_GLOBAL_STATIC(SurfaceHolders, surfaceHolders)
+Q_GLOBAL_STATIC(QMutex, shLock)
+
+AndroidSurfaceHolder::AndroidSurfaceHolder(QJNIObjectPrivate object)
+ : m_surfaceHolder(object)
+ , m_surfaceCreated(false)
+{
+ if (!m_surfaceHolder.isValid())
+ return;
+
+ {
+ QMutexLocker locker(shLock);
+ surfaceHolders->append(this);
+ }
+
+ QJNIObjectPrivate callback(QtSurfaceHolderCallbackClassName, "(J)V", reinterpret_cast<jlong>(this));
+ m_surfaceHolder.callMethod<void>("addCallback",
+ "(Landroid/view/SurfaceHolder$Callback;)V",
+ callback.object());
+}
+
+AndroidSurfaceHolder::~AndroidSurfaceHolder()
+{
+ QMutexLocker locker(shLock);
+ const int i = surfaceHolders->indexOf(this);
+ if (Q_UNLIKELY(i == -1))
+ return;
+
+ surfaceHolders->remove(i);
+}
+
+jobject AndroidSurfaceHolder::surfaceHolder() const
+{
+ return m_surfaceHolder.object();
+}
+
+bool AndroidSurfaceHolder::isSurfaceCreated() const
+{
+ QMutexLocker locker(shLock);
+ return m_surfaceCreated;
+}
+
+void AndroidSurfaceHolder::handleSurfaceCreated(JNIEnv*, jobject, jlong id)
+{
+ QMutexLocker locker(shLock);
+ const int i = surfaceHolders->indexOf(reinterpret_cast<AndroidSurfaceHolder *>(id));
+ if (Q_UNLIKELY(i == -1))
+ return;
+
+ (*surfaceHolders)[i]->m_surfaceCreated = true;
+ Q_EMIT (*surfaceHolders)[i]->surfaceCreated();
+}
+
+void AndroidSurfaceHolder::handleSurfaceDestroyed(JNIEnv*, jobject, jlong id)
+{
+ QMutexLocker locker(shLock);
+ const int i = surfaceHolders->indexOf(reinterpret_cast<AndroidSurfaceHolder *>(id));
+ if (Q_UNLIKELY(i == -1))
+ return;
+
+ (*surfaceHolders)[i]->m_surfaceCreated = false;
+}
+
+bool AndroidSurfaceHolder::initJNI(JNIEnv *env)
+{
+ jclass clazz = QJNIEnvironmentPrivate::findClass(QtSurfaceHolderCallbackClassName,
+ env);
+
+ static const JNINativeMethod methods[] = {
+ {"notifySurfaceCreated", "(J)V", (void *)AndroidSurfaceHolder::handleSurfaceCreated},
+ {"notifySurfaceDestroyed", "(J)V", (void *)AndroidSurfaceHolder::handleSurfaceDestroyed}
+ };
+
+ if (clazz && env->RegisterNatives(clazz,
+ methods,
+ sizeof(methods) / sizeof(methods[0])) != JNI_OK) {
+ return false;
+ }
+
+ return true;
+}
+
+AndroidSurfaceView::AndroidSurfaceView()
+ : m_window(0)
+ , m_surfaceHolder(0)
+ , m_pendingVisible(-1)
+{
+ setAutoDelete(false);
+ QtAndroidPrivate::runOnUiThread(this, QJNIEnvironmentPrivate());
+}
+
+AndroidSurfaceView::~AndroidSurfaceView()
+{
+ delete m_surfaceHolder;
+ delete m_window;
+}
+
+AndroidSurfaceHolder *AndroidSurfaceView::holder() const
+{
+ return m_surfaceHolder;
+}
+
+void AndroidSurfaceView::setVisible(bool v)
+{
+ if (m_window)
+ m_window->setVisible(v);
+ else
+ m_pendingVisible = int(v);
+}
+
+void AndroidSurfaceView::setGeometry(int x, int y, int width, int height)
+{
+ if (m_window)
+ m_window->setGeometry(x, y, width, height);
+ else
+ m_pendingGeometry = QRect(x, y, width, height);
+}
+
+bool AndroidSurfaceView::event(QEvent *e)
+{
+ if (e->type() == QEvent::User) {
+ Q_ASSERT(m_surfaceView.isValid());
+
+ QJNIObjectPrivate holder = m_surfaceView.callObjectMethod("getHolder",
+ "()Landroid/view/SurfaceHolder;");
+ if (!holder.isValid()) {
+ m_surfaceView = QJNIObjectPrivate();
+ } else {
+ m_surfaceHolder = new AndroidSurfaceHolder(holder);
+ connect(m_surfaceHolder, &AndroidSurfaceHolder::surfaceCreated,
+ this, &AndroidSurfaceView::surfaceCreated);
+ { // Lock now to avoid a race with handleSurfaceCreated()
+ QMutexLocker locker(shLock);
+ m_window = QWindow::fromWinId(WId(m_surfaceView.object()));
+
+ if (m_pendingVisible != -1)
+ m_window->setVisible(m_pendingVisible);
+ if (m_pendingGeometry.isValid())
+ m_window->setGeometry(m_pendingGeometry);
+ }
+ }
+
+ return true;
+ }
+
+ return QObject::event(e);
+}
+
+// Called on the Android UI thread.
+void AndroidSurfaceView::run()
+{
+ m_surfaceView = QJNIObjectPrivate("android/view/SurfaceView",
+ "(Landroid/content/Context;)V",
+ QtAndroidPrivate::activity());
+ QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/wrappers/jni/androidsurfaceview.h b/src/plugins/android/src/wrappers/jni/androidsurfaceview.h
new file mode 100644
index 000000000..661a5959f
--- /dev/null
+++ b/src/plugins/android/src/wrappers/jni/androidsurfaceview.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANDROIDSURFACEVIEW_H
+#define ANDROIDSURFACEVIEW_H
+
+#include <QtCore/private/qjni_p.h>
+#include <qrect.h>
+#include <QtCore/qrunnable.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWindow;
+
+class AndroidSurfaceHolder : public QObject
+{
+ Q_OBJECT
+public:
+ ~AndroidSurfaceHolder();
+
+ jobject surfaceHolder() const;
+ bool isSurfaceCreated() const;
+
+ static bool initJNI(JNIEnv *env);
+
+Q_SIGNALS:
+ void surfaceCreated();
+
+private:
+ AndroidSurfaceHolder(QJNIObjectPrivate object);
+
+ static void handleSurfaceCreated(JNIEnv*, jobject, jlong id);
+ static void handleSurfaceDestroyed(JNIEnv*, jobject, jlong id);
+
+ QJNIObjectPrivate m_surfaceHolder;
+ bool m_surfaceCreated;
+
+ friend class AndroidSurfaceView;
+};
+
+class AndroidSurfaceView : public QObject, public QRunnable
+{
+ Q_OBJECT
+public:
+ AndroidSurfaceView();
+ ~AndroidSurfaceView();
+
+ AndroidSurfaceHolder *holder() const;
+
+ void setVisible(bool v);
+ void setGeometry(int x, int y, int width, int height);
+
+ bool event(QEvent *);
+
+Q_SIGNALS:
+ void surfaceCreated();
+
+protected:
+ void run() override;
+
+private:
+ QJNIObjectPrivate m_surfaceView;
+ QWindow *m_window;
+ AndroidSurfaceHolder *m_surfaceHolder;
+ int m_pendingVisible;
+ QRect m_pendingGeometry;
+};
+
+QT_END_NAMESPACE
+
+#endif // ANDROIDSURFACEVIEW_H
diff --git a/src/plugins/android/src/wrappers/jni/jni.pri b/src/plugins/android/src/wrappers/jni/jni.pri
index ba2ad0801..930d7e922 100644
--- a/src/plugins/android/src/wrappers/jni/jni.pri
+++ b/src/plugins/android/src/wrappers/jni/jni.pri
@@ -1,4 +1,4 @@
-QT += platformsupport-private
+QT += core-private
INCLUDEPATH += $$PWD
@@ -8,7 +8,8 @@ HEADERS += \
$$PWD/androidmediametadataretriever.h \
$$PWD/androidcamera.h \
$$PWD/androidmultimediautils.h \
- $$PWD/androidmediarecorder.h
+ $$PWD/androidmediarecorder.h \
+ $$PWD/androidsurfaceview.h
SOURCES += \
$$PWD/androidmediaplayer.cpp \
@@ -16,4 +17,5 @@ SOURCES += \
$$PWD/androidmediametadataretriever.cpp \
$$PWD/androidcamera.cpp \
$$PWD/androidmultimediautils.cpp \
- $$PWD/androidmediarecorder.cpp
+ $$PWD/androidmediarecorder.cpp \
+ $$PWD/androidsurfaceview.cpp
diff --git a/src/plugins/audiocapture/audiocapturesession.cpp b/src/plugins/audiocapture/audiocapturesession.cpp
index 2b300964a..1b183db26 100644
--- a/src/plugins/audiocapture/audiocapturesession.cpp
+++ b/src/plugins/audiocapture/audiocapturesession.cpp
@@ -88,6 +88,8 @@ AudioCaptureSession::AudioCaptureSession(QObject *parent)
, m_audioInput(0)
, m_deviceInfo(QAudioDeviceInfo::defaultInputDevice())
, m_wavFile(true)
+ , m_volume(1.0)
+ , m_muted(false)
{
m_format = m_deviceInfo.preferredFormat();
}
@@ -312,6 +314,8 @@ void AudioCaptureSession::record()
file.write((char*)&header,sizeof(CombinedHeader));
}
+ setVolumeHelper(m_muted ? 0 : m_volume);
+
file.startProbes(m_format);
m_audioInput->start(qobject_cast<QIODevice*>(&file));
} else {
@@ -400,4 +404,51 @@ void AudioCaptureSession::setCaptureDevice(const QString &deviceName)
m_deviceInfo = QAudioDeviceInfo::defaultInputDevice();
}
+qreal AudioCaptureSession::volume() const
+{
+ return m_volume;
+}
+
+bool AudioCaptureSession::isMuted() const
+{
+ return m_muted;
+}
+
+void AudioCaptureSession::setVolume(qreal v)
+{
+ qreal boundedVolume = qBound(qreal(0), v, qreal(1));
+
+ if (m_volume == boundedVolume)
+ return;
+
+ m_volume = boundedVolume;
+
+ if (!m_muted)
+ setVolumeHelper(m_volume);
+
+ emit volumeChanged(m_volume);
+}
+
+void AudioCaptureSession::setMuted(bool muted)
+{
+ if (m_muted == muted)
+ return;
+
+ m_muted = muted;
+
+ setVolumeHelper(m_muted ? 0 : m_volume);
+
+ emit mutedChanged(m_muted);
+}
+
+void AudioCaptureSession::setVolumeHelper(qreal volume)
+{
+ if (!m_audioInput)
+ return;
+
+ m_audioInput->setVolume(volume);
+}
+
+
+
QT_END_NAMESPACE
diff --git a/src/plugins/audiocapture/audiocapturesession.h b/src/plugins/audiocapture/audiocapturesession.h
index 188312905..da30053ad 100644
--- a/src/plugins/audiocapture/audiocapturesession.h
+++ b/src/plugins/audiocapture/audiocapturesession.h
@@ -96,11 +96,19 @@ public:
void setCaptureDevice(const QString &deviceName);
+ void setVolume(qreal v);
+ qreal volume() const;
+
+ void setMuted(bool muted);
+ bool isMuted() const;
+
signals:
void stateChanged(QMediaRecorder::State state);
void statusChanged(QMediaRecorder::Status status);
void positionChanged(qint64 position);
void actualLocationChanged(const QUrl &location);
+ void volumeChanged(qreal volume);
+ void mutedChanged(bool muted);
void error(int error, const QString &errorString);
private slots:
@@ -114,6 +122,8 @@ private:
void setStatus(QMediaRecorder::Status status);
+ void setVolumeHelper(qreal volume);
+
QDir defaultDir() const;
QString generateFileName(const QString &requestedName,
const QString &extension) const;
@@ -129,6 +139,8 @@ private:
QAudioDeviceInfo m_deviceInfo;
QAudioFormat m_format;
bool m_wavFile;
+ qreal m_volume;
+ bool m_muted;
// WAV header stuff
diff --git a/src/plugins/audiocapture/audiomediarecordercontrol.cpp b/src/plugins/audiocapture/audiomediarecordercontrol.cpp
index 432ee3d08..d011d864e 100644
--- a/src/plugins/audiocapture/audiomediarecordercontrol.cpp
+++ b/src/plugins/audiocapture/audiomediarecordercontrol.cpp
@@ -50,6 +50,10 @@ AudioMediaRecorderControl::AudioMediaRecorderControl(QObject *parent)
this, SIGNAL(statusChanged(QMediaRecorder::Status)));
connect(m_session, SIGNAL(actualLocationChanged(QUrl)),
this, SIGNAL(actualLocationChanged(QUrl)));
+ connect(m_session, &AudioCaptureSession::volumeChanged,
+ this, &AudioMediaRecorderControl::volumeChanged);
+ connect(m_session, &AudioCaptureSession::mutedChanged,
+ this, &AudioMediaRecorderControl::mutedChanged);
connect(m_session, SIGNAL(error(int,QString)),
this, SIGNAL(error(int,QString)));
}
@@ -85,13 +89,12 @@ qint64 AudioMediaRecorderControl::duration() const
bool AudioMediaRecorderControl::isMuted() const
{
- return false;
+ return m_session->isMuted();
}
qreal AudioMediaRecorderControl::volume() const
{
- //TODO: implement muting and audio gain
- return 1.0;
+ return m_session->volume();
}
void AudioMediaRecorderControl::setState(QMediaRecorder::State state)
@@ -101,14 +104,12 @@ void AudioMediaRecorderControl::setState(QMediaRecorder::State state)
void AudioMediaRecorderControl::setMuted(bool muted)
{
- if (muted)
- qWarning("Muting the audio recording is not supported.");
+ m_session->setMuted(muted);
}
void AudioMediaRecorderControl::setVolume(qreal volume)
{
- if (!qFuzzyCompare(volume, qreal(1.0)))
- qWarning("Changing the audio recording volume is not supported.");
+ m_session->setVolume(volume);
}
QT_END_NAMESPACE
diff --git a/src/plugins/avfoundation/camera/avfcameraservice.mm b/src/plugins/avfoundation/camera/avfcameraservice.mm
index fd473b37b..20156f06f 100644
--- a/src/plugins/avfoundation/camera/avfcameraservice.mm
+++ b/src/plugins/avfoundation/camera/avfcameraservice.mm
@@ -203,18 +203,15 @@ QMediaControl *AVFCameraService::requestControl(const char *name)
void AVFCameraService::releaseControl(QMediaControl *control)
{
- if (m_videoOutput == control) {
- m_session->setVideoOutput(0);
- delete m_videoOutput;
- m_videoOutput = 0;
- }
AVFMediaVideoProbeControl *videoProbe = qobject_cast<AVFMediaVideoProbeControl *>(control);
if (videoProbe) {
m_session->removeProbe(videoProbe);
delete videoProbe;
- return;
+ } else if (m_videoOutput == control) {
+ m_session->setVideoOutput(0);
+ delete m_videoOutput;
+ m_videoOutput = 0;
}
-
}
AVFMediaRecorderControl *AVFCameraService::recorderControl() const
diff --git a/src/plugins/avfoundation/camera/avfcamerasession.h b/src/plugins/avfoundation/camera/avfcamerasession.h
index 1be847b7c..13a8a35c5 100644
--- a/src/plugins/avfoundation/camera/avfcamerasession.h
+++ b/src/plugins/avfoundation/camera/avfcamerasession.h
@@ -70,6 +70,7 @@ public:
static int defaultCameraIndex();
static const QList<AVFCameraInfo> &availableCameraDevices();
static AVFCameraInfo cameraDeviceInfo(const QByteArray &device);
+ AVFCameraInfo activeCameraInfo() const { return m_activeCameraInfo; }
void setVideoOutput(AVFCameraRendererControl *output);
AVCaptureSession *captureSession() const { return m_captureSession; }
@@ -93,10 +94,12 @@ public Q_SLOTS:
void processSessionStopped();
void onCameraFrameFetched(const QVideoFrame &frame);
+
Q_SIGNALS:
void readyToConfigureConnections();
void stateChanged(QCamera::State newState);
void activeChanged(bool);
+ void newViewfinderFrame(const QVideoFrame &frame);
void error(int error, const QString &errorString);
private:
@@ -107,6 +110,7 @@ private:
static int m_defaultCameraIndex;
static QList<AVFCameraInfo> m_cameraDevices;
+ AVFCameraInfo m_activeCameraInfo;
AVFCameraService *m_service;
AVFCameraRendererControl *m_videoOutput;
diff --git a/src/plugins/avfoundation/camera/avfcamerasession.mm b/src/plugins/avfoundation/camera/avfcamerasession.mm
index 4ede4a514..993e28319 100644
--- a/src/plugins/avfoundation/camera/avfcamerasession.mm
+++ b/src/plugins/avfoundation/camera/avfcamerasession.mm
@@ -220,7 +220,7 @@ void AVFCameraSession::updateCameraDevices()
// the screen when held in portrait ==> 270 degrees clockwise angle
// - Front-facing cameras have the top side of the sensor aligned with the left side of
// the screen when held in portrait ==> 270 degrees clockwise angle
- // On Mac OS, the position will always be unspecified and the sensor orientation unknown.
+ // On OS X, the position will always be unspecified and the sensor orientation unknown.
switch (device.position) {
case AVCaptureDevicePositionBack:
info.position = QCamera::BackFace;
@@ -346,6 +346,7 @@ void AVFCameraSession::attachVideoInputDevice()
[m_captureSession removeInput:m_videoInput];
[m_videoInput release];
m_videoInput = 0;
+ m_activeCameraInfo = AVFCameraInfo();
}
AVCaptureDevice *videoDevice = m_service->videoDeviceControl()->createCaptureDevice();
@@ -359,6 +360,7 @@ void AVFCameraSession::attachVideoInputDevice()
qWarning() << "Failed to create video device input";
} else {
if ([m_captureSession canAddInput:m_videoInput]) {
+ m_activeCameraInfo = m_cameraDevices.at(m_service->videoDeviceControl()->selectedDevice());
[m_videoInput retain];
[m_captureSession addInput:m_videoInput];
} else {
@@ -432,6 +434,8 @@ FourCharCode AVFCameraSession::defaultCodec()
void AVFCameraSession::onCameraFrameFetched(const QVideoFrame &frame)
{
+ Q_EMIT newViewfinderFrame(frame);
+
m_videoProbesMutex.lock();
QSet<AVFMediaVideoProbeControl *>::const_iterator i = m_videoProbes.constBegin();
while (i != m_videoProbes.constEnd()) {
diff --git a/src/plugins/avfoundation/camera/avfimagecapturecontrol.h b/src/plugins/avfoundation/camera/avfimagecapturecontrol.h
index 993725653..dd5e8e8bb 100644
--- a/src/plugins/avfoundation/camera/avfimagecapturecontrol.h
+++ b/src/plugins/avfoundation/camera/avfimagecapturecontrol.h
@@ -36,19 +36,23 @@
#import <AVFoundation/AVFoundation.h>
+#include <QtCore/qqueue.h>
+#include <QtCore/qsemaphore.h>
#include <QtMultimedia/qcameraimagecapturecontrol.h>
+#include "avfcamerasession.h"
#include "avfstoragelocation.h"
QT_BEGIN_NAMESPACE
-class AVFCameraSession;
-class AVFCameraService;
-class AVFCameraControl;
-
class AVFImageCaptureControl : public QCameraImageCaptureControl
{
Q_OBJECT
public:
+ struct CaptureRequest {
+ int captureId;
+ QSemaphore *previewReady;
+ };
+
AVFImageCaptureControl(AVFCameraService *service, QObject *parent = 0);
~AVFImageCaptureControl();
@@ -64,8 +68,11 @@ public:
private Q_SLOTS:
void updateCaptureConnection();
void updateReadyStatus();
+ void onNewViewfinderFrame(const QVideoFrame &frame);
private:
+ void makeCapturePreview(CaptureRequest request, const QVideoFrame &frame, int rotation);
+
AVFCameraSession *m_session;
AVFCameraControl *m_cameraControl;
bool m_ready;
@@ -73,8 +80,13 @@ private:
AVCaptureStillImageOutput *m_stillImageOutput;
AVCaptureConnection *m_videoConnection;
AVFStorageLocation m_storageLocation;
+
+ QMutex m_requestsMutex;
+ QQueue<CaptureRequest> m_captureRequests;
};
+Q_DECLARE_TYPEINFO(AVFImageCaptureControl::CaptureRequest, Q_PRIMITIVE_TYPE);
+
QT_END_NAMESPACE
#endif
diff --git a/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm
index c28ccef8e..edaaf8ce3 100644
--- a/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm
+++ b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm
@@ -33,14 +33,15 @@
#include "avfcameradebug.h"
#include "avfimagecapturecontrol.h"
-#include "avfcamerasession.h"
#include "avfcameraservice.h"
#include "avfcameracontrol.h"
#include <QtCore/qurl.h>
#include <QtCore/qfile.h>
#include <QtCore/qbuffer.h>
+#include <QtConcurrent/qtconcurrentrun.h>
#include <QtGui/qimagereader.h>
+#include <private/qvideoframe_p.h>
QT_USE_NAMESPACE
@@ -65,6 +66,10 @@ AVFImageCaptureControl::AVFImageCaptureControl(AVFCameraService *service, QObjec
connect(m_cameraControl, SIGNAL(statusChanged(QCamera::Status)), SLOT(updateReadyStatus()));
connect(m_session, SIGNAL(readyToConfigureConnections()), SLOT(updateCaptureConnection()));
+
+ connect(m_session, &AVFCameraSession::newViewfinderFrame,
+ this, &AVFImageCaptureControl::onNewViewfinderFrame,
+ Qt::DirectConnection);
}
AVFImageCaptureControl::~AVFImageCaptureControl()
@@ -106,9 +111,18 @@ int AVFImageCaptureControl::capture(const QString &fileName)
qDebugCamera() << "Capture image to" << actualFileName;
- int captureId = m_lastCaptureId;
+ CaptureRequest request = { m_lastCaptureId, new QSemaphore };
+ m_requestsMutex.lock();
+ m_captureRequests.enqueue(request);
+ m_requestsMutex.unlock();
+
[m_stillImageOutput captureStillImageAsynchronouslyFromConnection:m_videoConnection
completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
+
+ // Wait for the preview to be generated before saving the JPEG
+ request.previewReady->acquire();
+ delete request.previewReady;
+
if (error) {
QStringList messageParts;
messageParts << QString::fromUtf8([[error localizedDescription] UTF8String]);
@@ -119,64 +133,66 @@ int AVFImageCaptureControl::capture(const QString &fileName)
qDebugCamera() << "Image capture failed:" << errorMessage;
QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(int, captureId),
+ Q_ARG(int, request.captureId),
Q_ARG(int, QCameraImageCapture::ResourceError),
Q_ARG(QString, errorMessage));
} else {
- qDebugCamera() << "Image captured:" << actualFileName;
- //we can't find the exact time the image is exposed,
- //but image capture is very fast on desktop, so emit it here
- QMetaObject::invokeMethod(this, "imageExposed", Qt::QueuedConnection,
- Q_ARG(int, captureId));
+ qDebugCamera() << "Image capture completed:" << actualFileName;
NSData *nsJpgData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
QByteArray jpgData = QByteArray::fromRawData((const char *)[nsJpgData bytes], [nsJpgData length]);
- //Generate snap preview as downscalled image
- {
- QBuffer buffer(&jpgData);
- QImageReader imageReader(&buffer);
- QSize imgSize = imageReader.size();
- int downScaleSteps = 0;
- while (imgSize.width() > 800 && downScaleSteps < 8) {
- imgSize.rwidth() /= 2;
- imgSize.rheight() /= 2;
- downScaleSteps++;
- }
-
- imageReader.setScaledSize(imgSize);
- QImage snapPreview = imageReader.read();
-
- QMetaObject::invokeMethod(this, "imageCaptured", Qt::QueuedConnection,
- Q_ARG(int, captureId),
- Q_ARG(QImage, snapPreview));
- }
-
- qDebugCamera() << "Image captured" << actualFileName;
-
QFile f(actualFileName);
if (f.open(QFile::WriteOnly)) {
if (f.write(jpgData) != -1) {
QMetaObject::invokeMethod(this, "imageSaved", Qt::QueuedConnection,
- Q_ARG(int, captureId),
+ Q_ARG(int, request.captureId),
Q_ARG(QString, actualFileName));
} else {
QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(int, captureId),
+ Q_ARG(int, request.captureId),
Q_ARG(int, QCameraImageCapture::OutOfSpaceError),
Q_ARG(QString, f.errorString()));
}
} else {
QString errorMessage = tr("Could not open destination file:\n%1").arg(actualFileName);
QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(int, captureId),
+ Q_ARG(int, request.captureId),
Q_ARG(int, QCameraImageCapture::ResourceError),
Q_ARG(QString, errorMessage));
}
}
}];
- return captureId;
+ return request.captureId;
+}
+
+void AVFImageCaptureControl::onNewViewfinderFrame(const QVideoFrame &frame)
+{
+ QMutexLocker locker(&m_requestsMutex);
+
+ if (m_captureRequests.isEmpty())
+ return;
+
+ CaptureRequest request = m_captureRequests.dequeue();
+ Q_EMIT imageExposed(request.captureId);
+
+ QtConcurrent::run(this, &AVFImageCaptureControl::makeCapturePreview,
+ request,
+ frame,
+ 0 /* rotation */);
+}
+
+void AVFImageCaptureControl::makeCapturePreview(CaptureRequest request,
+ const QVideoFrame &frame,
+ int rotation)
+{
+ QTransform transform;
+ transform.rotate(rotation);
+
+ Q_EMIT imageCaptured(request.captureId, qt_imageFromVideoFrame(frame).transformed(transform));
+
+ request.previewReady->release();
}
void AVFImageCaptureControl::cancelCapture()
diff --git a/src/plugins/common/evr.pri b/src/plugins/common/evr.pri
new file mode 100644
index 000000000..f951f6730
--- /dev/null
+++ b/src/plugins/common/evr.pri
@@ -0,0 +1,8 @@
+INCLUDEPATH += $$PWD/evr
+
+qtHaveModule(widgets): QT += widgets
+
+HEADERS += $$PWD/evr/evrvideowindowcontrol.h \
+ $$PWD/evr/evrdefs.h
+
+SOURCES += $$PWD/evr/evrvideowindowcontrol.cpp
diff --git a/src/plugins/common/evr/evrdefs.h b/src/plugins/common/evr/evrdefs.h
new file mode 100644
index 000000000..ce6ca6584
--- /dev/null
+++ b/src/plugins/common/evr/evrdefs.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef EVRDEFS_H
+#define EVRDEFS_H
+
+#include <d3d9.h>
+#include <Evr9.h>
+#include <dxva2api.h>
+
+// The following is required to compile with MinGW
+
+#ifdef __GNUC__
+typedef struct MFVideoNormalizedRect {
+ float left;
+ float top;
+ float right;
+ float bottom;
+} MFVideoNormalizedRect;
+#endif
+
+#ifndef __IMFGetService_INTERFACE_DEFINED__
+#define __IMFGetService_INTERFACE_DEFINED__
+DEFINE_GUID(IID_IMFGetService, 0xfa993888, 0x4383, 0x415a, 0xa9,0x30, 0xdd,0x47,0x2a,0x8c,0xf6,0xf7);
+MIDL_INTERFACE("fa993888-4383-415a-a930-dd472a8cf6f7")
+IMFGetService : public IUnknown
+{
+ virtual HRESULT STDMETHODCALLTYPE GetService(REFGUID, REFIID, LPVOID *) = 0;
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IMFGetService, 0xfa993888, 0x4383, 0x415a, 0xa9,0x30, 0xdd,0x47,0x2a,0x8c,0xf6,0xf7)
+#endif
+#endif // __IMFGetService_INTERFACE_DEFINED__
+
+#ifndef __IMFVideoDisplayControl_INTERFACE_DEFINED__
+#define __IMFVideoDisplayControl_INTERFACE_DEFINED__
+typedef enum MFVideoAspectRatioMode
+{
+ MFVideoARMode_None = 0,
+ MFVideoARMode_PreservePicture = 0x1,
+ MFVideoARMode_PreservePixel = 0x2,
+ MFVideoARMode_NonLinearStretch = 0x4,
+ MFVideoARMode_Mask = 0x7
+} MFVideoAspectRatioMode;
+
+DEFINE_GUID(IID_IMFVideoDisplayControl, 0xa490b1e4, 0xab84, 0x4d31, 0xa1,0xb2, 0x18,0x1e,0x03,0xb1,0x07,0x7a);
+MIDL_INTERFACE("a490b1e4-ab84-4d31-a1b2-181e03b1077a")
+IMFVideoDisplayControl : public IUnknown
+{
+ virtual HRESULT STDMETHODCALLTYPE GetNativeVideoSize(SIZE *, SIZE *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetIdealVideoSize(SIZE *, SIZE *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetVideoPosition(const MFVideoNormalizedRect *, const LPRECT) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetVideoPosition(MFVideoNormalizedRect *, LPRECT) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetAspectRatioMode(DWORD) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetAspectRatioMode(DWORD *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetVideoWindow(HWND) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetVideoWindow(HWND *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE RepaintVideo(void) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentImage(BITMAPINFOHEADER *, BYTE **, DWORD *, LONGLONG *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetBorderColor(COLORREF) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetBorderColor(COLORREF *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetRenderingPrefs(DWORD) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetRenderingPrefs(DWORD *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetFullscreen(BOOL) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetFullscreen(BOOL *) = 0;
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IMFVideoDisplayControl, 0xa490b1e4, 0xab84, 0x4d31, 0xa1,0xb2, 0x18,0x1e,0x03,0xb1,0x07,0x7a)
+#endif
+#endif // __IMFVideoDisplayControl_INTERFACE_DEFINED__
+
+#ifndef __IMFVideoProcessor_INTERFACE_DEFINED__
+#define __IMFVideoProcessor_INTERFACE_DEFINED__
+DEFINE_GUID(IID_IMFVideoProcessor, 0x6AB0000C, 0xFECE, 0x4d1f, 0xA2,0xAC, 0xA9,0x57,0x35,0x30,0x65,0x6E);
+MIDL_INTERFACE("6AB0000C-FECE-4d1f-A2AC-A9573530656E")
+IMFVideoProcessor : public IUnknown
+{
+ virtual HRESULT STDMETHODCALLTYPE GetAvailableVideoProcessorModes(UINT *, GUID **) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetVideoProcessorCaps(LPGUID, DXVA2_VideoProcessorCaps *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetVideoProcessorMode(LPGUID) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetVideoProcessorMode(LPGUID) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetProcAmpRange(DWORD, DXVA2_ValueRange *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetProcAmpValues(DWORD, DXVA2_ProcAmpValues *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetProcAmpValues(DWORD, DXVA2_ProcAmpValues *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetFilteringRange(DWORD, DXVA2_ValueRange *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetFilteringValue(DWORD, DXVA2_Fixed32 *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetFilteringValue(DWORD, DXVA2_Fixed32 *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetBackgroundColor(COLORREF *) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetBackgroundColor(COLORREF) = 0;
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IMFVideoProcessor, 0x6AB0000C, 0xFECE, 0x4d1f, 0xA2,0xAC, 0xA9,0x57,0x35,0x30,0x65,0x6E)
+#endif
+#endif // __IMFVideoProcessor_INTERFACE_DEFINED__
+
+#endif // EVRDEFS_H
+
diff --git a/src/plugins/wmf/player/evr9videowindowcontrol.cpp b/src/plugins/common/evr/evrvideowindowcontrol.cpp
index e94918dba..faa23d6e5 100644
--- a/src/plugins/wmf/player/evr9videowindowcontrol.cpp
+++ b/src/plugins/common/evr/evrvideowindowcontrol.cpp
@@ -3,7 +3,7 @@
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
-** This file is part of the Qt Mobility Components.
+** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
@@ -31,14 +31,16 @@
**
****************************************************************************/
-#include "evr9videowindowcontrol.h"
-#include <QtWidgets/qwidget.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qglobal.h>
+#include "evrvideowindowcontrol.h"
-Evr9VideoWindowControl::Evr9VideoWindowControl(QObject *parent)
+#ifndef QT_NO_WIDGETS
+#include <qwidget.h>
+#endif
+
+EvrVideoWindowControl::EvrVideoWindowControl(QObject *parent)
: QVideoWindowControl(parent)
, m_windowId(0)
+ , m_windowColor(RGB(0, 0, 0))
, m_dirtyValues(0)
, m_aspectRatioMode(Qt::KeepAspectRatio)
, m_brightness(0)
@@ -46,68 +48,83 @@ Evr9VideoWindowControl::Evr9VideoWindowControl(QObject *parent)
, m_hue(0)
, m_saturation(0)
, m_fullScreen(false)
- , m_currentActivate(0)
- , m_evrSink(0)
, m_displayControl(0)
, m_processor(0)
{
}
-Evr9VideoWindowControl::~Evr9VideoWindowControl()
+EvrVideoWindowControl::~EvrVideoWindowControl()
{
clear();
}
-void Evr9VideoWindowControl::clear()
+bool EvrVideoWindowControl::setEvr(IUnknown *evr)
{
- if (m_processor)
- m_processor->Release();
- if (m_displayControl)
- m_displayControl->Release();
- if (m_evrSink)
- m_evrSink->Release();
- if (m_currentActivate) {
- m_currentActivate->ShutdownObject();
- m_currentActivate->Release();
+ clear();
+
+ if (!evr)
+ return true;
+
+ static const GUID mr_VIDEO_RENDER_SERVICE = { 0x1092a86c, 0xab1a, 0x459a, {0xa3, 0x36, 0x83, 0x1f, 0xbc, 0x4d, 0x11, 0xff} };
+ static const GUID mr_VIDEO_MIXER_SERVICE = { 0x73cd2fc, 0x6cf4, 0x40b7, {0x88, 0x59, 0xe8, 0x95, 0x52, 0xc8, 0x41, 0xf8} };
+ IMFGetService *service = NULL;
+
+ if (SUCCEEDED(evr->QueryInterface(IID_PPV_ARGS(&service)))
+ && SUCCEEDED(service->GetService(mr_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_displayControl)))) {
+
+ service->GetService(mr_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&m_processor));
+
+ setWinId(m_windowId);
+ setDisplayRect(m_displayRect);
+ setAspectRatioMode(m_aspectRatioMode);
+ m_dirtyValues = DXVA2_ProcAmp_Brightness | DXVA2_ProcAmp_Contrast | DXVA2_ProcAmp_Hue | DXVA2_ProcAmp_Saturation;
+ applyImageControls();
}
- m_processor = NULL;
- m_displayControl = NULL;
- m_evrSink = NULL;
- m_currentActivate = NULL;
+ if (service)
+ service->Release();
+
+ return m_displayControl != NULL;
}
-void Evr9VideoWindowControl::releaseActivate()
+void EvrVideoWindowControl::clear()
{
- clear();
+ if (m_displayControl)
+ m_displayControl->Release();
+ m_displayControl = NULL;
+
+ if (m_processor)
+ m_processor->Release();
+ m_processor = NULL;
}
-WId Evr9VideoWindowControl::winId() const
+WId EvrVideoWindowControl::winId() const
{
return m_windowId;
}
-void Evr9VideoWindowControl::setWinId(WId id)
+void EvrVideoWindowControl::setWinId(WId id)
{
m_windowId = id;
+#ifndef QT_NO_WIDGETS
if (QWidget *widget = QWidget::find(m_windowId)) {
const QColor color = widget->palette().color(QPalette::Window);
m_windowColor = RGB(color.red(), color.green(), color.blue());
}
+#endif
- if (m_displayControl) {
+ if (m_displayControl)
m_displayControl->SetVideoWindow(HWND(m_windowId));
- }
}
-QRect Evr9VideoWindowControl::displayRect() const
+QRect EvrVideoWindowControl::displayRect() const
{
return m_displayRect;
}
-void Evr9VideoWindowControl::setDisplayRect(const QRect &rect)
+void EvrVideoWindowControl::setDisplayRect(const QRect &rect)
{
m_displayRect = rect;
@@ -140,19 +157,19 @@ void Evr9VideoWindowControl::setDisplayRect(const QRect &rect)
}
}
-bool Evr9VideoWindowControl::isFullScreen() const
+bool EvrVideoWindowControl::isFullScreen() const
{
return m_fullScreen;
}
-void Evr9VideoWindowControl::setFullScreen(bool fullScreen)
+void EvrVideoWindowControl::setFullScreen(bool fullScreen)
{
if (m_fullScreen == fullScreen)
return;
emit fullScreenChanged(m_fullScreen = fullScreen);
}
-void Evr9VideoWindowControl::repaint()
+void EvrVideoWindowControl::repaint()
{
QSize size = nativeSize();
if (size.width() > 0 && size.height() > 0
@@ -181,7 +198,7 @@ void Evr9VideoWindowControl::repaint()
}
}
-QSize Evr9VideoWindowControl::nativeSize() const
+QSize EvrVideoWindowControl::nativeSize() const
{
QSize size;
if (m_displayControl) {
@@ -192,12 +209,12 @@ QSize Evr9VideoWindowControl::nativeSize() const
return size;
}
-Qt::AspectRatioMode Evr9VideoWindowControl::aspectRatioMode() const
+Qt::AspectRatioMode EvrVideoWindowControl::aspectRatioMode() const
{
return m_aspectRatioMode;
}
-void Evr9VideoWindowControl::setAspectRatioMode(Qt::AspectRatioMode mode)
+void EvrVideoWindowControl::setAspectRatioMode(Qt::AspectRatioMode mode)
{
m_aspectRatioMode = mode;
@@ -222,12 +239,12 @@ void Evr9VideoWindowControl::setAspectRatioMode(Qt::AspectRatioMode mode)
}
}
-int Evr9VideoWindowControl::brightness() const
+int EvrVideoWindowControl::brightness() const
{
return m_brightness;
}
-void Evr9VideoWindowControl::setBrightness(int brightness)
+void EvrVideoWindowControl::setBrightness(int brightness)
{
if (m_brightness == brightness)
return;
@@ -236,17 +253,17 @@ void Evr9VideoWindowControl::setBrightness(int brightness)
m_dirtyValues |= DXVA2_ProcAmp_Brightness;
- setProcAmpValues();
+ applyImageControls();
emit brightnessChanged(brightness);
}
-int Evr9VideoWindowControl::contrast() const
+int EvrVideoWindowControl::contrast() const
{
return m_contrast;
}
-void Evr9VideoWindowControl::setContrast(int contrast)
+void EvrVideoWindowControl::setContrast(int contrast)
{
if (m_contrast == contrast)
return;
@@ -255,17 +272,17 @@ void Evr9VideoWindowControl::setContrast(int contrast)
m_dirtyValues |= DXVA2_ProcAmp_Contrast;
- setProcAmpValues();
+ applyImageControls();
emit contrastChanged(contrast);
}
-int Evr9VideoWindowControl::hue() const
+int EvrVideoWindowControl::hue() const
{
return m_hue;
}
-void Evr9VideoWindowControl::setHue(int hue)
+void EvrVideoWindowControl::setHue(int hue)
{
if (m_hue == hue)
return;
@@ -274,17 +291,17 @@ void Evr9VideoWindowControl::setHue(int hue)
m_dirtyValues |= DXVA2_ProcAmp_Hue;
- setProcAmpValues();
+ applyImageControls();
emit hueChanged(hue);
}
-int Evr9VideoWindowControl::saturation() const
+int EvrVideoWindowControl::saturation() const
{
return m_saturation;
}
-void Evr9VideoWindowControl::setSaturation(int saturation)
+void EvrVideoWindowControl::setSaturation(int saturation)
{
if (m_saturation == saturation)
return;
@@ -293,41 +310,12 @@ void Evr9VideoWindowControl::setSaturation(int saturation)
m_dirtyValues |= DXVA2_ProcAmp_Saturation;
- setProcAmpValues();
+ applyImageControls();
emit saturationChanged(saturation);
}
-IMFActivate* Evr9VideoWindowControl::createActivate()
-{
- clear();
-
- if (FAILED(MFCreateVideoRendererActivate(0, &m_currentActivate))) {
- qWarning() << "Failed to create evr video renderer activate!";
- return 0;
- }
- if (FAILED(m_currentActivate->ActivateObject(IID_IMFMediaSink, (LPVOID*)(&m_evrSink)))) {
- qWarning() << "Failed to activate evr media sink!";
- return 0;
- }
- if (FAILED(MFGetService(m_evrSink, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_displayControl)))) {
- qWarning() << "Failed to get display control from evr media sink!";
- return 0;
- }
- if (FAILED(MFGetService(m_evrSink, MR_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&m_processor)))) {
- qWarning() << "Failed to get video processor from evr media sink!";
- return 0;
- }
-
- setWinId(m_windowId);
- setDisplayRect(m_displayRect);
- setAspectRatioMode(m_aspectRatioMode);
- m_dirtyValues = DXVA2_ProcAmp_Brightness | DXVA2_ProcAmp_Contrast | DXVA2_ProcAmp_Hue | DXVA2_ProcAmp_Saturation;
-
- return m_currentActivate;
-}
-
-void Evr9VideoWindowControl::setProcAmpValues()
+void EvrVideoWindowControl::applyImageControls()
{
if (m_processor) {
DXVA2_ProcAmpValues values;
@@ -350,7 +338,7 @@ void Evr9VideoWindowControl::setProcAmpValues()
}
}
-DXVA2_Fixed32 Evr9VideoWindowControl::scaleProcAmpValue(DWORD prop, int value) const
+DXVA2_Fixed32 EvrVideoWindowControl::scaleProcAmpValue(DWORD prop, int value) const
{
float scaledValue = 0.0;
diff --git a/src/plugins/wmf/player/evr9videowindowcontrol.h b/src/plugins/common/evr/evrvideowindowcontrol.h
index 05486f987..beb82ec05 100644
--- a/src/plugins/wmf/player/evr9videowindowcontrol.h
+++ b/src/plugins/common/evr/evrvideowindowcontrol.h
@@ -31,23 +31,23 @@
**
****************************************************************************/
-#ifndef EVR9VIDEOWINDOWCONTROL_H
-#define EVR9VIDEOWINDOWCONTROL_H
+#ifndef EVRVIDEOWINDOWCONTROL_H
+#define EVRVIDEOWINDOWCONTROL_H
#include "qvideowindowcontrol.h"
-#include <Mfidl.h>
-#include <d3d9.h>
-#include <Evr9.h>
+#include "evrdefs.h"
QT_USE_NAMESPACE
-class Evr9VideoWindowControl : public QVideoWindowControl
+class EvrVideoWindowControl : public QVideoWindowControl
{
Q_OBJECT
public:
- Evr9VideoWindowControl(QObject *parent = 0);
- ~Evr9VideoWindowControl();
+ EvrVideoWindowControl(QObject *parent = 0);
+ ~EvrVideoWindowControl();
+
+ bool setEvr(IUnknown *evr);
WId winId() const;
void setWinId(WId id);
@@ -77,10 +77,7 @@ public:
int saturation() const;
void setSaturation(int saturation);
- IMFActivate* createActivate();
- void releaseActivate();
-
- void setProcAmpValues();
+ void applyImageControls();
private:
void clear();
@@ -97,8 +94,6 @@ private:
int m_saturation;
bool m_fullScreen;
- IMFActivate *m_currentActivate;
- IMFMediaSink *m_evrSink;
IMFVideoDisplayControl *m_displayControl;
IMFVideoProcessor *m_processor;
};
diff --git a/src/plugins/directshow/camera/camera.pri b/src/plugins/directshow/camera/camera.pri
index 3a532f472..c6b16da59 100644
--- a/src/plugins/directshow/camera/camera.pri
+++ b/src/plugins/directshow/camera/camera.pri
@@ -14,7 +14,8 @@ HEADERS += \
$$PWD/dsimagecapturecontrol.h \
$$PWD/dscamerasession.h \
$$PWD/directshowglobal.h \
- $$PWD/dscameraviewfindersettingscontrol.h
+ $$PWD/dscameraviewfindersettingscontrol.h \
+ $$PWD/dscameraimageprocessingcontrol.h
SOURCES += \
$$PWD/dscameraservice.cpp \
@@ -23,7 +24,8 @@ SOURCES += \
$$PWD/dsvideodevicecontrol.cpp \
$$PWD/dsimagecapturecontrol.cpp \
$$PWD/dscamerasession.cpp \
- $$PWD/dscameraviewfindersettingscontrol.cpp
+ $$PWD/dscameraviewfindersettingscontrol.cpp \
+ $$PWD/dscameraimageprocessingcontrol.cpp
*-msvc*:INCLUDEPATH += $$(DXSDK_DIR)/include
LIBS += -lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32
diff --git a/src/plugins/directshow/camera/dscameraimageprocessingcontrol.cpp b/src/plugins/directshow/camera/dscameraimageprocessingcontrol.cpp
new file mode 100644
index 000000000..39fa471ec
--- /dev/null
+++ b/src/plugins/directshow/camera/dscameraimageprocessingcontrol.cpp
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "dscameraimageprocessingcontrol.h"
+#include "dscamerasession.h"
+
+QT_BEGIN_NAMESPACE
+
+DSCameraImageProcessingControl::DSCameraImageProcessingControl(DSCameraSession *session)
+ : QCameraImageProcessingControl(session)
+ , m_session(session)
+{
+}
+
+DSCameraImageProcessingControl::~DSCameraImageProcessingControl()
+{
+}
+
+bool DSCameraImageProcessingControl::isParameterSupported(
+ QCameraImageProcessingControl::ProcessingParameter parameter) const
+{
+ return m_session->isImageProcessingParameterSupported(parameter);
+}
+
+bool DSCameraImageProcessingControl::isParameterValueSupported(
+ QCameraImageProcessingControl::ProcessingParameter parameter,
+ const QVariant &value) const
+{
+ return m_session->isImageProcessingParameterValueSupported(parameter, value);
+}
+
+QVariant DSCameraImageProcessingControl::parameter(
+ QCameraImageProcessingControl::ProcessingParameter parameter) const
+{
+ return m_session->imageProcessingParameter(parameter);
+}
+
+void DSCameraImageProcessingControl::setParameter(QCameraImageProcessingControl::ProcessingParameter parameter,
+ const QVariant &value)
+{
+ m_session->setImageProcessingParameter(parameter, value);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/directshow/camera/dscameraimageprocessingcontrol.h b/src/plugins/directshow/camera/dscameraimageprocessingcontrol.h
new file mode 100644
index 000000000..2e50fe14d
--- /dev/null
+++ b/src/plugins/directshow/camera/dscameraimageprocessingcontrol.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DSCAMERAIMAGEPROCESSINGCONTROL_H
+#define DSCAMERAIMAGEPROCESSINGCONTROL_H
+
+#include <qcamera.h>
+#include <qcameraimageprocessingcontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class DSCameraSession;
+
+class DSCameraImageProcessingControl : public QCameraImageProcessingControl
+{
+ Q_OBJECT
+
+public:
+ DSCameraImageProcessingControl(DSCameraSession *session);
+ virtual ~DSCameraImageProcessingControl();
+
+ bool isParameterSupported(ProcessingParameter) const;
+ bool isParameterValueSupported(ProcessingParameter parameter, const QVariant &value) const;
+ QVariant parameter(ProcessingParameter parameter) const;
+ void setParameter(ProcessingParameter parameter, const QVariant &value);
+
+private:
+ DSCameraSession *m_session;
+};
+
+QT_END_NAMESPACE
+
+#endif // DSCAMERAIMAGEPROCESSINGCONTROL_H
diff --git a/src/plugins/directshow/camera/dscameraservice.cpp b/src/plugins/directshow/camera/dscameraservice.cpp
index 9fcd4de70..6c92df04b 100644
--- a/src/plugins/directshow/camera/dscameraservice.cpp
+++ b/src/plugins/directshow/camera/dscameraservice.cpp
@@ -41,6 +41,7 @@
#include "dsvideodevicecontrol.h"
#include "dsimagecapturecontrol.h"
#include "dscameraviewfindersettingscontrol.h"
+#include "dscameraimageprocessingcontrol.h"
QT_BEGIN_NAMESPACE
@@ -53,12 +54,14 @@ DSCameraService::DSCameraService(QObject *parent):
m_videoDevice = new DSVideoDeviceControl(m_session);
m_imageCapture = new DSImageCaptureControl(m_session);
m_viewfinderSettings = new DSCameraViewfinderSettingsControl(m_session);
+ m_imageProcessingControl = new DSCameraImageProcessingControl(m_session);
}
DSCameraService::~DSCameraService()
{
delete m_control;
delete m_viewfinderSettings;
+ delete m_imageProcessingControl;
delete m_videoDevice;
delete m_videoRenderer;
delete m_imageCapture;
@@ -86,6 +89,9 @@ QMediaControl* DSCameraService::requestControl(const char *name)
if (qstrcmp(name, QCameraViewfinderSettingsControl2_iid) == 0)
return m_viewfinderSettings;
+ if (qstrcmp(name, QCameraImageProcessingControl_iid) == 0)
+ return m_imageProcessingControl;
+
return 0;
}
diff --git a/src/plugins/directshow/camera/dscameraservice.h b/src/plugins/directshow/camera/dscameraservice.h
index c3c881d0e..05222ebc4 100644
--- a/src/plugins/directshow/camera/dscameraservice.h
+++ b/src/plugins/directshow/camera/dscameraservice.h
@@ -46,6 +46,7 @@ class DSVideoOutputControl;
class DSVideoDeviceControl;
class DSImageCaptureControl;
class DSCameraViewfinderSettingsControl;
+class DSCameraImageProcessingControl;
class DSCameraService : public QMediaService
{
@@ -66,6 +67,7 @@ private:
QMediaControl *m_videoRenderer;
DSImageCaptureControl *m_imageCapture;
DSCameraViewfinderSettingsControl *m_viewfinderSettings;
+ DSCameraImageProcessingControl *m_imageProcessingControl;
};
QT_END_NAMESPACE
diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp
index 2d3aa1bce..2e92cb37d 100644
--- a/src/plugins/directshow/camera/dscamerasession.cpp
+++ b/src/plugins/directshow/camera/dscamerasession.cpp
@@ -230,6 +230,240 @@ void DSCameraSession::setViewfinderSettings(const QCameraViewfinderSettings &set
m_viewfinderSettings = settings;
}
+qreal DSCameraSession::scaledImageProcessingParameterValue(
+ const ImageProcessingParameterInfo &sourceValueInfo)
+{
+ if (sourceValueInfo.currentValue == sourceValueInfo.defaultValue) {
+ return 0.0f;
+ } else if (sourceValueInfo.currentValue < sourceValueInfo.defaultValue) {
+ return ((sourceValueInfo.currentValue - sourceValueInfo.minimumValue)
+ / qreal(sourceValueInfo.defaultValue - sourceValueInfo.minimumValue))
+ + (-1.0f);
+ } else {
+ return ((sourceValueInfo.currentValue - sourceValueInfo.defaultValue)
+ / qreal(sourceValueInfo.maximumValue - sourceValueInfo.defaultValue));
+ }
+}
+
+qint32 DSCameraSession::sourceImageProcessingParameterValue(
+ qreal scaledValue, const ImageProcessingParameterInfo &valueRange)
+{
+ if (qFuzzyIsNull(scaledValue)) {
+ return valueRange.defaultValue;
+ } else if (scaledValue < 0.0f) {
+ return ((scaledValue - (-1.0f)) * (valueRange.defaultValue - valueRange.minimumValue))
+ + valueRange.minimumValue;
+ } else {
+ return (scaledValue * (valueRange.maximumValue - valueRange.defaultValue))
+ + valueRange.defaultValue;
+ }
+}
+
+static QCameraImageProcessingControl::ProcessingParameter searchRelatedResultingParameter(
+ QCameraImageProcessingControl::ProcessingParameter sourceParameter)
+{
+ if (sourceParameter == QCameraImageProcessingControl::WhiteBalancePreset)
+ return QCameraImageProcessingControl::ColorTemperature;
+ return sourceParameter;
+}
+
+bool DSCameraSession::isImageProcessingParameterSupported(
+ QCameraImageProcessingControl::ProcessingParameter parameter) const
+{
+ const QCameraImageProcessingControl::ProcessingParameter resultingParameter =
+ searchRelatedResultingParameter(parameter);
+
+ return m_imageProcessingParametersInfos.contains(resultingParameter);
+}
+
+bool DSCameraSession::isImageProcessingParameterValueSupported(
+ QCameraImageProcessingControl::ProcessingParameter parameter,
+ const QVariant &value) const
+{
+ const QCameraImageProcessingControl::ProcessingParameter resultingParameter =
+ searchRelatedResultingParameter(parameter);
+
+ QMap<QCameraImageProcessingControl::ProcessingParameter,
+ ImageProcessingParameterInfo>::const_iterator sourceValueInfo =
+ m_imageProcessingParametersInfos.constFind(resultingParameter);
+
+ if (sourceValueInfo == m_imageProcessingParametersInfos.constEnd())
+ return false;
+
+ switch (parameter) {
+
+ case QCameraImageProcessingControl::WhiteBalancePreset: {
+ const QCameraImageProcessing::WhiteBalanceMode checkedValue =
+ value.value<QCameraImageProcessing::WhiteBalanceMode>();
+ // Supports only the Manual and the Auto values
+ if (checkedValue != QCameraImageProcessing::WhiteBalanceManual
+ && checkedValue != QCameraImageProcessing::WhiteBalanceAuto) {
+ return false;
+ }
+ }
+ break;
+
+ case QCameraImageProcessingControl::ColorTemperature: {
+ const qint32 checkedValue = value.toInt();
+ if (checkedValue < (*sourceValueInfo).minimumValue
+ || checkedValue > (*sourceValueInfo).maximumValue) {
+ return false;
+ }
+ }
+ break;
+
+ case QCameraImageProcessingControl::ContrastAdjustment: // falling back
+ case QCameraImageProcessingControl::SaturationAdjustment: // falling back
+ case QCameraImageProcessingControl::BrightnessAdjustment: // falling back
+ case QCameraImageProcessingControl::SharpeningAdjustment: {
+ const qint32 sourceValue = sourceImageProcessingParameterValue(
+ value.toReal(), (*sourceValueInfo));
+ if (sourceValue < (*sourceValueInfo).minimumValue
+ || sourceValue > (*sourceValueInfo).maximumValue)
+ return false;
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+QVariant DSCameraSession::imageProcessingParameter(
+ QCameraImageProcessingControl::ProcessingParameter parameter) const
+{
+ if (!m_graphBuilder) {
+ qWarning() << "failed to access to the graph builder";
+ return QVariant();
+ }
+
+ const QCameraImageProcessingControl::ProcessingParameter resultingParameter =
+ searchRelatedResultingParameter(parameter);
+
+ QMap<QCameraImageProcessingControl::ProcessingParameter,
+ ImageProcessingParameterInfo>::const_iterator sourceValueInfo =
+ m_imageProcessingParametersInfos.constFind(resultingParameter);
+
+ if (sourceValueInfo == m_imageProcessingParametersInfos.constEnd())
+ return QVariant();
+
+ switch (parameter) {
+
+ case QCameraImageProcessingControl::WhiteBalancePreset:
+ return QVariant::fromValue<QCameraImageProcessing::WhiteBalanceMode>(
+ (*sourceValueInfo).capsFlags == VideoProcAmp_Flags_Auto
+ ? QCameraImageProcessing::WhiteBalanceAuto
+ : QCameraImageProcessing::WhiteBalanceManual);
+
+ case QCameraImageProcessingControl::ColorTemperature:
+ return QVariant::fromValue<qint32>((*sourceValueInfo).currentValue);
+
+ case QCameraImageProcessingControl::ContrastAdjustment: // falling back
+ case QCameraImageProcessingControl::SaturationAdjustment: // falling back
+ case QCameraImageProcessingControl::BrightnessAdjustment: // falling back
+ case QCameraImageProcessingControl::SharpeningAdjustment:
+ return scaledImageProcessingParameterValue((*sourceValueInfo));
+
+ default:
+ return QVariant();
+ }
+}
+
+void DSCameraSession::setImageProcessingParameter(
+ QCameraImageProcessingControl::ProcessingParameter parameter,
+ const QVariant &value)
+{
+ if (!m_graphBuilder) {
+ qWarning() << "failed to access to the graph builder";
+ return;
+ }
+
+ const QCameraImageProcessingControl::ProcessingParameter resultingParameter =
+ searchRelatedResultingParameter(parameter);
+
+ QMap<QCameraImageProcessingControl::ProcessingParameter,
+ ImageProcessingParameterInfo>::iterator sourceValueInfo =
+ m_imageProcessingParametersInfos.find(resultingParameter);
+
+ if (sourceValueInfo == m_imageProcessingParametersInfos.constEnd())
+ return;
+
+ LONG sourceValue = 0;
+ LONG capsFlags = VideoProcAmp_Flags_Manual;
+
+ switch (parameter) {
+
+ case QCameraImageProcessingControl::WhiteBalancePreset: {
+ const QCameraImageProcessing::WhiteBalanceMode checkedValue =
+ value.value<QCameraImageProcessing::WhiteBalanceMode>();
+ // Supports only the Manual and the Auto values
+ if (checkedValue == QCameraImageProcessing::WhiteBalanceManual)
+ capsFlags = VideoProcAmp_Flags_Manual;
+ else if (checkedValue == QCameraImageProcessing::WhiteBalanceAuto)
+ capsFlags = VideoProcAmp_Flags_Auto;
+ else
+ return;
+
+ sourceValue = ((*sourceValueInfo).hasBeenExplicitlySet)
+ ? (*sourceValueInfo).currentValue
+ : (*sourceValueInfo).defaultValue;
+ }
+ break;
+
+ case QCameraImageProcessingControl::ColorTemperature:
+ sourceValue = value.isValid() ?
+ value.value<qint32>() : (*sourceValueInfo).defaultValue;
+ capsFlags = (*sourceValueInfo).capsFlags;
+ break;
+
+ case QCameraImageProcessingControl::ContrastAdjustment: // falling back
+ case QCameraImageProcessingControl::SaturationAdjustment: // falling back
+ case QCameraImageProcessingControl::BrightnessAdjustment: // falling back
+ case QCameraImageProcessingControl::SharpeningAdjustment:
+ if (value.isValid()) {
+ sourceValue = sourceImageProcessingParameterValue(
+ value.toReal(), (*sourceValueInfo));
+ } else {
+ sourceValue = (*sourceValueInfo).defaultValue;
+ }
+ break;
+
+ default:
+ return;
+ }
+
+ IAMVideoProcAmp *pVideoProcAmp = NULL;
+ HRESULT hr = m_graphBuilder->FindInterface(
+ NULL,
+ NULL,
+ m_sourceFilter,
+ IID_IAMVideoProcAmp,
+ reinterpret_cast<void**>(&pVideoProcAmp)
+ );
+
+ if (FAILED(hr) || !pVideoProcAmp) {
+ qWarning() << "failed to find the video proc amp";
+ return;
+ }
+
+ hr = pVideoProcAmp->Set(
+ (*sourceValueInfo).videoProcAmpProperty,
+ sourceValue,
+ capsFlags);
+
+ pVideoProcAmp->Release();
+
+ if (FAILED(hr)) {
+ qWarning() << "failed to set the parameter value";
+ } else {
+ (*sourceValueInfo).capsFlags = capsFlags;
+ (*sourceValueInfo).hasBeenExplicitlySet = true;
+ (*sourceValueInfo).currentValue = sourceValue;
+ }
+}
+
bool DSCameraSession::load()
{
unload();
@@ -720,6 +954,81 @@ bool DSCameraSession::configurePreviewFormat()
return true;
}
+void DSCameraSession::updateImageProcessingParametersInfos()
+{
+ if (!m_graphBuilder) {
+ qWarning() << "failed to access to the graph builder";
+ return;
+ }
+
+ IAMVideoProcAmp *pVideoProcAmp = NULL;
+ const HRESULT hr = m_graphBuilder->FindInterface(
+ NULL,
+ NULL,
+ m_sourceFilter,
+ IID_IAMVideoProcAmp,
+ reinterpret_cast<void**>(&pVideoProcAmp)
+ );
+
+ if (FAILED(hr) || !pVideoProcAmp) {
+ qWarning() << "failed to find the video proc amp";
+ return;
+ }
+
+ for (int property = VideoProcAmp_Brightness; property <= VideoProcAmp_Gain; ++property) {
+
+ QCameraImageProcessingControl::ProcessingParameter processingParameter; // not initialized
+
+ switch (property) {
+ case VideoProcAmp_Brightness:
+ processingParameter = QCameraImageProcessingControl::BrightnessAdjustment;
+ break;
+ case VideoProcAmp_Contrast:
+ processingParameter = QCameraImageProcessingControl::ContrastAdjustment;
+ break;
+ case VideoProcAmp_Saturation:
+ processingParameter = QCameraImageProcessingControl::SaturationAdjustment;
+ break;
+ case VideoProcAmp_Sharpness:
+ processingParameter = QCameraImageProcessingControl::SharpeningAdjustment;
+ break;
+ case VideoProcAmp_WhiteBalance:
+ processingParameter = QCameraImageProcessingControl::ColorTemperature;
+ break;
+ default: // unsupported or not implemented yet parameter
+ continue;
+ }
+
+ ImageProcessingParameterInfo sourceValueInfo;
+ LONG steppingDelta = 0;
+
+ HRESULT hr = pVideoProcAmp->GetRange(
+ property,
+ &sourceValueInfo.minimumValue,
+ &sourceValueInfo.maximumValue,
+ &steppingDelta,
+ &sourceValueInfo.defaultValue,
+ &sourceValueInfo.capsFlags);
+
+ if (FAILED(hr))
+ continue;
+
+ hr = pVideoProcAmp->Get(
+ property,
+ &sourceValueInfo.currentValue,
+ &sourceValueInfo.capsFlags);
+
+ if (FAILED(hr))
+ continue;
+
+ sourceValueInfo.videoProcAmpProperty = static_cast<VideoProcAmpProperty>(property);
+
+ m_imageProcessingParametersInfos.insert(processingParameter, sourceValueInfo);
+ }
+
+ pVideoProcAmp->Release();
+}
+
bool DSCameraSession::connectGraph()
{
HRESULT hr = m_filterGraph->AddFilter(m_sourceFilter, L"Capture Filter");
@@ -806,6 +1115,7 @@ void DSCameraSession::updateSourceCapabilities()
Q_FOREACH (AM_MEDIA_TYPE f, m_supportedFormats)
_FreeMediaType(f);
m_supportedFormats.clear();
+ m_imageProcessingParametersInfos.clear();
IAMVideoControl *pVideoControl = 0;
hr = m_graphBuilder->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
@@ -915,6 +1225,8 @@ void DSCameraSession::updateSourceCapabilities()
}
pConfig->Release();
+
+ updateImageProcessingParametersInfos();
}
HRESULT getPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin)
diff --git a/src/plugins/directshow/camera/dscamerasession.h b/src/plugins/directshow/camera/dscamerasession.h
index 9ac121463..768e3583a 100644
--- a/src/plugins/directshow/camera/dscamerasession.h
+++ b/src/plugins/directshow/camera/dscamerasession.h
@@ -43,6 +43,7 @@
#include <QtMultimedia/qvideoframe.h>
#include <QtMultimedia/qabstractvideosurface.h>
#include <QtMultimedia/qvideosurfaceformat.h>
+#include <QtMultimedia/qcameraimageprocessingcontrol.h>
#include <private/qmediastoragelocation_p.h>
#include <tchar.h>
@@ -97,6 +98,20 @@ public:
QList<QCameraViewfinderSettings> supportedViewfinderSettings() const
{ return m_supportedViewfinderSettings; }
+ bool isImageProcessingParameterSupported(
+ QCameraImageProcessingControl::ProcessingParameter) const;
+
+ bool isImageProcessingParameterValueSupported(
+ QCameraImageProcessingControl::ProcessingParameter,
+ const QVariant &) const;
+
+ QVariant imageProcessingParameter(
+ QCameraImageProcessingControl::ProcessingParameter) const;
+
+ void setImageProcessingParameter(
+ QCameraImageProcessingControl::ProcessingParameter,
+ const QVariant &);
+
Q_SIGNALS:
void statusChanged(QCamera::Status);
void imageExposed(int id);
@@ -110,6 +125,27 @@ private Q_SLOTS:
void updateReadyForCapture();
private:
+ struct ImageProcessingParameterInfo {
+ ImageProcessingParameterInfo()
+ : minimumValue(0)
+ , maximumValue(0)
+ , defaultValue(0)
+ , currentValue(0)
+ , capsFlags(0)
+ , hasBeenExplicitlySet(false)
+ , videoProcAmpProperty(VideoProcAmp_Brightness)
+ {
+ }
+
+ LONG minimumValue;
+ LONG maximumValue;
+ LONG defaultValue;
+ LONG currentValue;
+ LONG capsFlags;
+ bool hasBeenExplicitlySet;
+ VideoProcAmpProperty videoProcAmpProperty;
+ };
+
void setStatus(QCamera::Status status);
void onFrameAvailable(const char *frameData, long len);
@@ -120,6 +156,14 @@ private:
void disconnectGraph();
void updateSourceCapabilities();
bool configurePreviewFormat();
+ void updateImageProcessingParametersInfos();
+
+ // These static functions are used for scaling of adjustable parameters,
+ // which have the ranges from -1.0 to +1.0 in the QCameraImageProcessing API.
+ static qreal scaledImageProcessingParameterValue(
+ const ImageProcessingParameterInfo &sourceValueInfo);
+ static qint32 sourceImageProcessingParameterValue(
+ qreal scaledValue, const ImageProcessingParameterInfo &sourceValueInfo);
QMutex m_presentMutex;
QMutex m_captureMutex;
@@ -135,6 +179,7 @@ private:
QList<AM_MEDIA_TYPE> m_supportedFormats;
QList<QCameraViewfinderSettings> m_supportedViewfinderSettings;
AM_MEDIA_TYPE m_sourceFormat;
+ QMap<QCameraImageProcessingControl::ProcessingParameter, ImageProcessingParameterInfo> m_imageProcessingParametersInfos;
// Preview
IBaseFilter *m_previewFilter;
diff --git a/src/plugins/directshow/directshow.pro b/src/plugins/directshow/directshow.pro
index 7815927db..4d7183923 100644
--- a/src/plugins/directshow/directshow.pro
+++ b/src/plugins/directshow/directshow.pro
@@ -13,11 +13,6 @@ SOURCES += dsserviceplugin.cpp
!config_wmsdk: DEFINES += QT_NO_WMSDK
-qtHaveModule(widgets) {
- QT += multimediawidgets
- DEFINES += HAVE_WIDGETS
-}
-
mingw: DEFINES += NO_DSHOW_STRSAFE
!config_wmf: include(player/player.pri)
diff --git a/src/plugins/directshow/player/directshowaudioendpointcontrol.cpp b/src/plugins/directshow/player/directshowaudioendpointcontrol.cpp
index 798a94102..d063447e3 100644
--- a/src/plugins/directshow/player/directshowaudioendpointcontrol.cpp
+++ b/src/plugins/directshow/player/directshowaudioendpointcontrol.cpp
@@ -44,7 +44,7 @@ DirectShowAudioEndpointControl::DirectShowAudioEndpointControl(
, m_deviceEnumerator(0)
{
if (CreateBindCtx(0, &m_bindContext) == S_OK) {
- m_deviceEnumerator = com_new<ICreateDevEnum>(CLSID_SystemDeviceEnum, IID_ICreateDevEnum);
+ m_deviceEnumerator = com_new<ICreateDevEnum>(CLSID_SystemDeviceEnum);
updateEndpoints();
diff --git a/src/plugins/directshow/player/directshowevrvideowindowcontrol.cpp b/src/plugins/directshow/player/directshowevrvideowindowcontrol.cpp
new file mode 100644
index 000000000..7bffe47d2
--- /dev/null
+++ b/src/plugins/directshow/player/directshowevrvideowindowcontrol.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "directshowevrvideowindowcontrol.h"
+
+#include "directshowglobal.h"
+
+DirectShowEvrVideoWindowControl::DirectShowEvrVideoWindowControl(QObject *parent)
+ : EvrVideoWindowControl(parent)
+ , m_evrFilter(NULL)
+{
+}
+
+DirectShowEvrVideoWindowControl::~DirectShowEvrVideoWindowControl()
+{
+ if (m_evrFilter)
+ m_evrFilter->Release();
+}
+
+IBaseFilter *DirectShowEvrVideoWindowControl::filter()
+{
+ static const GUID clsid_EnhancendVideoRenderer = { 0xfa10746c, 0x9b63, 0x4b6c, {0xbc, 0x49, 0xfc, 0x30, 0xe, 0xa5, 0xf2, 0x56} };
+
+ if (!m_evrFilter) {
+ m_evrFilter = com_new<IBaseFilter>(clsid_EnhancendVideoRenderer);
+ if (!setEvr(m_evrFilter)) {
+ m_evrFilter->Release();
+ m_evrFilter = NULL;
+ }
+ }
+
+ return m_evrFilter;
+}
diff --git a/config.tests/wmp/main.cpp b/src/plugins/directshow/player/directshowevrvideowindowcontrol.h
index 95883c62e..46171812b 100644
--- a/config.tests/wmp/main.cpp
+++ b/src/plugins/directshow/player/directshowevrvideowindowcontrol.h
@@ -3,7 +3,7 @@
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
-** This file is part of the Qt Mobility Components.
+** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
@@ -30,13 +30,26 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#ifndef _WIN32_WCE
-#include <wmp.h>
-#else
-#include <wmpcore.h>
-#endif
-int main(int, char**)
+#ifndef DIRECTSHOWEVRVIDEOWINDOWCONTROL_H
+#define DIRECTSHOWEVRVIDEOWINDOWCONTROL_H
+
+#include "evrvideowindowcontrol.h"
+
+struct IBaseFilter;
+
+QT_USE_NAMESPACE
+
+class DirectShowEvrVideoWindowControl : public EvrVideoWindowControl
{
- return 0;
-}
+public:
+ DirectShowEvrVideoWindowControl(QObject *parent = 0);
+ ~DirectShowEvrVideoWindowControl();
+
+ IBaseFilter *filter();
+
+private:
+ IBaseFilter *m_evrFilter;
+};
+
+#endif // DIRECTSHOWEVRVIDEOWINDOWCONTROL_H
diff --git a/src/plugins/directshow/player/directshowglobal.h b/src/plugins/directshow/player/directshowglobal.h
index 68cb23649..d8f1d1200 100644
--- a/src/plugins/directshow/player/directshowglobal.h
+++ b/src/plugins/directshow/player/directshowglobal.h
@@ -46,6 +46,18 @@ template <typename T> T *com_cast(IUnknown *unknown, const IID &iid)
: 0;
}
+template <typename T> T *com_new(const IID &clsid)
+{
+ T *object = 0;
+ return CoCreateInstance(
+ clsid,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_PPV_ARGS(&object)) == S_OK
+ ? object
+ : 0;
+}
+
template <typename T> T *com_new(const IID &clsid, const IID &iid)
{
T *object = 0;
diff --git a/src/plugins/directshow/player/directshowioreader.cpp b/src/plugins/directshow/player/directshowioreader.cpp
index bee072d3b..298d099d2 100644
--- a/src/plugins/directshow/player/directshowioreader.cpp
+++ b/src/plugins/directshow/player/directshowioreader.cpp
@@ -132,7 +132,7 @@ HRESULT DirectShowIOReader::RequestAllocator(
return S_OK;
} else {
- *ppActual = com_new<IMemAllocator>(CLSID_MemoryAllocator, IID_IMemAllocator);
+ *ppActual = com_new<IMemAllocator>(CLSID_MemoryAllocator);
if (*ppActual) {
if ((*ppActual)->SetProperties(pProps, &actualProperties) != S_OK) {
diff --git a/src/plugins/directshow/player/directshowiosource.cpp b/src/plugins/directshow/player/directshowiosource.cpp
index 424120fd8..e1034a9c6 100644
--- a/src/plugins/directshow/player/directshowiosource.cpp
+++ b/src/plugins/directshow/player/directshowiosource.cpp
@@ -413,7 +413,7 @@ HRESULT DirectShowIOSource::tryConnect(IPin *pin, const AM_MEDIA_TYPE *type)
hr = VFW_E_NO_TRANSPORT;
if (IMemInputPin *memPin = com_cast<IMemInputPin>(pin, IID_IMemInputPin)) {
- if ((m_allocator = com_new<IMemAllocator>(CLSID_MemoryAllocator, IID_IMemAllocator))) {
+ if ((m_allocator = com_new<IMemAllocator>(CLSID_MemoryAllocator))) {
ALLOCATOR_PROPERTIES properties;
if (memPin->GetAllocatorRequirements(&properties) == S_OK
|| m_allocator->GetProperties(&properties) == S_OK) {
diff --git a/src/plugins/directshow/player/directshowmetadatacontrol.cpp b/src/plugins/directshow/player/directshowmetadatacontrol.cpp
index 3f58be249..5400ac8d4 100644
--- a/src/plugins/directshow/player/directshowmetadatacontrol.cpp
+++ b/src/plugins/directshow/player/directshowmetadatacontrol.cpp
@@ -362,7 +362,18 @@ static QString convertBSTR(BSTR *string)
return value;
}
-void DirectShowMetaDataControl::updateGraph(IFilterGraph2 *graph, IBaseFilter *source, const QString &fileSrc)
+void DirectShowMetaDataControl::reset()
+{
+ bool hadMetadata = !m_metadata.isEmpty();
+ m_metadata.clear();
+
+ setMetadataAvailable(false);
+
+ if (hadMetadata)
+ emit metaDataChanged();
+}
+
+void DirectShowMetaDataControl::updateMetadata(IFilterGraph2 *graph, IBaseFilter *source, const QString &fileSrc)
{
m_metadata.clear();
@@ -568,13 +579,19 @@ void DirectShowMetaDataControl::customEvent(QEvent *event)
if (event->type() == QEvent::Type(MetaDataChanged)) {
event->accept();
- bool oldAvailable = m_available;
- m_available = !m_metadata.isEmpty();
- if (m_available != oldAvailable)
- emit metaDataAvailableChanged(m_available);
+ setMetadataAvailable(!m_metadata.isEmpty());
emit metaDataChanged();
} else {
QMetaDataReaderControl::customEvent(event);
}
}
+
+void DirectShowMetaDataControl::setMetadataAvailable(bool available)
+{
+ if (m_available == available)
+ return;
+
+ m_available = available;
+ emit metaDataAvailableChanged(m_available);
+}
diff --git a/src/plugins/directshow/player/directshowmetadatacontrol.h b/src/plugins/directshow/player/directshowmetadatacontrol.h
index d32ae8508..55504ba4b 100644
--- a/src/plugins/directshow/player/directshowmetadatacontrol.h
+++ b/src/plugins/directshow/player/directshowmetadatacontrol.h
@@ -56,13 +56,16 @@ public:
QVariant metaData(const QString &key) const;
QStringList availableMetaData() const;
- void updateGraph(IFilterGraph2 *graph, IBaseFilter *source,
- const QString &fileSrc = QString());
+ void reset();
+ void updateMetadata(IFilterGraph2 *graph, IBaseFilter *source,
+ const QString &fileSrc = QString());
protected:
void customEvent(QEvent *event);
private:
+ void setMetadataAvailable(bool available);
+
enum Event
{
MetaDataChanged = QEvent::User
diff --git a/src/plugins/directshow/player/directshowplayercontrol.cpp b/src/plugins/directshow/player/directshowplayercontrol.cpp
index a5fed4b95..3449c9270 100644
--- a/src/plugins/directshow/player/directshowplayercontrol.cpp
+++ b/src/plugins/directshow/player/directshowplayercontrol.cpp
@@ -53,17 +53,6 @@ static int volumeToDecibels(int volume)
}
}
-static int decibelsToVolume(int dB)
-{
- if (dB == -10000) {
- return 0;
- } else if (dB == 0) {
- return 100;
- } else {
- return qRound(100 * qPow(10, qreal(dB) / 5000));
- }
-}
-
DirectShowPlayerControl::DirectShowPlayerControl(DirectShowPlayerService *service, QObject *parent)
: QMediaPlayerControl(parent)
, m_service(service)
@@ -73,8 +62,9 @@ DirectShowPlayerControl::DirectShowPlayerControl(DirectShowPlayerService *servic
, m_status(QMediaPlayer::NoMedia)
, m_error(QMediaPlayer::NoError)
, m_streamTypes(0)
- , m_muteVolume(-1)
- , m_position(0)
+ , m_volume(100)
+ , m_muted(false)
+ , m_emitPosition(-1)
, m_pendingPosition(-1)
, m_duration(0)
, m_playbackRate(0)
@@ -108,11 +98,16 @@ qint64 DirectShowPlayerControl::position() const
if (m_pendingPosition != -1)
return m_pendingPosition;
- return const_cast<qint64 &>(m_position) = m_service->position();
+ return m_service->position();
}
void DirectShowPlayerControl::setPosition(qint64 position)
{
+ if (m_status == QMediaPlayer::EndOfMedia) {
+ m_status = QMediaPlayer::LoadedMedia;
+ emit mediaStatusChanged(m_status);
+ }
+
if (m_state == QMediaPlayer::StoppedState && m_pendingPosition != position) {
m_pendingPosition = position;
emit positionChanged(m_pendingPosition);
@@ -125,63 +120,47 @@ void DirectShowPlayerControl::setPosition(qint64 position)
int DirectShowPlayerControl::volume() const
{
- if (m_muteVolume >= 0) {
- return m_muteVolume;
- } else if (m_audio) {
- long dB = 0;
-
- m_audio->get_Volume(&dB);
-
- return decibelsToVolume(dB);
- } else {
- return 0;
- }
+ return m_volume;
}
void DirectShowPlayerControl::setVolume(int volume)
{
int boundedVolume = qBound(0, volume, 100);
- if (m_muteVolume >= 0) {
- m_muteVolume = boundedVolume;
+ if (m_volume == boundedVolume)
+ return;
- emit volumeChanged(m_muteVolume);
- } else if (m_audio) {
- m_audio->put_Volume(volumeToDecibels(volume));
+ m_volume = boundedVolume;
- emit volumeChanged(boundedVolume);
- }
+ if (!m_muted)
+ setVolumeHelper(m_volume);
+
+ emit volumeChanged(m_volume);
}
bool DirectShowPlayerControl::isMuted() const
{
- return m_muteVolume >= 0;
+ return m_muted;
}
void DirectShowPlayerControl::setMuted(bool muted)
{
- if (muted && m_muteVolume < 0) {
- if (m_audio) {
- long dB = 0;
+ if (m_muted == muted)
+ return;
- m_audio->get_Volume(&dB);
+ m_muted = muted;
- m_muteVolume = decibelsToVolume(dB);
+ setVolumeHelper(m_muted ? 0 : m_volume);
- m_audio->put_Volume(-10000);
- } else {
- m_muteVolume = 0;
- }
+ emit mutedChanged(m_muted);
+}
- emit mutedChanged(muted);
- } else if (!muted && m_muteVolume >= 0) {
- if (m_audio) {
- m_audio->put_Volume(volumeToDecibels(m_muteVolume));
- }
- m_muteVolume = -1;
+void DirectShowPlayerControl::setVolumeHelper(int volume)
+{
+ if (!m_audio)
+ return;
- emit mutedChanged(muted);
- }
+ m_audio->put_Volume(volumeToDecibels(volume));
}
int DirectShowPlayerControl::bufferStatus() const
@@ -235,6 +214,9 @@ const QIODevice *DirectShowPlayerControl::mediaStream() const
void DirectShowPlayerControl::setMedia(const QMediaContent &media, QIODevice *stream)
{
+ m_pendingPosition = -1;
+ m_emitPosition = -1;
+
m_media = media;
m_stream = stream;
@@ -248,34 +230,41 @@ void DirectShowPlayerControl::setMedia(const QMediaContent &media, QIODevice *st
void DirectShowPlayerControl::play()
{
- if (m_status == QMediaPlayer::NoMedia)
- return;
- if (m_status == QMediaPlayer::InvalidMedia) {
- setMedia(m_media, m_stream);
- if (m_error != QMediaPlayer::NoError)
- return;
- }
- m_service->play();
- if (m_pendingPosition != -1)
- setPosition(m_pendingPosition);
- emit stateChanged(m_state = QMediaPlayer::PlayingState);
+ playOrPause(QMediaPlayer::PlayingState);
}
void DirectShowPlayerControl::pause()
{
- if (m_status == QMediaPlayer::NoMedia)
+ playOrPause(QMediaPlayer::PausedState);
+}
+
+void DirectShowPlayerControl::playOrPause(QMediaPlayer::State state)
+{
+ if (m_status == QMediaPlayer::NoMedia || state == QMediaPlayer::StoppedState)
return;
if (m_status == QMediaPlayer::InvalidMedia) {
setMedia(m_media, m_stream);
if (m_error != QMediaPlayer::NoError)
return;
}
- m_service->pause();
- emit stateChanged(m_state = QMediaPlayer::PausedState);
+
+ m_emitPosition = -1;
+ m_state = state;
+
+ if (m_pendingPosition != -1)
+ setPosition(m_pendingPosition);
+
+ if (state == QMediaPlayer::PausedState)
+ m_service->pause();
+ else
+ m_service->play();
+
+ emit stateChanged(m_state);
}
void DirectShowPlayerControl::stop()
{
+ m_emitPosition = -1;
m_service->stop();
emit stateChanged(m_state = QMediaPlayer::StoppedState);
}
@@ -307,8 +296,8 @@ void DirectShowPlayerControl::emitPropertyChanges()
emit videoAvailableChanged(m_streamTypes & DirectShowPlayerService::VideoStream);
}
- if (properties & PositionProperty)
- emit positionChanged(m_position);
+ if (properties & PositionProperty && m_emitPosition != -1)
+ emit positionChanged(m_emitPosition);
if (properties & DurationProperty)
emit durationChanged(m_duration);
@@ -389,6 +378,7 @@ void DirectShowPlayerControl::updateAudioOutput(IBaseFilter *filter)
m_audio->Release();
m_audio = com_cast<IBasicAudio>(filter, IID_IBasicAudio);
+ setVolumeHelper(m_muted ? 0 : m_volume);
}
void DirectShowPlayerControl::updateError(QMediaPlayer::Error error, const QString &errorString)
@@ -402,8 +392,8 @@ void DirectShowPlayerControl::updateError(QMediaPlayer::Error error, const QStri
void DirectShowPlayerControl::updatePosition(qint64 position)
{
- if (m_position != position) {
- m_position = position;
+ if (m_emitPosition != position) {
+ m_emitPosition = position;
scheduleUpdate(PositionProperty);
}
diff --git a/src/plugins/directshow/player/directshowplayercontrol.h b/src/plugins/directshow/player/directshowplayercontrol.h
index a42d3c7b1..f67c4108b 100644
--- a/src/plugins/directshow/player/directshowplayercontrol.h
+++ b/src/plugins/directshow/player/directshowplayercontrol.h
@@ -114,8 +114,11 @@ private:
PropertiesChanged = QEvent::User
};
+ void playOrPause(QMediaPlayer::State state);
+
void scheduleUpdate(int properties);
void emitPropertyChanges();
+ void setVolumeHelper(int volume);
DirectShowPlayerService *m_service;
IBasicAudio *m_audio;
@@ -125,8 +128,9 @@ private:
QMediaPlayer::MediaStatus m_status;
QMediaPlayer::Error m_error;
int m_streamTypes;
- int m_muteVolume;
- qint64 m_position;
+ int m_volume;
+ bool m_muted;
+ qint64 m_emitPosition;
qint64 m_pendingPosition;
qint64 m_duration;
qreal m_playbackRate;
diff --git a/src/plugins/directshow/player/directshowplayerservice.cpp b/src/plugins/directshow/player/directshowplayerservice.cpp
index 67aea6e9a..8e9e50cbf 100644
--- a/src/plugins/directshow/player/directshowplayerservice.cpp
+++ b/src/plugins/directshow/player/directshowplayerservice.cpp
@@ -38,8 +38,10 @@
#include "directshowmetadatacontrol.h"
#include "directshowplayercontrol.h"
#include "directshowvideorenderercontrol.h"
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
#include "vmr9videowindowcontrol.h"
+
+#ifdef HAVE_EVR
+#include "directshowevrvideowindowcontrol.h"
#endif
#ifndef QT_NO_WMSDK
@@ -79,9 +81,7 @@ DirectShowPlayerService::DirectShowPlayerService(QObject *parent)
, m_playerControl(0)
, m_metaDataControl(0)
, m_videoRendererControl(0)
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
, m_videoWindowControl(0)
-#endif
, m_audioEndpointControl(0)
, m_taskThread(0)
, m_loop(qt_directShowEventLoop())
@@ -98,10 +98,12 @@ DirectShowPlayerService::DirectShowPlayerService(QObject *parent)
, m_videoOutput(0)
, m_rate(1.0)
, m_position(0)
+ , m_seekPosition(-1)
, m_duration(0)
, m_buffering(false)
, m_seekable(false)
, m_atEnd(false)
+ , m_dontCacheNextSeekResult(false)
{
m_playerControl = new DirectShowPlayerControl(this);
m_metaDataControl = new DirectShowMetaDataControl(this);
@@ -139,9 +141,7 @@ DirectShowPlayerService::~DirectShowPlayerService()
delete m_audioEndpointControl;
delete m_metaDataControl;
delete m_videoRendererControl;
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
delete m_videoWindowControl;
-#endif
::CloseHandle(m_taskHandle);
}
@@ -155,11 +155,7 @@ QMediaControl *DirectShowPlayerService::requestControl(const char *name)
} else if (qstrcmp(name, QMetaDataReaderControl_iid) == 0) {
return m_metaDataControl;
} else if (qstrcmp(name, QVideoRendererControl_iid) == 0) {
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
if (!m_videoRendererControl && !m_videoWindowControl) {
-#else
- if (!m_videoRendererControl) {
-#endif
m_videoRendererControl = new DirectShowVideoRendererControl(m_loop);
connect(m_videoRendererControl, SIGNAL(filterChanged()),
@@ -167,16 +163,28 @@ QMediaControl *DirectShowPlayerService::requestControl(const char *name)
return m_videoRendererControl;
}
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
} else if (qstrcmp(name, QVideoWindowControl_iid) == 0) {
if (!m_videoRendererControl && !m_videoWindowControl) {
- m_videoWindowControl = new Vmr9VideoWindowControl;
+ IBaseFilter *filter;
- setVideoOutput(m_videoWindowControl->filter());
+#ifdef HAVE_EVR
+ DirectShowEvrVideoWindowControl *evrControl = new DirectShowEvrVideoWindowControl;
+ if ((filter = evrControl->filter()))
+ m_videoWindowControl = evrControl;
+ else
+ delete evrControl;
+#endif
+ // Fall back to the VMR9 if the EVR is not available
+ if (!m_videoWindowControl) {
+ Vmr9VideoWindowControl *vmr9Control = new Vmr9VideoWindowControl;
+ filter = vmr9Control->filter();
+ m_videoWindowControl = vmr9Control;
+ }
+
+ setVideoOutput(filter);
return m_videoWindowControl;
}
-#endif
}
return 0;
}
@@ -192,14 +200,12 @@ void DirectShowPlayerService::releaseControl(QMediaControl *control)
delete m_videoRendererControl;
m_videoRendererControl = 0;
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
} else if (control == m_videoWindowControl) {
setVideoOutput(0);
delete m_videoWindowControl;
m_videoWindowControl = 0;
-#endif
}
}
@@ -217,13 +223,15 @@ void DirectShowPlayerService::load(const QMediaContent &media, QIODevice *stream
m_error = QMediaPlayer::NoError;
m_errorString = QString();
m_position = 0;
+ m_seekPosition = -1;
m_duration = 0;
m_streamTypes = 0;
m_executedTasks = 0;
m_buffering = false;
m_seekable = false;
m_atEnd = false;
- m_metaDataControl->updateGraph(0, 0);
+ m_dontCacheNextSeekResult = false;
+ m_metaDataControl->reset();
if (m_resources.isEmpty() && !stream) {
m_pendingTasks = 0;
@@ -273,8 +281,7 @@ void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker)
static const GUID iid_IFileSourceFilter = {
0x56a868a6, 0x0ad4, 0x11ce, {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70} };
- if (IFileSourceFilter *fileSource = com_new<IFileSourceFilter>(
- clsid_WMAsfReader, iid_IFileSourceFilter)) {
+ if (IFileSourceFilter *fileSource = com_new<IFileSourceFilter>(clsid_WMAsfReader, iid_IFileSourceFilter)) {
locker->unlock();
hr = fileSource->Load(reinterpret_cast<const OLECHAR *>(m_url.toString().utf16()), 0);
@@ -322,6 +329,7 @@ void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker)
m_error = QMediaPlayer::FormatError;
m_errorString = QString();
break;
+ case E_FAIL:
case E_OUTOFMEMORY:
case VFW_E_CANNOT_LOAD_SOURCE_FILTER:
case VFW_E_NOT_FOUND:
@@ -562,9 +570,6 @@ void DirectShowPlayerService::doReleaseGraph(QMutexLocker *locker)
control->Release();
}
- //release m_headerInfo -> decrease ref counter of m_source
- m_metaDataControl->updateGraph(0, 0);
-
if (m_source) {
m_source->Release();
m_source = 0;
@@ -665,8 +670,12 @@ void DirectShowPlayerService::play()
if (m_executedTasks & Render) {
if (m_executedTasks & Stop) {
m_atEnd = false;
- m_position = 0;
- m_pendingTasks |= Seek;
+ if (m_seekPosition == -1) {
+ m_dontCacheNextSeekResult = true;
+ m_seekPosition = 0;
+ m_position = 0;
+ m_pendingTasks |= Seek;
+ }
m_executedTasks ^= Stop;
}
@@ -709,8 +718,12 @@ void DirectShowPlayerService::pause()
if (m_executedTasks & Render) {
if (m_executedTasks & Stop) {
m_atEnd = false;
- m_position = 0;
- m_pendingTasks |= Seek;
+ if (m_seekPosition == -1) {
+ m_dontCacheNextSeekResult = true;
+ m_seekPosition = 0;
+ m_position = 0;
+ m_pendingTasks |= Seek;
+ }
m_executedTasks ^= Stop;
}
@@ -780,7 +793,9 @@ void DirectShowPlayerService::doStop(QMutexLocker *locker)
control->Release();
}
+ m_seekPosition = 0;
m_position = 0;
+ m_dontCacheNextSeekResult = true;
m_pendingTasks |= Seek;
m_executedTasks &= ~(Play | Pause);
@@ -884,7 +899,7 @@ void DirectShowPlayerService::seek(qint64 position)
{
QMutexLocker locker(&m_mutex);
- m_position = position;
+ m_seekPosition = position;
m_pendingTasks |= Seek;
@@ -894,14 +909,19 @@ void DirectShowPlayerService::seek(qint64 position)
void DirectShowPlayerService::doSeek(QMutexLocker *locker)
{
+ if (m_seekPosition == -1)
+ return;
+
if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph, IID_IMediaSeeking)) {
- LONGLONG seekPosition = LONGLONG(m_position) * qt_directShowTimeScale;
+ LONGLONG seekPosition = LONGLONG(m_seekPosition) * qt_directShowTimeScale;
// Cache current values as we can't query IMediaSeeking during a seek due to the
// possibility of a deadlock when flushing the VideoSurfaceFilter.
LONGLONG currentPosition = 0;
- seeking->GetCurrentPosition(&currentPosition);
- m_position = currentPosition / qt_directShowTimeScale;
+ if (!m_dontCacheNextSeekResult) {
+ seeking->GetCurrentPosition(&currentPosition);
+ m_position = currentPosition / qt_directShowTimeScale;
+ }
LONGLONG minimum = 0;
LONGLONG maximum = 0;
@@ -915,15 +935,18 @@ void DirectShowPlayerService::doSeek(QMutexLocker *locker)
&seekPosition, AM_SEEKING_AbsolutePositioning, 0, AM_SEEKING_NoPositioning);
locker->relock();
- seeking->GetCurrentPosition(&currentPosition);
- m_position = currentPosition / qt_directShowTimeScale;
+ if (!m_dontCacheNextSeekResult) {
+ seeking->GetCurrentPosition(&currentPosition);
+ m_position = currentPosition / qt_directShowTimeScale;
+ }
seeking->Release();
- } else {
- m_position = 0;
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(PositionChange)));
}
- QCoreApplication::postEvent(this, new QEvent(QEvent::Type(PositionChange)));
+ m_seekPosition = -1;
+ m_dontCacheNextSeekResult = false;
}
int DirectShowPlayerService::bufferStatus() const
@@ -1112,7 +1135,7 @@ void DirectShowPlayerService::customEvent(QEvent *event)
QMutexLocker locker(&m_mutex);
m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable);
- m_metaDataControl->updateGraph(m_graph, m_source, m_url.toString());
+ m_metaDataControl->updateMetadata(m_graph, m_source, m_url.toString());
updateStatus();
} else if (event->type() == QEvent::Type(Error)) {
diff --git a/src/plugins/directshow/player/directshowplayerservice.h b/src/plugins/directshow/player/directshowplayerservice.h
index c9d10351e..4d3762f74 100644
--- a/src/plugins/directshow/player/directshowplayerservice.h
+++ b/src/plugins/directshow/player/directshowplayerservice.h
@@ -51,12 +51,10 @@ class DirectShowAudioEndpointControl;
class DirectShowMetaDataControl;
class DirectShowPlayerControl;
class DirectShowVideoRendererControl;
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
-class Vmr9VideoWindowControl;
-#endif
QT_BEGIN_NAMESPACE
class QMediaContent;
+class QVideoWindowControl;
QT_END_NAMESPACE
QT_USE_NAMESPACE
@@ -172,9 +170,7 @@ private:
DirectShowPlayerControl *m_playerControl;
DirectShowMetaDataControl *m_metaDataControl;
DirectShowVideoRendererControl *m_videoRendererControl;
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
- Vmr9VideoWindowControl *m_videoWindowControl;
-#endif
+ QVideoWindowControl *m_videoWindowControl;
DirectShowAudioEndpointControl *m_audioEndpointControl;
QThread *m_taskThread;
@@ -194,10 +190,12 @@ private:
int m_streamTypes;
qreal m_rate;
qint64 m_position;
+ qint64 m_seekPosition;
qint64 m_duration;
bool m_buffering;
bool m_seekable;
bool m_atEnd;
+ bool m_dontCacheNextSeekResult;
QMediaTimeRange m_playbackRange;
QUrl m_url;
QMediaResourceList m_resources;
diff --git a/src/plugins/directshow/player/directshowvideorenderercontrol.cpp b/src/plugins/directshow/player/directshowvideorenderercontrol.cpp
index da4764880..6a1580ea5 100644
--- a/src/plugins/directshow/player/directshowvideorenderercontrol.cpp
+++ b/src/plugins/directshow/player/directshowvideorenderercontrol.cpp
@@ -45,7 +45,8 @@ DirectShowVideoRendererControl::DirectShowVideoRendererControl(DirectShowEventLo
DirectShowVideoRendererControl::~DirectShowVideoRendererControl()
{
- delete m_filter;
+ if (m_filter)
+ m_filter->Release();
}
QAbstractVideoSurface *DirectShowVideoRendererControl::surface() const
@@ -68,7 +69,8 @@ void DirectShowVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
emit filterChanged();
- delete existingFilter;
+ if (existingFilter)
+ existingFilter->Release();
}
}
diff --git a/src/plugins/directshow/player/player.pri b/src/plugins/directshow/player/player.pri
index c5c934a38..8586ea5da 100644
--- a/src/plugins/directshow/player/player.pri
+++ b/src/plugins/directshow/player/player.pri
@@ -1,5 +1,9 @@
INCLUDEPATH += $$PWD
+LIBS += -lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32 -lgdi32
+
+qtHaveModule(widgets): QT += widgets
+
DEFINES += QMEDIA_DIRECTSHOW_PLAYER
HEADERS += \
@@ -17,7 +21,8 @@ HEADERS += \
$$PWD/directshowsamplescheduler.h \
$$PWD/directshowvideorenderercontrol.h \
$$PWD/mediasamplevideobuffer.h \
- $$PWD/videosurfacefilter.h
+ $$PWD/videosurfacefilter.h \
+ $$PWD/vmr9videowindowcontrol.h
SOURCES += \
$$PWD/directshowaudioendpointcontrol.cpp \
@@ -33,14 +38,16 @@ SOURCES += \
$$PWD/directshowsamplescheduler.cpp \
$$PWD/directshowvideorenderercontrol.cpp \
$$PWD/mediasamplevideobuffer.cpp \
- $$PWD/videosurfacefilter.cpp
+ $$PWD/videosurfacefilter.cpp \
+ $$PWD/vmr9videowindowcontrol.cpp
-qtHaveModule(widgets):!simulator {
- HEADERS += \
- $$PWD/vmr9videowindowcontrol.h
+config_evr {
+ DEFINES += HAVE_EVR
- SOURCES += \
- $$PWD/vmr9videowindowcontrol.cpp
+ include($$PWD/../../common/evr.pri)
+
+ HEADERS += $$PWD/directshowevrvideowindowcontrol.h
+ SOURCES += $$PWD/directshowevrvideowindowcontrol.cpp
}
config_wshellitem {
@@ -48,6 +55,3 @@ config_wshellitem {
} else {
DEFINES += QT_NO_SHELLITEM
}
-
-LIBS += -lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32 -lgdi32
-
diff --git a/src/plugins/directshow/player/videosurfacefilter.cpp b/src/plugins/directshow/player/videosurfacefilter.cpp
index 2f52e33de..1fa7329cc 100644
--- a/src/plugins/directshow/player/videosurfacefilter.cpp
+++ b/src/plugins/directshow/player/videosurfacefilter.cpp
@@ -69,7 +69,7 @@ VideoSurfaceFilter::VideoSurfaceFilter(
VideoSurfaceFilter::~VideoSurfaceFilter()
{
- Q_ASSERT(m_ref == 1);
+ Q_ASSERT(m_ref == 0);
}
HRESULT VideoSurfaceFilter::QueryInterface(REFIID riid, void **ppvObject)
@@ -110,8 +110,8 @@ ULONG VideoSurfaceFilter::AddRef()
ULONG VideoSurfaceFilter::Release()
{
ULONG ref = InterlockedDecrement(&m_ref);
-
- Q_ASSERT(ref != 0);
+ if (ref == 0)
+ delete this;
return ref;
}
@@ -147,6 +147,14 @@ HRESULT VideoSurfaceFilter::Stop()
m_sampleScheduler.stop();
+ if (thread() == QThread::currentThread()) {
+ flush();
+ } else {
+ QMutexLocker locker(&m_mutex);
+ m_loop->postEvent(this, new QEvent(QEvent::Type(FlushSurface)));
+ m_wait.wait(&m_mutex);
+ }
+
return S_OK;
}
@@ -606,10 +614,24 @@ void VideoSurfaceFilter::sampleReady()
IMediaSample *sample = m_sampleScheduler.takeSample(&eos);
if (sample) {
- m_surface->present(QVideoFrame(
- new MediaSampleVideoBuffer(sample, m_bytesPerLine),
- m_surfaceFormat.frameSize(),
- m_surfaceFormat.pixelFormat()));
+ QVideoFrame frame(new MediaSampleVideoBuffer(sample, m_bytesPerLine),
+ m_surfaceFormat.frameSize(),
+ m_surfaceFormat.pixelFormat());
+
+ if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph, IID_IMediaSeeking)) {
+ LONGLONG position = 0;
+ seeking->GetCurrentPosition(&position);
+ seeking->Release();
+
+ frame.setStartTime(position * 0.1);
+
+ REFERENCE_TIME startTime = -1;
+ REFERENCE_TIME endTime = -1;
+ if (sample->GetTime(&startTime, &endTime) == S_OK)
+ frame.setEndTime(frame.startTime() + (endTime - startTime) * 0.1);
+ }
+
+ m_surface->present(frame);
sample->Release();
diff --git a/src/plugins/directshow/player/vmr9videowindowcontrol.cpp b/src/plugins/directshow/player/vmr9videowindowcontrol.cpp
index 48ff6c2c3..853ca031c 100644
--- a/src/plugins/directshow/player/vmr9videowindowcontrol.cpp
+++ b/src/plugins/directshow/player/vmr9videowindowcontrol.cpp
@@ -35,13 +35,16 @@
#include "directshowglobal.h"
+#ifndef QT_NO_WIDGETS
#include <QtGui/QPalette>
#include <QtWidgets/QWidget>
+#endif
Vmr9VideoWindowControl::Vmr9VideoWindowControl(QObject *parent)
: QVideoWindowControl(parent)
- , m_filter(com_new<IBaseFilter>(CLSID_VideoMixingRenderer9, IID_IBaseFilter))
+ , m_filter(com_new<IBaseFilter>(CLSID_VideoMixingRenderer9))
, m_windowId(0)
+ , m_windowColor(RGB(0, 0, 0))
, m_dirtyValues(0)
, m_aspectRatioMode(Qt::KeepAspectRatio)
, m_brightness(0)
@@ -74,11 +77,13 @@ void Vmr9VideoWindowControl::setWinId(WId id)
{
m_windowId = id;
+#ifndef QT_NO_WIDGETS
if (QWidget *widget = QWidget::find(m_windowId)) {
const QColor color = widget->palette().color(QPalette::Window);
m_windowColor = RGB(color.red(), color.green(), color.blue());
}
+#endif
if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(
m_filter, IID_IVMRWindowlessControl9)) {
diff --git a/src/plugins/gstreamer/camerabin/camerabin.pro b/src/plugins/gstreamer/camerabin/camerabin.pro
index 80d992960..b807071f2 100644
--- a/src/plugins/gstreamer/camerabin/camerabin.pro
+++ b/src/plugins/gstreamer/camerabin/camerabin.pro
@@ -89,6 +89,15 @@ config_gstreamer_encodingprofiles {
DEFINES += HAVE_GST_ENCODING_PROFILES
}
+config_linux_v4l: {
+ DEFINES += USE_V4L
+
+ HEADERS += \
+ $$PWD/camerabinv4limageprocessing.h
+
+ SOURCES += \
+ $$PWD/camerabinv4limageprocessing.cpp
+}
+
OTHER_FILES += \
camerabin.json
-
diff --git a/src/plugins/gstreamer/camerabin/camerabinimageprocessing.cpp b/src/plugins/gstreamer/camerabin/camerabinimageprocessing.cpp
index 633662c70..2d1659900 100644
--- a/src/plugins/gstreamer/camerabin/camerabinimageprocessing.cpp
+++ b/src/plugins/gstreamer/camerabin/camerabinimageprocessing.cpp
@@ -34,6 +34,10 @@
#include "camerabinimageprocessing.h"
#include "camerabinsession.h"
+#ifdef USE_V4L
+#include "camerabinv4limageprocessing.h"
+#endif
+
#if GST_CHECK_VERSION(1,0,0)
# include <gst/video/colorbalance.h>
#else
@@ -43,9 +47,12 @@
QT_BEGIN_NAMESPACE
CameraBinImageProcessing::CameraBinImageProcessing(CameraBinSession *session)
- :QCameraImageProcessingControl(session),
- m_session(session),
- m_whiteBalanceMode(QCameraImageProcessing::WhiteBalanceAuto)
+ : QCameraImageProcessingControl(session)
+ , m_session(session)
+ , m_whiteBalanceMode(QCameraImageProcessing::WhiteBalanceAuto)
+#ifdef USE_V4L
+ , m_v4lImageControl(Q_NULLPTR)
+#endif
{
#ifdef HAVE_GST_PHOTOGRAPHY
if (m_session->photography()) {
@@ -83,6 +90,12 @@ CameraBinImageProcessing::CameraBinImageProcessing(CameraBinSession *session)
#endif
#endif
+#ifdef USE_V4L
+ m_v4lImageControl = new CameraBinV4LImageProcessing(m_session);
+ connect(m_session, &CameraBinSession::statusChanged,
+ m_v4lImageControl, &CameraBinV4LImageProcessing::updateParametersInfo);
+#endif
+
updateColorBalanceValues();
}
@@ -160,7 +173,7 @@ QCameraImageProcessing::WhiteBalanceMode CameraBinImageProcessing::whiteBalanceM
return m_whiteBalanceMode;
}
-void CameraBinImageProcessing::setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode)
+bool CameraBinImageProcessing::setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode)
{
#ifdef HAVE_GST_PHOTOGRAPHY
if (isWhiteBalanceModeSupported(mode)) {
@@ -172,11 +185,13 @@ void CameraBinImageProcessing::setWhiteBalanceMode(QCameraImageProcessing::White
#endif
{
unlockWhiteBalance();
+ return true;
}
}
#else
Q_UNUSED(mode);
#endif
+ return false;
}
bool CameraBinImageProcessing::isWhiteBalanceModeSupported(QCameraImageProcessing::WhiteBalanceMode mode) const
@@ -184,7 +199,8 @@ bool CameraBinImageProcessing::isWhiteBalanceModeSupported(QCameraImageProcessin
#ifdef HAVE_GST_PHOTOGRAPHY
return m_mappedWbValues.values().contains(mode);
#else
- return mode == QCameraImageProcessing::WhiteBalanceAuto;
+ Q_UNUSED(mode);
+ return false;
#endif
}
@@ -192,16 +208,24 @@ bool CameraBinImageProcessing::isParameterSupported(QCameraImageProcessingContro
{
#ifdef HAVE_GST_PHOTOGRAPHY
if (parameter == QCameraImageProcessingControl::WhiteBalancePreset
- || parameter == QCameraImageProcessingControl::ColorFilter)
- return m_session->photography();
+ || parameter == QCameraImageProcessingControl::ColorFilter) {
+ if (m_session->photography())
+ return true;
+ }
#endif
if (parameter == QCameraImageProcessingControl::Contrast
|| parameter == QCameraImageProcessingControl::Brightness
|| parameter == QCameraImageProcessingControl::Saturation) {
- return GST_IS_COLOR_BALANCE(m_session->cameraBin());
+ if (GST_IS_COLOR_BALANCE(m_session->cameraBin()))
+ return true;
}
+#ifdef USE_V4L
+ if (m_v4lImageControl->isParameterSupported(parameter))
+ return true;
+#endif
+
return false;
}
@@ -210,10 +234,39 @@ bool CameraBinImageProcessing::isParameterValueSupported(QCameraImageProcessingC
switch (parameter) {
case ContrastAdjustment:
case BrightnessAdjustment:
- case SaturationAdjustment:
- return GST_IS_COLOR_BALANCE(m_session->cameraBin()) && qAbs(value.toReal()) <= 1.0;
- case WhiteBalancePreset:
- return isWhiteBalanceModeSupported(value.value<QCameraImageProcessing::WhiteBalanceMode>());
+ case SaturationAdjustment: {
+ const bool isGstColorBalanceValueSupported = GST_IS_COLOR_BALANCE(m_session->cameraBin())
+ && qAbs(value.toReal()) <= 1.0;
+#ifdef USE_V4L
+ if (!isGstColorBalanceValueSupported)
+ return m_v4lImageControl->isParameterValueSupported(parameter, value);
+#endif
+ return isGstColorBalanceValueSupported;
+ }
+ case SharpeningAdjustment: {
+#ifdef USE_V4L
+ return m_v4lImageControl->isParameterValueSupported(parameter, value);
+#else
+ return false;
+#endif
+ }
+ case WhiteBalancePreset: {
+ const QCameraImageProcessing::WhiteBalanceMode mode =
+ value.value<QCameraImageProcessing::WhiteBalanceMode>();
+ const bool isPhotographyWhiteBalanceSupported = isWhiteBalanceModeSupported(mode);
+#ifdef USE_V4L
+ if (!isPhotographyWhiteBalanceSupported)
+ return m_v4lImageControl->isParameterValueSupported(parameter, value);
+#endif
+ return isPhotographyWhiteBalanceSupported;
+ }
+ case ColorTemperature: {
+#ifdef USE_V4L
+ return m_v4lImageControl->isParameterValueSupported(parameter, value);
+#else
+ return false;
+#endif
+ }
case ColorFilter: {
const QCameraImageProcessing::ColorFilter filter = value.value<QCameraImageProcessing::ColorFilter>();
#ifdef HAVE_GST_PHOTOGRAPHY
@@ -233,8 +286,23 @@ QVariant CameraBinImageProcessing::parameter(
QCameraImageProcessingControl::ProcessingParameter parameter) const
{
switch (parameter) {
- case QCameraImageProcessingControl::WhiteBalancePreset:
- return QVariant::fromValue<QCameraImageProcessing::WhiteBalanceMode>(whiteBalanceMode());
+ case QCameraImageProcessingControl::WhiteBalancePreset: {
+ const QCameraImageProcessing::WhiteBalanceMode mode = whiteBalanceMode();
+#ifdef USE_V4L
+ if (mode == QCameraImageProcessing::WhiteBalanceAuto
+ || mode == QCameraImageProcessing::WhiteBalanceManual) {
+ return m_v4lImageControl->parameter(parameter);
+ }
+#endif
+ return QVariant::fromValue<QCameraImageProcessing::WhiteBalanceMode>(mode);
+ }
+ case QCameraImageProcessingControl::ColorTemperature: {
+#ifdef USE_V4L
+ return m_v4lImageControl->parameter(parameter);
+#else
+ return QVariant();
+#endif
+ }
case QCameraImageProcessingControl::ColorFilter:
#ifdef HAVE_GST_PHOTOGRAPHY
if (GstPhotography *photography = m_session->photography()) {
@@ -249,29 +317,79 @@ QVariant CameraBinImageProcessing::parameter(
}
#endif
return QVariant::fromValue(QCameraImageProcessing::ColorFilterNone);
- default:
- return m_values.contains(parameter)
+ default: {
+ const bool isGstParameterSupported = m_values.contains(parameter);
+#ifdef USE_V4L
+ if (!isGstParameterSupported) {
+ if (parameter == QCameraImageProcessingControl::BrightnessAdjustment
+ || parameter == QCameraImageProcessingControl::ContrastAdjustment
+ || parameter == QCameraImageProcessingControl::SaturationAdjustment
+ || parameter == QCameraImageProcessingControl::SharpeningAdjustment) {
+ return m_v4lImageControl->parameter(parameter);
+ }
+ }
+#endif
+ return isGstParameterSupported
? QVariant(m_values.value(parameter))
: QVariant();
}
+ }
}
void CameraBinImageProcessing::setParameter(QCameraImageProcessingControl::ProcessingParameter parameter,
const QVariant &value)
{
switch (parameter) {
- case ContrastAdjustment:
- setColorBalanceValue("contrast", value.toReal());
+ case ContrastAdjustment: {
+ if (!setColorBalanceValue("contrast", value.toReal())) {
+#ifdef USE_V4L
+ m_v4lImageControl->setParameter(parameter, value);
+#endif
+ }
+ }
break;
- case BrightnessAdjustment:
- setColorBalanceValue("brightness", value.toReal());
+ case BrightnessAdjustment: {
+ if (!setColorBalanceValue("brightness", value.toReal())) {
+#ifdef USE_V4L
+ m_v4lImageControl->setParameter(parameter, value);
+#endif
+ }
+ }
+ break;
+ case SaturationAdjustment: {
+ if (!setColorBalanceValue("saturation", value.toReal())) {
+#ifdef USE_V4L
+ m_v4lImageControl->setParameter(parameter, value);
+#endif
+ }
+ }
+ break;
+ case SharpeningAdjustment: {
+#ifdef USE_V4L
+ m_v4lImageControl->setParameter(parameter, value);
+#endif
+ }
break;
- case SaturationAdjustment:
- setColorBalanceValue("saturation", value.toReal());
+ case WhiteBalancePreset: {
+ if (!setWhiteBalanceMode(value.value<QCameraImageProcessing::WhiteBalanceMode>())) {
+#ifdef USE_V4L
+ const QCameraImageProcessing::WhiteBalanceMode mode =
+ value.value<QCameraImageProcessing::WhiteBalanceMode>();
+ if (mode == QCameraImageProcessing::WhiteBalanceAuto
+ || mode == QCameraImageProcessing::WhiteBalanceManual) {
+ m_v4lImageControl->setParameter(parameter, value);
+ return;
+ }
+#endif
+ }
+ }
break;
- case WhiteBalancePreset:
- setWhiteBalanceMode(value.value<QCameraImageProcessing::WhiteBalanceMode>());
+ case QCameraImageProcessingControl::ColorTemperature: {
+#ifdef USE_V4L
+ m_v4lImageControl->setParameter(parameter, value);
+#endif
break;
+ }
case QCameraImageProcessingControl::ColorFilter:
#ifdef HAVE_GST_PHOTOGRAPHY
if (GstPhotography *photography = m_session->photography()) {
diff --git a/src/plugins/gstreamer/camerabin/camerabinimageprocessing.h b/src/plugins/gstreamer/camerabin/camerabinimageprocessing.h
index 9f280c485..6b2a114ec 100644
--- a/src/plugins/gstreamer/camerabin/camerabinimageprocessing.h
+++ b/src/plugins/gstreamer/camerabin/camerabinimageprocessing.h
@@ -50,6 +50,10 @@ typedef GstColourToneMode GstPhotographyColorToneMode;
QT_BEGIN_NAMESPACE
+#ifdef USE_V4L
+class CameraBinV4LImageProcessing;
+#endif
+
class CameraBinSession;
class CameraBinImageProcessing : public QCameraImageProcessingControl
@@ -61,7 +65,7 @@ public:
virtual ~CameraBinImageProcessing();
QCameraImageProcessing::WhiteBalanceMode whiteBalanceMode() const;
- void setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode);
+ bool setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode);
bool isWhiteBalanceModeSupported(QCameraImageProcessing::WhiteBalanceMode mode) const;
bool isParameterSupported(ProcessingParameter) const;
@@ -86,6 +90,10 @@ private:
QMap<QCameraImageProcessing::ColorFilter, GstPhotographyColorToneMode> m_filterMap;
#endif
QCameraImageProcessing::WhiteBalanceMode m_whiteBalanceMode;
+
+#ifdef USE_V4L
+ CameraBinV4LImageProcessing *m_v4lImageControl;
+#endif
};
QT_END_NAMESPACE
diff --git a/src/plugins/gstreamer/camerabin/camerabinsession.h b/src/plugins/gstreamer/camerabin/camerabinsession.h
index 1c5c9899d..dda900a8b 100644
--- a/src/plugins/gstreamer/camerabin/camerabinsession.h
+++ b/src/plugins/gstreamer/camerabin/camerabinsession.h
@@ -153,6 +153,8 @@ public:
bool isMuted() const;
+ QString device() const { return m_inputDevice; }
+
bool processSyncMessage(const QGstreamerMessage &message);
bool processBusMessage(const QGstreamerMessage &message);
diff --git a/src/plugins/gstreamer/camerabin/camerabinv4limageprocessing.cpp b/src/plugins/gstreamer/camerabin/camerabinv4limageprocessing.cpp
new file mode 100644
index 000000000..bf51cbfd0
--- /dev/null
+++ b/src/plugins/gstreamer/camerabin/camerabinv4limageprocessing.cpp
@@ -0,0 +1,304 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "camerabinv4limageprocessing.h"
+#include "camerabinsession.h"
+
+#include <QDebug>
+
+#include <private/qcore_unix_p.h>
+#include <linux/videodev2.h>
+
+QT_BEGIN_NAMESPACE
+
+CameraBinV4LImageProcessing::CameraBinV4LImageProcessing(CameraBinSession *session)
+ : QCameraImageProcessingControl(session)
+ , m_session(session)
+{
+}
+
+CameraBinV4LImageProcessing::~CameraBinV4LImageProcessing()
+{
+}
+
+bool CameraBinV4LImageProcessing::isParameterSupported(
+ ProcessingParameter parameter) const
+{
+ return m_parametersInfo.contains(parameter);
+}
+
+bool CameraBinV4LImageProcessing::isParameterValueSupported(
+ ProcessingParameter parameter, const QVariant &value) const
+{
+ QMap<ProcessingParameter, SourceParameterValueInfo>::const_iterator sourceValueInfo =
+ m_parametersInfo.constFind(parameter);
+ if (sourceValueInfo == m_parametersInfo.constEnd())
+ return false;
+
+ switch (parameter) {
+
+ case QCameraImageProcessingControl::WhiteBalancePreset: {
+ const QCameraImageProcessing::WhiteBalanceMode checkedValue =
+ value.value<QCameraImageProcessing::WhiteBalanceMode>();
+ const QCameraImageProcessing::WhiteBalanceMode firstAllowedValue =
+ (*sourceValueInfo).minimumValue ? QCameraImageProcessing::WhiteBalanceAuto
+ : QCameraImageProcessing::WhiteBalanceManual;
+ const QCameraImageProcessing::WhiteBalanceMode secondAllowedValue =
+ (*sourceValueInfo).maximumValue ? QCameraImageProcessing::WhiteBalanceAuto
+ : QCameraImageProcessing::WhiteBalanceManual;
+ if (checkedValue != firstAllowedValue
+ && checkedValue != secondAllowedValue) {
+ return false;
+ }
+ }
+ break;
+
+ case QCameraImageProcessingControl::ColorTemperature: {
+ const qint32 checkedValue = value.toInt();
+ if (checkedValue < (*sourceValueInfo).minimumValue
+ || checkedValue > (*sourceValueInfo).maximumValue) {
+ return false;
+ }
+ }
+ break;
+
+ case QCameraImageProcessingControl::ContrastAdjustment: // falling back
+ case QCameraImageProcessingControl::SaturationAdjustment: // falling back
+ case QCameraImageProcessingControl::BrightnessAdjustment: // falling back
+ case QCameraImageProcessingControl::SharpeningAdjustment: {
+ const qint32 sourceValue = sourceImageProcessingParameterValue(
+ value.toReal(), (*sourceValueInfo));
+ if (sourceValue < (*sourceValueInfo).minimumValue
+ || sourceValue > (*sourceValueInfo).maximumValue) {
+ return false;
+ }
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+QVariant CameraBinV4LImageProcessing::parameter(
+ ProcessingParameter parameter) const
+{
+ QMap<ProcessingParameter, SourceParameterValueInfo>::const_iterator sourceValueInfo =
+ m_parametersInfo.constFind(parameter);
+ if (sourceValueInfo == m_parametersInfo.constEnd()) {
+ qWarning() << "Unable to get the parameter value: the parameter is not supported.";
+ return QVariant();
+ }
+
+ const QString deviceName = m_session->device();
+ const int fd = qt_safe_open(deviceName.toLocal8Bit().constData(), O_RDONLY);
+ if (fd == -1) {
+ qWarning() << "Unable to open the camera" << deviceName
+ << "for read to get the parameter value:" << qt_error_string(errno);
+ return QVariant();
+ }
+
+ struct v4l2_control control;
+ ::memset(&control, 0, sizeof(control));
+ control.id = (*sourceValueInfo).cid;
+
+ const bool ret = (::ioctl(fd, VIDIOC_G_CTRL, &control) == 0);
+
+ qt_safe_close(fd);
+
+ if (!ret) {
+ qWarning() << "Unable to get the parameter value:" << qt_error_string(errno);
+ return QVariant();
+ }
+
+ switch (parameter) {
+
+ case QCameraImageProcessingControl::WhiteBalancePreset:
+ return QVariant::fromValue<QCameraImageProcessing::WhiteBalanceMode>(
+ control.value ? QCameraImageProcessing::WhiteBalanceAuto
+ : QCameraImageProcessing::WhiteBalanceManual);
+
+ case QCameraImageProcessingControl::ColorTemperature:
+ return QVariant::fromValue<qint32>(control.value);
+
+ case QCameraImageProcessingControl::ContrastAdjustment: // falling back
+ case QCameraImageProcessingControl::SaturationAdjustment: // falling back
+ case QCameraImageProcessingControl::BrightnessAdjustment: // falling back
+ case QCameraImageProcessingControl::SharpeningAdjustment: {
+ return scaledImageProcessingParameterValue(
+ control.value, (*sourceValueInfo));
+ }
+
+ default:
+ return QVariant();
+ }
+}
+
+void CameraBinV4LImageProcessing::setParameter(
+ ProcessingParameter parameter, const QVariant &value)
+{
+ QMap<ProcessingParameter, SourceParameterValueInfo>::const_iterator sourceValueInfo =
+ m_parametersInfo.constFind(parameter);
+ if (sourceValueInfo == m_parametersInfo.constEnd()) {
+ qWarning() << "Unable to set the parameter value: the parameter is not supported.";
+ return;
+ }
+
+ const QString deviceName = m_session->device();
+ const int fd = qt_safe_open(deviceName.toLocal8Bit().constData(), O_WRONLY);
+ if (fd == -1) {
+ qWarning() << "Unable to open the camera" << deviceName
+ << "for write to set the parameter value:" << qt_error_string(errno);
+ return;
+ }
+
+ struct v4l2_control control;
+ ::memset(&control, 0, sizeof(control));
+ control.id = (*sourceValueInfo).cid;
+
+ switch (parameter) {
+
+ case QCameraImageProcessingControl::WhiteBalancePreset: {
+ const QCameraImageProcessing::WhiteBalanceMode m =
+ value.value<QCameraImageProcessing::WhiteBalanceMode>();
+ if (m != QCameraImageProcessing::WhiteBalanceAuto
+ && m != QCameraImageProcessing::WhiteBalanceManual)
+ return;
+
+ control.value = (m == QCameraImageProcessing::WhiteBalanceAuto) ? true : false;
+ }
+ break;
+
+ case QCameraImageProcessingControl::ColorTemperature:
+ control.value = value.toInt();
+ break;
+
+ case QCameraImageProcessingControl::ContrastAdjustment: // falling back
+ case QCameraImageProcessingControl::SaturationAdjustment: // falling back
+ case QCameraImageProcessingControl::BrightnessAdjustment: // falling back
+ case QCameraImageProcessingControl::SharpeningAdjustment:
+ control.value = sourceImageProcessingParameterValue(
+ value.toReal(), (*sourceValueInfo));
+ break;
+
+ default:
+ return;
+ }
+
+ if (::ioctl(fd, VIDIOC_S_CTRL, &control) != 0)
+ qWarning() << "Unable to set the parameter value:" << qt_error_string(errno);
+
+ qt_safe_close(fd);
+}
+
+void CameraBinV4LImageProcessing::updateParametersInfo(
+ QCamera::Status cameraStatus)
+{
+ if (cameraStatus == QCamera::UnloadedStatus)
+ m_parametersInfo.clear();
+ else if (cameraStatus == QCamera::LoadedStatus) {
+ const QString deviceName = m_session->device();
+ const int fd = qt_safe_open(deviceName.toLocal8Bit().constData(), O_RDONLY);
+ if (fd == -1) {
+ qWarning() << "Unable to open the camera" << deviceName
+ << "for read to query the parameter info:" << qt_error_string(errno);
+ return;
+ }
+
+ static const struct SupportedParameterEntry {
+ quint32 cid;
+ QCameraImageProcessingControl::ProcessingParameter parameter;
+ } supportedParametersEntries[] = {
+ { V4L2_CID_AUTO_WHITE_BALANCE, QCameraImageProcessingControl::WhiteBalancePreset },
+ { V4L2_CID_WHITE_BALANCE_TEMPERATURE, QCameraImageProcessingControl::ColorTemperature },
+ { V4L2_CID_CONTRAST, QCameraImageProcessingControl::ContrastAdjustment },
+ { V4L2_CID_SATURATION, QCameraImageProcessingControl::SaturationAdjustment },
+ { V4L2_CID_BRIGHTNESS, QCameraImageProcessingControl::BrightnessAdjustment },
+ { V4L2_CID_SHARPNESS, QCameraImageProcessingControl::SharpeningAdjustment }
+ };
+
+ for (int i = 0; i < int(sizeof(supportedParametersEntries) / sizeof(SupportedParameterEntry)); ++i) {
+ struct v4l2_queryctrl queryControl;
+ ::memset(&queryControl, 0, sizeof(queryControl));
+ queryControl.id = supportedParametersEntries[i].cid;
+
+ if (::ioctl(fd, VIDIOC_QUERYCTRL, &queryControl) != 0) {
+ qWarning() << "Unable to query the parameter info:" << qt_error_string(errno);
+ continue;
+ }
+
+ SourceParameterValueInfo sourceValueInfo;
+ sourceValueInfo.cid = queryControl.id;
+ sourceValueInfo.defaultValue = queryControl.default_value;
+ sourceValueInfo.maximumValue = queryControl.maximum;
+ sourceValueInfo.minimumValue = queryControl.minimum;
+
+ m_parametersInfo.insert(supportedParametersEntries[i].parameter, sourceValueInfo);
+ }
+
+ qt_safe_close(fd);
+ }
+}
+
+qreal CameraBinV4LImageProcessing::scaledImageProcessingParameterValue(
+ qint32 sourceValue, const SourceParameterValueInfo &sourceValueInfo)
+{
+ if (sourceValue == sourceValueInfo.defaultValue) {
+ return 0.0f;
+ } else if (sourceValue < sourceValueInfo.defaultValue) {
+ return ((sourceValue - sourceValueInfo.minimumValue)
+ / qreal(sourceValueInfo.defaultValue - sourceValueInfo.minimumValue))
+ + (-1.0f);
+ } else {
+ return ((sourceValue - sourceValueInfo.defaultValue)
+ / qreal(sourceValueInfo.maximumValue - sourceValueInfo.defaultValue));
+ }
+}
+
+qint32 CameraBinV4LImageProcessing::sourceImageProcessingParameterValue(
+ qreal scaledValue, const SourceParameterValueInfo &valueRange)
+{
+ if (qFuzzyIsNull(scaledValue)) {
+ return valueRange.defaultValue;
+ } else if (scaledValue < 0.0f) {
+ return ((scaledValue - (-1.0f)) * (valueRange.defaultValue - valueRange.minimumValue))
+ + valueRange.minimumValue;
+ } else {
+ return (scaledValue * (valueRange.maximumValue - valueRange.defaultValue))
+ + valueRange.defaultValue;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/gstreamer/camerabin/camerabinv4limageprocessing.h b/src/plugins/gstreamer/camerabin/camerabinv4limageprocessing.h
new file mode 100644
index 000000000..7961d6c0d
--- /dev/null
+++ b/src/plugins/gstreamer/camerabin/camerabinv4limageprocessing.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CAMERABINV4LIMAGEPROCESSINGCONTROL_H
+#define CAMERABINV4LIMAGEPROCESSINGCONTROL_H
+
+#include <qcamera.h>
+#include <qcameraimageprocessingcontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class CameraBinSession;
+
+class CameraBinV4LImageProcessing : public QCameraImageProcessingControl
+{
+ Q_OBJECT
+
+public:
+ CameraBinV4LImageProcessing(CameraBinSession *session);
+ virtual ~CameraBinV4LImageProcessing();
+
+ bool isParameterSupported(ProcessingParameter) const;
+ bool isParameterValueSupported(ProcessingParameter parameter, const QVariant &value) const;
+ QVariant parameter(ProcessingParameter parameter) const;
+ void setParameter(ProcessingParameter parameter, const QVariant &value);
+
+public slots:
+ void updateParametersInfo(QCamera::Status cameraStatus);
+
+private:
+ struct SourceParameterValueInfo {
+ SourceParameterValueInfo()
+ : cid(0)
+ {
+ }
+
+ qint32 defaultValue;
+ qint32 minimumValue;
+ qint32 maximumValue;
+ quint32 cid; // V4L control id
+ };
+
+ static qreal scaledImageProcessingParameterValue(
+ qint32 sourceValue, const SourceParameterValueInfo &sourceValueInfo);
+ static qint32 sourceImageProcessingParameterValue(
+ qreal scaledValue, const SourceParameterValueInfo &valueRange);
+private:
+ CameraBinSession *m_session;
+ QMap<ProcessingParameter, SourceParameterValueInfo> m_parametersInfo;
+};
+
+QT_END_NAMESPACE
+
+#endif // CAMERABINV4LIMAGEPROCESSINGCONTROL_H
diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercaptureserviceplugin.cpp b/src/plugins/gstreamer/mediacapture/qgstreamercaptureserviceplugin.cpp
index 8cbdb6717..ba21ff307 100644
--- a/src/plugins/gstreamer/mediacapture/qgstreamercaptureserviceplugin.cpp
+++ b/src/plugins/gstreamer/mediacapture/qgstreamercaptureserviceplugin.cpp
@@ -88,7 +88,7 @@ QList<QByteArray> QGstreamerCaptureServicePlugin::devices(const QByteArray &serv
QString QGstreamerCaptureServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device)
{
- return service == Q_MEDIASERVICE_CAMERA ? QGstUtils::cameraDescription(deviceName) : QString();
+ return service == Q_MEDIASERVICE_CAMERA ? QGstUtils::cameraDescription(device) : QString();
}
QVariant QGstreamerCaptureServicePlugin::deviceProperty(const QByteArray &service, const QByteArray &device, const QByteArray &property)
diff --git a/src/plugins/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp b/src/plugins/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp
index 7132c29ab..91bfd67f3 100644
--- a/src/plugins/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp
+++ b/src/plugins/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp
@@ -252,7 +252,7 @@ void QGstreamerRecorderControl::applySettings()
bool found = false;
foreach (const QString &audioCandidate, audioCandidates) {
QSet<QString> audioTypes = audioEncodeControl->supportedStreamTypes(audioCandidate);
- if (!audioTypes.intersect(supportedTypes).isEmpty()) {
+ if (audioTypes.intersects(supportedTypes)) {
found = true;
audioCodec = audioCandidate;
break;
@@ -266,7 +266,7 @@ void QGstreamerRecorderControl::applySettings()
bool found = false;
foreach (const QString &videoCandidate, videoCandidates) {
QSet<QString> videoTypes = videoEncodeControl->supportedStreamTypes(videoCandidate);
- if (!videoTypes.intersect(supportedTypes).isEmpty()) {
+ if (videoTypes.intersects(supportedTypes)) {
found = true;
videoCodec = videoCandidate;
break;
diff --git a/src/plugins/pulseaudio/qaudioinput_pulse.h b/src/plugins/pulseaudio/qaudioinput_pulse.h
index 971c8d74b..7b898c480 100644
--- a/src/plugins/pulseaudio/qaudioinput_pulse.h
+++ b/src/plugins/pulseaudio/qaudioinput_pulse.h
@@ -117,8 +117,6 @@ private:
void close();
void setPulseVolume();
- static QMap<void *, QPulseAudioInput*> s_inputsMap;
-
static void sourceInfoCallback(pa_context *c, const pa_source_info *i, int eol, void *userdata);
static void inputVolumeCallback(pa_context *context, int success, void *userdata);
diff --git a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp
index 4a225e9ce..cf62843f7 100644
--- a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp
+++ b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp
@@ -182,6 +182,8 @@ public:
QThread renderThread;
bool active;
+ QWinRTAbstractVideoRendererControl::BlitMode blitMode;
+ CRITICAL_SECTION mutex;
};
ID3D11Device *QWinRTAbstractVideoRendererControl::d3dDevice()
@@ -212,6 +214,8 @@ QWinRTAbstractVideoRendererControl::QWinRTAbstractVideoRendererControl(const QSi
d->eglConfig = 0;
d->eglSurface = EGL_NO_SURFACE;
d->active = false;
+ d->blitMode = DirectVideo;
+ InitializeCriticalSectionEx(&d->mutex, 0, 0);
connect(&d->renderThread, &QThread::started,
this, &QWinRTAbstractVideoRendererControl::syncAndRender,
@@ -220,7 +224,11 @@ QWinRTAbstractVideoRendererControl::QWinRTAbstractVideoRendererControl(const QSi
QWinRTAbstractVideoRendererControl::~QWinRTAbstractVideoRendererControl()
{
+ Q_D(QWinRTAbstractVideoRendererControl);
+ CriticalSectionLocker locker(&d->mutex);
shutdown();
+ DeleteCriticalSection(&d->mutex);
+ eglDestroySurface(d->eglDisplay, d->eglSurface);
}
QAbstractVideoSurface *QWinRTAbstractVideoRendererControl::surface() const
@@ -244,31 +252,45 @@ void QWinRTAbstractVideoRendererControl::syncAndRender()
forever {
if (currentThread->isInterruptionRequested())
break;
+ {
+ CriticalSectionLocker lock(&d->mutex);
+ HRESULT hr;
+ if (d->dirtyState == TextureDirty) {
+ CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, d->format.frameWidth(), d->format.frameHeight(), 1, 1);
+ desc.BindFlags |= D3D11_BIND_RENDER_TARGET;
+ desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
+ hr = g->device->CreateTexture2D(&desc, NULL, d->texture.ReleaseAndGetAddressOf());
+ BREAK_IF_FAILED("Failed to get create video texture");
+ ComPtr<IDXGIResource> resource;
+ hr = d->texture.As(&resource);
+ BREAK_IF_FAILED("Failed to cast texture to resource");
+ hr = resource->GetSharedHandle(&d->shareHandle);
+ BREAK_IF_FAILED("Failed to get texture share handle");
+ d->dirtyState = SurfaceDirty;
+ }
- HRESULT hr;
- if (d->dirtyState == TextureDirty) {
- CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, d->format.frameWidth(), d->format.frameHeight(), 1, 1);
- desc.BindFlags |= D3D11_BIND_RENDER_TARGET;
- desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
- hr = g->device->CreateTexture2D(&desc, NULL, d->texture.ReleaseAndGetAddressOf());
- BREAK_IF_FAILED("Failed to get create video texture");
- ComPtr<IDXGIResource> resource;
- hr = d->texture.As(&resource);
- BREAK_IF_FAILED("Failed to cast texture to resource");
- hr = resource->GetSharedHandle(&d->shareHandle);
- BREAK_IF_FAILED("Failed to get texture share handle");
- d->dirtyState = SurfaceDirty;
- }
-
- hr = g->output->WaitForVBlank();
- CONTINUE_IF_FAILED("Failed to wait for vertical blank");
+ hr = g->output->WaitForVBlank();
+ CONTINUE_IF_FAILED("Failed to wait for vertical blank");
+
+ bool success = false;
+ switch (d->blitMode) {
+ case DirectVideo:
+ success = render(d->texture.Get());
+ break;
+ case MediaFoundation:
+ success = dequeueFrame(&d->presentFrame);
+ break;
+ default:
+ success = false;
+ }
- if (!render(d->texture.Get()))
- continue;
+ if (!success)
+ continue;
- // Queue to the control's thread for presentation
- present.invoke(this, Qt::QueuedConnection);
- currentThread->eventDispatcher()->processEvents(QEventLoop::AllEvents);
+ // Queue to the control's thread for presentation
+ present.invoke(this, Qt::QueuedConnection);
+ currentThread->eventDispatcher()->processEvents(QEventLoop::AllEvents);
+ }
}
// All done, exit render loop
@@ -326,7 +348,44 @@ void QWinRTAbstractVideoRendererControl::setActive(bool active)
d->surface->stop();
}
-void QWinRTAbstractVideoRendererControl::present()
+QWinRTAbstractVideoRendererControl::BlitMode QWinRTAbstractVideoRendererControl::blitMode() const
+{
+ Q_D(const QWinRTAbstractVideoRendererControl);
+ return d->blitMode;
+}
+
+void QWinRTAbstractVideoRendererControl::setBlitMode(QWinRTAbstractVideoRendererControl::BlitMode mode)
+{
+ Q_D(QWinRTAbstractVideoRendererControl);
+ CriticalSectionLocker lock(&d->mutex);
+
+ if (d->blitMode == mode)
+ return;
+
+ d->blitMode = mode;
+ d->dirtyState = d->blitMode == MediaFoundation ? NotDirty : TextureDirty;
+
+ if (d->blitMode == DirectVideo)
+ return;
+
+ if (d->texture) {
+ d->texture.Reset();
+ d->shareHandle = 0;
+ }
+
+ if (d->eglSurface) {
+ eglDestroySurface(d->eglDisplay, d->eglSurface);
+ d->eglSurface = EGL_NO_SURFACE;
+ }
+}
+
+bool QWinRTAbstractVideoRendererControl::dequeueFrame(QVideoFrame *frame)
+{
+ Q_UNUSED(frame)
+ return false;
+}
+
+void QWinRTAbstractVideoRendererControl::textureToFrame()
{
Q_D(QWinRTAbstractVideoRendererControl);
@@ -387,6 +446,13 @@ void QWinRTAbstractVideoRendererControl::present()
d->dirtyState = NotDirty;
}
+}
+
+void QWinRTAbstractVideoRendererControl::present()
+{
+ Q_D(QWinRTAbstractVideoRendererControl);
+ if (d->blitMode == DirectVideo)
+ textureToFrame();
// Present the frame
d->surface->present(d->presentFrame);
diff --git a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h
index ed8b76a6e..70227c53c 100644
--- a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h
+++ b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h
@@ -40,6 +40,8 @@
#include <QtMultimedia/QVideoRendererControl>
#include <QtMultimedia/QVideoSurfaceFormat>
+#include <qt_windows.h>
+
struct ID3D11Device;
struct ID3D11Texture2D;
@@ -53,6 +55,11 @@ public:
explicit QWinRTAbstractVideoRendererControl(const QSize &size, QObject *parent = 0);
~QWinRTAbstractVideoRendererControl();
+ enum BlitMode {
+ DirectVideo,
+ MediaFoundation
+ };
+
QAbstractVideoSurface *surface() const Q_DECL_OVERRIDE;
void setSurface(QAbstractVideoSurface *surface) Q_DECL_OVERRIDE;
@@ -63,7 +70,11 @@ public:
void setActive(bool active);
+ BlitMode blitMode() const;
+ void setBlitMode(BlitMode mode);
+
virtual bool render(ID3D11Texture2D *texture) = 0;
+ virtual bool dequeueFrame(QVideoFrame *frame);
static ID3D11Device *d3dDevice();
@@ -74,12 +85,29 @@ private slots:
void syncAndRender();
private:
+ void textureToFrame();
Q_INVOKABLE void present();
QScopedPointer<QWinRTAbstractVideoRendererControlPrivate> d_ptr;
Q_DECLARE_PRIVATE(QWinRTAbstractVideoRendererControl)
};
+class CriticalSectionLocker
+{
+public:
+ CriticalSectionLocker(CRITICAL_SECTION *section)
+ : m_section(section)
+ {
+ EnterCriticalSection(m_section);
+ }
+ ~CriticalSectionLocker()
+ {
+ LeaveCriticalSection(m_section);
+ }
+private:
+ CRITICAL_SECTION *m_section;
+};
+
QT_END_NAMESPACE
#endif // QWINRTABSTRACTVIDEORENDERERCONTROL_H
diff --git a/src/plugins/winrt/qwinrtcameracontrol.cpp b/src/plugins/winrt/qwinrtcameracontrol.cpp
index 9013416fe..19b718cdd 100644
--- a/src/plugins/winrt/qwinrtcameracontrol.cpp
+++ b/src/plugins/winrt/qwinrtcameracontrol.cpp
@@ -39,10 +39,12 @@
#include "qwinrtvideodeviceselectorcontrol.h"
#include "qwinrtcameraimagecapturecontrol.h"
#include "qwinrtimageencodercontrol.h"
+#include "qwinrtcamerafocuscontrol.h"
+#include "qwinrtcameralockscontrol.h"
#include <QtCore/qfunctions_winrt.h>
-#include <QtCore/QCoreApplication>
#include <QtCore/QPointer>
+#include <QtGui/QGuiApplication>
#include <mfapi.h>
#include <mferror.h>
@@ -51,11 +53,7 @@
#include <windows.devices.enumeration.h>
#include <windows.media.capture.h>
#include <windows.storage.streams.h>
-
-#ifdef Q_OS_WINPHONE
-#include <Windows.Security.ExchangeActiveSyncProvisioning.h>
-using namespace ABI::Windows::Security::ExchangeActiveSyncProvisioning;
-#endif
+#include <windows.media.devices.h>
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
@@ -76,43 +74,130 @@ QT_BEGIN_NAMESPACE
RETURN_VOID_IF_FAILED(msg); \
}
-inline uint qHash (const QSize &key) {
- return key.width() * key.height();
+#define FOCUS_RECT_SIZE 0.01f
+#define FOCUS_RECT_HALF_SIZE 0.005f // FOCUS_RECT_SIZE / 2
+#define FOCUS_RECT_BOUNDARY 1.0f
+#define FOCUS_RECT_POSITION_MIN 0.0f
+#define FOCUS_RECT_POSITION_MAX 0.995f // FOCUS_RECT_BOUNDARY - FOCUS_RECT_HALF_SIZE
+#define ASPECTRATIO_EPSILON 0.01f
+
+HRESULT getMediaStreamResolutions(IMediaDeviceController *device,
+ MediaStreamType type,
+ IVectorView<IMediaEncodingProperties *> **propertiesList,
+ QVector<QSize> *resolutions)
+{
+ HRESULT hr;
+ hr = device->GetAvailableMediaStreamProperties(type, propertiesList);
+ Q_ASSERT_SUCCEEDED(hr);
+ quint32 listSize;
+ hr = (*propertiesList)->get_Size(&listSize);
+ Q_ASSERT_SUCCEEDED(hr);
+ resolutions->reserve(listSize);
+ for (quint32 index = 0; index < listSize; ++index) {
+ ComPtr<IMediaEncodingProperties> properties;
+ hr = (*propertiesList)->GetAt(index, &properties);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IVideoEncodingProperties> videoProperties;
+ hr = properties.As(&videoProperties);
+ Q_ASSERT_SUCCEEDED(hr);
+ UINT32 width, height;
+ hr = videoProperties->get_Width(&width);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = videoProperties->get_Height(&height);
+ Q_ASSERT_SUCCEEDED(hr);
+ resolutions->append(QSize(width, height));
+ }
+ return resolutions->isEmpty() ? MF_E_INVALID_FORMAT : hr;
+}
+
+template<typename T, size_t typeSize> struct CustomPropertyValue;
+
+inline static ComPtr<IPropertyValueStatics> propertyValueStatics()
+{
+ ComPtr<IPropertyValueStatics> valueStatics;
+ GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), &valueStatics);
+ return valueStatics;
}
-class CriticalSectionLocker
+template <typename T>
+struct CustomPropertyValue<T, 4>
+{
+ static ComPtr<IReference<T>> create(T value)
+ {
+ ComPtr<IInspectable> propertyValueObject;
+ HRESULT hr = propertyValueStatics()->CreateUInt32(value, &propertyValueObject);
+ ComPtr<IReference<UINT32>> uint32Object;
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = propertyValueObject.As(&uint32Object);
+ Q_ASSERT_SUCCEEDED(hr);
+ return reinterpret_cast<IReference<T> *>(uint32Object.Get());
+ }
+};
+
+template <typename T>
+struct CustomPropertyValue<T, 8>
+{
+ static ComPtr<IReference<T>> create(T value)
+ {
+ ComPtr<IInspectable> propertyValueObject;
+ HRESULT hr = propertyValueStatics()->CreateUInt64(value, &propertyValueObject);
+ ComPtr<IReference<UINT64>> uint64Object;
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = propertyValueObject.As(&uint64Object);
+ Q_ASSERT_SUCCEEDED(hr);
+ return reinterpret_cast<IReference<T> *>(uint64Object.Get());
+ }
+};
+
+// Required camera point focus
+class WindowsRegionOfInterestIterableIterator : public RuntimeClass<IIterator<RegionOfInterest *>>
{
public:
- CriticalSectionLocker(CRITICAL_SECTION *section)
- : m_section(section)
+ explicit WindowsRegionOfInterestIterableIterator(const ComPtr<IRegionOfInterest> &item)
+ {
+ regionOfInterest = item;
+ }
+ HRESULT __stdcall get_Current(IRegionOfInterest **current)
+ {
+ *current = regionOfInterest.Detach();
+ return S_OK;
+ }
+ HRESULT __stdcall get_HasCurrent(boolean *hasCurrent)
{
- EnterCriticalSection(m_section);
+ *hasCurrent = true;
+ return S_OK;
}
- ~CriticalSectionLocker()
+ HRESULT __stdcall MoveNext(boolean *hasCurrent)
{
- LeaveCriticalSection(m_section);
+ *hasCurrent = false;
+ return S_OK;
}
private:
- CRITICAL_SECTION *m_section;
+ ComPtr<IRegionOfInterest> regionOfInterest;
};
-class MediaStream : public RuntimeClass<RuntimeClassFlags<WinRtClassicComMix>, IMFStreamSink, IMFMediaEventGenerator, IMFMediaTypeHandler>
+class WindowsRegionOfInterestIterable : public RuntimeClass<IIterable<RegionOfInterest *>>
{
- enum Flags { NoFlag = 0, BufferLockRequired = 1 };
-
- template <int n>
- static Flags bufferLockRequired(const wchar_t (&blackListName)[n], const HString &deviceModel)
+public:
+ explicit WindowsRegionOfInterestIterable(const ComPtr<IRegionOfInterest> &item)
+ {
+ regionOfInterest = item;
+ }
+ HRESULT __stdcall First(IIterator<RegionOfInterest *> **first)
{
- quint32 deviceNameLength;
- const wchar_t *deviceName = deviceModel.GetRawBuffer(&deviceNameLength);
- if (n - 1 <= deviceNameLength && !wmemcmp(blackListName, deviceName, n - 1))
- return BufferLockRequired;
- return NoFlag;
+ ComPtr<WindowsRegionOfInterestIterableIterator> iterator = Make<WindowsRegionOfInterestIterableIterator>(regionOfInterest);
+ *first = iterator.Detach();
+ return S_OK;
}
+private:
+ ComPtr<IRegionOfInterest> regionOfInterest;
+};
+class MediaStream : public RuntimeClass<RuntimeClassFlags<WinRtClassicComMix>, IMFStreamSink, IMFMediaEventGenerator, IMFMediaTypeHandler>
+{
public:
MediaStream(IMFMediaType *type, IMFMediaSink *mediaSink, QWinRTCameraVideoRendererControl *videoRenderer)
- : m_type(type), m_sink(mediaSink), m_videoRenderer(videoRenderer), m_flags(NoFlag)
+ : m_type(type), m_sink(mediaSink), m_videoRenderer(videoRenderer)
{
Q_ASSERT(m_videoRenderer);
@@ -123,19 +208,6 @@ public:
Q_ASSERT_SUCCEEDED(hr);
hr = MFAllocateSerialWorkQueue(MFASYNC_CALLBACK_QUEUE_STANDARD, &m_workQueueId);
Q_ASSERT_SUCCEEDED(hr);
-
-#ifdef Q_OS_WINPHONE
- // Workaround for certain devices which fail to blit software buffers without first mapping them
- ComPtr<IEasClientDeviceInformation> deviceInfo;
- hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Security_ExchangeActiveSyncProvisioning_EasClientDeviceInformation).Get(),
- &deviceInfo);
- Q_ASSERT_SUCCEEDED(hr);
- HString deviceModel;
- hr = deviceInfo->get_SystemSku(deviceModel.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- m_flags |= bufferLockRequired(L"NOKIA RM-976", deviceModel);
- m_flags |= bufferLockRequired(L"NOKIA RM-1019", deviceModel);
-#endif
}
~MediaStream()
@@ -209,16 +281,6 @@ public:
hr = buffer.As(&buffer2d);
RETURN_HR_IF_FAILED("Failed to cast camera sample buffer to 2D buffer");
-#ifdef Q_OS_WINPHONE
- if (m_flags & BufferLockRequired) {
- BYTE *bytes;
- LONG stride;
- hr = buffer2d->Lock2D(&bytes, &stride);
- RETURN_HR_IF_FAILED("Failed to lock camera frame buffer");
- hr = buffer2d->Unlock2D();
- RETURN_HR_IF_FAILED("Failed to unlock camera frame buffer");
- }
-#endif
m_pendingSamples.deref();
m_videoRenderer->queueBuffer(buffer2d.Get());
@@ -292,7 +354,6 @@ private:
QWinRTCameraVideoRendererControl *m_videoRenderer;
QAtomicInt m_pendingSamples;
- quint32 m_flags;
};
class MediaSink : public RuntimeClass<RuntimeClassFlags<WinRtClassicComMix>, IMediaExtension, IMFMediaSink, IMFClockStateSink>
@@ -384,7 +445,7 @@ public:
{
m_stream->Flush();
m_videoRenderer->setActive(false);
- return m_presentationClock->Stop();
+ return m_presentationClock ? m_presentationClock->Stop() : S_OK;
}
HRESULT __stdcall OnClockStart(MFTIME systemTime, LONGLONG clockStartOffset) Q_DECL_OVERRIDE
@@ -454,12 +515,18 @@ public:
ComPtr<IMediaEncodingProfile> encodingProfile;
ComPtr<MediaSink> mediaSink;
+ ComPtr<IFocusControl> focusControl;
+ ComPtr<IRegionsOfInterestControl> regionsOfInterestControl;
+ ComPtr<IAsyncAction> focusOperation;
- QSize size;
QPointer<QWinRTCameraVideoRendererControl> videoRenderer;
QPointer<QWinRTVideoDeviceSelectorControl> videoDeviceSelector;
QPointer<QWinRTCameraImageCaptureControl> imageCaptureControl;
QPointer<QWinRTImageEncoderControl> imageEncoderControl;
+ QPointer<QWinRTCameraFocusControl> cameraFocusControl;
+ QPointer<QWinRTCameraLocksControl> cameraLocksControl;
+ QAtomicInt framesMapped;
+ QEventLoop *delayClose;
};
QWinRTCameraControl::QWinRTCameraControl(QObject *parent)
@@ -467,17 +534,25 @@ QWinRTCameraControl::QWinRTCameraControl(QObject *parent)
{
Q_D(QWinRTCameraControl);
+ d->delayClose = nullptr;
d->state = QCamera::UnloadedState;
d->status = QCamera::UnloadedStatus;
d->captureMode = QCamera::CaptureStillImage;
d->captureFailedCookie.value = 0;
d->recordLimitationCookie.value = 0;
- d->videoRenderer = new QWinRTCameraVideoRendererControl(d->size, this);
+ d->videoRenderer = new QWinRTCameraVideoRendererControl(QSize(), this);
connect(d->videoRenderer, &QWinRTCameraVideoRendererControl::bufferRequested,
this, &QWinRTCameraControl::onBufferRequested);
d->videoDeviceSelector = new QWinRTVideoDeviceSelectorControl(this);
d->imageCaptureControl = new QWinRTCameraImageCaptureControl(this);
d->imageEncoderControl = new QWinRTImageEncoderControl(this);
+ d->cameraFocusControl = new QWinRTCameraFocusControl(this);
+ d->cameraLocksControl = new QWinRTCameraLocksControl(this);
+
+ if (qGuiApp) {
+ connect(qGuiApp, &QGuiApplication::applicationStateChanged,
+ this, &QWinRTCameraControl::onApplicationStateChanged);
+ }
}
QWinRTCameraControl::~QWinRTCameraControl()
@@ -524,10 +599,15 @@ void QWinRTCameraControl::setState(QCamera::State state)
return;
}
+ QCameraFocus::FocusModes focusMode = d->cameraFocusControl->focusMode();
+ if (setFocus(focusMode) && focusMode == QCameraFocus::ContinuousFocus)
+ focus();
+
d->state = QCamera::ActiveState;
emit stateChanged(d->state);
d->status = QCamera::ActiveStatus;
emit statusChanged(d->status);
+ d->mediaSink->RequestSample();
break;
}
case QCamera::LoadedState: {
@@ -541,6 +621,19 @@ void QWinRTCameraControl::setState(QCamera::State state)
case QCamera::UnloadedState: {
// Stop the camera if it is running (transition to LoadedState)
if (d->status == QCamera::ActiveStatus) {
+ HRESULT hr;
+ if (d->focusOperation) {
+ hr = QWinRTFunctions::await(d->focusOperation);
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ if (d->framesMapped > 0) {
+ qWarning("%d QVideoFrame(s) mapped when closing down camera. Camera will wait for unmap before closing down.",
+ d->framesMapped);
+ if (!d->delayClose)
+ d->delayClose = new QEventLoop(this);
+ d->delayClose->exec();
+ }
+
ComPtr<IAsyncAction> op;
hr = d->capturePreview->StopPreviewAsync(&op);
RETURN_VOID_AND_EMIT_ERROR("Failed to stop camera preview");
@@ -553,8 +646,10 @@ void QWinRTCameraControl::setState(QCamera::State state)
if (FAILED(hr))
emit error(QCamera::InvalidRequestError, qt_error_string(hr));
- d->mediaSink->Shutdown();
- d->mediaSink.Reset();
+ if (d->mediaSink) {
+ d->mediaSink->Shutdown();
+ d->mediaSink.Reset();
+ }
d->state = QCamera::LoadedState;
emit stateChanged(d->state);
@@ -668,6 +763,18 @@ QImageEncoderControl *QWinRTCameraControl::imageEncoderControl() const
return d->imageEncoderControl;
}
+QCameraFocusControl *QWinRTCameraControl::cameraFocusControl() const
+{
+ Q_D(const QWinRTCameraControl);
+ return d->cameraFocusControl;
+}
+
+QCameraLocksControl *QWinRTCameraControl::cameraLocksControl() const
+{
+ Q_D(const QWinRTCameraControl);
+ return d->cameraLocksControl;
+}
+
IMediaCapture *QWinRTCameraControl::handle() const
{
Q_D(const QWinRTCameraControl);
@@ -682,6 +789,25 @@ void QWinRTCameraControl::onBufferRequested()
d->mediaSink->RequestSample();
}
+void QWinRTCameraControl::onApplicationStateChanged(Qt::ApplicationState state)
+{
+ Q_D(QWinRTCameraControl);
+ static QCamera::State savedState = d->state;
+ switch (state) {
+ case Qt::ApplicationInactive:
+ if (d->state != QCamera::UnloadedState) {
+ savedState = d->state;
+ setState(QCamera::UnloadedState);
+ }
+ break;
+ case Qt::ApplicationActive:
+ setState(QCamera::State(savedState));
+ break;
+ default:
+ break;
+ }
+}
+
HRESULT QWinRTCameraControl::initialize()
{
Q_D(QWinRTCameraControl);
@@ -720,9 +846,9 @@ HRESULT QWinRTCameraControl::initialize()
return E_FAIL;
}
- if (d->videoDeviceSelector->cameraPosition(deviceName) == QCamera::FrontFace)
- d->videoRenderer->setScanLineDirection(QVideoSurfaceFormat::BottomToTop);
-
+ const QCamera::Position position = d->videoDeviceSelector->cameraPosition(deviceName);
+ d->videoRenderer->setScanLineDirection(position == QCamera::BackFace ? QVideoSurfaceFormat::TopToBottom
+ : QVideoSurfaceFormat::BottomToTop);
ComPtr<IMediaCaptureInitializationSettings> settings;
hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Media_Capture_MediaCaptureInitializationSettings).Get(),
&settings);
@@ -749,76 +875,96 @@ HRESULT QWinRTCameraControl::initialize()
ComPtr<IVideoDeviceController> videoDeviceController;
hr = d->capture->get_VideoDeviceController(&videoDeviceController);
+ ComPtr<IAdvancedVideoCaptureDeviceController2> advancedVideoDeviceController;
+ hr = videoDeviceController.As(&advancedVideoDeviceController);
Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IMediaDeviceController> deviceController;
- hr = videoDeviceController.As(&deviceController);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IVectorView<IMediaEncodingProperties *>> encodingPropertiesList;
- MediaStreamType mediaStreamType;
- switch (d->captureMode) {
- default:
- case QCamera::CaptureViewfinder:
- mediaStreamType = MediaStreamType_VideoPreview;
- break;
- case QCamera::CaptureStillImage:
- mediaStreamType = MediaStreamType_Photo;
- break;
- case QCamera::CaptureVideo:
- mediaStreamType = MediaStreamType_VideoRecord;
- break;
- }
- hr = deviceController->GetAvailableMediaStreamProperties(mediaStreamType, &encodingPropertiesList);
+ hr = advancedVideoDeviceController->get_FocusControl(&d->focusControl);
Q_ASSERT_SUCCEEDED(hr);
- d->size = QSize();
- quint32 encodingPropertiesListSize;
- hr = encodingPropertiesList->get_Size(&encodingPropertiesListSize);
+ boolean isFocusSupported;
+ hr = d->focusControl->get_Supported(&isFocusSupported);
Q_ASSERT_SUCCEEDED(hr);
- QHash<QSize, ComPtr<IVideoEncodingProperties>> videoEncodingPropertiesList;
- int pixelCount = 0;
- for (quint32 i = 0; i < encodingPropertiesListSize; ++i) {
- ComPtr<IMediaEncodingProperties> properties;
- hr = encodingPropertiesList->GetAt(i, &properties);
+ if (isFocusSupported) {
+ hr = advancedVideoDeviceController->get_RegionsOfInterestControl(&d->regionsOfInterestControl);
Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IVideoEncodingProperties> videoProperties;
- hr = properties.As(&videoProperties);
- Q_ASSERT_SUCCEEDED(hr);
- UINT32 width, height;
- hr = videoProperties->get_Width(&width);
- Q_ASSERT_SUCCEEDED(hr);
- hr = videoProperties->get_Height(&height);
+ hr = initializeFocus();
Q_ASSERT_SUCCEEDED(hr);
- if (d->captureMode != QCamera::CaptureStillImage && int(width * height) > pixelCount) {
- d->size = QSize(width, height);// Choose the Highest-quality format
- pixelCount = d->size.width() * d->size.height();
- }
- videoEncodingPropertiesList.insert(QSize(width, height), videoProperties);
+ } else {
+ d->cameraFocusControl->setSupportedFocusMode(0);
+ d->cameraFocusControl->setSupportedFocusPointMode(QSet<QCameraFocus::FocusPointMode>());
}
+ d->cameraLocksControl->initialize();
- if (videoEncodingPropertiesList.isEmpty()) {
- hr = MF_E_INVALID_FORMAT;
- RETURN_HR_IF_FAILED("Failed to find a suitable video format");
- }
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IMediaDeviceController> deviceController;
+ hr = videoDeviceController.As(&deviceController);
+ Q_ASSERT_SUCCEEDED(hr);
- if (d->captureMode == QCamera::CaptureStillImage) {
- d->imageEncoderControl->setSupportedResolutionsList(videoEncodingPropertiesList.keys());
- d->size = d->imageEncoderControl->imageSettings().resolution();
+ // Get preview stream properties.
+ ComPtr<IVectorView<IMediaEncodingProperties *>> previewPropertiesList;
+ QVector<QSize> previewResolutions;
+ hr = getMediaStreamResolutions(deviceController.Get(),
+ MediaStreamType_VideoPreview,
+ &previewPropertiesList,
+ &previewResolutions);
+ RETURN_HR_IF_FAILED("Failed to find a suitable video format");
+
+ MediaStreamType mediaStreamType =
+ d->captureMode == QCamera::CaptureVideo ? MediaStreamType_VideoRecord : MediaStreamType_Photo;
+
+ // Get capture stream properties.
+ ComPtr<IVectorView<IMediaEncodingProperties *>> capturePropertiesList;
+ QVector<QSize> captureResolutions;
+ hr = getMediaStreamResolutions(deviceController.Get(),
+ mediaStreamType,
+ &capturePropertiesList,
+ &captureResolutions);
+ RETURN_HR_IF_FAILED("Failed to find a suitable video format");
+
+ // Set capture resolutions.
+ d->imageEncoderControl->setSupportedResolutionsList(captureResolutions.toList());
+ const QSize captureResolution = d->imageEncoderControl->imageSettings().resolution();
+ const quint32 captureResolutionIndex = captureResolutions.indexOf(captureResolution);
+ ComPtr<IMediaEncodingProperties> captureProperties;
+ hr = capturePropertiesList->GetAt(captureResolutionIndex, &captureProperties);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = deviceController->SetMediaStreamPropertiesAsync(mediaStreamType, captureProperties.Get(), &op);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = QWinRTFunctions::await(op);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ // Set preview resolution.
+ QVector<QSize> filtered;
+ const float captureAspectRatio = float(captureResolution.width()) / captureResolution.height();
+ foreach (const QSize &resolution, previewResolutions) {
+ const float aspectRatio = float(resolution.width()) / resolution.height();
+ if (qAbs(aspectRatio - captureAspectRatio) <= ASPECTRATIO_EPSILON)
+ filtered.append(resolution);
}
+ qSort(filtered.begin(),
+ filtered.end(),
+ [](QSize size1, QSize size2) { return size1.width() * size1.height() < size2.width() * size2.height(); });
+ const QSize &viewfinderResolution = filtered.first();
+ const quint32 viewfinderResolutionIndex = previewResolutions.indexOf(viewfinderResolution);
hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Media_MediaProperties_MediaEncodingProfile).Get(),
&d->encodingProfile);
Q_ASSERT_SUCCEEDED(hr);
-
- const ComPtr<IVideoEncodingProperties> videoEncodingProperties = videoEncodingPropertiesList[d->size];
- if (!videoEncodingProperties) {
- hr = MF_E_INVALID_FORMAT;
- RETURN_HR_IF_FAILED("Failed to find a suitable video format properties");
- }
-
- hr = d->encodingProfile->put_Video(videoEncodingProperties.Get());
+ ComPtr<IMediaEncodingProperties> previewProperties;
+ hr = previewPropertiesList->GetAt(viewfinderResolutionIndex, &previewProperties);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = deviceController->SetMediaStreamPropertiesAsync(MediaStreamType_VideoPreview, previewProperties.Get(), &op);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = QWinRTFunctions::await(op);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IVideoEncodingProperties> videoPreviewProperties;
+ hr = previewProperties.As(&videoPreviewProperties);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = d->encodingProfile->put_Video(videoPreviewProperties.Get());
Q_ASSERT_SUCCEEDED(hr);
+
if (d->videoRenderer)
- d->videoRenderer->setSize(d->size);
+ d->videoRenderer->setSize(viewfinderResolution);
if (SUCCEEDED(hr) && d->state != QCamera::LoadedState) {
d->state = QCamera::LoadedState;
@@ -831,6 +977,311 @@ HRESULT QWinRTCameraControl::initialize()
return hr;
}
+#ifdef Q_OS_WINPHONE
+
+HRESULT QWinRTCameraControl::initializeFocus()
+{
+ Q_D(QWinRTCameraControl);
+ ComPtr<IFocusControl2> focusControl2;
+ HRESULT hr = d->focusControl.As(&focusControl2);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IVectorView<enum FocusMode>> focusModes;
+ hr = focusControl2->get_SupportedFocusModes(&focusModes);
+ if (FAILED(hr)) {
+ d->cameraFocusControl->setSupportedFocusMode(0);
+ d->cameraFocusControl->setSupportedFocusPointMode(QSet<QCameraFocus::FocusPointMode>());
+ qErrnoWarning(hr, "Failed to get camera supported focus mode list");
+ return hr;
+ }
+ quint32 size;
+ hr = focusModes->get_Size(&size);
+ Q_ASSERT_SUCCEEDED(hr);
+ QCameraFocus::FocusModes supportedModeFlag = 0;
+ for (quint32 i = 0; i < size; ++i) {
+ FocusMode mode;
+ hr = focusModes->GetAt(i, &mode);
+ Q_ASSERT_SUCCEEDED(hr);
+ switch (mode) {
+ case FocusMode_Continuous:
+ supportedModeFlag |= QCameraFocus::ContinuousFocus;
+ break;
+ case FocusMode_Single:
+ supportedModeFlag |= QCameraFocus::AutoFocus;
+ break;
+ default:
+ break;
+ }
+ }
+
+ ComPtr<IVectorView<enum AutoFocusRange>> focusRange;
+ hr = focusControl2->get_SupportedFocusRanges(&focusRange);
+ if (FAILED(hr)) {
+ qErrnoWarning(hr, "Failed to get camera supported focus range list");
+ } else {
+ hr = focusRange->get_Size(&size);
+ Q_ASSERT_SUCCEEDED(hr);
+ for (quint32 i = 0; i < size; ++i) {
+ AutoFocusRange range;
+ hr = focusRange->GetAt(i, &range);
+ Q_ASSERT_SUCCEEDED(hr);
+ switch (range) {
+ case AutoFocusRange_Macro:
+ supportedModeFlag |= QCameraFocus::MacroFocus;
+ break;
+ case AutoFocusRange_FullRange:
+ supportedModeFlag |= QCameraFocus::InfinityFocus;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ d->cameraFocusControl->setSupportedFocusMode(supportedModeFlag);
+ if (!d->regionsOfInterestControl) {
+ d->cameraFocusControl->setSupportedFocusPointMode(QSet<QCameraFocus::FocusPointMode>());
+ return S_OK;
+ }
+ boolean isRegionsfocusSupported = false;
+ hr = d->regionsOfInterestControl->get_AutoFocusSupported(&isRegionsfocusSupported);
+ Q_ASSERT_SUCCEEDED(hr);
+ UINT32 maxRegions;
+ hr = d->regionsOfInterestControl->get_MaxRegions(&maxRegions);
+ Q_ASSERT_SUCCEEDED(hr);
+ if (!isRegionsfocusSupported || maxRegions == 0) {
+ d->cameraFocusControl->setSupportedFocusPointMode(QSet<QCameraFocus::FocusPointMode>());
+ return S_OK;
+ }
+ QSet<QCameraFocus::FocusPointMode> supportedFocusPointModes;
+ supportedFocusPointModes << QCameraFocus::FocusPointCustom
+ << QCameraFocus::FocusPointCenter
+ << QCameraFocus::FocusPointAuto;
+ d->cameraFocusControl->setSupportedFocusPointMode(supportedFocusPointModes);
+ return S_OK;
+}
+
+bool QWinRTCameraControl::setFocus(QCameraFocus::FocusModes modes)
+{
+ Q_D(QWinRTCameraControl);
+ if (d->status == QCamera::UnloadedStatus)
+ return false;
+
+ ComPtr<IFocusSettings> focusSettings;
+ ComPtr<IInspectable> focusSettingsObject;
+ HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Media_Devices_FocusSettings).Get(), &focusSettingsObject);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = focusSettingsObject.As(&focusSettings);
+ Q_ASSERT_SUCCEEDED(hr);
+ FocusMode mode;
+ if (modes.testFlag(QCameraFocus::ContinuousFocus)) {
+ mode = FocusMode_Continuous;
+ } else if (modes.testFlag(QCameraFocus::AutoFocus)
+ || modes.testFlag(QCameraFocus::MacroFocus)
+ || modes.testFlag(QCameraFocus::InfinityFocus)) {
+ // The Macro and infinity focus modes are only supported in auto focus mode on WinRT.
+ // QML camera focus doesn't support combined focus flags settings. In the case of macro
+ // and infinity Focus modes, the auto focus setting is applied.
+ mode = FocusMode_Single;
+ } else {
+ emit error(QCamera::NotSupportedFeatureError, QStringLiteral("Unsupported camera focus modes."));
+ return false;
+ }
+ hr = focusSettings->put_Mode(mode);
+ Q_ASSERT_SUCCEEDED(hr);
+ AutoFocusRange range = AutoFocusRange_Normal;
+ if (modes.testFlag(QCameraFocus::MacroFocus))
+ range = AutoFocusRange_Macro;
+ else if (modes.testFlag(QCameraFocus::InfinityFocus))
+ range = AutoFocusRange_FullRange;
+ hr = focusSettings->put_AutoFocusRange(range);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = focusSettings->put_WaitForFocus(true);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = focusSettings->put_DisableDriverFallback(false);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IFocusControl2> focusControl2;
+ hr = d->focusControl.As(&focusControl2);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = focusControl2->Configure(focusSettings.Get());
+ RETURN_FALSE_IF_FAILED("Failed to configure camera focus control");
+ return true;
+}
+
+bool QWinRTCameraControl::setFocusPoint(const QPointF &focusPoint)
+{
+ Q_D(QWinRTCameraControl);
+ if (focusPoint.x() < FOCUS_RECT_POSITION_MIN || focusPoint.x() > FOCUS_RECT_BOUNDARY) {
+ emit error(QCamera::CameraError, QStringLiteral("Focus horizontal location should be between 0.0 and 1.0."));
+ return false;
+ }
+
+ if (focusPoint.y() < FOCUS_RECT_POSITION_MIN || focusPoint.y() > FOCUS_RECT_BOUNDARY) {
+ emit error(QCamera::CameraError, QStringLiteral("Focus vertical location should be between 0.0 and 1.0."));
+ return false;
+ }
+
+ ABI::Windows::Foundation::Rect rect;
+ rect.X = qBound<float>(FOCUS_RECT_POSITION_MIN, focusPoint.x() - FOCUS_RECT_HALF_SIZE, FOCUS_RECT_POSITION_MAX);
+ rect.Y = qBound<float>(FOCUS_RECT_POSITION_MIN, focusPoint.y() - FOCUS_RECT_HALF_SIZE, FOCUS_RECT_POSITION_MAX);
+ rect.Width = (rect.X + FOCUS_RECT_SIZE) < FOCUS_RECT_BOUNDARY ? FOCUS_RECT_SIZE : FOCUS_RECT_BOUNDARY - rect.X;
+ rect.Height = (rect.Y + FOCUS_RECT_SIZE) < FOCUS_RECT_BOUNDARY ? FOCUS_RECT_SIZE : FOCUS_RECT_BOUNDARY - rect.Y;
+
+ ComPtr<IRegionOfInterest> regionOfInterest;
+ ComPtr<IInspectable> regionOfInterestObject;
+ HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Media_Devices_RegionOfInterest).Get(), &regionOfInterestObject);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = regionOfInterestObject.As(&regionOfInterest);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IRegionOfInterest2> regionOfInterest2;
+ hr = regionOfInterestObject.As(&regionOfInterest2);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = regionOfInterest2->put_BoundsNormalized(true);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = regionOfInterest2->put_Weight(1);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = regionOfInterest2->put_Type(RegionOfInterestType_Unknown);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = regionOfInterest->put_AutoFocusEnabled(true);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = regionOfInterest->put_Bounds(rect);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<WindowsRegionOfInterestIterable> regionOfInterestIterable = Make<WindowsRegionOfInterestIterable>(regionOfInterest);
+ ComPtr<IAsyncAction> op;
+ hr = d->regionsOfInterestControl->SetRegionsAsync(regionOfInterestIterable.Get(), &op);
+ Q_ASSERT_SUCCEEDED(hr);
+ return QWinRTFunctions::await(op) == S_OK;
+}
+
+bool QWinRTCameraControl::focus()
+{
+ Q_D(QWinRTCameraControl);
+ HRESULT hr;
+ AsyncStatus status = AsyncStatus::Completed;
+ if (d->focusOperation) {
+ ComPtr<IAsyncInfo> info;
+ hr = d->focusOperation.As(&info);
+ Q_ASSERT_SUCCEEDED(hr);
+ info->get_Status(&status);
+ }
+
+ if (!d->focusControl || status == AsyncStatus::Started)
+ return false;
+
+ hr = d->focusControl->FocusAsync(&d->focusOperation);
+ const long errorCode = HRESULT_CODE(hr);
+ if (errorCode == ERROR_OPERATION_IN_PROGRESS
+ || errorCode == ERROR_WRITE_PROTECT) {
+ return false;
+ }
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = QWinRTFunctions::await(d->focusOperation, QWinRTFunctions::ProcessThreadEvents);
+ Q_ASSERT_SUCCEEDED(hr);
+ return hr == S_OK;
+}
+
+void QWinRTCameraControl::clearFocusPoint()
+{
+ Q_D(QWinRTCameraControl);
+ if (!d->focusControl)
+ return;
+ ComPtr<IAsyncAction> op;
+ HRESULT hr = d->regionsOfInterestControl->ClearRegionsAsync(&op);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = QWinRTFunctions::await(op);
+ Q_ASSERT_SUCCEEDED(hr);
+}
+
+bool QWinRTCameraControl::lockFocus()
+{
+ Q_D(QWinRTCameraControl);
+ if (!d->focusControl)
+ return false;
+ ComPtr<IFocusControl2> focusControl2;
+ HRESULT hr = d->focusControl.As(&focusControl2);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IAsyncAction> op;
+ hr = focusControl2->LockAsync(&op);
+ if (HRESULT_CODE(hr) == ERROR_WRITE_PROTECT)
+ return false;
+ Q_ASSERT_SUCCEEDED(hr);
+ return QWinRTFunctions::await(op) == S_OK;
+}
+
+bool QWinRTCameraControl::unlockFocus()
+{
+ Q_D(QWinRTCameraControl);
+ if (!d->focusControl)
+ return false;
+ ComPtr<IFocusControl2> focusControl2;
+ HRESULT hr = d->focusControl.As(&focusControl2);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IAsyncAction> op;
+ hr = focusControl2->UnlockAsync(&op);
+ if (HRESULT_CODE(hr) == ERROR_WRITE_PROTECT)
+ return false;
+ Q_ASSERT_SUCCEEDED(hr);
+ return QWinRTFunctions::await(op) == S_OK;
+}
+
+#else // Q_OS_WINPHONE
+
+HRESULT QWinRTCameraControl::initializeFocus()
+{
+ Q_D(QWinRTCameraControl);
+ d->cameraFocusControl->setSupportedFocusMode(0);
+ d->cameraFocusControl->setSupportedFocusPointMode(QSet<QCameraFocus::FocusPointMode>());
+ return S_OK;
+}
+
+bool QWinRTCameraControl::setFocus(QCameraFocus::FocusModes modes)
+{
+ Q_UNUSED(modes)
+ return false;
+}
+
+bool QWinRTCameraControl::setFocusPoint(const QPointF &focusPoint)
+{
+ Q_UNUSED(focusPoint)
+ return false;
+}
+
+bool QWinRTCameraControl::focus()
+{
+ return false;
+}
+
+void QWinRTCameraControl::clearFocusPoint()
+{
+}
+
+bool QWinRTCameraControl::lockFocus()
+{
+ return false;
+}
+
+bool QWinRTCameraControl::unlockFocus()
+{
+ return false;
+}
+
+#endif // !Q_OS_WINPHONE
+
+void QWinRTCameraControl::frameMapped()
+{
+ Q_D(QWinRTCameraControl);
+ ++d->framesMapped;
+}
+
+void QWinRTCameraControl::frameUnmapped()
+{
+ Q_D(QWinRTCameraControl);
+ --d->framesMapped;
+ Q_ASSERT(d->framesMapped >= 0);
+ if (!d->framesMapped && d->delayClose && d->delayClose->isRunning())
+ d->delayClose->exit();
+}
+
HRESULT QWinRTCameraControl::onCaptureFailed(IMediaCapture *, IMediaCaptureFailedEventArgs *args)
{
HRESULT hr;
@@ -854,4 +1305,9 @@ HRESULT QWinRTCameraControl::onRecordLimitationExceeded(IMediaCapture *)
return S_OK;
}
+void QWinRTCameraControl::emitError(int errorCode, const QString &errorString)
+{
+ emit error(errorCode, errorString);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/winrt/qwinrtcameracontrol.h b/src/plugins/winrt/qwinrtcameracontrol.h
index 307667eb1..b3c86adf9 100644
--- a/src/plugins/winrt/qwinrtcameracontrol.h
+++ b/src/plugins/winrt/qwinrtcameracontrol.h
@@ -61,6 +61,8 @@ class QVideoRendererControl;
class QVideoDeviceSelectorControl;
class QCameraImageCaptureControl;
class QImageEncoderControl;
+class QCameraFocusControl;
+class QCameraLocksControl;
class QWinRTCameraControlPrivate;
class QWinRTCameraControl : public QCameraControl
@@ -85,15 +87,29 @@ public:
QVideoDeviceSelectorControl *videoDeviceSelector() const;
QCameraImageCaptureControl *imageCaptureControl() const;
QImageEncoderControl *imageEncoderControl() const;
+ QCameraFocusControl *cameraFocusControl() const;
+ QCameraLocksControl *cameraLocksControl() const;
ABI::Windows::Media::Capture::IMediaCapture *handle() const;
+ bool setFocus(QCameraFocus::FocusModes mode);
+ bool setFocusPoint(const QPointF &point);
+ bool focus();
+ void clearFocusPoint();
+ void emitError(int errorCode, const QString &errorString);
+ bool lockFocus();
+ bool unlockFocus();
+ void frameMapped();
+ void frameUnmapped();
+
private slots:
void onBufferRequested();
+ void onApplicationStateChanged(Qt::ApplicationState state);
private:
HRESULT enumerateDevices();
HRESULT initialize();
+ HRESULT initializeFocus();
HRESULT onCaptureFailed(ABI::Windows::Media::Capture::IMediaCapture *,
ABI::Windows::Media::Capture::IMediaCaptureFailedEventArgs *);
HRESULT onRecordLimitationExceeded(ABI::Windows::Media::Capture::IMediaCapture *);
diff --git a/src/plugins/winrt/qwinrtcamerafocuscontrol.cpp b/src/plugins/winrt/qwinrtcamerafocuscontrol.cpp
new file mode 100644
index 000000000..7eda823dd
--- /dev/null
+++ b/src/plugins/winrt/qwinrtcamerafocuscontrol.cpp
@@ -0,0 +1,273 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwinrtcamerafocuscontrol.h"
+#include "qwinrtcameraimagecapturecontrol.h"
+#include "qwinrtcameracontrol.h"
+
+QT_BEGIN_NAMESPACE
+
+class QWinRTCameraFocusControlPrivate
+{
+public:
+ QCameraFocus::FocusModes focusModes;
+ QCameraFocus::FocusModes supportedFocusModes;
+ QCameraFocus::FocusPointMode focusPointMode;
+ QSet<QCameraFocus::FocusPointMode> supportedFocusPointModes;
+ QPointF focusPoint;
+ bool focusModeInitialized;
+ bool focusPointModeInitialized;
+ bool imageCaptureIdle;
+};
+
+QWinRTCameraFocusControl::QWinRTCameraFocusControl(QWinRTCameraControl *parent)
+ : QCameraFocusControl(parent), d_ptr(new QWinRTCameraFocusControlPrivate)
+{
+ Q_D(QWinRTCameraFocusControl);
+ d->focusModeInitialized = false;
+ d->focusPointModeInitialized = false;
+ d->focusModes = QCameraFocus::ContinuousFocus;
+ d->focusPointMode = QCameraFocus::FocusPointAuto;
+ d->imageCaptureIdle = true;
+ QWinRTCameraImageCaptureControl *imageCaptureControl = static_cast<QWinRTCameraImageCaptureControl *>(parent->imageCaptureControl());
+ Q_ASSERT(imageCaptureControl);
+ connect(imageCaptureControl, &QWinRTCameraImageCaptureControl::captureQueueChanged,
+ this, &QWinRTCameraFocusControl::imageCaptureQueueChanged, Qt::QueuedConnection);
+}
+
+QCameraFocus::FocusModes QWinRTCameraFocusControl::focusMode() const
+{
+ Q_D(const QWinRTCameraFocusControl);
+ return d->focusModes;
+}
+
+void QWinRTCameraFocusControl::setFocusMode(QCameraFocus::FocusModes modes)
+{
+ QMetaObject::invokeMethod(this, "applyFocusMode", Qt::QueuedConnection, Q_ARG(QCameraFocus::FocusModes, modes));
+}
+
+bool QWinRTCameraFocusControl::isFocusModeSupported(QCameraFocus::FocusModes modes) const
+{
+ Q_D(const QWinRTCameraFocusControl);
+ return (d->focusModeInitialized && modes) ? !((d->supportedFocusModes & modes) ^ modes) : false;
+}
+
+QCameraFocus::FocusPointMode QWinRTCameraFocusControl::focusPointMode() const
+{
+ Q_D(const QWinRTCameraFocusControl);
+ return d->focusPointMode;
+}
+
+void QWinRTCameraFocusControl::setFocusPointMode(QCameraFocus::FocusPointMode mode)
+{
+ QMetaObject::invokeMethod(this, "applyFocusPointMode", Qt::QueuedConnection, Q_ARG(QCameraFocus::FocusPointMode, mode));
+}
+
+bool QWinRTCameraFocusControl::isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const
+{
+ Q_D(const QWinRTCameraFocusControl);
+ return d->supportedFocusPointModes.contains(mode);
+}
+
+QPointF QWinRTCameraFocusControl::customFocusPoint() const
+{
+ Q_D(const QWinRTCameraFocusControl);
+ return d->focusPoint;
+}
+
+void QWinRTCameraFocusControl::setCustomFocusPoint(const QPointF &point)
+{
+ QMetaObject::invokeMethod(this, "applyFocusCustomPoint", Qt::QueuedConnection, Q_ARG(const QPointF, point));
+}
+
+QCameraFocusZoneList QWinRTCameraFocusControl::focusZones() const
+{
+ return QCameraFocusZoneList();
+}
+
+void QWinRTCameraFocusControl::setSupportedFocusMode(QCameraFocus::FocusModes modes)
+{
+ Q_D(QWinRTCameraFocusControl);
+ d->supportedFocusModes = modes;
+ d->focusModeInitialized = true;
+ if (isFocusModeSupported(d->focusModes))
+ return;
+ d->focusModes = 0;
+ if (!modes) {
+ emit focusModeChanged(d->focusModes);
+ return;
+ }
+ if (isFocusModeSupported(QCameraFocus::ContinuousFocus))
+ d->focusModes = QCameraFocus::ContinuousFocus;
+ else if (isFocusModeSupported(QCameraFocus::AutoFocus))
+ d->focusModes = QCameraFocus::AutoFocus;
+ else if (isFocusModeSupported(QCameraFocus::ManualFocus))
+ d->focusModes = QCameraFocus::ManualFocus;
+ emit focusModeChanged(d->focusModes);
+}
+
+void QWinRTCameraFocusControl::setSupportedFocusPointMode(const QSet<QCameraFocus::FocusPointMode> &supportedFocusPointModes)
+{
+ Q_D(QWinRTCameraFocusControl);
+ d->supportedFocusPointModes = supportedFocusPointModes;
+ d->focusPointModeInitialized = true;
+
+ if (supportedFocusPointModes.isEmpty()) {
+ if (d->focusPointMode != QCameraFocus::FocusPointAuto) {
+ d->focusPointMode = QCameraFocus::FocusPointAuto;
+ emit focusPointModeChanged(d->focusPointMode);
+ }
+ return;
+ }
+
+ if (isFocusPointModeSupported(d->focusPointMode))
+ return;
+
+ if (isFocusPointModeSupported(QCameraFocus::FocusPointCenter))
+ d->focusPointMode = QCameraFocus::FocusPointCenter;
+ else if (isFocusPointModeSupported(QCameraFocus::FocusPointAuto))
+ d->focusPointMode = QCameraFocus::FocusPointAuto;
+ else if (isFocusPointModeSupported(QCameraFocus::FocusPointCustom))
+ d->focusPointMode = QCameraFocus::FocusPointCustom;
+ else if (isFocusPointModeSupported(QCameraFocus::FocusPointFaceDetection))
+ d->focusPointMode = QCameraFocus::FocusPointFaceDetection;
+ emit focusPointModeChanged(d->focusPointMode);
+}
+
+void QWinRTCameraFocusControl::imageCaptureQueueChanged(bool isEmpty)
+{
+ Q_D(QWinRTCameraFocusControl);
+ d->imageCaptureIdle = isEmpty;
+}
+
+void QWinRTCameraFocusControl::applyFocusCustomPoint(const QPointF &point)
+{
+ Q_D(QWinRTCameraFocusControl);
+ if (d->focusPointMode != QCameraFocus::FocusPointCustom) {
+ QWinRTCameraControl *cameraControl = static_cast<QWinRTCameraControl *>(parent());
+ Q_ASSERT(cameraControl);
+ cameraControl->emitError(QCamera::InvalidRequestError, QStringLiteral("Custom focus point can be set only in FocusPointCustom focus mode."));
+ return;
+ }
+ if (d->focusPoint == point)
+ return;
+ if (changeFocusCustomPoint(point)) {
+ d->focusPoint = point;
+ emit customFocusPointChanged(point);
+ }
+}
+
+void QWinRTCameraFocusControl::applyFocusMode(QCameraFocus::FocusModes modes)
+{
+ Q_D(QWinRTCameraFocusControl);
+ if (d->focusModes == modes)
+ return;
+ QWinRTCameraControl *cameraControl = static_cast<QWinRTCameraControl *>(parent());
+ Q_ASSERT(cameraControl);
+ if (!modes) {
+ cameraControl->emitError(QCamera::InvalidRequestError, QStringLiteral("Can't set empty camera focus modes."));
+ return;
+ }
+ if (!d->focusModeInitialized) {
+ d->focusModes = modes;
+ emit focusModeChanged(modes);
+ return;
+ }
+ if (!isFocusModeSupported(modes)) {
+ cameraControl->emitError(QCamera::NotSupportedFeatureError, QStringLiteral("Unsupported camera focus modes."));
+ return;
+ }
+ if (modes.testFlag(QCameraFocus::ContinuousFocus)) {
+ if (QCameraFocus::FocusPointCustom == d->focusPointMode) {
+ cameraControl->emitError(QCamera::NotSupportedFeatureError,
+ QStringLiteral("Unsupported camera focus modes: ContinuousFocus with FocusPointCustom."));
+ return;
+ } else if (!d->imageCaptureIdle) {
+ cameraControl->emitError(QCamera::NotSupportedFeatureError,
+ QStringLiteral("Can't set ContinuousFocus camera focus mode while capturing image."));
+ return;
+ }
+ }
+ if (!cameraControl->setFocus(modes))
+ return;
+ if (modes.testFlag(QCameraFocus::ContinuousFocus) || d->focusModes.testFlag(QCameraFocus::ContinuousFocus))
+ cameraControl->focus();
+ d->focusModes = modes;
+ emit focusModeChanged(modes);
+}
+
+void QWinRTCameraFocusControl::applyFocusPointMode(QCameraFocus::FocusPointMode mode)
+{
+ Q_D(QWinRTCameraFocusControl);
+ if (d->focusPointMode == mode)
+ return;
+
+ if (!d->focusModeInitialized) {
+ d->focusPointMode = mode;
+ emit focusPointModeChanged(mode);
+ return;
+ }
+ QWinRTCameraControl *cameraControl = static_cast<QWinRTCameraControl *>(parent());
+ Q_ASSERT(cameraControl);
+ if (!d->supportedFocusPointModes.contains(mode)) {
+ cameraControl->emitError(QCamera::NotSupportedFeatureError, QStringLiteral("Unsupported camera point focus mode."));
+ return;
+ }
+ if (QCameraFocus::FocusPointCenter == mode || QCameraFocus::FocusPointAuto == mode)
+ d->focusPoint = QPointF(0.5, 0.5);
+ // Don't apply focus point focus settings if camera is in continuous focus mode
+ if (!d->focusModes.testFlag(QCameraFocus::ContinuousFocus)) {
+ changeFocusCustomPoint(d->focusPoint);
+ } else if (QCameraFocus::FocusPointCustom == mode) {
+ cameraControl->emitError(QCamera::NotSupportedFeatureError, QStringLiteral("Unsupported camera focus modes: ContinuousFocus with FocusPointCustom."));
+ return;
+ }
+ d->focusPointMode = mode;
+ emit focusPointModeChanged(mode);
+}
+
+bool QWinRTCameraFocusControl::changeFocusCustomPoint(const QPointF &point)
+{
+ Q_D(QWinRTCameraFocusControl);
+ if (!d->focusPointModeInitialized || point.isNull())
+ return true;
+ QWinRTCameraControl *cameraControl = static_cast<QWinRTCameraControl *>(parent());
+ Q_ASSERT(cameraControl);
+ cameraControl->clearFocusPoint();
+ return cameraControl->setFocusPoint(point);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/winrt/qwinrtcamerafocuscontrol.h b/src/plugins/winrt/qwinrtcamerafocuscontrol.h
new file mode 100644
index 000000000..4862c0115
--- /dev/null
+++ b/src/plugins/winrt/qwinrtcamerafocuscontrol.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTCAMERAFOCUSCONTROL_H
+#define QWINRTCAMERAFOCUSCONTROL_H
+#include <qcamerafocuscontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWinRTCameraControl;
+class QWinRTCameraFocusControlPrivate;
+class QWinRTCameraFocusControl : public QCameraFocusControl
+{
+ Q_OBJECT
+public:
+ explicit QWinRTCameraFocusControl(QWinRTCameraControl *parent);
+
+ QCameraFocus::FocusModes focusMode() const Q_DECL_OVERRIDE;
+ void setFocusMode(QCameraFocus::FocusModes mode) Q_DECL_OVERRIDE;
+ bool isFocusModeSupported(QCameraFocus::FocusModes mode) const Q_DECL_OVERRIDE;
+ QCameraFocus::FocusPointMode focusPointMode() const Q_DECL_OVERRIDE;
+ void setFocusPointMode(QCameraFocus::FocusPointMode mode) Q_DECL_OVERRIDE;
+ bool isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const Q_DECL_OVERRIDE;
+ QPointF customFocusPoint() const Q_DECL_OVERRIDE;
+ void setCustomFocusPoint(const QPointF &point) Q_DECL_OVERRIDE;
+ QCameraFocusZoneList focusZones() const Q_DECL_OVERRIDE;
+
+ void setSupportedFocusMode(QCameraFocus::FocusModes flag);
+ void setSupportedFocusPointMode(const QSet<QCameraFocus::FocusPointMode> &supportedFocusPointModes);
+
+private slots:
+ void imageCaptureQueueChanged(bool isEmpty);
+
+private:
+ Q_INVOKABLE void applyFocusCustomPoint(const QPointF &point);
+ Q_INVOKABLE void applyFocusMode(QCameraFocus::FocusModes modes);
+ Q_INVOKABLE void applyFocusPointMode(QCameraFocus::FocusPointMode mode);
+ bool changeFocusCustomPoint(const QPointF &point);
+
+ QScopedPointer<QWinRTCameraFocusControlPrivate> d_ptr;
+ Q_DECLARE_PRIVATE(QWinRTCameraFocusControl)
+};
+
+#endif // QWINRTCAMERAFOCUSCONTROL_H
diff --git a/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp b/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp
index 55f553778..ae67e33f4 100644
--- a/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp
+++ b/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp
@@ -179,6 +179,7 @@ int QWinRTCameraImageCaptureControl::capture(const QString &fileName)
qErrnoWarning("Camera photo capture failed.");
return -1;
}
+ emit captureQueueChanged(false);
d->requests.insert(request.op.Get(), request);
hr = request.op->put_Completed(Callback<IAsyncActionCompletedHandler>(
@@ -199,6 +200,7 @@ void QWinRTCameraImageCaptureControl::cancelCapture()
info->Cancel();
it = d->requests.erase(it);
}
+ emit captureQueueChanged(true);
}
HRESULT QWinRTCameraImageCaptureControl::onCaptureCompleted(IAsyncAction *asyncInfo, AsyncStatus status)
@@ -209,7 +211,7 @@ HRESULT QWinRTCameraImageCaptureControl::onCaptureCompleted(IAsyncAction *asyncI
return S_OK;
CaptureRequest request = d->requests.take(asyncInfo);
-
+ emit captureQueueChanged(d->requests.isEmpty());
HRESULT hr;
if (status == Error) {
hr = asyncInfo->GetResults();
diff --git a/src/plugins/winrt/qwinrtcameraimagecapturecontrol.h b/src/plugins/winrt/qwinrtcameraimagecapturecontrol.h
index dc8802552..1fbdccf6b 100644
--- a/src/plugins/winrt/qwinrtcameraimagecapturecontrol.h
+++ b/src/plugins/winrt/qwinrtcameraimagecapturecontrol.h
@@ -68,6 +68,9 @@ public:
int capture(const QString &fileName) Q_DECL_OVERRIDE;
void cancelCapture() Q_DECL_OVERRIDE;
+signals:
+ void captureQueueChanged(bool isEmpty);
+
private:
HRESULT onCaptureCompleted(ABI::Windows::Foundation::IAsyncAction *,
ABI::Windows::Foundation::AsyncStatus);
diff --git a/src/plugins/winrt/qwinrtcameralockscontrol.cpp b/src/plugins/winrt/qwinrtcameralockscontrol.cpp
new file mode 100644
index 000000000..8528d16fb
--- /dev/null
+++ b/src/plugins/winrt/qwinrtcameralockscontrol.cpp
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QCameraFocusControl>
+
+#include "qwinrtcameralockscontrol.h"
+#include "qwinrtcameracontrol.h"
+
+QT_BEGIN_NAMESPACE
+
+QWinRTCameraLocksControl::QWinRTCameraLocksControl(QObject *parent)
+ : QCameraLocksControl(parent)
+ , m_supportedLocks(QCamera::NoLock)
+ , m_focusLockStatus(QCamera::Unlocked)
+{
+}
+
+QCamera::LockTypes QWinRTCameraLocksControl::supportedLocks() const
+{
+ return m_supportedLocks;
+}
+
+QCamera::LockStatus QWinRTCameraLocksControl::lockStatus(QCamera::LockType lock) const
+{
+ switch (lock) {
+ case QCamera::LockFocus:
+ return m_focusLockStatus;
+ case QCamera::LockExposure:
+ case QCamera::LockWhiteBalance:
+ default:
+ return QCamera::Unlocked;
+ }
+}
+
+void QWinRTCameraLocksControl::searchAndLock(QCamera::LockTypes locks)
+{
+ QWinRTCameraControl *cameraControl = qobject_cast<QWinRTCameraControl *>(parent());
+ Q_ASSERT(cameraControl);
+ if (cameraControl->state() != QCamera::ActiveState)
+ return;
+ else if (locks.testFlag(QCamera::LockFocus))
+ QMetaObject::invokeMethod(this, "searchAndLockFocus", Qt::QueuedConnection);
+ else
+ cameraControl->emitError(QCamera::InvalidRequestError, QStringLiteral("Unsupported camera lock type."));
+}
+
+void QWinRTCameraLocksControl::unlock(QCamera::LockTypes locks)
+{
+ if (locks.testFlag(QCamera::LockFocus))
+ QMetaObject::invokeMethod(this, "unlockFocus", Qt::QueuedConnection);
+}
+
+void QWinRTCameraLocksControl::initialize()
+{
+ QWinRTCameraControl *cameraControl = qobject_cast<QWinRTCameraControl *>(parent());
+ Q_ASSERT(cameraControl);
+ QCameraFocusControl *focusControl = cameraControl->cameraFocusControl();
+ Q_ASSERT(focusControl);
+ if (focusControl->isFocusModeSupported(QCameraFocus::AutoFocus))
+ m_supportedLocks |= QCamera::LockFocus;
+}
+
+void QWinRTCameraLocksControl::searchAndLockFocus()
+{
+ if (QCamera::Locked == m_focusLockStatus)
+ unlockFocus();
+ QWinRTCameraControl *cameraControl = qobject_cast<QWinRTCameraControl *>(parent());
+ Q_ASSERT(cameraControl);
+ QCameraFocusControl *focusControl = cameraControl->cameraFocusControl();
+ Q_ASSERT(focusControl);
+ if (focusControl->focusMode().testFlag(QCameraFocus::ContinuousFocus)) {
+ cameraControl->emitError(QCamera::NotSupportedFeatureError, QStringLiteral("Camera can't lock focus in continuous focus mode."));
+ } else {
+ m_focusLockStatus = QCamera::Searching;
+ emit lockStatusChanged(QCamera::LockFocus, m_focusLockStatus, QCamera::LockAcquired);
+ if (cameraControl->focus()) {
+ m_focusLockStatus = cameraControl->lockFocus() ? QCamera::Locked : QCamera::Unlocked;
+ emit lockStatusChanged(QCamera::LockFocus, m_focusLockStatus, QCamera::LockAcquired);
+ }
+ }
+}
+
+void QWinRTCameraLocksControl::unlockFocus()
+{
+ if (QCamera::Unlocked == m_focusLockStatus)
+ return;
+ QWinRTCameraControl *cameraControl = qobject_cast<QWinRTCameraControl *>(parent());
+ Q_ASSERT(cameraControl);
+ m_focusLockStatus = cameraControl->unlockFocus() ? QCamera::Unlocked : QCamera::Locked;
+ emit lockStatusChanged(QCamera::LockFocus, m_focusLockStatus, QCamera::UserRequest);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/winrt/qwinrtcameralockscontrol.h b/src/plugins/winrt/qwinrtcameralockscontrol.h
new file mode 100644
index 000000000..5a7b57c11
--- /dev/null
+++ b/src/plugins/winrt/qwinrtcameralockscontrol.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINRTCAMERALOCKSCONTROL_H
+#define QWINRTCAMERALOCKSCONTROL_H
+
+#include <QCameraLocksControl>
+
+QT_BEGIN_NAMESPACE
+
+class QWinRTCameraControl;
+class QWinRTCameraLocksControl : public QCameraLocksControl
+{
+ Q_OBJECT
+public:
+ explicit QWinRTCameraLocksControl(QObject *parent);
+
+ QCamera::LockTypes supportedLocks() const Q_DECL_OVERRIDE;
+ QCamera::LockStatus lockStatus(QCamera::LockType lock) const Q_DECL_OVERRIDE;
+ void searchAndLock(QCamera::LockTypes locks) Q_DECL_OVERRIDE;
+ void unlock(QCamera::LockTypes locks) Q_DECL_OVERRIDE;
+ void initialize();
+
+private:
+ Q_INVOKABLE void searchAndLockFocus();
+ Q_INVOKABLE void unlockFocus();
+ QCamera::LockTypes m_supportedLocks;
+ QCamera::LockStatus m_focusLockStatus;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINRTCAMERALOCKSCONTROL_H
diff --git a/src/plugins/winrt/qwinrtcameraservice.cpp b/src/plugins/winrt/qwinrtcameraservice.cpp
index be67b4742..977acdcab 100644
--- a/src/plugins/winrt/qwinrtcameraservice.cpp
+++ b/src/plugins/winrt/qwinrtcameraservice.cpp
@@ -37,6 +37,8 @@
#include "qwinrtcameraservice.h"
#include "qwinrtcameracontrol.h"
#include "qwinrtcamerainfocontrol.h"
+#include "qwinrtvideoprobecontrol.h"
+#include "qwinrtcameravideorenderercontrol.h"
#include <QtCore/QCoreApplication>
#include <QtCore/qfunctions_winrt.h>
@@ -45,6 +47,9 @@
#include <QtMultimedia/QVideoRendererControl>
#include <QtMultimedia/QVideoDeviceSelectorControl>
#include <QtMultimedia/QImageEncoderControl>
+#include <QtMultimedia/QCameraFocusControl>
+#include <QtMultimedia/QCameraLocksControl>
+#include <QtMultimedia/QMediaVideoProbeControl>
QT_BEGIN_NAMESPACE
@@ -69,39 +74,44 @@ QMediaControl *QWinRTCameraService::requestControl(const char *name)
d->cameraControl = new QWinRTCameraControl(this);
return d->cameraControl;
}
-
- if (qstrcmp(name, QVideoRendererControl_iid) == 0) {
- if (d->cameraControl)
- return d->cameraControl->videoRenderer();
- }
-
- if (qstrcmp(name, QVideoDeviceSelectorControl_iid) == 0) {
- if (d->cameraControl)
- return d->cameraControl->videoDeviceSelector();
- }
-
if (qstrcmp(name, QCameraInfoControl_iid) == 0) {
if (!d->cameraInfoControl)
d->cameraInfoControl = new QWinRTCameraInfoControl(this);
return d->cameraInfoControl;
}
- if (qstrcmp(name, QCameraImageCaptureControl_iid) == 0) {
- if (d->cameraControl)
- return d->cameraControl->imageCaptureControl();
- }
+ if (!d->cameraControl)
+ return nullptr;
- if (qstrcmp(name, QImageEncoderControl_iid) == 0) {
- if (d->cameraControl)
- return d->cameraControl->imageEncoderControl();
- }
+ if (qstrcmp(name, QVideoRendererControl_iid) == 0)
+ return d->cameraControl->videoRenderer();
+
+ if (qstrcmp(name, QVideoDeviceSelectorControl_iid) == 0)
+ return d->cameraControl->videoDeviceSelector();
+
+ if (qstrcmp(name, QCameraImageCaptureControl_iid) == 0)
+ return d->cameraControl->imageCaptureControl();
+
+ if (qstrcmp(name, QImageEncoderControl_iid) == 0)
+ return d->cameraControl->imageEncoderControl();
+
+ if (qstrcmp(name, QCameraFocusControl_iid) == 0)
+ return d->cameraControl->cameraFocusControl();
+
+ if (qstrcmp(name, QCameraLocksControl_iid) == 0)
+ return d->cameraControl->cameraLocksControl();
+
+ if (qstrcmp(name, QMediaVideoProbeControl_iid) == 0)
+ return new QWinRTVideoProbeControl(qobject_cast<QWinRTCameraVideoRendererControl *>(d->cameraControl->videoRenderer()));
- return Q_NULLPTR;
+ return nullptr;
}
void QWinRTCameraService::releaseControl(QMediaControl *control)
{
- Q_UNUSED(control);
+ Q_ASSERT(control);
+ if (QWinRTVideoProbeControl *videoProbe = qobject_cast<QWinRTVideoProbeControl *>(control))
+ videoProbe->deleteLater();
}
QT_END_NAMESPACE
diff --git a/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp b/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp
index 4878c55c9..fe07581c9 100644
--- a/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp
+++ b/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp
@@ -38,30 +38,106 @@
#include <QtCore/qfunctions_winrt.h>
#include <QtCore/QSize>
+#include <QtCore/QPointer>
#include <QtCore/QVector>
+#include <QVideoFrame>
#include <d3d11.h>
#include <mfapi.h>
#include <wrl.h>
+
+#include "qwinrtcameracontrol.h"
+
+#ifdef Q_OS_WINPHONE
+#include <Windows.Security.ExchangeActiveSyncProvisioning.h>
+using namespace ABI::Windows::Security::ExchangeActiveSyncProvisioning;
+#endif
+
using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
QT_BEGIN_NAMESPACE
+#ifdef Q_OS_WINPHONE
+template <int n>
+static bool blacklisted(const wchar_t (&blackListName)[n], const HString &deviceModel)
+{
+ quint32 deviceNameLength;
+ const wchar_t *deviceName = deviceModel.GetRawBuffer(&deviceNameLength);
+ return n - 1 <= deviceNameLength && !wmemcmp(blackListName, deviceName, n - 1);
+}
+#endif
+
+class QWinRTCameraVideoBuffer : public QAbstractVideoBuffer
+{
+public:
+ QWinRTCameraVideoBuffer(IMF2DBuffer *buffer, int size, QWinRTCameraControl *control)
+ : QAbstractVideoBuffer(NoHandle)
+ , currentMode(NotMapped)
+ , buffer(buffer)
+ , size(size)
+ , control(control)
+ {
+ Q_ASSERT(control);
+ }
+
+ ~QWinRTCameraVideoBuffer()
+ {
+ unmap();
+ }
+
+ MapMode mapMode() const Q_DECL_OVERRIDE
+ {
+ return currentMode;
+ }
+
+ uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) Q_DECL_OVERRIDE
+ {
+ if (currentMode != NotMapped || mode == NotMapped || control && control->state() != QCamera::ActiveState)
+ return nullptr;
+
+ BYTE *bytes;
+ LONG stride;
+ HRESULT hr = buffer->Lock2D(&bytes, &stride);
+ RETURN_IF_FAILED("Failed to lock camera frame buffer", nullptr);
+ control->frameMapped();
+
+ if (bytesPerLine)
+ *bytesPerLine = stride;
+ if (numBytes)
+ *numBytes = size;
+ currentMode = mode;
+ return bytes;
+ }
+
+ void unmap() Q_DECL_OVERRIDE
+ {
+ if (currentMode == NotMapped)
+ return;
+ HRESULT hr = buffer->Unlock2D();
+ RETURN_VOID_IF_FAILED("Failed to unlock camera frame buffer");
+ currentMode = NotMapped;
+ if (control)
+ control->frameUnmapped();
+ }
+
+private:
+ ComPtr<IMF2DBuffer> buffer;
+ MapMode currentMode;
+ int size;
+ QPointer<QWinRTCameraControl> control;
+};
+
class D3DVideoBlitter
{
public:
- D3DVideoBlitter(ID3D11Device *device, ID3D11Texture2D *target)
- : m_d3dDevice(device), m_target(target)
+ D3DVideoBlitter(ID3D11Texture2D *target)
+ : m_target(target)
{
+ Q_ASSERT(target);
+ target->GetDevice(&m_d3dDevice);
+ Q_ASSERT(m_d3dDevice);
HRESULT hr;
- ComPtr<IDXGIResource> targetResource;
- hr = target->QueryInterface(IID_PPV_ARGS(&targetResource));
- Q_ASSERT_SUCCEEDED(hr);
- HANDLE sharedHandle;
- hr = targetResource->GetSharedHandle(&sharedHandle);
- Q_ASSERT_SUCCEEDED(hr);
- hr = m_d3dDevice->OpenSharedResource(sharedHandle, IID_PPV_ARGS(&m_targetTexture));
- Q_ASSERT_SUCCEEDED(hr);
hr = m_d3dDevice.As(&m_videoDevice);
Q_ASSERT_SUCCEEDED(hr);
}
@@ -86,7 +162,7 @@ public:
D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE,
{ 0 }, desc.Width, desc.Height,
{ 0 }, desc.Width, desc.Height,
- D3D11_VIDEO_USAGE_PLAYBACK_NORMAL
+ D3D11_VIDEO_USAGE_OPTIMAL_SPEED
};
hr = m_videoDevice->CreateVideoProcessorEnumerator(&videoProcessorDesc, &m_videoEnumerator);
RETURN_VOID_IF_FAILED("Failed to create video enumerator");
@@ -100,16 +176,26 @@ public:
if (!m_outputView) {
D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outputDesc = { D3D11_VPOV_DIMENSION_TEXTURE2D };
hr = m_videoDevice->CreateVideoProcessorOutputView(
- m_targetTexture.Get(), m_videoEnumerator.Get(), &outputDesc, &m_outputView);
+ m_target, m_videoEnumerator.Get(), &outputDesc, &m_outputView);
RETURN_VOID_IF_FAILED("Failed to create video output view");
}
+ ComPtr<IDXGIResource> sourceResource;
+ hr = texture->QueryInterface(IID_PPV_ARGS(&sourceResource));
+ Q_ASSERT_SUCCEEDED(hr);
+ HANDLE sharedHandle;
+ hr = sourceResource->GetSharedHandle(&sharedHandle);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<ID3D11Texture2D> sharedTexture;
+ hr = m_d3dDevice->OpenSharedResource(sharedHandle, IID_PPV_ARGS(&sharedTexture));
+ Q_ASSERT_SUCCEEDED(hr);
+
D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inputViewDesc = {
0, D3D11_VPIV_DIMENSION_TEXTURE2D, { 0, 0 }
};
ComPtr<ID3D11VideoProcessorInputView> inputView;
hr = m_videoDevice->CreateVideoProcessorInputView(
- texture, m_videoEnumerator.Get(), &inputViewDesc, &inputView);
+ sharedTexture.Get(), m_videoEnumerator.Get(), &inputViewDesc, &inputView);
RETURN_VOID_IF_FAILED("Failed to create video input view");
ComPtr<ID3D11DeviceContext> context;
@@ -127,7 +213,6 @@ public:
private:
ComPtr<ID3D11Device> m_d3dDevice;
- ComPtr<ID3D11Texture2D> m_targetTexture;
ID3D11Texture2D *m_target;
ComPtr<ID3D11VideoDevice> m_videoDevice;
ComPtr<ID3D11VideoProcessorEnumerator> m_videoEnumerator;
@@ -143,11 +228,73 @@ public:
ComPtr<IMF2DBuffer> buffers[CAMERA_SAMPLE_QUEUE_SIZE];
QAtomicInteger<quint16> writeIndex;
QAtomicInteger<quint16> readIndex;
+ QVideoFrame::PixelFormat cameraSampleformat;
+ int cameraSampleSize;
+ uint videoProbesCounter;
+ bool getCameraSampleInfo(const ComPtr<IMF2DBuffer> &buffer,
+ QWinRTAbstractVideoRendererControl::BlitMode *mode);
+ ComPtr<IMF2DBuffer> dequeueBuffer();
};
+bool QWinRTCameraVideoRendererControlPrivate::getCameraSampleInfo(const ComPtr<IMF2DBuffer> &buffer,
+ QWinRTAbstractVideoRendererControl::BlitMode *mode)
+{
+ Q_ASSERT(mode);
+ ComPtr<ID3D11Texture2D> sourceTexture;
+ ComPtr<IMFDXGIBuffer> dxgiBuffer;
+ HRESULT hr = buffer.As(&dxgiBuffer);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = dxgiBuffer->GetResource(IID_PPV_ARGS(&sourceTexture));
+ if (FAILED(hr)) {
+ qErrnoWarning(hr, "The video frame does not support texture output");
+ cameraSampleformat = QVideoFrame::Format_Invalid;
+ return false;
+ }
+ D3D11_TEXTURE2D_DESC desc;
+ sourceTexture->GetDesc(&desc);
+
+ if (!(desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED))
+ *mode = QWinRTAbstractVideoRendererControl::MediaFoundation;
+
+ switch (desc.Format) {
+ case DXGI_FORMAT_R8G8B8A8_TYPELESS:
+ cameraSampleformat = QVideoFrame::Format_ARGB32;
+ break;
+ case DXGI_FORMAT_NV12:
+ cameraSampleformat = QVideoFrame::Format_NV12;
+ break;
+ default:
+ cameraSampleformat = QVideoFrame::Format_Invalid;
+ qErrnoWarning("Unsupported camera probe format.");
+ return false;
+ }
+ DWORD pcbLength;
+ hr = buffer->GetContiguousLength(&pcbLength);
+ Q_ASSERT_SUCCEEDED(hr);
+ cameraSampleSize = pcbLength;
+ return true;
+}
+
QWinRTCameraVideoRendererControl::QWinRTCameraVideoRendererControl(const QSize &size, QObject *parent)
: QWinRTAbstractVideoRendererControl(size, parent), d_ptr(new QWinRTCameraVideoRendererControlPrivate)
{
+ Q_D(QWinRTCameraVideoRendererControl);
+ d->cameraSampleformat = QVideoFrame::Format_User;
+ d->videoProbesCounter = 0;
+
+#ifdef Q_OS_WINPHONE
+ // Workaround for certain devices which fail to blit.
+ ComPtr<IEasClientDeviceInformation> deviceInfo;
+ HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Security_ExchangeActiveSyncProvisioning_EasClientDeviceInformation).Get(),
+ &deviceInfo);
+ Q_ASSERT_SUCCEEDED(hr);
+ HString deviceModel;
+ hr = deviceInfo->get_SystemProductName(deviceModel.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ const bool blacklist = blacklisted(L"RM-1045", deviceModel) // Lumia 930
+ || blacklisted(L"RM-937", deviceModel); // Lumia 1520
+ setBlitMode(blacklist ? MediaFoundation : DirectVideo);
+#endif
}
QWinRTCameraVideoRendererControl::~QWinRTCameraVideoRendererControl()
@@ -158,22 +305,15 @@ QWinRTCameraVideoRendererControl::~QWinRTCameraVideoRendererControl()
bool QWinRTCameraVideoRendererControl::render(ID3D11Texture2D *target)
{
Q_D(QWinRTCameraVideoRendererControl);
-
- const quint16 readIndex = d->readIndex;
- if (readIndex == d->writeIndex) {
+ ComPtr<IMF2DBuffer> buffer = d->dequeueBuffer();
+ if (!buffer) {
emit bufferRequested();
return false;
}
- HRESULT hr;
- ComPtr<IMF2DBuffer> buffer = d->buffers[readIndex];
- Q_ASSERT(buffer);
- d->buffers[readIndex].Reset();
- d->readIndex = (readIndex + 1) % CAMERA_SAMPLE_QUEUE_SIZE;
-
ComPtr<ID3D11Texture2D> sourceTexture;
ComPtr<IMFDXGIBuffer> dxgiBuffer;
- hr = buffer.As(&dxgiBuffer);
+ HRESULT hr = buffer.As(&dxgiBuffer);
Q_ASSERT_SUCCEEDED(hr);
hr = dxgiBuffer->GetResource(IID_PPV_ARGS(&sourceTexture));
if (FAILED(hr)) {
@@ -181,10 +321,8 @@ bool QWinRTCameraVideoRendererControl::render(ID3D11Texture2D *target)
return false;
}
- ComPtr<ID3D11Device> device;
- sourceTexture->GetDevice(&device);
- if (!d->blitter || d->blitter->device() != device.Get() || d->blitter->target() != target)
- d->blitter.reset(new D3DVideoBlitter(device.Get(), target));
+ if (!d->blitter || d->blitter->target() != target)
+ d->blitter.reset(new D3DVideoBlitter(target));
d->blitter->blit(sourceTexture.Get());
@@ -192,15 +330,68 @@ bool QWinRTCameraVideoRendererControl::render(ID3D11Texture2D *target)
return true;
}
+bool QWinRTCameraVideoRendererControl::dequeueFrame(QVideoFrame *frame)
+{
+ Q_ASSERT(frame);
+ Q_D(QWinRTCameraVideoRendererControl);
+
+ ComPtr<IMF2DBuffer> buffer = d->dequeueBuffer();
+ if (!buffer || d->cameraSampleformat == QVideoFrame::Format_Invalid) {
+ emit bufferRequested();
+ return false;
+ }
+
+ QWinRTCameraVideoBuffer *videoBuffer = new QWinRTCameraVideoBuffer(buffer.Get(),
+ d->cameraSampleSize,
+ static_cast<QWinRTCameraControl *>(parent()));
+ *frame = QVideoFrame(videoBuffer, size(), d->cameraSampleformat);
+
+ emit bufferRequested();
+ return true;
+}
+
void QWinRTCameraVideoRendererControl::queueBuffer(IMF2DBuffer *buffer)
{
Q_D(QWinRTCameraVideoRendererControl);
Q_ASSERT(buffer);
+
+ if (d->cameraSampleformat == QVideoFrame::Format_User) {
+ BlitMode mode = blitMode();
+ d->getCameraSampleInfo(buffer, &mode);
+ setBlitMode(mode);
+ }
+
+ if (d->videoProbesCounter > 0 && d->cameraSampleformat != QVideoFrame::Format_Invalid) {
+ QWinRTCameraVideoBuffer *videoBuffer = new QWinRTCameraVideoBuffer(buffer,
+ d->cameraSampleSize,
+ static_cast<QWinRTCameraControl *>(parent()));
+ QVideoFrame frame(videoBuffer, size(), d->cameraSampleformat);
+ emit videoFrameProbed(frame);
+ }
+
const quint16 writeIndex = (d->writeIndex + 1) % CAMERA_SAMPLE_QUEUE_SIZE;
if (d->readIndex == writeIndex) // Drop new sample if queue is full
return;
d->buffers[d->writeIndex] = buffer;
d->writeIndex = writeIndex;
+
+ if (!surface()) {
+ d->dequeueBuffer();
+ emit bufferRequested();
+ }
+}
+
+ComPtr<IMF2DBuffer> QWinRTCameraVideoRendererControlPrivate::dequeueBuffer()
+{
+ const quint16 currentReadIndex = readIndex;
+ if (currentReadIndex == writeIndex)
+ return nullptr;
+
+ ComPtr<IMF2DBuffer> buffer = buffers[currentReadIndex];
+ Q_ASSERT(buffer);
+ buffers[currentReadIndex].Reset();
+ readIndex = (currentReadIndex + 1) % CAMERA_SAMPLE_QUEUE_SIZE;
+ return buffer;
}
void QWinRTCameraVideoRendererControl::discardBuffers()
@@ -211,4 +402,17 @@ void QWinRTCameraVideoRendererControl::discardBuffers()
buffer.Reset();
}
+void QWinRTCameraVideoRendererControl::incrementProbe()
+{
+ Q_D(QWinRTCameraVideoRendererControl);
+ ++d->videoProbesCounter;
+}
+
+void QWinRTCameraVideoRendererControl::decrementProbe()
+{
+ Q_D(QWinRTCameraVideoRendererControl);
+ Q_ASSERT(d->videoProbesCounter > 0);
+ --d->videoProbesCounter;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/winrt/qwinrtcameravideorenderercontrol.h b/src/plugins/winrt/qwinrtcameravideorenderercontrol.h
index 68e9bd9f8..76bff5e0b 100644
--- a/src/plugins/winrt/qwinrtcameravideorenderercontrol.h
+++ b/src/plugins/winrt/qwinrtcameravideorenderercontrol.h
@@ -39,10 +39,13 @@
#include "qwinrtabstractvideorenderercontrol.h"
+#include <QVideoFrame>
+
struct IMF2DBuffer;
QT_BEGIN_NAMESPACE
+class QWinRTVideoProbeControl;
class QVideoSurfaceFormat;
class QWinRTCameraVideoRendererControlPrivate;
class QWinRTCameraVideoRendererControl : public QWinRTAbstractVideoRendererControl
@@ -53,11 +56,15 @@ public:
~QWinRTCameraVideoRendererControl();
bool render(ID3D11Texture2D *texture) Q_DECL_OVERRIDE;
+ bool dequeueFrame(QVideoFrame *frame) Q_DECL_OVERRIDE;
void queueBuffer(IMF2DBuffer *buffer);
void discardBuffers();
+ void incrementProbe();
+ void decrementProbe();
signals:
void bufferRequested();
+ void videoFrameProbed(const QVideoFrame &frame);
private:
QScopedPointer<QWinRTCameraVideoRendererControlPrivate> d_ptr;
diff --git a/src/plugins/winrt/qwinrtimageencodercontrol.cpp b/src/plugins/winrt/qwinrtimageencodercontrol.cpp
index 0ab7a7cfb..6260a1d66 100644
--- a/src/plugins/winrt/qwinrtimageencodercontrol.cpp
+++ b/src/plugins/winrt/qwinrtimageencodercontrol.cpp
@@ -99,23 +99,23 @@ void QWinRTImageEncoderControl::setSupportedResolutionsList(const QList<QSize> r
void QWinRTImageEncoderControl::applySettings()
{
Q_D(QWinRTImageEncoderControl);
- d->imageEncoderSetting.setCodec(QStringLiteral("jpeg"));
+ if (d->imageEncoderSetting.codec().isEmpty())
+ d->imageEncoderSetting.setCodec(QStringLiteral("jpeg"));
QSize requestResolution = d->imageEncoderSetting.resolution();
if (d->supportedResolutions.isEmpty() || d->supportedResolutions.contains(requestResolution))
return;
- if (!requestResolution.isValid())
- requestResolution = QSize(0, 0);// Find the minimal available resolution
-
// Find closest resolution from the list
const int pixelCount = requestResolution.width() * requestResolution.height();
- int minPixelCountGap = -1;
- for (int i = 0; i < d->supportedResolutions.size(); ++i) {
- int gap = qAbs(pixelCount - d->supportedResolutions.at(i).width() * d->supportedResolutions.at(i).height());
- if (gap < minPixelCountGap || minPixelCountGap < 0) {
- minPixelCountGap = gap;
- requestResolution = d->supportedResolutions.at(i);
+ int minimumGap = std::numeric_limits<int>::max();
+ foreach (const QSize &size, d->supportedResolutions) {
+ int gap = qAbs(pixelCount - size.width() * size.height());
+ if (gap < minimumGap) {
+ minimumGap = gap;
+ requestResolution = size;
+ if (gap == 0)
+ break;
}
}
d->imageEncoderSetting.setResolution(requestResolution);
diff --git a/src/plugins/winrt/qwinrtimageencodercontrol.h b/src/plugins/winrt/qwinrtimageencodercontrol.h
index 7682e7626..10a09916e 100644
--- a/src/plugins/winrt/qwinrtimageencodercontrol.h
+++ b/src/plugins/winrt/qwinrtimageencodercontrol.h
@@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE
class QWinRTImageEncoderControlPrivate;
class QWinRTImageEncoderControl : public QImageEncoderControl
{
+ Q_OBJECT
public:
explicit QWinRTImageEncoderControl(QObject *parent = 0);
diff --git a/src/plugins/winrt/qwinrtmediaplayercontrol.cpp b/src/plugins/winrt/qwinrtmediaplayercontrol.cpp
index 8954d4445..ed2dbb943 100644
--- a/src/plugins/winrt/qwinrtmediaplayercontrol.cpp
+++ b/src/plugins/winrt/qwinrtmediaplayercontrol.cpp
@@ -51,7 +51,6 @@
#include <mfapi.h>
#include <mfmediaengine.h>
-#include <comdef.h>
#include <wrl.h>
using namespace Microsoft::WRL;
diff --git a/src/plugins/winrt/qwinrtvideoprobecontrol.cpp b/src/plugins/winrt/qwinrtvideoprobecontrol.cpp
new file mode 100644
index 000000000..7242efe60
--- /dev/null
+++ b/src/plugins/winrt/qwinrtvideoprobecontrol.cpp
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qwinrtvideoprobecontrol.h"
+#include "qwinrtcameravideorenderercontrol.h"
+
+QT_BEGIN_NAMESPACE
+
+QWinRTVideoProbeControl::QWinRTVideoProbeControl(QWinRTCameraVideoRendererControl *parent)
+ : QMediaVideoProbeControl(parent)
+{
+ QObject::connect(parent, &QWinRTCameraVideoRendererControl::videoFrameProbed,
+ this, &QMediaVideoProbeControl::videoFrameProbed, Qt::QueuedConnection);
+ parent->incrementProbe();
+}
+
+QWinRTVideoProbeControl::~QWinRTVideoProbeControl()
+{
+ if (QWinRTCameraVideoRendererControl *renderer = qobject_cast<QWinRTCameraVideoRendererControl *>(parent()))
+ renderer->decrementProbe();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/winrt/qwinrtvideoprobecontrol.h b/src/plugins/winrt/qwinrtvideoprobecontrol.h
new file mode 100644
index 000000000..dc9a8392e
--- /dev/null
+++ b/src/plugins/winrt/qwinrtvideoprobecontrol.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QWINRTVIDEOPROBECONTROL_H
+#define QWINRTVIDEOPROBECONTROL_H
+
+#include <qmediavideoprobecontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWinRTCameraVideoRendererControl;
+class QWinRTVideoProbeControl : public QMediaVideoProbeControl
+{
+ Q_OBJECT
+public:
+ explicit QWinRTVideoProbeControl(QWinRTCameraVideoRendererControl *parent);
+ ~QWinRTVideoProbeControl();
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINRTVIDEOPROBECONTROL_H
diff --git a/src/plugins/winrt/winrt.pro b/src/plugins/winrt/winrt.pro
index 58c2371f9..2f87ea8ff 100644
--- a/src/plugins/winrt/winrt.pro
+++ b/src/plugins/winrt/winrt.pro
@@ -10,30 +10,36 @@ LIBS += -lmfplat -lmfuuid -loleaut32 -ld3d11 -lruntimeobject
HEADERS += \
qwinrtabstractvideorenderercontrol.h \
qwinrtcameracontrol.h \
- qwinrtcamerainfocontrol.h \
+ qwinrtcamerafocuscontrol.h \
qwinrtcameraimagecapturecontrol.h \
+ qwinrtcamerainfocontrol.h \
+ qwinrtcameralockscontrol.h \
qwinrtcameraservice.h \
qwinrtcameravideorenderercontrol.h \
+ qwinrtimageencodercontrol.h \
qwinrtmediaplayercontrol.h \
qwinrtmediaplayerservice.h \
qwinrtplayerrenderercontrol.h \
qwinrtserviceplugin.h \
qwinrtvideodeviceselectorcontrol.h \
- qwinrtimageencodercontrol.h
+ qwinrtvideoprobecontrol.h
SOURCES += \
qwinrtabstractvideorenderercontrol.cpp \
qwinrtcameracontrol.cpp \
- qwinrtcamerainfocontrol.cpp \
+ qwinrtcamerafocuscontrol.cpp \
qwinrtcameraimagecapturecontrol.cpp \
+ qwinrtcamerainfocontrol.cpp \
+ qwinrtcameralockscontrol.cpp \
qwinrtcameraservice.cpp \
qwinrtcameravideorenderercontrol.cpp \
+ qwinrtimageencodercontrol.cpp \
qwinrtmediaplayercontrol.cpp \
qwinrtmediaplayerservice.cpp \
qwinrtplayerrenderercontrol.cpp \
qwinrtserviceplugin.cpp \
qwinrtvideodeviceselectorcontrol.cpp \
- qwinrtimageencodercontrol.cpp
+ qwinrtvideoprobecontrol.cpp
OTHER_FILES += \
winrt.json
diff --git a/src/plugins/wmf/mftvideo.cpp b/src/plugins/wmf/mftvideo.cpp
index b141d49a2..1b3c5bbca 100644
--- a/src/plugins/wmf/mftvideo.cpp
+++ b/src/plugins/wmf/mftvideo.cpp
@@ -52,6 +52,7 @@ MFTransform::MFTransform():
m_inputType(0),
m_outputType(0),
m_sample(0),
+ m_videoSinkTypeHandler(0),
m_bytesPerLine(0)
{
}
@@ -64,8 +65,8 @@ MFTransform::~MFTransform()
if (m_outputType)
m_outputType->Release();
- for (int i = 0; i < m_mediaTypes.size(); ++i)
- m_mediaTypes[i]->Release();
+ if (m_videoSinkTypeHandler)
+ m_videoSinkTypeHandler->Release();
}
void MFTransform::addProbe(MFVideoProbeControl *probe)
@@ -84,12 +85,18 @@ void MFTransform::removeProbe(MFVideoProbeControl *probe)
m_videoProbes.removeOne(probe);
}
-void MFTransform::addSupportedMediaType(IMFMediaType *type)
+void MFTransform::setVideoSink(IUnknown *videoSink)
{
- if (!type)
- return;
- QMutexLocker locker(&m_mutex);
- m_mediaTypes.append(type);
+ // This transform supports the same input types as the video sink.
+ // Store its type handler interface in order to report the correct supported types.
+
+ if (m_videoSinkTypeHandler) {
+ m_videoSinkTypeHandler->Release();
+ m_videoSinkTypeHandler = NULL;
+ }
+
+ if (videoSink)
+ videoSink->QueryInterface(IID_PPV_ARGS(&m_videoSinkTypeHandler));
}
STDMETHODIMP MFTransform::QueryInterface(REFIID riid, void** ppv)
@@ -165,9 +172,12 @@ STDMETHODIMP MFTransform::GetInputStreamInfo(DWORD dwInputStreamID, MFT_INPUT_ST
pStreamInfo->cbSize = 0;
pStreamInfo->hnsMaxLatency = 0;
- pStreamInfo->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER;
pStreamInfo->cbMaxLookahead = 0;
pStreamInfo->cbAlignment = 0;
+ pStreamInfo->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES
+ | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
+ | MFT_INPUT_STREAM_PROCESSES_IN_PLACE;
+
return S_OK;
}
@@ -182,8 +192,11 @@ STDMETHODIMP MFTransform::GetOutputStreamInfo(DWORD dwOutputStreamID, MFT_OUTPUT
return E_POINTER;
pStreamInfo->cbSize = 0;
- pStreamInfo->dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER;
pStreamInfo->cbAlignment = 0;
+ pStreamInfo->dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES
+ | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
+ | MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
+ | MFT_OUTPUT_STREAM_DISCARDABLE;
return S_OK;
}
@@ -228,20 +241,42 @@ STDMETHODIMP MFTransform::AddInputStreams(DWORD cStreams, DWORD *adwStreamIDs)
STDMETHODIMP MFTransform::GetInputAvailableType(DWORD dwInputStreamID, DWORD dwTypeIndex, IMFMediaType **ppType)
{
- // This MFT does not have a list of preferred input types
- Q_UNUSED(dwInputStreamID);
- Q_UNUSED(dwTypeIndex);
- Q_UNUSED(ppType);
- return E_NOTIMPL;
+ // We support the same input types as the video sink
+ if (!m_videoSinkTypeHandler)
+ return E_NOTIMPL;
+
+ if (dwInputStreamID > 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (!ppType)
+ return E_POINTER;
+
+ return m_videoSinkTypeHandler->GetMediaTypeByIndex(dwTypeIndex, ppType);
}
-STDMETHODIMP MFTransform::GetOutputAvailableType(DWORD dwOutputStreamID,DWORD dwTypeIndex, IMFMediaType **ppType)
+STDMETHODIMP MFTransform::GetOutputAvailableType(DWORD dwOutputStreamID, DWORD dwTypeIndex, IMFMediaType **ppType)
{
- // This MFT does not have a list of preferred output types
- Q_UNUSED(dwOutputStreamID);
- Q_UNUSED(dwTypeIndex);
- Q_UNUSED(ppType);
- return E_NOTIMPL;
+ // Since we don't modify the samples, the output type must be the same as the input type.
+ // Report our input type as the only available output type.
+
+ if (dwOutputStreamID > 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (!ppType)
+ return E_POINTER;
+
+ // Input type must be set first
+ if (!m_inputType)
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+ if (dwTypeIndex > 0)
+ return MF_E_NO_MORE_TYPES;
+
+ // Return a copy to make sure our type is not modified
+ if (FAILED(MFCreateMediaType(ppType)))
+ return E_OUTOFMEMORY;
+
+ return m_inputType->CopyAllItems(*ppType);
}
STDMETHODIMP MFTransform::SetInputType(DWORD dwInputStreamID, IMFMediaType *pType, DWORD dwFlags)
@@ -257,17 +292,14 @@ STDMETHODIMP MFTransform::SetInputType(DWORD dwInputStreamID, IMFMediaType *pTyp
if (!isMediaTypeSupported(pType))
return MF_E_INVALIDMEDIATYPE;
- DWORD flags = 0;
- if (pType && !m_inputType && m_outputType && m_outputType->IsEqual(pType, &flags) != S_OK)
- return MF_E_INVALIDMEDIATYPE;
-
if (dwFlags == MFT_SET_TYPE_TEST_ONLY)
return pType ? S_OK : E_POINTER;
if (m_inputType) {
m_inputType->Release();
// Input type has changed, discard output type (if it's set) so it's reset later on
- if (m_outputType && m_outputType->IsEqual(pType, &flags) != S_OK) {
+ DWORD flags = 0;
+ if (m_outputType && m_outputType->IsEqual(pType, &flags) != S_OK) {
m_outputType->Release();
m_outputType = 0;
}
@@ -286,29 +318,27 @@ STDMETHODIMP MFTransform::SetOutputType(DWORD dwOutputStreamID, IMFMediaType *pT
if (dwOutputStreamID > 0)
return MF_E_INVALIDSTREAMNUMBER;
+ if (dwFlags == MFT_SET_TYPE_TEST_ONLY && !pType)
+ return E_POINTER;
+
QMutexLocker locker(&m_mutex);
+ // Input type must be set first
+ if (!m_inputType)
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+
if (m_sample)
return MF_E_TRANSFORM_CANNOT_CHANGE_MEDIATYPE_WHILE_PROCESSING;
- if (!isMediaTypeSupported(pType))
- return MF_E_INVALIDMEDIATYPE;
-
DWORD flags = 0;
- if (pType && !m_outputType && m_inputType && m_inputType->IsEqual(pType, &flags) != S_OK)
+ if (pType && m_inputType->IsEqual(pType, &flags) != S_OK)
return MF_E_INVALIDMEDIATYPE;
if (dwFlags == MFT_SET_TYPE_TEST_ONLY)
return pType ? S_OK : E_POINTER;
- if (m_outputType) {
+ if (m_outputType)
m_outputType->Release();
- // Output type has changed, discard input type (if it's set) so it's reset later on
- if (m_inputType && m_inputType->IsEqual(pType, &flags) != S_OK) {
- m_inputType->Release();
- m_inputType = 0;
- }
- }
m_outputType = pType;
@@ -333,10 +363,11 @@ STDMETHODIMP MFTransform::GetInputCurrentType(DWORD dwInputStreamID, IMFMediaTyp
if (!m_inputType)
return MF_E_TRANSFORM_TYPE_NOT_SET;
- *ppType = m_inputType;
- (*ppType)->AddRef();
+ // Return a copy to make sure our type is not modified
+ if (FAILED(MFCreateMediaType(ppType)))
+ return E_OUTOFMEMORY;
- return S_OK;
+ return m_inputType->CopyAllItems(*ppType);
}
STDMETHODIMP MFTransform::GetOutputCurrentType(DWORD dwOutputStreamID, IMFMediaType **ppType)
@@ -349,19 +380,14 @@ STDMETHODIMP MFTransform::GetOutputCurrentType(DWORD dwOutputStreamID, IMFMediaT
QMutexLocker locker(&m_mutex);
- if (!m_outputType) {
- if (m_inputType) {
- *ppType = m_inputType;
- (*ppType)->AddRef();
- return S_OK;
- }
+ if (!m_outputType)
return MF_E_TRANSFORM_TYPE_NOT_SET;
- }
- *ppType = m_outputType;
- (*ppType)->AddRef();
+ // Return a copy to make sure our type is not modified
+ if (FAILED(MFCreateMediaType(ppType)))
+ return E_OUTOFMEMORY;
- return S_OK;
+ return m_outputType->CopyAllItems(*ppType);
}
STDMETHODIMP MFTransform::GetInputStatus(DWORD dwInputStreamID, DWORD *pdwFlags)
@@ -374,7 +400,7 @@ STDMETHODIMP MFTransform::GetInputStatus(DWORD dwInputStreamID, DWORD *pdwFlags)
QMutexLocker locker(&m_mutex);
- if (!m_inputType)
+ if (!m_inputType || !m_outputType)
return MF_E_TRANSFORM_TYPE_NOT_SET;
if (m_sample)
@@ -392,7 +418,7 @@ STDMETHODIMP MFTransform::GetOutputStatus(DWORD *pdwFlags)
QMutexLocker locker(&m_mutex);
- if (!m_outputType)
+ if (!m_inputType || !m_outputType)
return MF_E_TRANSFORM_TYPE_NOT_SET;
if (m_sample)
@@ -464,7 +490,7 @@ STDMETHODIMP MFTransform::ProcessInput(DWORD dwInputStreamID, IMFSample *pSample
QMutexLocker locker(&m_mutex);
- if (!m_inputType || !m_outputType)
+ if (!m_inputType)
return MF_E_TRANSFORM_TYPE_NOT_SET;
if (m_sample)
@@ -485,23 +511,11 @@ STDMETHODIMP MFTransform::ProcessInput(DWORD dwInputStreamID, IMFSample *pSample
m_sample = pSample;
m_sample->AddRef();
- QMutexLocker lockerProbe(&m_videoProbeMutex);
-
- if (!m_videoProbes.isEmpty()) {
- QVideoFrame frame = makeVideoFrame();
-
- foreach (MFVideoProbeControl* probe, m_videoProbes)
- probe->bufferProbed(frame);
- }
-
return S_OK;
}
STDMETHODIMP MFTransform::ProcessOutput(DWORD dwFlags, DWORD cOutputBufferCount, MFT_OUTPUT_DATA_BUFFER *pOutputSamples, DWORD *pdwStatus)
{
- if (dwFlags != 0)
- return E_INVALIDARG;
-
if (pOutputSamples == NULL || pdwStatus == NULL)
return E_POINTER;
@@ -510,57 +524,44 @@ STDMETHODIMP MFTransform::ProcessOutput(DWORD dwFlags, DWORD cOutputBufferCount,
QMutexLocker locker(&m_mutex);
- if (!m_sample)
- return MF_E_TRANSFORM_NEED_MORE_INPUT;
+ if (!m_inputType)
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+ if (!m_outputType) {
+ pOutputSamples[0].dwStatus = MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
+ return MF_E_TRANSFORM_STREAM_CHANGE;
+ }
IMFMediaBuffer *input = NULL;
IMFMediaBuffer *output = NULL;
- DWORD sampleLength = 0;
- m_sample->GetTotalLength(&sampleLength);
-
- // If the sample length is null, it means we're getting DXVA buffers.
- // In that case just pass on the sample we got as input.
- // Otherwise we need to copy the input buffer into the buffer the sink
- // is giving us.
- if (pOutputSamples[0].pSample && sampleLength > 0) {
-
- if (FAILED(m_sample->ConvertToContiguousBuffer(&input)))
- goto done;
-
- if (FAILED(pOutputSamples[0].pSample->ConvertToContiguousBuffer(&output)))
- goto done;
-
- DWORD inputLength = 0;
- DWORD outputLength = 0;
- input->GetMaxLength(&inputLength);
- output->GetMaxLength(&outputLength);
+ if (dwFlags == MFT_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER)
+ goto done;
+ else if (dwFlags != 0)
+ return E_INVALIDARG;
- if (outputLength < inputLength) {
- pOutputSamples[0].pSample->RemoveAllBuffers();
- output->Release();
- output = NULL;
- if (SUCCEEDED(MFCreateMemoryBuffer(inputLength, &output)))
- pOutputSamples[0].pSample->AddBuffer(output);
- }
+ if (!m_sample)
+ return MF_E_TRANSFORM_NEED_MORE_INPUT;
- if (output)
- m_sample->CopyToBuffer(output);
+ // Since the MFT_OUTPUT_STREAM_PROVIDES_SAMPLES flag is set, the client
+ // should not be providing samples here
+ if (pOutputSamples[0].pSample != NULL)
+ return E_INVALIDARG;
- LONGLONG hnsDuration = 0;
- LONGLONG hnsTime = 0;
- if (SUCCEEDED(m_sample->GetSampleDuration(&hnsDuration)))
- pOutputSamples[0].pSample->SetSampleDuration(hnsDuration);
- if (SUCCEEDED(m_sample->GetSampleTime(&hnsTime)))
- pOutputSamples[0].pSample->SetSampleTime(hnsTime);
+ pOutputSamples[0].pSample = m_sample;
+ pOutputSamples[0].pSample->AddRef();
+ // Send video frame to probes
+ // We do it here (instead of inside ProcessInput) to make sure samples discarded by the renderer
+ // are not sent.
+ m_videoProbeMutex.lock();
+ if (!m_videoProbes.isEmpty()) {
+ QVideoFrame frame = makeVideoFrame();
- } else {
- if (pOutputSamples[0].pSample)
- pOutputSamples[0].pSample->Release();
- pOutputSamples[0].pSample = m_sample;
- pOutputSamples[0].pSample->AddRef();
+ foreach (MFVideoProbeControl* probe, m_videoProbes)
+ probe->bufferProbed(frame);
}
+ m_videoProbeMutex.unlock();
done:
pOutputSamples[0].dwStatus = 0;
@@ -728,16 +729,10 @@ QByteArray MFTransform::dataFromBuffer(IMFMediaBuffer *buffer, int height, int *
bool MFTransform::isMediaTypeSupported(IMFMediaType *type)
{
- // if the list is empty, it supports all formats
- if (!type || m_mediaTypes.isEmpty())
+ // If we don't have the video sink's type handler,
+ // assume it supports anything...
+ if (!m_videoSinkTypeHandler || !type)
return true;
- for (int i = 0; i < m_mediaTypes.size(); ++i) {
- DWORD flags = 0;
- m_mediaTypes.at(i)->IsEqual(type, &flags);
- if (flags & MF_MEDIATYPE_EQUAL_FORMAT_TYPES)
- return true;
- }
-
- return false;
+ return m_videoSinkTypeHandler->IsMediaTypeSupported(type, NULL) == S_OK;
}
diff --git a/src/plugins/wmf/mftvideo.h b/src/plugins/wmf/mftvideo.h
index 1a188c4db..c37c8f700 100644
--- a/src/plugins/wmf/mftvideo.h
+++ b/src/plugins/wmf/mftvideo.h
@@ -53,7 +53,7 @@ public:
void addProbe(MFVideoProbeControl* probe);
void removeProbe(MFVideoProbeControl* probe);
- void addSupportedMediaType(IMFMediaType *type);
+ void setVideoSink(IUnknown *videoSink);
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
@@ -99,7 +99,7 @@ private:
IMFSample *m_sample;
QMutex m_mutex;
- QList<IMFMediaType*> m_mediaTypes;
+ IMFMediaTypeHandler *m_videoSinkTypeHandler;
QList<MFVideoProbeControl*> m_videoProbes;
QMutex m_videoProbeMutex;
diff --git a/src/plugins/wmf/player/mfevrvideowindowcontrol.cpp b/src/plugins/wmf/player/mfevrvideowindowcontrol.cpp
new file mode 100644
index 000000000..404f38125
--- /dev/null
+++ b/src/plugins/wmf/player/mfevrvideowindowcontrol.cpp
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mfevrvideowindowcontrol.h"
+
+#include <qdebug.h>
+
+MFEvrVideoWindowControl::MFEvrVideoWindowControl(QObject *parent)
+ : EvrVideoWindowControl(parent)
+ , m_currentActivate(NULL)
+ , m_evrSink(NULL)
+{
+}
+
+MFEvrVideoWindowControl::~MFEvrVideoWindowControl()
+{
+ clear();
+}
+
+void MFEvrVideoWindowControl::clear()
+{
+ setEvr(NULL);
+
+ if (m_evrSink)
+ m_evrSink->Release();
+ if (m_currentActivate) {
+ m_currentActivate->ShutdownObject();
+ m_currentActivate->Release();
+ }
+ m_evrSink = NULL;
+ m_currentActivate = NULL;
+}
+
+IMFActivate* MFEvrVideoWindowControl::createActivate()
+{
+ clear();
+
+ if (FAILED(MFCreateVideoRendererActivate(0, &m_currentActivate))) {
+ qWarning() << "Failed to create evr video renderer activate!";
+ return NULL;
+ }
+ if (FAILED(m_currentActivate->ActivateObject(IID_IMFMediaSink, (LPVOID*)(&m_evrSink)))) {
+ qWarning() << "Failed to activate evr media sink!";
+ return NULL;
+ }
+ if (!setEvr(m_evrSink))
+ return NULL;
+
+ return m_currentActivate;
+}
+
+void MFEvrVideoWindowControl::releaseActivate()
+{
+ clear();
+}
diff --git a/src/plugins/wmf/player/mfevrvideowindowcontrol.h b/src/plugins/wmf/player/mfevrvideowindowcontrol.h
new file mode 100644
index 000000000..e5a38f27d
--- /dev/null
+++ b/src/plugins/wmf/player/mfevrvideowindowcontrol.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MFEVRVIDEOWINDOWCONTROL_H
+#define MFEVRVIDEOWINDOWCONTROL_H
+
+#include "evrvideowindowcontrol.h"
+
+QT_USE_NAMESPACE
+
+class MFEvrVideoWindowControl : public EvrVideoWindowControl
+{
+public:
+ MFEvrVideoWindowControl(QObject *parent = 0);
+ ~MFEvrVideoWindowControl();
+
+ IMFActivate* createActivate();
+ void releaseActivate();
+
+private:
+ void clear();
+
+ IMFActivate *m_currentActivate;
+ IMFMediaSink *m_evrSink;
+};
+
+#endif // MFEVRVIDEOWINDOWCONTROL_H
diff --git a/src/plugins/wmf/player/mfplayerservice.cpp b/src/plugins/wmf/player/mfplayerservice.cpp
index 4e88b0498..99c6abb3e 100644
--- a/src/plugins/wmf/player/mfplayerservice.cpp
+++ b/src/plugins/wmf/player/mfplayerservice.cpp
@@ -36,9 +36,7 @@
#include <QtCore/qdebug.h>
#include "mfplayercontrol.h"
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
-#include "evr9videowindowcontrol.h"
-#endif
+#include "mfevrvideowindowcontrol.h"
#include "mfvideorenderercontrol.h"
#include "mfaudioendpointcontrol.h"
#include "mfaudioprobecontrol.h"
@@ -50,9 +48,7 @@
MFPlayerService::MFPlayerService(QObject *parent)
: QMediaService(parent)
, m_session(0)
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
, m_videoWindowControl(0)
-#endif
, m_videoRendererControl(0)
{
m_audioEndpointControl = new MFAudioEndpointControl(this);
@@ -65,10 +61,8 @@ MFPlayerService::~MFPlayerService()
{
m_session->close();
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
if (m_videoWindowControl)
delete m_videoWindowControl;
-#endif
if (m_videoRendererControl)
delete m_videoRendererControl;
@@ -85,21 +79,15 @@ QMediaControl* MFPlayerService::requestControl(const char *name)
} else if (qstrcmp(name, QMetaDataReaderControl_iid) == 0) {
return m_metaDataControl;
} else if (qstrcmp(name, QVideoRendererControl_iid) == 0) {
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
if (!m_videoRendererControl && !m_videoWindowControl) {
-#else
- if (!m_videoRendererControl) {
-#endif
m_videoRendererControl = new MFVideoRendererControl;
return m_videoRendererControl;
}
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
} else if (qstrcmp(name, QVideoWindowControl_iid) == 0) {
if (!m_videoRendererControl && !m_videoWindowControl) {
- m_videoWindowControl = new Evr9VideoWindowControl;
+ m_videoWindowControl = new MFEvrVideoWindowControl;
return m_videoWindowControl;
}
-#endif
} else if (qstrcmp(name,QMediaAudioProbeControl_iid) == 0) {
if (m_session) {
MFAudioProbeControl *probe = new MFAudioProbeControl(this);
@@ -129,12 +117,10 @@ void MFPlayerService::releaseControl(QMediaControl *control)
delete m_videoRendererControl;
m_videoRendererControl = 0;
return;
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
} else if (control == m_videoWindowControl) {
delete m_videoWindowControl;
m_videoWindowControl = 0;
return;
-#endif
}
MFAudioProbeControl* audioProbe = qobject_cast<MFAudioProbeControl*>(control);
@@ -164,12 +150,10 @@ MFVideoRendererControl* MFPlayerService::videoRendererControl() const
return m_videoRendererControl;
}
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
-Evr9VideoWindowControl* MFPlayerService::videoWindowControl() const
+MFEvrVideoWindowControl* MFPlayerService::videoWindowControl() const
{
return m_videoWindowControl;
}
-#endif
MFMetaDataControl* MFPlayerService::metaDataControl() const
{
diff --git a/src/plugins/wmf/player/mfplayerservice.h b/src/plugins/wmf/player/mfplayerservice.h
index 62eb6b640..b3db70799 100644
--- a/src/plugins/wmf/player/mfplayerservice.h
+++ b/src/plugins/wmf/player/mfplayerservice.h
@@ -48,9 +48,7 @@ QT_END_NAMESPACE
QT_USE_NAMESPACE
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
-class Evr9VideoWindowControl;
-#endif
+class MFEvrVideoWindowControl;
class MFAudioEndpointControl;
class MFVideoRendererControl;
class MFPlayerControl;
@@ -69,18 +67,14 @@ public:
MFAudioEndpointControl* audioEndpointControl() const;
MFVideoRendererControl* videoRendererControl() const;
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
- Evr9VideoWindowControl* videoWindowControl() const;
-#endif
+ MFEvrVideoWindowControl* videoWindowControl() const;
MFMetaDataControl* metaDataControl() const;
private:
MFPlayerSession *m_session;
MFVideoRendererControl *m_videoRendererControl;
MFAudioEndpointControl *m_audioEndpointControl;
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
- Evr9VideoWindowControl *m_videoWindowControl;
-#endif
+ MFEvrVideoWindowControl *m_videoWindowControl;
MFPlayerControl *m_player;
MFMetaDataControl *m_metaDataControl;
};
diff --git a/src/plugins/wmf/player/mfplayersession.cpp b/src/plugins/wmf/player/mfplayersession.cpp
index 283853def..0ac1c3d66 100644
--- a/src/plugins/wmf/player/mfplayersession.cpp
+++ b/src/plugins/wmf/player/mfplayersession.cpp
@@ -43,9 +43,7 @@
#include <QtCore/qbuffer.h>
#include "mfplayercontrol.h"
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
-#include "evr9videowindowcontrol.h"
-#endif
+#include "mfevrvideowindowcontrol.h"
#include "mfvideorenderercontrol.h"
#include "mfaudioendpointcontrol.h"
@@ -140,10 +138,8 @@ void MFPlayerSession::close()
if (m_playerService->videoRendererControl()) {
m_playerService->videoRendererControl()->releaseActivate();
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
} else if (m_playerService->videoWindowControl()) {
m_playerService->videoWindowControl()->releaseActivate();
-#endif
}
if (m_session)
@@ -270,6 +266,25 @@ void MFPlayerSession::handleMediaSourceReady()
}
}
+MFPlayerSession::MediaType MFPlayerSession::getStreamType(IMFStreamDescriptor *stream) const
+{
+ if (!stream)
+ return Unknown;
+
+ IMFMediaTypeHandler *typeHandler = NULL;
+ if (SUCCEEDED(stream->GetMediaTypeHandler(&typeHandler))) {
+ GUID guidMajorType;
+ if (SUCCEEDED(typeHandler->GetMajorType(&guidMajorType))) {
+ if (guidMajorType == MFMediaType_Audio)
+ return Audio;
+ else if (guidMajorType == MFMediaType_Video)
+ return Video;
+ }
+ }
+
+ return Unknown;
+}
+
void MFPlayerSession::setupPlaybackTopology(IMFMediaSource *source, IMFPresentationDescriptor *sourcePD)
{
HRESULT hr = S_OK;
@@ -298,45 +313,58 @@ void MFPlayerSession::setupPlaybackTopology(IMFMediaSource *source, IMFPresentat
for (DWORD i = 0; i < cSourceStreams; i++)
{
BOOL fSelected = FALSE;
+ bool streamAdded = false;
IMFStreamDescriptor *streamDesc = NULL;
HRESULT hr = sourcePD->GetStreamDescriptorByIndex(i, &fSelected, &streamDesc);
if (SUCCEEDED(hr)) {
- MediaType mediaType = Unknown;
- IMFTopologyNode *sourceNode = addSourceNode(topology, source, sourcePD, streamDesc);
- if (sourceNode) {
- IMFTopologyNode *outputNode = addOutputNode(streamDesc, mediaType, topology, 0);
- if (outputNode) {
- bool connected = false;
- if (mediaType == Audio) {
- if (!m_audioSampleGrabberNode)
- connected = setupAudioSampleGrabber(topology, sourceNode, outputNode);
- } else if (mediaType == Video && outputNodeId == -1) {
- // Remember video output node ID.
- outputNode->GetTopoNodeID(&outputNodeId);
- }
+ // The media might have multiple audio and video streams,
+ // only use one of each kind, and only if it is selected by default.
+ MediaType mediaType = getStreamType(streamDesc);
+ if (mediaType != Unknown
+ && ((m_mediaTypes & mediaType) == 0) // Check if this type isn't already added
+ && fSelected) {
+
+ IMFTopologyNode *sourceNode = addSourceNode(topology, source, sourcePD, streamDesc);
+ if (sourceNode) {
+ IMFTopologyNode *outputNode = addOutputNode(mediaType, topology, 0);
+ if (outputNode) {
+ bool connected = false;
+ if (mediaType == Audio) {
+ if (!m_audioSampleGrabberNode)
+ connected = setupAudioSampleGrabber(topology, sourceNode, outputNode);
+ } else if (mediaType == Video && outputNodeId == -1) {
+ // Remember video output node ID.
+ outputNode->GetTopoNodeID(&outputNodeId);
+ }
- if (!connected)
- hr = sourceNode->ConnectOutput(0, outputNode, 0);
- if (FAILED(hr)) {
- emit error(QMediaPlayer::FormatError, tr("Unable to play any stream."), false);
- }
- else {
- succeededCount++;
- m_mediaTypes |= mediaType;
- switch (mediaType) {
- case Audio:
- emit audioAvailable();
- break;
- case Video:
- emit videoAvailable();
- break;
+ if (!connected)
+ hr = sourceNode->ConnectOutput(0, outputNode, 0);
+
+ if (FAILED(hr)) {
+ emit error(QMediaPlayer::FormatError, tr("Unable to play any stream."), false);
+ } else {
+ streamAdded = true;
+ succeededCount++;
+ m_mediaTypes |= mediaType;
+ switch (mediaType) {
+ case Audio:
+ emit audioAvailable();
+ break;
+ case Video:
+ emit videoAvailable();
+ break;
+ }
}
+ outputNode->Release();
}
- outputNode->Release();
+ sourceNode->Release();
}
- sourceNode->Release();
}
+
+ if (fSelected && !streamAdded)
+ sourcePD->DeselectStream(i);
+
streamDesc->Release();
}
}
@@ -381,58 +409,38 @@ IMFTopologyNode* MFPlayerSession::addSourceNode(IMFTopology* topology, IMFMediaS
return NULL;
}
-IMFTopologyNode* MFPlayerSession::addOutputNode(IMFStreamDescriptor *streamDesc, MediaType& mediaType, IMFTopology* topology, DWORD sinkID)
+IMFTopologyNode* MFPlayerSession::addOutputNode(MediaType mediaType, IMFTopology* topology, DWORD sinkID)
{
IMFTopologyNode *node = NULL;
- HRESULT hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node);
- if (FAILED(hr))
+ if (FAILED(MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node)))
return NULL;
- node->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
- mediaType = Unknown;
- IMFMediaTypeHandler *handler = NULL;
- hr = streamDesc->GetMediaTypeHandler(&handler);
- if (SUCCEEDED(hr)) {
- GUID guidMajorType;
- hr = handler->GetMajorType(&guidMajorType);
- if (SUCCEEDED(hr)) {
- IMFActivate *activate = NULL;
- if (MFMediaType_Audio == guidMajorType) {
- mediaType = Audio;
- activate = m_playerService->audioEndpointControl()->createActivate();
- } else if (MFMediaType_Video == guidMajorType) {
- mediaType = Video;
- if (m_playerService->videoRendererControl()) {
- activate = m_playerService->videoRendererControl()->createActivate();
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
- } else if (m_playerService->videoWindowControl()) {
- activate = m_playerService->videoWindowControl()->createActivate();
-#endif
- } else {
- qWarning() << "no videoWindowControl or videoRendererControl, unable to add output node for video data";
- }
- } else {
- // Unknown stream type.
- emit error(QMediaPlayer::FormatError, tr("Unknown stream type."), false);
- }
-
- if (activate) {
- hr = node->SetObject(activate);
- if (SUCCEEDED(hr)) {
- hr = node->SetUINT32(MF_TOPONODE_STREAMID, sinkID);
- if (SUCCEEDED(hr)) {
- if (SUCCEEDED(topology->AddNode(node))) {
- handler->Release();
- return node;
- }
- }
- }
- }
+ IMFActivate *activate = NULL;
+ if (mediaType == Audio) {
+ activate = m_playerService->audioEndpointControl()->createActivate();
+ } else if (mediaType == Video) {
+ if (m_playerService->videoRendererControl()) {
+ activate = m_playerService->videoRendererControl()->createActivate();
+ } else if (m_playerService->videoWindowControl()) {
+ activate = m_playerService->videoWindowControl()->createActivate();
+ } else {
+ qWarning() << "no videoWindowControl or videoRendererControl, unable to add output node for video data";
}
- handler->Release();
+ } else {
+ // Unknown stream type.
+ emit error(QMediaPlayer::FormatError, tr("Unknown stream type."), false);
}
- node->Release();
- return NULL;
+
+ if (!activate
+ || FAILED(node->SetObject(activate))
+ || FAILED(node->SetUINT32(MF_TOPONODE_STREAMID, sinkID))
+ || FAILED(node->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE))
+ || FAILED(topology->AddNode(node))) {
+ node->Release();
+ node = NULL;
+ }
+
+ return node;
}
bool MFPlayerSession::addAudioSampleGrabberNode(IMFTopology *topology)
@@ -698,7 +706,6 @@ IMFTopology *MFPlayerSession::insertMFT(IMFTopology *topology, TOPOID outputNode
IUnknown *element = 0;
IMFTopologyNode *node = 0;
IUnknown *outputObject = 0;
- IMFMediaTypeHandler *videoSink = 0;
IMFTopologyNode *inputNode = 0;
IMFTopologyNode *mftNode = 0;
bool mftAdded = false;
@@ -717,22 +724,10 @@ IMFTopology *MFPlayerSession::insertMFT(IMFTopology *topology, TOPOID outputNode
if (id != outputNodeId)
break;
- // Use output supported media types for the MFT
if (FAILED(node->GetObject(&outputObject)))
break;
- if (FAILED(outputObject->QueryInterface(IID_IMFMediaTypeHandler, (void**)&videoSink)))
- break;
-
- DWORD mtCount;
- if (FAILED(videoSink->GetMediaTypeCount(&mtCount)))
- break;
-
- for (DWORD i = 0; i < mtCount; ++i) {
- IMFMediaType *type = 0;
- if (SUCCEEDED(videoSink->GetMediaTypeByIndex(i, &type)))
- m_videoProbeMFT->addSupportedMediaType(type);
- }
+ m_videoProbeMFT->setVideoSink(outputObject);
// Insert MFT between the output node and the node connected to it.
DWORD outputIndex = 0;
@@ -766,13 +761,13 @@ IMFTopology *MFPlayerSession::insertMFT(IMFTopology *topology, TOPOID outputNode
node->Release();
if (element)
element->Release();
- if (videoSink)
- videoSink->Release();
if (outputObject)
outputObject->Release();
if (mftAdded)
break;
+ else
+ m_videoProbeMFT->setVideoSink(NULL);
}
} while (false);
@@ -1580,13 +1575,11 @@ void MFPlayerSession::handleSessionEvent(IMFMediaEvent *sessionEvent)
}
updatePendingCommands(CmdStart);
-#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR)
// playback started, we can now set again the procAmpValues if they have been
// changed previously (these are lost when loading a new media)
if (m_playerService->videoWindowControl()) {
- m_playerService->videoWindowControl()->setProcAmpValues();
+ m_playerService->videoWindowControl()->applyImageControls();
}
-#endif
break;
case MESessionStopped:
if (m_status != QMediaPlayer::EndOfMedia) {
diff --git a/src/plugins/wmf/player/mfplayersession.h b/src/plugins/wmf/player/mfplayersession.h
index effb36fa2..5bbf8e212 100644
--- a/src/plugins/wmf/player/mfplayersession.h
+++ b/src/plugins/wmf/player/mfplayersession.h
@@ -57,7 +57,7 @@ QT_USE_NAMESPACE
class SourceResolver;
#ifndef Q_WS_SIMULATOR
-class Evr9VideoWindowControl;
+class EvrVideoWindowControl;
#endif
class MFAudioEndpointControl;
class MFVideoRendererControl;
@@ -215,9 +215,10 @@ private:
void createSession();
void setupPlaybackTopology(IMFMediaSource *source, IMFPresentationDescriptor *sourcePD);
+ MediaType getStreamType(IMFStreamDescriptor *stream) const;
IMFTopologyNode* addSourceNode(IMFTopology* topology, IMFMediaSource* source,
IMFPresentationDescriptor* presentationDesc, IMFStreamDescriptor *streamDesc);
- IMFTopologyNode* addOutputNode(IMFStreamDescriptor *streamDesc, MediaType& mediaType, IMFTopology* topology, DWORD sinkID);
+ IMFTopologyNode* addOutputNode(MediaType mediaType, IMFTopology* topology, DWORD sinkID);
bool addAudioSampleGrabberNode(IMFTopology* topology);
bool setupAudioSampleGrabber(IMFTopology *topology, IMFTopologyNode *sourceNode, IMFTopologyNode *outputNode);
diff --git a/src/plugins/wmf/player/player.pri b/src/plugins/wmf/player/player.pri
index dd5c9dc12..c24370eea 100644
--- a/src/plugins/wmf/player/player.pri
+++ b/src/plugins/wmf/player/player.pri
@@ -12,7 +12,8 @@ HEADERS += \
$$PWD/mfaudioendpointcontrol.h \
$$PWD/mfmetadatacontrol.h \
$$PWD/mfaudioprobecontrol.h \
- $$PWD/mfvideoprobecontrol.h
+ $$PWD/mfvideoprobecontrol.h \
+ $$PWD/mfevrvideowindowcontrol.h
SOURCES += \
$$PWD/mfplayerservice.cpp \
@@ -22,9 +23,7 @@ SOURCES += \
$$PWD/mfaudioendpointcontrol.cpp \
$$PWD/mfmetadatacontrol.cpp \
$$PWD/mfaudioprobecontrol.cpp \
- $$PWD/mfvideoprobecontrol.cpp
+ $$PWD/mfvideoprobecontrol.cpp \
+ $$PWD/mfevrvideowindowcontrol.cpp
-qtHaveModule(widgets):!simulator {
- HEADERS += $$PWD/evr9videowindowcontrol.h
- SOURCES += $$PWD/evr9videowindowcontrol.cpp
-}
+include($$PWD/../../common/evr.pri)
diff --git a/src/plugins/wmf/wmf.pro b/src/plugins/wmf/wmf.pro
index 60fc3f641..68a777f37 100644
--- a/src/plugins/wmf/wmf.pro
+++ b/src/plugins/wmf/wmf.pro
@@ -1,9 +1,6 @@
TARGET = wmfengine
QT += multimedia-private network
-qtHaveModule(widgets) {
- QT += multimediawidgets-private
- DEFINES += HAVE_WIDGETS
-}
+
win32:!qtHaveModule(opengl) {
LIBS_PRIVATE += -lgdi32 -luser32
}
@@ -37,15 +34,14 @@ contains(QT_CONFIG, angle)|contains(QT_CONFIG, dynamicgl) {
QT += gui-private
HEADERS += \
- evrcustompresenter.h \
- evrd3dpresentengine.h
+ $$PWD/evrcustompresenter.h \
+ $$PWD/evrd3dpresentengine.h
SOURCES += \
- evrcustompresenter.cpp \
- evrd3dpresentengine.cpp
+ $$PWD/evrcustompresenter.cpp \
+ $$PWD/evrd3dpresentengine.cpp
}
-
include (player/player.pri)
include (decoder/decoder.pri)
diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput_render_p.h b/src/qtmultimediaquicktools/qdeclarativevideooutput_render_p.h
index cb1168ee9..e05adc3b1 100644
--- a/src/qtmultimediaquicktools/qdeclarativevideooutput_render_p.h
+++ b/src/qtmultimediaquicktools/qdeclarativevideooutput_render_p.h
@@ -35,10 +35,21 @@
#ifndef QDECLARATIVEVIDEOOUTPUT_RENDER_P_H
#define QDECLARATIVEVIDEOOUTPUT_RENDER_P_H
-#include "qdeclarativevideooutput_backend_p.h"
-#include "qsgvideonode_yuv.h"
-#include "qsgvideonode_rgb.h"
-#include "qsgvideonode_texture.h"
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists 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/qdeclarativevideooutput_backend_p.h>
+#include <private/qsgvideonode_yuv_p.h>
+#include <private/qsgvideonode_rgb_p.h>
+#include <private/qsgvideonode_texture_p.h>
#include <QtCore/qmutex.h>
#include <QtMultimedia/qabstractvideosurface.h>
diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput_window_p.h b/src/qtmultimediaquicktools/qdeclarativevideooutput_window_p.h
index 446ce52cd..a7c5ee810 100644
--- a/src/qtmultimediaquicktools/qdeclarativevideooutput_window_p.h
+++ b/src/qtmultimediaquicktools/qdeclarativevideooutput_window_p.h
@@ -34,7 +34,18 @@
#ifndef QDECLARATIVEVIDEOOUTPUT_WINDOW_P_H
#define QDECLARATIVEVIDEOOUTPUT_WINDOW_P_H
-#include "qdeclarativevideooutput_backend_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/qdeclarativevideooutput_backend_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qtmultimediaquicktools/qsgvideonode_p.cpp b/src/qtmultimediaquicktools/qsgvideonode_p.cpp
index 0fb4239d6..28d11e239 100644
--- a/src/qtmultimediaquicktools/qsgvideonode_p.cpp
+++ b/src/qtmultimediaquicktools/qsgvideonode_p.cpp
@@ -118,4 +118,8 @@ void QSGVideoNode::setTexturedRectGeometry(const QRectF &rect, const QRectF &tex
markDirty(DirtyGeometry);
}
+QSGVideoNodeFactoryInterface::~QSGVideoNodeFactoryInterface()
+{
+}
+
QT_END_NAMESPACE
diff --git a/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp b/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp
index 5093acb59..1ba8f98bf 100644
--- a/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp
+++ b/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp
@@ -30,7 +30,7 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#include "qsgvideonode_rgb.h"
+#include "qsgvideonode_rgb_p.h"
#include <QtQuick/qsgtexturematerial.h>
#include <QtQuick/qsgmaterial.h>
#include <QtCore/qmutex.h>
diff --git a/src/qtmultimediaquicktools/qsgvideonode_rgb.h b/src/qtmultimediaquicktools/qsgvideonode_rgb_p.h
index 77d11b6d8..501df9cbc 100644
--- a/src/qtmultimediaquicktools/qsgvideonode_rgb.h
+++ b/src/qtmultimediaquicktools/qsgvideonode_rgb_p.h
@@ -34,6 +34,17 @@
#ifndef QSGVIDEONODE_RGB_H
#define QSGVIDEONODE_RGB_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists 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/qsgvideonode_p.h>
#include <QtMultimedia/qvideosurfaceformat.h>
diff --git a/src/qtmultimediaquicktools/qsgvideonode_texture.cpp b/src/qtmultimediaquicktools/qsgvideonode_texture.cpp
index 500c1c62f..1170af792 100644
--- a/src/qtmultimediaquicktools/qsgvideonode_texture.cpp
+++ b/src/qtmultimediaquicktools/qsgvideonode_texture.cpp
@@ -30,7 +30,7 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#include "qsgvideonode_texture.h"
+#include "qsgvideonode_texture_p.h"
#include <QtQuick/qsgtexturematerial.h>
#include <QtQuick/qsgmaterial.h>
#include <QtCore/qmutex.h>
diff --git a/src/qtmultimediaquicktools/qsgvideonode_texture.h b/src/qtmultimediaquicktools/qsgvideonode_texture_p.h
index 0849c574f..0304b2efe 100644
--- a/src/qtmultimediaquicktools/qsgvideonode_texture.h
+++ b/src/qtmultimediaquicktools/qsgvideonode_texture_p.h
@@ -34,6 +34,17 @@
#ifndef QSGVIDEONODE_TEXTURE_H
#define QSGVIDEONODE_TEXTURE_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists 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/qsgvideonode_p.h>
#include <QtMultimedia/qvideosurfaceformat.h>
diff --git a/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp b/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp
index af1e98cdf..b2979f50b 100644
--- a/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp
+++ b/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp
@@ -30,7 +30,7 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#include "qsgvideonode_yuv.h"
+#include "qsgvideonode_yuv_p.h"
#include <QtCore/qmutex.h>
#include <QtQuick/qsgtexturematerial.h>
#include <QtQuick/qsgmaterial.h>
diff --git a/src/qtmultimediaquicktools/qsgvideonode_yuv.h b/src/qtmultimediaquicktools/qsgvideonode_yuv_p.h
index 776f0a5a2..9c0a1f36a 100644
--- a/src/qtmultimediaquicktools/qsgvideonode_yuv.h
+++ b/src/qtmultimediaquicktools/qsgvideonode_yuv_p.h
@@ -34,6 +34,17 @@
#ifndef QSGVIDEONODE_YUV_H
#define QSGVIDEONODE_YUV_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists 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/qsgvideonode_p.h>
#include <QtMultimedia/qvideosurfaceformat.h>
diff --git a/src/qtmultimediaquicktools/qtmultimediaquicktools.pro b/src/qtmultimediaquicktools/qtmultimediaquicktools.pro
index 61c5f7b20..b38f209e3 100644
--- a/src/qtmultimediaquicktools/qtmultimediaquicktools.pro
+++ b/src/qtmultimediaquicktools/qtmultimediaquicktools.pro
@@ -9,12 +9,21 @@ DEFINES += QT_BUILD_QTMM_QUICK_LIB
# Header files must go inside source directory of a module
# to be installed by syncqt.
INCLUDEPATH += ../multimedia/qtmultimediaquicktools_headers/
+VPATH += ../multimedia/qtmultimediaquicktools_headers/
PRIVATE_HEADERS += \
- ../multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_p.h \
- ../multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_backend_p.h \
- ../multimedia/qtmultimediaquicktools_headers/qsgvideonode_p.h \
- ../multimedia/qtmultimediaquicktools_headers/qtmultimediaquickdefs_p.h
+ qdeclarativevideooutput_p.h \
+ qdeclarativevideooutput_backend_p.h \
+ qsgvideonode_p.h \
+ qtmultimediaquickdefs_p.h
+
+HEADERS += \
+ $$PRIVATE_HEADERS \
+ qdeclarativevideooutput_render_p.h \
+ qdeclarativevideooutput_window_p.h \
+ qsgvideonode_yuv_p.h \
+ qsgvideonode_rgb_p.h \
+ qsgvideonode_texture_p.h
SOURCES += \
qsgvideonode_p.cpp \
@@ -25,14 +34,6 @@ SOURCES += \
qsgvideonode_rgb.cpp \
qsgvideonode_texture.cpp
-HEADERS += \
- $$PRIVATE_HEADERS \
- qdeclarativevideooutput_render_p.h \
- qdeclarativevideooutput_window_p.h \
- qsgvideonode_yuv.h \
- qsgvideonode_rgb.h \
- qsgvideonode_texture.h
-
RESOURCES += \
qtmultimediaquicktools.qrc
diff --git a/src/src.pro b/src/src.pro
index 26f99bc29..e8d430e51 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -20,6 +20,9 @@ qtHaveModule(quick) {
src_imports.subdir = imports
src_imports.depends = multimedia src_qtmultimediaquicktools
+ # For the videonode plugin
+ src_plugins.depends += src_qtmultimediaquicktools
+
SUBDIRS += \
src_qtmultimediaquicktools \
src_imports
diff --git a/tests/auto/integration/qaudiodecoderbackend/BLACKLIST b/tests/auto/integration/qaudiodecoderbackend/BLACKLIST
new file mode 100644
index 000000000..038b89022
--- /dev/null
+++ b/tests/auto/integration/qaudiodecoderbackend/BLACKLIST
@@ -0,0 +1,41 @@
+# QTBUG-46331
+
+[fileTest]
+opensuse-13.1 64bit
+redhatenterpriselinuxworkstation-6.6
+osx-10.8
+osx-10.9
+osx-10.10
+osx-10.11
+windows 32bit developer-build
+windows 64bit developer-build
+
+[unsupportedFileTest]
+opensuse-13.1 64bit
+redhatenterpriselinuxworkstation-6.6
+osx-10.8
+osx-10.9
+osx-10.10
+osx-10.11
+windows 32bit developer-build
+windows 64bit developer-build
+
+[corruptedFileTest]
+opensuse-13.1 64bit
+redhatenterpriselinuxworkstation-6.6
+osx-10.8
+osx-10.9
+osx-10.10
+osx-10.11
+windows 32bit developer-build
+windows 64bit developer-build
+
+[deviceTest]
+opensuse-13.1 64bit
+redhatenterpriselinuxworkstation-6.6
+osx-10.8
+osx-10.9
+osx-10.10
+osx-10.11
+windows 32bit developer-build
+windows 64bit developer-build
diff --git a/tests/auto/integration/qaudiodecoderbackend/qaudiodecoderbackend.pro b/tests/auto/integration/qaudiodecoderbackend/qaudiodecoderbackend.pro
index 80ce0c112..c9f5a089c 100644
--- a/tests/auto/integration/qaudiodecoderbackend/qaudiodecoderbackend.pro
+++ b/tests/auto/integration/qaudiodecoderbackend/qaudiodecoderbackend.pro
@@ -3,7 +3,7 @@ TARGET = tst_qaudiodecoderbackend
QT += multimedia multimedia-private testlib
# This is more of a system test
-CONFIG += testcase insignificant_test
+CONFIG += testcase
TESTDATA += testdata/*
INCLUDEPATH += \
diff --git a/tests/auto/integration/qaudiodeviceinfo/BLACKLIST b/tests/auto/integration/qaudiodeviceinfo/BLACKLIST
new file mode 100644
index 000000000..40dc63a09
--- /dev/null
+++ b/tests/auto/integration/qaudiodeviceinfo/BLACKLIST
@@ -0,0 +1,4 @@
+# QTBUG-46409
+
+[deviceName]
+redhatenterpriselinuxworkstation-6.6
diff --git a/tests/auto/integration/qaudiodeviceinfo/qaudiodeviceinfo.pro b/tests/auto/integration/qaudiodeviceinfo/qaudiodeviceinfo.pro
index 69bd792bc..98ed7e69c 100644
--- a/tests/auto/integration/qaudiodeviceinfo/qaudiodeviceinfo.pro
+++ b/tests/auto/integration/qaudiodeviceinfo/qaudiodeviceinfo.pro
@@ -3,7 +3,7 @@ TARGET = tst_qaudiodeviceinfo
QT += core multimedia-private testlib
# This is more of a system test
-CONFIG += testcase insignificant_test
+CONFIG += testcase
SOURCES += tst_qaudiodeviceinfo.cpp
diff --git a/tests/auto/integration/qaudioinput/tst_qaudioinput.cpp b/tests/auto/integration/qaudioinput/tst_qaudioinput.cpp
index 242787841..242787841 100755..100644
--- a/tests/auto/integration/qaudioinput/tst_qaudioinput.cpp
+++ b/tests/auto/integration/qaudioinput/tst_qaudioinput.cpp
diff --git a/tests/auto/integration/qaudioinput/wavheader.cpp b/tests/auto/integration/qaudioinput/wavheader.cpp
index adb28e7a7..adb28e7a7 100755..100644
--- a/tests/auto/integration/qaudioinput/wavheader.cpp
+++ b/tests/auto/integration/qaudioinput/wavheader.cpp
diff --git a/tests/auto/integration/qaudioinput/wavheader.h b/tests/auto/integration/qaudioinput/wavheader.h
index 04fd951f6..04fd951f6 100755..100644
--- a/tests/auto/integration/qaudioinput/wavheader.h
+++ b/tests/auto/integration/qaudioinput/wavheader.h
diff --git a/tests/auto/integration/qaudiooutput/BLACKLIST b/tests/auto/integration/qaudiooutput/BLACKLIST
new file mode 100644
index 000000000..e640ef926
--- /dev/null
+++ b/tests/auto/integration/qaudiooutput/BLACKLIST
@@ -0,0 +1,4 @@
+[pullSuspendResume]
+redhatenterpriselinuxworkstation-6.6
+ubuntu-14.04
+opensuse-13.1 64bit
diff --git a/tests/auto/integration/qaudiooutput/tst_qaudiooutput.cpp b/tests/auto/integration/qaudiooutput/tst_qaudiooutput.cpp
index 81aa97d91..81aa97d91 100755..100644
--- a/tests/auto/integration/qaudiooutput/tst_qaudiooutput.cpp
+++ b/tests/auto/integration/qaudiooutput/tst_qaudiooutput.cpp
diff --git a/tests/auto/integration/qaudiooutput/wavheader.cpp b/tests/auto/integration/qaudiooutput/wavheader.cpp
index adb28e7a7..adb28e7a7 100755..100644
--- a/tests/auto/integration/qaudiooutput/wavheader.cpp
+++ b/tests/auto/integration/qaudiooutput/wavheader.cpp
diff --git a/tests/auto/integration/qaudiooutput/wavheader.h b/tests/auto/integration/qaudiooutput/wavheader.h
index 04fd951f6..04fd951f6 100755..100644
--- a/tests/auto/integration/qaudiooutput/wavheader.h
+++ b/tests/auto/integration/qaudiooutput/wavheader.h
diff --git a/tests/auto/integration/qmediaplayerbackend/BLACKLIST b/tests/auto/integration/qmediaplayerbackend/BLACKLIST
new file mode 100644
index 000000000..9f0d4b746
--- /dev/null
+++ b/tests/auto/integration/qmediaplayerbackend/BLACKLIST
@@ -0,0 +1,62 @@
+# QTBUG-46368
+
+osx-10.8
+osx-10.9
+osx-10.10
+osx-10.11
+windows 32bit developer-build
+windows 64bit developer-build
+
+[construction]
+opensuse-13.1 64bit
+
+[loadMedia]
+opensuse-13.1 64bit
+windows 64bit developer-build
+
+[unloadMedia]
+opensuse-13.1 64bit
+windows 64bit developer-build
+
+[playPauseStop]
+opensuse-13.1 64bit
+redhatenterpriselinuxworkstation-6.6
+ubuntu-14.04 64bit
+windows 64bit developer-build
+
+[processEOS]
+opensuse-13.1 64bit
+windows 64bit developer-build
+
+[deleteLaterAtEOS]
+opensuse-13.1 64bit
+windows 64bit developer-build
+
+[volumeAndMuted]
+opensuse-13.1 64bit
+
+[volumeAcrossFiles]
+opensuse-13.1 64bit
+
+[initialVolume]
+opensuse-13.1 64bit
+windows 64bit developer-build
+
+[playlist]
+opensuse-13.1 64bit
+redhatenterpriselinuxworkstation-6.6
+
+[seekPauseSeek]
+redhatenterpriselinuxworkstation-6.6
+
+[seekInStoppedState]
+redhatenterpriselinuxworkstation-6.6
+
+[subsequentPlayback]
+redhatenterpriselinuxworkstation-6.6
+
+[probes]
+redhatenterpriselinuxworkstation-6.6
+
+[surfaceTest]
+redhatenterpriselinuxworkstation-6.6
diff --git a/tests/auto/integration/qmediaplayerbackend/qmediaplayerbackend.pro b/tests/auto/integration/qmediaplayerbackend/qmediaplayerbackend.pro
index 79028d885..a2c1bdf87 100644
--- a/tests/auto/integration/qmediaplayerbackend/qmediaplayerbackend.pro
+++ b/tests/auto/integration/qmediaplayerbackend/qmediaplayerbackend.pro
@@ -3,7 +3,7 @@ TARGET = tst_qmediaplayerbackend
QT += multimedia-private testlib
# This is more of a system test
-CONFIG += testcase insignificant_test
+CONFIG += testcase
SOURCES += \
diff --git a/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp b/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp
index 916f70eff..c032734c5 100644
--- a/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp
+++ b/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp
@@ -220,13 +220,13 @@ void tst_QMediaPlayerBackend::initTestCase()
qRegisterMetaType<QMediaContent>();
QStringList mediaCandidates;
- mediaCandidates << QFINDTESTDATA("testdata/colors.ogv");
mediaCandidates << QFINDTESTDATA("testdata/colors.mp4");
+ mediaCandidates << QFINDTESTDATA("testdata/colors.ogv");
localVideoFile = selectMediaFile(mediaCandidates);
mediaCandidates.clear();
- mediaCandidates << QFINDTESTDATA("testdata/nokia-tune.mkv");
mediaCandidates << QFINDTESTDATA("testdata/nokia-tune.mp3");
+ mediaCandidates << QFINDTESTDATA("testdata/nokia-tune.mkv");
localCompressedSoundFile = selectMediaFile(mediaCandidates);
localFileWithMetadata = selectMediaFile(QStringList() << QFINDTESTDATA("testdata/nokia-tune.mp3"));
@@ -478,7 +478,7 @@ void tst_QMediaPlayerBackend::processEOS()
//position is reset to start
QTRY_VERIFY(player.position() < 100);
- QVERIFY(positionSpy.count() > 0);
+ QTRY_VERIFY(positionSpy.count() > 0);
QCOMPARE(positionSpy.first()[0].value<qint64>(), 0);
QCOMPARE(player.state(), QMediaPlayer::PlayingState);
@@ -720,7 +720,7 @@ void tst_QMediaPlayerBackend::seekPauseSeek()
player.pause();
QTRY_COMPARE(player.state(), QMediaPlayer::PausedState); // it might take some time for the operation to be completed
- QTRY_COMPARE(surface->m_frameList.size(), 1); // we must see a frame at position 7000 here
+ QTRY_VERIFY(!surface->m_frameList.isEmpty()); // we must see a frame at position 7000 here
{
QVideoFrame frame = surface->m_frameList.back();
@@ -739,12 +739,13 @@ void tst_QMediaPlayerBackend::seekPauseSeek()
frame.unmap();
}
+ surface->m_frameList.clear();
positionSpy.clear();
position = 12000;
player.setPosition(position);
QTRY_VERIFY(!positionSpy.isEmpty() && qAbs(player.position() - position) < (qint64)500);
QCOMPARE(player.state(), QMediaPlayer::PausedState);
- QCOMPARE(surface->m_frameList.size(), 2);
+ QVERIFY(!surface->m_frameList.isEmpty());
{
QVideoFrame frame = surface->m_frameList.back();
diff --git a/tests/auto/integration/qsoundeffect/BLACKLIST b/tests/auto/integration/qsoundeffect/BLACKLIST
new file mode 100644
index 000000000..f290cc8ff
--- /dev/null
+++ b/tests/auto/integration/qsoundeffect/BLACKLIST
@@ -0,0 +1,6 @@
+# QTBUG-46689
+
+[testLooping]
+ubuntu-14.04 64bit
+redhatenterpriselinuxworkstation-6.6
+opensuse-13.1
diff --git a/tests/auto/integration/qsoundeffect/qsoundeffect.pro b/tests/auto/integration/qsoundeffect/qsoundeffect.pro
index cb186db20..bce5fc77a 100644
--- a/tests/auto/integration/qsoundeffect/qsoundeffect.pro
+++ b/tests/auto/integration/qsoundeffect/qsoundeffect.pro
@@ -15,6 +15,6 @@ unix:!mac {
TESTDATA += test.wav
-win32:CONFIG += insignificant_test # QTBUG-26509
-linux-*:CONFIG += insignificant_test # QTBUG-26748
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
+
+config_pulseaudio: CONFIG += insignificant_testcase # Crashes in QSoundEffectPrivate::sampleReady with bufferAttr == 0
diff --git a/tests/auto/unit/qaudiodecoder/tst_qaudiodecoder.cpp b/tests/auto/unit/qaudiodecoder/tst_qaudiodecoder.cpp
index 72ba0484c..5d1e045d0 100644
--- a/tests/auto/unit/qaudiodecoder/tst_qaudiodecoder.cpp
+++ b/tests/auto/unit/qaudiodecoder/tst_qaudiodecoder.cpp
@@ -128,7 +128,7 @@ void tst_QAudioDecoder::read()
QVERIFY(!b.isValid());
// Wait a while
- QTRY_COMPARE(d.bufferAvailable(), 1);
+ QTRY_VERIFY(d.bufferAvailable());
QVERIFY(d.bufferAvailable());
@@ -189,7 +189,7 @@ void tst_QAudioDecoder::stop()
QVERIFY(!b.isValid());
// Wait a while
- QTRY_COMPARE(d.bufferAvailable(), 1);
+ QTRY_VERIFY(d.bufferAvailable());
QVERIFY(d.bufferAvailable());
@@ -231,7 +231,7 @@ void tst_QAudioDecoder::format()
QVERIFY(!b.isValid());
// Wait a while
- QTRY_COMPARE(d.bufferAvailable(), 1);
+ QTRY_VERIFY(d.bufferAvailable());
b = d.read();
QVERIFY(d.audioFormat() == b.format());
@@ -251,7 +251,7 @@ void tst_QAudioDecoder::format()
// Decode again
d.start();
- QTRY_COMPARE(d.bufferAvailable(), 1);
+ QTRY_VERIFY(d.bufferAvailable());
b = d.read();
QVERIFY(d.audioFormat() == f);
diff --git a/tests/auto/unit/qdeclarativeaudio/qdeclarativeaudio.pro b/tests/auto/unit/qdeclarativeaudio/qdeclarativeaudio.pro
index 6471f7b2a..e36c7dc1f 100644
--- a/tests/auto/unit/qdeclarativeaudio/qdeclarativeaudio.pro
+++ b/tests/auto/unit/qdeclarativeaudio/qdeclarativeaudio.pro
@@ -13,3 +13,7 @@ SOURCES += \
INCLUDEPATH += ../../../../src/imports/multimedia
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
+
+include (../qmultimedia_common/mock.pri)
+include (../qmultimedia_common/mockplayer.pri)
+
diff --git a/tests/auto/unit/qdeclarativeaudio/tst_qdeclarativeaudio.cpp b/tests/auto/unit/qdeclarativeaudio/tst_qdeclarativeaudio.cpp
index a257ee7b6..355e25331 100644
--- a/tests/auto/unit/qdeclarativeaudio/tst_qdeclarativeaudio.cpp
+++ b/tests/auto/unit/qdeclarativeaudio/tst_qdeclarativeaudio.cpp
@@ -38,6 +38,9 @@
#include "qdeclarativeaudio_p.h"
#include "qdeclarativemediametadata_p.h"
+#include "mockmediaserviceprovider.h"
+#include "mockmediaplayerservice.h"
+
#include <QtMultimedia/qmediametadata.h>
#include <qmediaplayercontrol.h>
#include <qmediaservice.h>
@@ -45,6 +48,8 @@
#include <qmetadatareadercontrol.h>
#include <QtGui/qguiapplication.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcomponent.h>
class tst_QDeclarativeAudio : public QObject
{
@@ -73,9 +78,11 @@ private slots:
void metaData();
void error();
void loops();
+ void audioRole();
};
Q_DECLARE_METATYPE(QDeclarativeAudio::Error);
+Q_DECLARE_METATYPE(QDeclarativeAudio::AudioRole);
class QtTestMediaPlayerControl : public QMediaPlayerControl
{
@@ -285,6 +292,7 @@ public:
void tst_QDeclarativeAudio::initTestCase()
{
qRegisterMetaType<QDeclarativeAudio::Error>();
+ qRegisterMetaType<QDeclarativeAudio::AudioRole>();
}
void tst_QDeclarativeAudio::nullPlayerControl()
@@ -1007,6 +1015,47 @@ void tst_QDeclarativeAudio::loops()
qDebug() << "Testing version 5";
}
+void tst_QDeclarativeAudio::audioRole()
+{
+ MockMediaPlayerService mockService;
+ MockMediaServiceProvider mockProvider(&mockService);
+ QMediaServiceProvider::setDefaultServiceProvider(&mockProvider);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick 2.0 \n import QtMultimedia 5.6 \n Audio { }", QUrl());
+
+ {
+ mockService.setHasAudioRole(false);
+ QDeclarativeAudio *audio = static_cast<QDeclarativeAudio*>(component.create());
+
+ QCOMPARE(audio->audioRole(), QDeclarativeAudio::UnknownRole);
+ QVERIFY(audio->supportedAudioRoles().isArray());
+ QVERIFY(audio->supportedAudioRoles().toVariant().toList().isEmpty());
+
+ QSignalSpy spy(audio, SIGNAL(audioRoleChanged()));
+ audio->setAudioRole(QDeclarativeAudio::MusicRole);
+ QCOMPARE(audio->audioRole(), QDeclarativeAudio::UnknownRole);
+ QCOMPARE(spy.count(), 0);
+ }
+
+ {
+ mockService.reset();
+ mockService.setHasAudioRole(true);
+ QDeclarativeAudio *audio = static_cast<QDeclarativeAudio*>(component.create());
+ QSignalSpy spy(audio, SIGNAL(audioRoleChanged()));
+
+ QCOMPARE(audio->audioRole(), QDeclarativeAudio::UnknownRole);
+ QVERIFY(audio->supportedAudioRoles().isArray());
+ QVERIFY(!audio->supportedAudioRoles().toVariant().toList().isEmpty());
+
+ audio->setAudioRole(QDeclarativeAudio::MusicRole);
+ QCOMPARE(audio->audioRole(), QDeclarativeAudio::MusicRole);
+ QCOMPARE(mockService.mockAudioRoleControl->audioRole(), QAudio::MusicRole);
+ QCOMPARE(spy.count(), 1);
+ }
+}
+
QTEST_MAIN(tst_QDeclarativeAudio)
#include "tst_qdeclarativeaudio.moc"
diff --git a/tests/auto/unit/qmediaplayer/tst_qmediaplayer.cpp b/tests/auto/unit/qmediaplayer/tst_qmediaplayer.cpp
index 0271f1a8f..84248cd46 100644
--- a/tests/auto/unit/qmediaplayer/tst_qmediaplayer.cpp
+++ b/tests/auto/unit/qmediaplayer/tst_qmediaplayer.cpp
@@ -135,6 +135,7 @@ private slots:
void testSupportedMimeTypes();
void testQrc_data();
void testQrc();
+ void testAudioRole();
private:
void setupCommonTestData();
@@ -1296,5 +1297,45 @@ void tst_QMediaPlayer::testQrc()
QCOMPARE(bool(mockService->mockControl->mediaStream()), backendHasStream);
}
+void tst_QMediaPlayer::testAudioRole()
+{
+ {
+ mockService->setHasAudioRole(false);
+ QMediaPlayer player;
+
+ QCOMPARE(player.audioRole(), QAudio::UnknownRole);
+ QVERIFY(player.supportedAudioRoles().isEmpty());
+
+ QSignalSpy spy(&player, SIGNAL(audioRoleChanged(QAudio::Role)));
+ player.setAudioRole(QAudio::MusicRole);
+ QCOMPARE(player.audioRole(), QAudio::UnknownRole);
+ QCOMPARE(spy.count(), 0);
+ }
+
+ {
+ mockService->reset();
+ mockService->setHasAudioRole(true);
+ QMediaPlayer player;
+ QSignalSpy spy(&player, SIGNAL(audioRoleChanged(QAudio::Role)));
+
+ QCOMPARE(player.audioRole(), QAudio::UnknownRole);
+ QVERIFY(!player.supportedAudioRoles().isEmpty());
+
+ player.setAudioRole(QAudio::MusicRole);
+ QCOMPARE(player.audioRole(), QAudio::MusicRole);
+ QCOMPARE(mockService->mockAudioRoleControl->audioRole(), QAudio::MusicRole);
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(qvariant_cast<QAudio::Role>(spy.last().value(0)), QAudio::MusicRole);
+
+ spy.clear();
+
+ player.setProperty("audioRole", qVariantFromValue(QAudio::AlarmRole));
+ QCOMPARE(qvariant_cast<QAudio::Role>(player.property("audioRole")), QAudio::AlarmRole);
+ QCOMPARE(mockService->mockAudioRoleControl->audioRole(), QAudio::AlarmRole);
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(qvariant_cast<QAudio::Role>(spy.last().value(0)), QAudio::AlarmRole);
+ }
+}
+
QTEST_GUILESS_MAIN(tst_QMediaPlayer)
#include "tst_qmediaplayer.moc"
diff --git a/tests/auto/unit/qmediaplaylist/tst_qmediaplaylist.cpp b/tests/auto/unit/qmediaplaylist/tst_qmediaplaylist.cpp
index daecda82b..104046d0e 100644
--- a/tests/auto/unit/qmediaplaylist/tst_qmediaplaylist.cpp
+++ b/tests/auto/unit/qmediaplaylist/tst_qmediaplaylist.cpp
@@ -51,14 +51,16 @@
QT_USE_NAMESPACE
-class MockReadOnlyPlaylistObject : public QMediaObject
+class MockPlaylistObject : public QMediaObject
{
Q_OBJECT
public:
- MockReadOnlyPlaylistObject(QObject *parent = 0)
- :QMediaObject(parent, new MockPlaylistService)
+ MockPlaylistObject(QObject *parent = 0)
+ : QMediaObject(parent, mockService = new MockPlaylistService)
{
}
+
+ MockPlaylistService *mockService;
};
class tst_QMediaPlaylist : public QObject
@@ -711,7 +713,9 @@ void tst_QMediaPlaylist::shuffle()
void tst_QMediaPlaylist::readOnlyPlaylist()
{
- MockReadOnlyPlaylistObject mediaObject;
+ MockPlaylistObject mediaObject;
+ mediaObject.mockService->mockControl->setReadOnly(true);
+
QMediaPlaylist playlist;
mediaObject.bind(&playlist);
@@ -777,26 +781,280 @@ void tst_QMediaPlaylist::readOnlyPlaylist()
void tst_QMediaPlaylist::setMediaObject()
{
- MockReadOnlyPlaylistObject mediaObject;
-
- QMediaPlaylist playlist;
- QVERIFY(playlist.mediaObject() == 0);
- QVERIFY(!playlist.isReadOnly());
-
- mediaObject.bind(&playlist);
- QCOMPARE(playlist.mediaObject(), qobject_cast<QMediaObject*>(&mediaObject));
- QCOMPARE(playlist.mediaCount(), 3);
- QVERIFY(playlist.isReadOnly());
-
- mediaObject.unbind(&playlist);
- QVERIFY(playlist.mediaObject() == 0);
- QCOMPARE(playlist.mediaCount(), 0);
- QVERIFY(!playlist.isReadOnly());
+ QMediaContent content0(QUrl(QLatin1String("test://audio/song1.mp3")));
+ QMediaContent content1(QUrl(QLatin1String("test://audio/song2.mp3")));
+ QMediaContent content2(QUrl(QLatin1String("test://video/movie1.mp4")));
+ QMediaContent content3(QUrl(QLatin1String("test://video/movie2.mp4")));
- mediaObject.bind(&playlist);
- QCOMPARE(playlist.mediaObject(), qobject_cast<QMediaObject*>(&mediaObject));
- QCOMPARE(playlist.mediaCount(), 3);
- QVERIFY(playlist.isReadOnly());
+ {
+ MockPlaylistObject mediaObject;
+
+ QMediaPlaylist playlist;
+ QSignalSpy currentIndexSpy(&playlist, SIGNAL(currentIndexChanged(int)));
+ QSignalSpy playbackModeSpy(&playlist, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)));
+ QSignalSpy mediaAboutToBeInsertedSpy(&playlist, SIGNAL(mediaAboutToBeInserted(int, int)));
+ QSignalSpy mediaInsertedSpy(&playlist, SIGNAL(mediaInserted(int, int)));
+ QSignalSpy mediaAboutToBeRemovedSpy(&playlist, SIGNAL(mediaAboutToBeRemoved(int, int)));
+ QSignalSpy mediaRemovedSpy(&playlist, SIGNAL(mediaRemoved(int, int)));
+ QSignalSpy mediaChangedSpy(&playlist, SIGNAL(mediaChanged(int, int)));
+
+ QVERIFY(playlist.isEmpty());
+
+ mediaObject.bind(&playlist);
+
+ // Playlist is now using the service's control, nothing should have changed
+ QVERIFY(playlist.isEmpty());
+ QCOMPARE(playlist.currentIndex(), -1);
+ QCOMPARE(playlist.playbackMode(), QMediaPlaylist::Sequential);
+ QCOMPARE(currentIndexSpy.count(), 0);
+ QCOMPARE(playbackModeSpy.count(), 0);
+ QCOMPARE(mediaAboutToBeInsertedSpy.count(), 0);
+ QCOMPARE(mediaInsertedSpy.count(), 0);
+ QCOMPARE(mediaAboutToBeRemovedSpy.count(), 0);
+ QCOMPARE(mediaRemovedSpy.count(), 0);
+ QCOMPARE(mediaChangedSpy.count(), 0);
+
+ // add items to service's playlist control
+ playlist.addMedia(content0);
+ playlist.addMedia(content1);
+ playlist.setCurrentIndex(1);
+ playlist.setPlaybackMode(QMediaPlaylist::Random);
+ QCOMPARE(playlist.mediaCount(), 2);
+ QCOMPARE(playlist.currentIndex(), 1);
+ QCOMPARE(playlist.currentMedia(), content1);
+ QCOMPARE(playlist.playbackMode(), QMediaPlaylist::Random);
+
+ currentIndexSpy.clear();
+ playbackModeSpy.clear();
+ mediaAboutToBeInsertedSpy.clear();
+ mediaInsertedSpy.clear();
+ mediaAboutToBeRemovedSpy.clear();
+ mediaRemovedSpy.clear();
+ mediaChangedSpy.clear();
+
+ // unbind the playlist, reverting back to the internal control.
+ // playlist content should't have changed.
+ mediaObject.unbind(&playlist);
+ QCOMPARE(playlist.mediaCount(), 2);
+ QCOMPARE(playlist.currentIndex(), 1);
+ QCOMPARE(playlist.currentMedia(), content1);
+ QCOMPARE(playlist.playbackMode(), QMediaPlaylist::Random);
+ QCOMPARE(playbackModeSpy.count(), 0);
+ QCOMPARE(mediaAboutToBeInsertedSpy.count(), 0);
+ QCOMPARE(mediaInsertedSpy.count(), 0);
+ QCOMPARE(mediaAboutToBeRemovedSpy.count(), 0);
+ QCOMPARE(mediaRemovedSpy.count(), 0);
+ QCOMPARE(mediaChangedSpy.count(), 0);
+ }
+ {
+ MockPlaylistObject mediaObject;
+
+ QMediaPlaylist playlist;
+ QVERIFY(playlist.isEmpty());
+ // Add items to playlist before binding to the service (internal control)
+ playlist.addMedia(content0);
+ playlist.addMedia(content1);
+ playlist.addMedia(content2);
+ playlist.setCurrentIndex(2);
+ playlist.setPlaybackMode(QMediaPlaylist::CurrentItemOnce);
+
+ QSignalSpy currentIndexSpy(&playlist, SIGNAL(currentIndexChanged(int)));
+ QSignalSpy playbackModeSpy(&playlist, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)));
+ QSignalSpy mediaAboutToBeInsertedSpy(&playlist, SIGNAL(mediaAboutToBeInserted(int, int)));
+ QSignalSpy mediaInsertedSpy(&playlist, SIGNAL(mediaInserted(int, int)));
+ QSignalSpy mediaAboutToBeRemovedSpy(&playlist, SIGNAL(mediaAboutToBeRemoved(int, int)));
+ QSignalSpy mediaRemovedSpy(&playlist, SIGNAL(mediaRemoved(int, int)));
+ QSignalSpy mediaChangedSpy(&playlist, SIGNAL(mediaChanged(int, int)));
+
+ // Bind playlist, content should be unchanged
+ mediaObject.bind(&playlist);
+ QCOMPARE(playlist.mediaCount(), 3);
+ QCOMPARE(playlist.currentIndex(), 2);
+ QCOMPARE(playlist.currentMedia(), content2);
+ QCOMPARE(playlist.playbackMode(), QMediaPlaylist::CurrentItemOnce);
+ QCOMPARE(currentIndexSpy.count(), 0);
+ QCOMPARE(playbackModeSpy.count(), 0);
+ QCOMPARE(mediaAboutToBeInsertedSpy.count(), 0);
+ QCOMPARE(mediaInsertedSpy.count(), 0);
+ QCOMPARE(mediaAboutToBeRemovedSpy.count(), 0);
+ QCOMPARE(mediaRemovedSpy.count(), 0);
+ QCOMPARE(mediaChangedSpy.count(), 0);
+
+ // Clear playlist content (service's playlist control)
+ playlist.clear();
+ playlist.setCurrentIndex(-1);
+ playlist.setPlaybackMode(QMediaPlaylist::Random);
+
+ currentIndexSpy.clear();
+ playbackModeSpy.clear();
+ mediaAboutToBeInsertedSpy.clear();
+ mediaInsertedSpy.clear();
+ mediaAboutToBeRemovedSpy.clear();
+ mediaRemovedSpy.clear();
+ mediaChangedSpy.clear();
+
+ // unbind playlist from service, reverting back to the internal control.
+ // playlist should still be empty
+ mediaObject.unbind(&playlist);
+ QCOMPARE(playlist.mediaCount(), 0);
+ QCOMPARE(playlist.currentIndex(), -1);
+ QCOMPARE(playlist.currentMedia(), QMediaContent());
+ QCOMPARE(playlist.playbackMode(), QMediaPlaylist::Random);
+ QCOMPARE(playbackModeSpy.count(), 0);
+ QCOMPARE(mediaAboutToBeInsertedSpy.count(), 0);
+ QCOMPARE(mediaInsertedSpy.count(), 0);
+ QCOMPARE(mediaAboutToBeRemovedSpy.count(), 0);
+ QCOMPARE(mediaRemovedSpy.count(), 0);
+ QCOMPARE(mediaChangedSpy.count(), 0);
+ }
+ {
+ MockPlaylistObject mediaObject;
+
+ QMediaPlaylist playlist;
+ QVERIFY(playlist.isEmpty());
+ // Add items to playlist before attaching to media player (internal control)
+ playlist.addMedia(content0);
+ playlist.addMedia(content1);
+ playlist.setCurrentIndex(-1);
+ playlist.setPlaybackMode(QMediaPlaylist::CurrentItemOnce);
+
+ // Add items to service's playlist before binding
+ QMediaPlaylistProvider *pp = mediaObject.mockService->mockControl->playlistProvider();
+ pp->addMedia(content2);
+ pp->addMedia(content3);
+ mediaObject.mockService->mockControl->setCurrentIndex(1);
+ mediaObject.mockService->mockControl->setPlaybackMode(QMediaPlaylist::Random);
+
+ QSignalSpy currentIndexSpy(&playlist, SIGNAL(currentIndexChanged(int)));
+ QSignalSpy playbackModeSpy(&playlist, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)));
+ QSignalSpy mediaAboutToBeInsertedSpy(&playlist, SIGNAL(mediaAboutToBeInserted(int, int)));
+ QSignalSpy mediaInsertedSpy(&playlist, SIGNAL(mediaInserted(int, int)));
+ QSignalSpy mediaAboutToBeRemovedSpy(&playlist, SIGNAL(mediaAboutToBeRemoved(int, int)));
+ QSignalSpy mediaRemovedSpy(&playlist, SIGNAL(mediaRemoved(int, int)));
+ QSignalSpy mediaChangedSpy(&playlist, SIGNAL(mediaChanged(int, int)));
+
+ // Bind playlist, it should contain only what was explicitly added to the playlist.
+ // Anything that was present in the service's control should have been cleared
+ mediaObject.bind(&playlist);
+ QCOMPARE(playlist.mediaCount(), 2);
+ QCOMPARE(playlist.currentIndex(), -1);
+ QCOMPARE(playlist.playbackMode(), QMediaPlaylist::CurrentItemOnce);
+ QCOMPARE(currentIndexSpy.count(), 0);
+ QCOMPARE(playbackModeSpy.count(), 0);
+ QCOMPARE(mediaAboutToBeInsertedSpy.count(), 0);
+ QCOMPARE(mediaInsertedSpy.count(), 0);
+ QCOMPARE(mediaAboutToBeRemovedSpy.count(), 0);
+ QCOMPARE(mediaRemovedSpy.count(), 0);
+ QCOMPARE(mediaChangedSpy.count(), 0);
+
+ // do some changes
+ playlist.removeMedia(0); // content0
+ playlist.addMedia(content3);
+ playlist.setCurrentIndex(0);
+
+ currentIndexSpy.clear();
+ playbackModeSpy.clear();
+ mediaAboutToBeInsertedSpy.clear();
+ mediaInsertedSpy.clear();
+ mediaAboutToBeRemovedSpy.clear();
+ mediaRemovedSpy.clear();
+ mediaChangedSpy.clear();
+
+ // unbind playlist from service
+ mediaObject.unbind(&playlist);
+ QCOMPARE(playlist.mediaCount(), 2);
+ QCOMPARE(playlist.currentIndex(), 0);
+ QCOMPARE(playlist.currentMedia(), content1);
+ QCOMPARE(playlist.playbackMode(), QMediaPlaylist::CurrentItemOnce);
+ QCOMPARE(currentIndexSpy.count(), 0);
+ QCOMPARE(playbackModeSpy.count(), 0);
+ QCOMPARE(mediaAboutToBeInsertedSpy.count(), 0);
+ QCOMPARE(mediaInsertedSpy.count(), 0);
+ QCOMPARE(mediaAboutToBeRemovedSpy.count(), 0);
+ QCOMPARE(mediaRemovedSpy.count(), 0);
+ QCOMPARE(mediaChangedSpy.count(), 0);
+
+ // bind again, nothing should have changed
+ mediaObject.bind(&playlist);
+ QCOMPARE(playlist.mediaCount(), 2);
+ QCOMPARE(playlist.currentIndex(), 0);
+ QCOMPARE(playlist.currentMedia(), content1);
+ QCOMPARE(playlist.playbackMode(), QMediaPlaylist::CurrentItemOnce);
+ QCOMPARE(currentIndexSpy.count(), 0);
+ QCOMPARE(playbackModeSpy.count(), 0);
+ QCOMPARE(mediaAboutToBeInsertedSpy.count(), 0);
+ QCOMPARE(mediaInsertedSpy.count(), 0);
+ QCOMPARE(mediaAboutToBeRemovedSpy.count(), 0);
+ QCOMPARE(mediaRemovedSpy.count(), 0);
+ QCOMPARE(mediaChangedSpy.count(), 0);
+ }
+ {
+ MockPlaylistObject mediaObject;
+ mediaObject.mockService->mockControl->setReadOnly(true);
+
+ QMediaPlaylist playlist;
+ QVERIFY(playlist.isEmpty());
+ // Add items to playlist before binding to the service internal control)
+ playlist.addMedia(content0);
+ playlist.addMedia(content1);
+ playlist.setCurrentIndex(-1);
+ playlist.setPlaybackMode(QMediaPlaylist::CurrentItemOnce);
+
+ QSignalSpy currentIndexSpy(&playlist, SIGNAL(currentIndexChanged(int)));
+ QSignalSpy playbackModeSpy(&playlist, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)));
+ QSignalSpy mediaAboutToBeInsertedSpy(&playlist, SIGNAL(mediaAboutToBeInserted(int, int)));
+ QSignalSpy mediaInsertedSpy(&playlist, SIGNAL(mediaInserted(int, int)));
+ QSignalSpy mediaAboutToBeRemovedSpy(&playlist, SIGNAL(mediaAboutToBeRemoved(int, int)));
+ QSignalSpy mediaRemovedSpy(&playlist, SIGNAL(mediaRemoved(int, int)));
+ QSignalSpy mediaChangedSpy(&playlist, SIGNAL(mediaChanged(int, int)));
+
+ // Bind playlist. Since the service's control is read-only, no synchronization
+ // should be done with the internal control. The mediaRemoved() and mediaInserted()
+ // should be emitted to notify about the change.
+ mediaObject.bind(&playlist);
+ QCOMPARE(playlist.mediaCount(), 3);
+ QCOMPARE(playlist.currentIndex(), -1);
+ QCOMPARE(playlist.playbackMode(), QMediaPlaylist::CurrentItemOnce);
+ QCOMPARE(currentIndexSpy.count(), 0);
+ QCOMPARE(playbackModeSpy.count(), 0);
+
+ QCOMPARE(mediaAboutToBeRemovedSpy.count(), 1);
+ QCOMPARE(mediaAboutToBeRemovedSpy.last().at(0).toInt(), 0);
+ QCOMPARE(mediaAboutToBeRemovedSpy.last().at(1).toInt(), 1);
+ QCOMPARE(mediaRemovedSpy.count(), 1);
+ QCOMPARE(mediaRemovedSpy.last().at(0).toInt(), 0);
+ QCOMPARE(mediaRemovedSpy.last().at(1).toInt(), 1);
+
+ QCOMPARE(mediaAboutToBeInsertedSpy.count(), 1);
+ QCOMPARE(mediaAboutToBeInsertedSpy.last().at(0).toInt(), 0);
+ QCOMPARE(mediaAboutToBeInsertedSpy.last().at(1).toInt(), 2);
+ QCOMPARE(mediaInsertedSpy.count(), 1);
+ QCOMPARE(mediaInsertedSpy.last().at(0).toInt(), 0);
+ QCOMPARE(mediaInsertedSpy.last().at(1).toInt(), 2);
+
+ QCOMPARE(mediaChangedSpy.count(), 0);
+
+ currentIndexSpy.clear();
+ playbackModeSpy.clear();
+ mediaAboutToBeInsertedSpy.clear();
+ mediaInsertedSpy.clear();
+ mediaAboutToBeRemovedSpy.clear();
+ mediaRemovedSpy.clear();
+ mediaChangedSpy.clear();
+
+ // detach playlist from player
+ mediaObject.unbind(&playlist);
+ QCOMPARE(playlist.mediaCount(), 3);
+ QCOMPARE(playlist.currentIndex(), -1);
+ QCOMPARE(playlist.playbackMode(), QMediaPlaylist::CurrentItemOnce);
+ QCOMPARE(currentIndexSpy.count(), 0);
+ QCOMPARE(playbackModeSpy.count(), 0);
+ QCOMPARE(mediaAboutToBeInsertedSpy.count(), 0);
+ QCOMPARE(mediaInsertedSpy.count(), 0);
+ QCOMPARE(mediaAboutToBeRemovedSpy.count(), 0);
+ QCOMPARE(mediaRemovedSpy.count(), 0);
+ QCOMPARE(mediaChangedSpy.count(), 0);
+ }
}
void tst_QMediaPlaylist::testCurrentIndexChanged_signal()
diff --git a/tests/auto/unit/qmultimedia_common/mockaudiorolecontrol.h b/tests/auto/unit/qmultimedia_common/mockaudiorolecontrol.h
new file mode 100644
index 000000000..6ba2328b9
--- /dev/null
+++ b/tests/auto/unit/qmultimedia_common/mockaudiorolecontrol.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MOCKAUDIOROLECONTROL_H
+#define MOCKAUDIOROLECONTROL_H
+
+#include <qaudiorolecontrol.h>
+
+class MockAudioRoleControl : public QAudioRoleControl
+{
+ friend class MockMediaPlayerService;
+
+public:
+ MockAudioRoleControl()
+ : QAudioRoleControl()
+ , m_audioRole(QAudio::UnknownRole)
+ {
+ }
+
+ QAudio::Role audioRole() const
+ {
+ return m_audioRole;
+ }
+
+ void setAudioRole(QAudio::Role role)
+ {
+ if (role != m_audioRole)
+ emit audioRoleChanged(m_audioRole = role);
+ }
+
+ QList<QAudio::Role> supportedAudioRoles() const
+ {
+ return QList<QAudio::Role>() << QAudio::MusicRole
+ << QAudio::AlarmRole
+ << QAudio::NotificationRole;
+ }
+
+ QAudio::Role m_audioRole;
+};
+
+#endif // MOCKAUDIOROLECONTROL_H
+
diff --git a/tests/auto/unit/qmultimedia_common/mockmediaplayerservice.h b/tests/auto/unit/qmultimedia_common/mockmediaplayerservice.h
index d5c6d2e9f..398f92ac2 100644
--- a/tests/auto/unit/qmultimedia_common/mockmediaplayerservice.h
+++ b/tests/auto/unit/qmultimedia_common/mockmediaplayerservice.h
@@ -42,6 +42,7 @@
#include "mockvideorenderercontrol.h"
#include "mockvideoprobecontrol.h"
#include "mockvideowindowcontrol.h"
+#include "mockaudiorolecontrol.h"
class MockMediaPlayerService : public QMediaService
{
@@ -51,6 +52,7 @@ public:
MockMediaPlayerService():QMediaService(0)
{
mockControl = new MockMediaPlayerControl;
+ mockAudioRoleControl = new MockAudioRoleControl;
mockStreamsControl = new MockStreamsControl;
mockNetworkControl = new MockNetworkAccessControl;
rendererControl = new MockVideoRendererControl;
@@ -58,11 +60,13 @@ public:
mockVideoProbeControl = new MockVideoProbeControl;
windowControl = new MockVideoWindowControl;
windowRef = 0;
+ enableAudioRole = true;
}
~MockMediaPlayerService()
{
delete mockControl;
+ delete mockAudioRoleControl;
delete mockStreamsControl;
delete mockNetworkControl;
delete rendererControl;
@@ -87,6 +91,8 @@ public:
windowRef += 1;
return windowControl;
}
+ } else if (enableAudioRole && qstrcmp(iid, QAudioRoleControl_iid) == 0) {
+ return mockAudioRoleControl;
}
if (qstrcmp(iid, QMediaNetworkAccessControl_iid) == 0)
@@ -125,6 +131,8 @@ public:
void selectCurrentConfiguration(QNetworkConfiguration config) { mockNetworkControl->setCurrentConfiguration(config); }
+ void setHasAudioRole(bool enable) { enableAudioRole = enable; }
+
void reset()
{
mockControl->_state = QMediaPlayer::StoppedState;
@@ -143,11 +151,15 @@ public:
mockControl->_isValid = false;
mockControl->_errorString = QString();
+ enableAudioRole = true;
+ mockAudioRoleControl->m_audioRole = QAudio::UnknownRole;
+
mockNetworkControl->_current = QNetworkConfiguration();
mockNetworkControl->_configurations = QList<QNetworkConfiguration>();
}
MockMediaPlayerControl *mockControl;
+ MockAudioRoleControl *mockAudioRoleControl;
MockStreamsControl *mockStreamsControl;
MockNetworkAccessControl *mockNetworkControl;
MockVideoRendererControl *rendererControl;
@@ -155,6 +167,7 @@ public:
MockVideoWindowControl *windowControl;
int windowRef;
int rendererRef;
+ bool enableAudioRole;
};
diff --git a/tests/auto/unit/qmultimedia_common/mockmediaplaylistcontrol.h b/tests/auto/unit/qmultimedia_common/mockmediaplaylistcontrol.h
index 6620aa763..9f4eabf38 100644
--- a/tests/auto/unit/qmultimedia_common/mockmediaplaylistcontrol.h
+++ b/tests/auto/unit/qmultimedia_common/mockmediaplaylistcontrol.h
@@ -36,24 +36,52 @@
#include <private/qmediaplaylistcontrol_p.h>
#include <private/qmediaplaylistnavigator_p.h>
+#include <private/qmedianetworkplaylistprovider_p.h>
#include "mockreadonlyplaylistprovider.h"
-// Hmm, read only.
class MockMediaPlaylistControl : public QMediaPlaylistControl
{
- Q_OBJECT
public:
- MockMediaPlaylistControl(QObject *parent) : QMediaPlaylistControl(parent)
+ MockMediaPlaylistControl(bool readonly = false, QObject *parent = 0)
+ : QMediaPlaylistControl(parent)
+ , m_navigator(0)
+ , m_playlist(0)
+ , m_ownsProvider(false)
+ , m_readOnly(readonly)
{
- m_navigator = new QMediaPlaylistNavigator(new MockReadOnlyPlaylistProvider(this), this);
+ reset();
}
~MockMediaPlaylistControl()
{
}
- QMediaPlaylistProvider* playlistProvider() const { return m_navigator->playlist(); }
+ void reset()
+ {
+ delete m_navigator;
+ if (m_ownsProvider)
+ delete m_playlist;
+
+ if (m_readOnly)
+ m_playlist = new MockReadOnlyPlaylistProvider(this);
+ else
+ m_playlist = new QMediaNetworkPlaylistProvider(this);
+
+ m_ownsProvider = true;
+ m_navigator = new QMediaPlaylistNavigator(m_playlist, this);
+ }
+
+ void setReadOnly(bool ro)
+ {
+ if (m_readOnly == ro)
+ return;
+
+ m_readOnly = ro;
+ reset();
+ }
+
+ QMediaPlaylistProvider* playlistProvider() const { return m_playlist; }
bool setPlaylistProvider(QMediaPlaylistProvider *newProvider)
{
bool bMediaContentChanged = false;
@@ -70,6 +98,11 @@ public:
emit currentMediaChanged(newProvider->media(i));
}
+ if (m_ownsProvider)
+ delete m_playlist;
+ m_playlist = newProvider;
+ m_ownsProvider = false;
+
m_navigator->setPlaylist(newProvider);
return true;
}
@@ -99,6 +132,9 @@ public:
private:
QMediaPlaylistNavigator *m_navigator;
+ QMediaPlaylistProvider *m_playlist;
+ bool m_ownsProvider;
+ bool m_readOnly;
};
#endif // MOCKMEDIAPLAYLISTCONTROL_H
diff --git a/tests/auto/unit/qmultimedia_common/mockplayer.pri b/tests/auto/unit/qmultimedia_common/mockplayer.pri
index 74f289d47..c43fb31e5 100644
--- a/tests/auto/unit/qmultimedia_common/mockplayer.pri
+++ b/tests/auto/unit/qmultimedia_common/mockplayer.pri
@@ -8,6 +8,7 @@ HEADERS *= \
../qmultimedia_common/mockmediaplayercontrol.h \
../qmultimedia_common/mockmediastreamscontrol.h \
../qmultimedia_common/mockmedianetworkaccesscontrol.h \
- ../qmultimedia_common/mockvideoprobecontrol.h
+ ../qmultimedia_common/mockvideoprobecontrol.h \
+ ../qmultimedia_common/mockaudiorolecontrol.h
include(mockvideo.pri)
diff --git a/tests/auto/unit/qmultimedia_common/mockplaylistservice.h b/tests/auto/unit/qmultimedia_common/mockplaylistservice.h
index 95d95dbff..6c038abfe 100644
--- a/tests/auto/unit/qmultimedia_common/mockplaylistservice.h
+++ b/tests/auto/unit/qmultimedia_common/mockplaylistservice.h
@@ -44,7 +44,7 @@ class MockPlaylistService : public QMediaService
public:
MockPlaylistService():QMediaService(0)
{
- mockControl = new MockMediaPlaylistControl(this);
+ mockControl = new MockMediaPlaylistControl(false, this);
}
~MockPlaylistService()
diff --git a/tests/auto/unit/qmultimedia_common/mockreadonlyplaylistprovider.h b/tests/auto/unit/qmultimedia_common/mockreadonlyplaylistprovider.h
index 50747c1ad..39b1598b0 100644
--- a/tests/auto/unit/qmultimedia_common/mockreadonlyplaylistprovider.h
+++ b/tests/auto/unit/qmultimedia_common/mockreadonlyplaylistprovider.h
@@ -38,7 +38,6 @@
class MockReadOnlyPlaylistProvider : public QMediaPlaylistProvider
{
- Q_OBJECT
public:
MockReadOnlyPlaylistProvider(QObject *parent)
:QMediaPlaylistProvider(parent)