From 2a34e88c1e1ced28e75c487cd13402e1c9cf9fa3 Mon Sep 17 00:00:00 2001 From: Michael Goddard Date: Wed, 29 Jun 2011 13:38:46 +1000 Subject: Initial copy of QtMultimediaKit. Comes from original repo, with SHA1: 2c82d5611655e5967f5c5095af50c0991c4378b2 --- src/harmattaninstalls/README | 19 + src/harmattaninstalls/api | 92 + src/harmattaninstalls/changelog | 178 ++ src/harmattaninstalls/compat | 1 + src/harmattaninstalls/control | 716 +++++ src/harmattaninstalls/docs | 2 + src/harmattaninstalls/libqtm-contacts-tests.aegis | 13 + src/harmattaninstalls/libqtm-doc.install | 1 + src/harmattaninstalls/libqtm-examples.aegis | 54 + src/harmattaninstalls/libqtm-examples.install | 100 + .../libqtm-multimedia-dev.install | 145 + .../libqtm-multimedia-tests.install | 32 + src/harmattaninstalls/libqtm-multimedia.install | 8 + .../libqtm-systeminfo-tests.aegis | 10 + src/harmattaninstalls/patches/series | 0 src/harmattaninstalls/rules | 110 + src/harmattaninstalls/tests/install_tests | 201 ++ src/harmattaninstalls/tests/testset.txt | 11 + src/harmattaninstalls/tests/testsuite_footer.txt | 2 + src/harmattaninstalls/tests/testsuite_header.txt | 4 + src/imports/imports.pro | 5 + src/imports/multimedia/multimedia.cpp | 85 + src/imports/multimedia/multimedia.pro | 41 + src/imports/multimedia/qdeclarativeaudio.cpp | 698 +++++ src/imports/multimedia/qdeclarativeaudio_p.h | 178 ++ src/imports/multimedia/qdeclarativecamera.cpp | 1342 +++++++++ src/imports/multimedia/qdeclarativecamera_p.h | 302 ++ .../qdeclarativecamerapreviewprovider.cpp | 97 + .../qdeclarativecamerapreviewprovider_p.h | 76 + src/imports/multimedia/qdeclarativemediabase.cpp | 567 ++++ src/imports/multimedia/qdeclarativemediabase_p.h | 187 ++ .../multimedia/qdeclarativemediametadata_p.h | 185 ++ src/imports/multimedia/qdeclarativevideo.cpp | 951 +++++++ src/imports/multimedia/qdeclarativevideo_p.h | 202 ++ src/imports/multimedia/qmldir | 1 + src/imports/qimportbase.pri | 38 + src/meegoinstalls/Makefile | 40 + src/meegoinstalls/README | 95 + src/meegoinstalls/qt-mobility.spec | 1360 +++++++++ src/meegoinstalls/qt-mobility.yaml | 353 +++ src/multimediakit/audio/audio.pri | 79 + src/multimediakit/audio/qaudio.cpp | 103 + src/multimediakit/audio/qaudio.h | 71 + src/multimediakit/audio/qaudio_mac.cpp | 145 + src/multimediakit/audio/qaudio_mac_p.h | 142 + src/multimediakit/audio/qaudio_symbian_p.cpp | 663 +++++ src/multimediakit/audio/qaudio_symbian_p.h | 204 ++ src/multimediakit/audio/qaudiodevicefactory.cpp | 292 ++ src/multimediakit/audio/qaudiodevicefactory_p.h | 97 + src/multimediakit/audio/qaudiodeviceinfo.cpp | 487 ++++ src/multimediakit/audio/qaudiodeviceinfo.h | 113 + .../audio/qaudiodeviceinfo_alsa_p.cpp | 535 ++++ src/multimediakit/audio/qaudiodeviceinfo_alsa_p.h | 121 + src/multimediakit/audio/qaudiodeviceinfo_mac_p.cpp | 351 +++ src/multimediakit/audio/qaudiodeviceinfo_mac_p.h | 96 + .../audio/qaudiodeviceinfo_symbian_p.cpp | 235 ++ .../audio/qaudiodeviceinfo_symbian_p.h | 116 + .../audio/qaudiodeviceinfo_win32_p.cpp | 471 +++ src/multimediakit/audio/qaudiodeviceinfo_win32_p.h | 112 + src/multimediakit/audio/qaudioformat.cpp | 407 +++ src/multimediakit/audio/qaudioformat.h | 106 + src/multimediakit/audio/qaudioinput.cpp | 426 +++ src/multimediakit/audio/qaudioinput.h | 111 + src/multimediakit/audio/qaudioinput_alsa_p.cpp | 867 ++++++ src/multimediakit/audio/qaudioinput_alsa_p.h | 183 ++ src/multimediakit/audio/qaudioinput_mac_p.cpp | 989 +++++++ src/multimediakit/audio/qaudioinput_mac_p.h | 171 ++ src/multimediakit/audio/qaudioinput_symbian_p.cpp | 594 ++++ src/multimediakit/audio/qaudioinput_symbian_p.h | 178 ++ src/multimediakit/audio/qaudioinput_win32_p.cpp | 649 +++++ src/multimediakit/audio/qaudioinput_win32_p.h | 171 ++ src/multimediakit/audio/qaudiooutput.cpp | 393 +++ src/multimediakit/audio/qaudiooutput.h | 111 + src/multimediakit/audio/qaudiooutput_alsa_p.cpp | 834 ++++++ src/multimediakit/audio/qaudiooutput_alsa_p.h | 167 ++ src/multimediakit/audio/qaudiooutput_mac_p.cpp | 729 +++++ src/multimediakit/audio/qaudiooutput_mac_p.h | 171 ++ src/multimediakit/audio/qaudiooutput_symbian_p.cpp | 713 +++++ src/multimediakit/audio/qaudiooutput_symbian_p.h | 201 ++ src/multimediakit/audio/qaudiooutput_win32_p.cpp | 715 +++++ src/multimediakit/audio/qaudiooutput_win32_p.h | 167 ++ src/multimediakit/audio/qaudiopluginloader.cpp | 180 ++ src/multimediakit/audio/qaudiopluginloader_p.h | 92 + src/multimediakit/audio/qaudiosystem.cpp | 423 +++ src/multimediakit/audio/qaudiosystem.h | 136 + src/multimediakit/audio/qaudiosystemplugin.cpp | 143 + src/multimediakit/audio/qaudiosystemplugin.h | 93 + src/multimediakit/effects/effects.pri | 32 + src/multimediakit/effects/qsamplecache_p.cpp | 398 +++ src/multimediakit/effects/qsamplecache_p.h | 158 ++ src/multimediakit/effects/qsoundeffect.cpp | 301 ++ src/multimediakit/effects/qsoundeffect_p.h | 140 + src/multimediakit/effects/qsoundeffect_pulse_p.cpp | 955 +++++++ src/multimediakit/effects/qsoundeffect_pulse_p.h | 160 ++ .../effects/qsoundeffect_qmedia_p.cpp | 233 ++ src/multimediakit/effects/qsoundeffect_qmedia_p.h | 119 + .../effects/qsoundeffect_qsound_p.cpp | 222 ++ src/multimediakit/effects/qsoundeffect_qsound_p.h | 118 + src/multimediakit/effects/qwavedecoder_p.cpp | 232 ++ src/multimediakit/effects/qwavedecoder_p.h | 134 + src/multimediakit/multimediakit.pro | 217 ++ src/multimediakit/qaudiocapturesource.cpp | 275 ++ src/multimediakit/qaudiocapturesource.h | 95 + src/multimediakit/qaudioencodercontrol.cpp | 167 ++ src/multimediakit/qaudioencodercontrol.h | 87 + src/multimediakit/qaudioendpointselector.cpp | 142 + src/multimediakit/qaudioendpointselector.h | 78 + src/multimediakit/qaudionamespace.qdoc | 70 + src/multimediakit/qcamera.cpp | 1027 +++++++ src/multimediakit/qcamera.h | 231 ++ .../qcameracapturebufferformatcontrol.cpp | 118 + .../qcameracapturebufferformatcontrol.h | 73 + .../qcameracapturedestinationcontrol.cpp | 122 + .../qcameracapturedestinationcontrol.h | 73 + src/multimediakit/qcameracontrol.cpp | 215 ++ src/multimediakit/qcameracontrol.h | 93 + src/multimediakit/qcameraexposure.cpp | 646 +++++ src/multimediakit/qcameraexposure.h | 178 ++ src/multimediakit/qcameraexposurecontrol.cpp | 252 ++ src/multimediakit/qcameraexposurecontrol.h | 116 + src/multimediakit/qcameraflashcontrol.cpp | 143 + src/multimediakit/qcameraflashcontrol.h | 79 + src/multimediakit/qcamerafocus.cpp | 478 ++++ src/multimediakit/qcamerafocus.h | 176 ++ src/multimediakit/qcamerafocuscontrol.cpp | 253 ++ src/multimediakit/qcamerafocuscontrol.h | 95 + src/multimediakit/qcameraimagecapture.cpp | 668 +++++ src/multimediakit/qcameraimagecapture.h | 162 ++ src/multimediakit/qcameraimagecapturecontrol.cpp | 208 ++ src/multimediakit/qcameraimagecapturecontrol.h | 91 + src/multimediakit/qcameraimageprocessing.cpp | 353 +++ src/multimediakit/qcameraimageprocessing.h | 118 + .../qcameraimageprocessingcontrol.cpp | 169 ++ src/multimediakit/qcameraimageprocessingcontrol.h | 93 + src/multimediakit/qcameralockscontrol.cpp | 134 + src/multimediakit/qcameralockscontrol.h | 78 + src/multimediakit/qcameraviewfinder.cpp | 115 + src/multimediakit/qcameraviewfinder.h | 82 + src/multimediakit/qeglimagetexturesurface.cpp | 554 ++++ src/multimediakit/qeglimagetexturesurface_p.h | 142 + src/multimediakit/qgraphicsvideoitem.cpp | 432 +++ src/multimediakit/qgraphicsvideoitem.h | 107 + src/multimediakit/qgraphicsvideoitem_maemo5.cpp | 647 +++++ src/multimediakit/qgraphicsvideoitem_maemo6.cpp | 498 ++++ src/multimediakit/qgraphicsvideoitem_overlay.cpp | 436 +++ src/multimediakit/qgraphicsvideoitem_symbian.cpp | 604 ++++ src/multimediakit/qimageencodercontrol.cpp | 142 + src/multimediakit/qimageencodercontrol.h | 83 + src/multimediakit/qlocalmediaplaylistprovider.cpp | 194 ++ src/multimediakit/qlocalmediaplaylistprovider.h | 79 + src/multimediakit/qmediabindableinterface.cpp | 85 + src/multimediakit/qmediabindableinterface.h | 69 + src/multimediakit/qmediacontainercontrol.cpp | 126 + src/multimediakit/qmediacontainercontrol.h | 72 + src/multimediakit/qmediacontent.cpp | 254 ++ src/multimediakit/qmediacontent.h | 90 + src/multimediakit/qmediacontrol.cpp | 140 + src/multimediakit/qmediacontrol.h | 79 + src/multimediakit/qmediacontrol_p.h | 72 + src/multimediakit/qmediaencodersettings.cpp | 822 ++++++ src/multimediakit/qmediaencodersettings.h | 160 ++ src/multimediakit/qmediaenumdebug.h | 76 + src/multimediakit/qmediaimageviewer.cpp | 599 ++++ src/multimediakit/qmediaimageviewer.h | 135 + src/multimediakit/qmediaimageviewerservice.cpp | 465 +++ src/multimediakit/qmediaimageviewerservice_p.h | 141 + src/multimediakit/qmedianetworkaccesscontrol.cpp | 103 + src/multimediakit/qmedianetworkaccesscontrol.h | 75 + src/multimediakit/qmediaobject.cpp | 427 +++ src/multimediakit/qmediaobject.h | 110 + src/multimediakit/qmediaobject_p.h | 91 + src/multimediakit/qmediaplayer.cpp | 1134 ++++++++ src/multimediakit/qmediaplayer.h | 224 ++ src/multimediakit/qmediaplayercontrol.cpp | 414 +++ src/multimediakit/qmediaplayercontrol.h | 123 + src/multimediakit/qmediaplaylist.cpp | 756 +++++ src/multimediakit/qmediaplaylist.h | 147 + src/multimediakit/qmediaplaylist_p.h | 169 ++ src/multimediakit/qmediaplaylistcontrol.cpp | 219 ++ src/multimediakit/qmediaplaylistcontrol.h | 90 + src/multimediakit/qmediaplaylistioplugin.cpp | 204 ++ src/multimediakit/qmediaplaylistioplugin.h | 118 + src/multimediakit/qmediaplaylistnavigator.cpp | 568 ++++ src/multimediakit/qmediaplaylistnavigator.h | 107 + src/multimediakit/qmediaplaylistprovider.cpp | 329 +++ src/multimediakit/qmediaplaylistprovider.h | 107 + src/multimediakit/qmediaplaylistprovider_p.h | 72 + src/multimediakit/qmediaplaylistsourcecontrol.cpp | 128 + src/multimediakit/qmediaplaylistsourcecontrol.h | 74 + src/multimediakit/qmediapluginloader.cpp | 271 ++ src/multimediakit/qmediapluginloader_p.h | 91 + src/multimediakit/qmediarecorder.cpp | 899 ++++++ src/multimediakit/qmediarecorder.h | 190 ++ src/multimediakit/qmediarecordercontrol.cpp | 209 ++ src/multimediakit/qmediarecordercontrol.h | 93 + src/multimediakit/qmediaresource.cpp | 440 +++ src/multimediakit/qmediaresource.h | 128 + src/multimediakit/qmediaservice.cpp | 151 + src/multimediakit/qmediaservice.h | 89 + src/multimediakit/qmediaservice_p.h | 72 + src/multimediakit/qmediaserviceprovider.cpp | 780 +++++ src/multimediakit/qmediaserviceprovider.h | 170 ++ src/multimediakit/qmediaserviceproviderplugin.h | 121 + src/multimediakit/qmediastreamscontrol.cpp | 162 ++ src/multimediakit/qmediastreamscontrol.h | 88 + src/multimediakit/qmediatimerange.cpp | 759 +++++ src/multimediakit/qmediatimerange.h | 132 + src/multimediakit/qmetadatareadercontrol.cpp | 163 ++ src/multimediakit/qmetadatareadercontrol.h | 84 + src/multimediakit/qmetadatawritercontrol.cpp | 195 ++ src/multimediakit/qmetadatawritercontrol.h | 89 + src/multimediakit/qmobilityglobal.h | 245 ++ src/multimediakit/qpaintervideosurface.cpp | 1728 +++++++++++ src/multimediakit/qpaintervideosurface_mac.mm | 284 ++ src/multimediakit/qpaintervideosurface_mac_p.h | 100 + src/multimediakit/qpaintervideosurface_p.h | 183 ++ src/multimediakit/qradiotuner.cpp | 614 ++++ src/multimediakit/qradiotuner.h | 151 + src/multimediakit/qradiotunercontrol.cpp | 364 +++ src/multimediakit/qradiotunercontrol.h | 115 + src/multimediakit/qtmedianamespace.h | 190 ++ src/multimediakit/qtmedianamespace.qdoc | 208 ++ src/multimediakit/qvideodevicecontrol.cpp | 159 ++ src/multimediakit/qvideodevicecontrol.h | 83 + src/multimediakit/qvideoencodercontrol.cpp | 190 ++ src/multimediakit/qvideoencodercontrol.h | 90 + src/multimediakit/qvideorenderercontrol.cpp | 114 + src/multimediakit/qvideorenderercontrol.h | 73 + src/multimediakit/qvideosurfaceoutput.cpp | 100 + src/multimediakit/qvideosurfaceoutput_p.h | 78 + src/multimediakit/qvideowidget.cpp | 1049 +++++++ src/multimediakit/qvideowidget.h | 131 + src/multimediakit/qvideowidget_p.h | 282 ++ src/multimediakit/qvideowidgetcontrol.cpp | 245 ++ src/multimediakit/qvideowidgetcontrol.h | 97 + src/multimediakit/qvideowindowcontrol.cpp | 284 ++ src/multimediakit/qvideowindowcontrol.h | 104 + src/multimediakit/qxvideosurface_maemo5.cpp | 497 ++++ src/multimediakit/qxvideosurface_maemo5_p.h | 111 + src/multimediakit/video/qabstractvideobuffer.cpp | 208 ++ src/multimediakit/video/qabstractvideobuffer.h | 109 + src/multimediakit/video/qabstractvideobuffer_p.h | 80 + src/multimediakit/video/qabstractvideosurface.cpp | 344 +++ src/multimediakit/video/qabstractvideosurface.h | 112 + src/multimediakit/video/qimagevideobuffer.cpp | 106 + src/multimediakit/video/qimagevideobuffer_p.h | 79 + src/multimediakit/video/qmemoryvideobuffer.cpp | 133 + src/multimediakit/video/qmemoryvideobuffer_p.h | 81 + src/multimediakit/video/qvideoframe.cpp | 793 ++++++ src/multimediakit/video/qvideoframe.h | 172 ++ src/multimediakit/video/qvideosurfaceformat.cpp | 709 +++++ src/multimediakit/video/qvideosurfaceformat.h | 145 + src/multimediakit/video/video.pri | 22 + src/plugins/audiocapture/audiocapture.pro | 25 + src/plugins/audiocapture/audiocaptureservice.cpp | 90 + src/plugins/audiocapture/audiocaptureservice.h | 74 + .../audiocapture/audiocaptureserviceplugin.cpp | 69 + .../audiocapture/audiocaptureserviceplugin.h | 60 + src/plugins/audiocapture/audiocapturesession.cpp | 358 +++ src/plugins/audiocapture/audiocapturesession.h | 152 + src/plugins/audiocapture/audiocontainercontrol.cpp | 74 + src/plugins/audiocapture/audiocontainercontrol.h | 70 + src/plugins/audiocapture/audioencodercontrol.cpp | 168 ++ src/plugins/audiocapture/audioencodercontrol.h | 79 + src/plugins/audiocapture/audioendpointselector.cpp | 110 + src/plugins/audiocapture/audioendpointselector.h | 77 + .../audiocapture/audiomediarecordercontrol.cpp | 102 + .../audiocapture/audiomediarecordercontrol.h | 82 + src/plugins/directshow/camera/camera.pri | 31 + src/plugins/directshow/camera/directshowglobal.h | 236 ++ src/plugins/directshow/camera/dscameracontrol.cpp | 103 + src/plugins/directshow/camera/dscameracontrol.h | 94 + src/plugins/directshow/camera/dscameraservice.cpp | 114 + src/plugins/directshow/camera/dscameraservice.h | 88 + src/plugins/directshow/camera/dscamerasession.cpp | 1160 ++++++++ src/plugins/directshow/camera/dscamerasession.h | 208 ++ .../directshow/camera/dsimagecapturecontrol.cpp | 83 + .../directshow/camera/dsimagecapturecontrol.h | 80 + .../directshow/camera/dsvideodevicecontrol.cpp | 168 ++ .../directshow/camera/dsvideodevicecontrol.h | 83 + src/plugins/directshow/camera/dsvideorenderer.cpp | 72 + src/plugins/directshow/camera/dsvideorenderer.h | 77 + .../directshow/camera/dsvideowidgetcontrol.cpp | 250 ++ .../directshow/camera/dsvideowidgetcontrol.h | 154 + src/plugins/directshow/directshow.pro | 23 + src/plugins/directshow/dsserviceplugin.cpp | 211 ++ src/plugins/directshow/dsserviceplugin.h | 76 + .../player/directshowaudioendpointcontrol.cpp | 161 ++ .../player/directshowaudioendpointcontrol.h | 82 + .../directshow/player/directshoweventloop.cpp | 150 + .../directshow/player/directshoweventloop.h | 78 + src/plugins/directshow/player/directshowglobal.h | 139 + .../directshow/player/directshowioreader.cpp | 496 ++++ src/plugins/directshow/player/directshowioreader.h | 120 + .../directshow/player/directshowiosource.cpp | 639 +++++ src/plugins/directshow/player/directshowiosource.h | 149 + .../directshow/player/directshowmediatype.cpp | 184 ++ .../directshow/player/directshowmediatype.h | 74 + .../directshow/player/directshowmediatypelist.cpp | 226 ++ .../directshow/player/directshowmediatypelist.h | 69 + .../player/directshowmetadatacontrol.cpp | 352 +++ .../directshow/player/directshowmetadatacontrol.h | 93 + .../directshow/player/directshowpinenum.cpp | 134 + src/plugins/directshow/player/directshowpinenum.h | 72 + .../directshow/player/directshowplayercontrol.cpp | 405 +++ .../directshow/player/directshowplayercontrol.h | 146 + .../directshow/player/directshowplayerservice.cpp | 1408 +++++++++ .../directshow/player/directshowplayerservice.h | 219 ++ .../player/directshowsamplescheduler.cpp | 437 +++ .../directshow/player/directshowsamplescheduler.h | 117 + .../player/directshowvideorenderercontrol.cpp | 86 + .../player/directshowvideorenderercontrol.h | 75 + .../directshow/player/mediasamplevideobuffer.cpp | 86 + .../directshow/player/mediasamplevideobuffer.h | 69 + src/plugins/directshow/player/player.pri | 47 + .../directshow/player/videosurfacefilter.cpp | 631 +++++ src/plugins/directshow/player/videosurfacefilter.h | 176 ++ .../directshow/player/vmr9videowindowcontrol.cpp | 329 +++ .../directshow/player/vmr9videowindowcontrol.h | 108 + src/plugins/gstreamer/camerabin/camerabin.pri | 50 + .../gstreamer/camerabin/camerabinaudioencoder.cpp | 293 ++ .../gstreamer/camerabin/camerabinaudioencoder.h | 105 + .../camerabin/camerabincapturebufferformat.cpp | 78 + .../camerabin/camerabincapturebufferformat.h | 72 + .../camerabin/camerabincapturedestination.cpp | 74 + .../camerabin/camerabincapturedestination.h | 69 + .../gstreamer/camerabin/camerabincontainer.cpp | 122 + .../gstreamer/camerabin/camerabincontainer.h | 103 + .../gstreamer/camerabin/camerabincontrol.cpp | 356 +++ src/plugins/gstreamer/camerabin/camerabincontrol.h | 101 + .../gstreamer/camerabin/camerabinexposure.cpp | 232 ++ .../gstreamer/camerabin/camerabinexposure.h | 83 + src/plugins/gstreamer/camerabin/camerabinflash.cpp | 104 + src/plugins/gstreamer/camerabin/camerabinflash.h | 73 + src/plugins/gstreamer/camerabin/camerabinfocus.cpp | 245 ++ src/plugins/gstreamer/camerabin/camerabinfocus.h | 104 + .../gstreamer/camerabin/camerabinimagecapture.cpp | 347 +++ .../gstreamer/camerabin/camerabinimagecapture.h | 82 + .../gstreamer/camerabin/camerabinimageencoder.cpp | 87 + .../gstreamer/camerabin/camerabinimageencoder.h | 86 + .../camerabin/camerabinimageprocessing.cpp | 171 ++ .../gstreamer/camerabin/camerabinimageprocessing.h | 84 + src/plugins/gstreamer/camerabin/camerabinlocks.cpp | 88 + src/plugins/gstreamer/camerabin/camerabinlocks.h | 79 + .../gstreamer/camerabin/camerabinmetadata.cpp | 198 ++ .../gstreamer/camerabin/camerabinmetadata.h | 75 + .../gstreamer/camerabin/camerabinrecorder.cpp | 225 ++ .../gstreamer/camerabin/camerabinrecorder.h | 85 + .../camerabin/camerabinresourcepolicy.cpp | 188 ++ .../gstreamer/camerabin/camerabinresourcepolicy.h | 84 + .../gstreamer/camerabin/camerabinservice.cpp | 261 ++ src/plugins/gstreamer/camerabin/camerabinservice.h | 96 + .../gstreamer/camerabin/camerabinsession.cpp | 1267 +++++++++ src/plugins/gstreamer/camerabin/camerabinsession.h | 234 ++ .../gstreamer/camerabin/camerabinvideoencoder.cpp | 346 +++ .../gstreamer/camerabin/camerabinvideoencoder.h | 106 + .../gstreamer/camerabuttonlistener_maemo.cpp | 121 + src/plugins/gstreamer/camerabuttonlistener_maemo.h | 64 + .../gstreamer/camerabuttonlistener_meego.cpp | 92 + src/plugins/gstreamer/camerabuttonlistener_meego.h | 65 + src/plugins/gstreamer/gstreamer.pro | 101 + src/plugins/gstreamer/gstvideoconnector.c | 421 +++ src/plugins/gstreamer/gstvideoconnector.h | 87 + .../gstreamer/mediacapture/mediacapture.pri | 27 + .../mediacapture/qgstreameraudioencode.cpp | 292 ++ .../gstreamer/mediacapture/qgstreameraudioencode.h | 97 + .../mediacapture/qgstreamercameracontrol.cpp | 185 ++ .../mediacapture/qgstreamercameracontrol.h | 98 + .../qgstreamercapturemetadatacontrol.cpp | 198 ++ .../qgstreamercapturemetadatacontrol.h | 75 + .../mediacapture/qgstreamercaptureservice.cpp | 185 ++ .../mediacapture/qgstreamercaptureservice.h | 96 + .../mediacapture/qgstreamercapturesession.cpp | 1051 +++++++ .../mediacapture/qgstreamercapturesession.h | 211 ++ .../mediacapture/qgstreamerimagecapturecontrol.cpp | 98 + .../mediacapture/qgstreamerimagecapturecontrol.h | 73 + .../mediacapture/qgstreamerimageencode.cpp | 90 + .../gstreamer/mediacapture/qgstreamerimageencode.h | 80 + .../qgstreamermediacontainercontrol.cpp | 135 + .../mediacapture/qgstreamermediacontainercontrol.h | 84 + .../mediacapture/qgstreamerrecordercontrol.cpp | 289 ++ .../mediacapture/qgstreamerrecordercontrol.h | 91 + .../gstreamer/mediacapture/qgstreamerv4l2input.cpp | 297 ++ .../gstreamer/mediacapture/qgstreamerv4l2input.h | 83 + .../mediacapture/qgstreamervideoencode.cpp | 331 +++ .../gstreamer/mediacapture/qgstreamervideoencode.h | 98 + src/plugins/gstreamer/mediaplayer/mediaplayer.pri | 30 + .../gstreamer/mediaplayer/playerresourcepolicy.cpp | 180 ++ .../gstreamer/mediaplayer/playerresourcepolicy.h | 90 + src/plugins/gstreamer/mediaplayer/qgstappsrc.cpp | 224 ++ src/plugins/gstreamer/mediaplayer/qgstappsrc.h | 106 + .../mediaplayer/qgstreamermetadataprovider.cpp | 192 ++ .../mediaplayer/qgstreamermetadataprovider.h | 74 + .../mediaplayer/qgstreamerplayercontrol.cpp | 748 +++++ .../mediaplayer/qgstreamerplayercontrol.h | 157 + .../mediaplayer/qgstreamerplayerservice.cpp | 134 + .../mediaplayer/qgstreamerplayerservice.h | 90 + .../mediaplayer/qgstreamerplayersession.cpp | 1537 ++++++++++ .../mediaplayer/qgstreamerplayersession.h | 217 ++ .../mediaplayer/qgstreamerstreamscontrol.cpp | 89 + .../mediaplayer/qgstreamerstreamscontrol.h | 71 + src/plugins/gstreamer/qabstractgstbufferpool.h | 75 + .../qgstreameraudioinputendpointselector.cpp | 174 ++ .../qgstreameraudioinputendpointselector.h | 76 + src/plugins/gstreamer/qgstreamerbushelper.cpp | 203 ++ src/plugins/gstreamer/qgstreamerbushelper.h | 77 + .../gstreamer/qgstreamergltexturerenderer.cpp | 578 ++++ .../gstreamer/qgstreamergltexturerenderer.h | 127 + src/plugins/gstreamer/qgstreamermessage.cpp | 93 + src/plugins/gstreamer/qgstreamermessage.h | 68 + src/plugins/gstreamer/qgstreamerserviceplugin.cpp | 401 +++ src/plugins/gstreamer/qgstreamerserviceplugin.h | 86 + .../qgstreamervideoinputdevicecontrol.cpp | 162 ++ .../gstreamer/qgstreamervideoinputdevicecontrol.h | 77 + src/plugins/gstreamer/qgstreamervideooverlay.cpp | 232 ++ src/plugins/gstreamer/qgstreamervideooverlay.h | 119 + src/plugins/gstreamer/qgstreamervideorenderer.cpp | 120 + src/plugins/gstreamer/qgstreamervideorenderer.h | 80 + .../gstreamer/qgstreamervideorendererinterface.cpp | 46 + .../gstreamer/qgstreamervideorendererinterface.h | 79 + src/plugins/gstreamer/qgstreamervideowidget.cpp | 331 +++ src/plugins/gstreamer/qgstreamervideowidget.h | 108 + src/plugins/gstreamer/qgstreamervideowindow.cpp | 342 +++ src/plugins/gstreamer/qgstreamervideowindow.h | 131 + src/plugins/gstreamer/qgstutils.cpp | 165 ++ src/plugins/gstreamer/qgstutils.h | 59 + src/plugins/gstreamer/qgstvideobuffer.cpp | 97 + src/plugins/gstreamer/qgstvideobuffer.h | 72 + src/plugins/gstreamer/qgstxvimagebuffer.cpp | 311 ++ src/plugins/gstreamer/qgstxvimagebuffer.h | 130 + src/plugins/gstreamer/qvideosurfacegstsink.cpp | 772 +++++ src/plugins/gstreamer/qvideosurfacegstsink.h | 162 ++ src/plugins/gstreamer/qx11videosurface.cpp | 535 ++++ src/plugins/gstreamer/qx11videosurface.h | 117 + src/plugins/m3u/m3u.pro | 23 + src/plugins/m3u/main.cpp | 47 + src/plugins/m3u/qm3uhandler.cpp | 237 ++ src/plugins/m3u/qm3uhandler.h | 70 + src/plugins/plugins.pro | 46 + src/plugins/pulseaudio/pulseaudio.pro | 26 + src/plugins/pulseaudio/qaudiodeviceinfo_pulse.cpp | 105 + src/plugins/pulseaudio/qaudiodeviceinfo_pulse.h | 92 + src/plugins/pulseaudio/qaudioinput_pulse.cpp | 600 ++++ src/plugins/pulseaudio/qaudioinput_pulse.h | 153 + src/plugins/pulseaudio/qaudiooutput_pulse.cpp | 573 ++++ src/plugins/pulseaudio/qaudiooutput_pulse.h | 153 + src/plugins/pulseaudio/qpulseaudioengine.cpp | 354 +++ src/plugins/pulseaudio/qpulseaudioengine.h | 100 + src/plugins/pulseaudio/qpulseaudioplugin.cpp | 89 + src/plugins/pulseaudio/qpulseaudioplugin.h | 71 + src/plugins/pulseaudio/qpulsehelpers.cpp | 220 ++ src/plugins/pulseaudio/qpulsehelpers.h | 73 + src/plugins/qt7/mediaplayer/mediaplayer.pri | 16 + src/plugins/qt7/mediaplayer/qt7playercontrol.h | 109 + src/plugins/qt7/mediaplayer/qt7playercontrol.mm | 191 ++ src/plugins/qt7/mediaplayer/qt7playermetadata.h | 77 + src/plugins/qt7/mediaplayer/qt7playermetadata.mm | 260 ++ src/plugins/qt7/mediaplayer/qt7playerservice.h | 82 + src/plugins/qt7/mediaplayer/qt7playerservice.mm | 129 + src/plugins/qt7/mediaplayer/qt7playersession.h | 194 ++ src/plugins/qt7/mediaplayer/qt7playersession.mm | 751 +++++ src/plugins/qt7/qcvdisplaylink.h | 88 + src/plugins/qt7/qcvdisplaylink.mm | 156 + src/plugins/qt7/qt7.pro | 58 + src/plugins/qt7/qt7backend.h | 68 + src/plugins/qt7/qt7backend.mm | 60 + src/plugins/qt7/qt7ciimagevideobuffer.h | 86 + src/plugins/qt7/qt7ciimagevideobuffer.mm | 107 + src/plugins/qt7/qt7movierenderer.h | 107 + src/plugins/qt7/qt7movierenderer.mm | 479 ++++ src/plugins/qt7/qt7movievideowidget.h | 126 + src/plugins/qt7/qt7movievideowidget.mm | 437 +++ src/plugins/qt7/qt7movieviewoutput.h | 116 + src/plugins/qt7/qt7movieviewoutput.mm | 339 +++ src/plugins/qt7/qt7movieviewrenderer.h | 93 + src/plugins/qt7/qt7movieviewrenderer.mm | 371 +++ src/plugins/qt7/qt7serviceplugin.h | 75 + src/plugins/qt7/qt7serviceplugin.mm | 129 + src/plugins/qt7/qt7videooutput.h | 116 + src/plugins/qt7/qt7videooutput.mm | 91 + src/plugins/simulator/camera/simulatorcamera.pri | 25 + .../simulator/camera/simulatorcameracontrol.cpp | 179 ++ .../simulator/camera/simulatorcameracontrol.h | 87 + .../camera/simulatorcameraexposurecontrol.cpp | 502 ++++ .../camera/simulatorcameraexposurecontrol.h | 125 + .../camera/simulatorcameraimagecapturecontrol.cpp | 120 + .../camera/simulatorcameraimagecapturecontrol.h | 87 + .../simulator/camera/simulatorcameraservice.cpp | 161 ++ .../simulator/camera/simulatorcameraservice.h | 92 + .../simulator/camera/simulatorcamerasession.cpp | 147 + .../simulator/camera/simulatorcamerasession.h | 96 + .../simulator/camera/simulatorcamerasettings.cpp | 174 ++ .../simulator/camera/simulatorcamerasettings.h | 110 + .../camera/simulatorvideoinputdevicecontrol.cpp | 152 + .../camera/simulatorvideoinputdevicecontrol.h | 83 + .../camera/simulatorvideorenderercontrol.cpp | 130 + .../camera/simulatorvideorenderercontrol.h | 82 + .../simulator/qsimulatormultimediaconnection.cpp | 122 + .../simulator/qsimulatormultimediaconnection_p.h | 89 + src/plugins/simulator/qsimulatormultimediadata.cpp | 78 + src/plugins/simulator/qsimulatormultimediadata_p.h | 81 + src/plugins/simulator/qsimulatorserviceplugin.cpp | 127 + src/plugins/simulator/qsimulatorserviceplugin.h | 75 + src/plugins/simulator/simulator.pro | 28 + src/plugins/symbian/ecam/camera_s60.pri | 157 + src/plugins/symbian/ecam/ecam.pro | 40 + .../symbian/ecam/s60audioencodercontrol.cpp | 159 ++ src/plugins/symbian/ecam/s60audioencodercontrol.h | 90 + src/plugins/symbian/ecam/s60cameraconstants.h | 257 ++ src/plugins/symbian/ecam/s60cameracontrol.cpp | 983 +++++++ src/plugins/symbian/ecam/s60cameracontrol.h | 178 ++ src/plugins/symbian/ecam/s60cameraengine.cpp | 824 ++++++ src/plugins/symbian/ecam/s60cameraengine.h | 407 +++ src/plugins/symbian/ecam/s60cameraengineobserver.h | 178 ++ .../symbian/ecam/s60cameraexposurecontrol.cpp | 584 ++++ .../symbian/ecam/s60cameraexposurecontrol.h | 138 + src/plugins/symbian/ecam/s60cameraflashcontrol.cpp | 109 + src/plugins/symbian/ecam/s60cameraflashcontrol.h | 93 + src/plugins/symbian/ecam/s60camerafocuscontrol.cpp | 193 ++ src/plugins/symbian/ecam/s60camerafocuscontrol.h | 112 + .../symbian/ecam/s60cameraimagecapturecontrol.cpp | 124 + .../symbian/ecam/s60cameraimagecapturecontrol.h | 99 + .../ecam/s60cameraimageprocessingcontrol.cpp | 254 ++ .../symbian/ecam/s60cameraimageprocessingcontrol.h | 118 + src/plugins/symbian/ecam/s60cameralockscontrol.cpp | 263 ++ src/plugins/symbian/ecam/s60cameralockscontrol.h | 115 + src/plugins/symbian/ecam/s60cameraservice.cpp | 259 ++ src/plugins/symbian/ecam/s60cameraservice.h | 111 + .../symbian/ecam/s60cameraserviceplugin.cpp | 115 + src/plugins/symbian/ecam/s60cameraserviceplugin.h | 81 + src/plugins/symbian/ecam/s60camerasettings.cpp | 986 +++++++ src/plugins/symbian/ecam/s60camerasettings.h | 177 ++ .../symbian/ecam/s60cameraviewfinderengine.cpp | 789 ++++++ .../symbian/ecam/s60cameraviewfinderengine.h | 182 ++ .../symbian/ecam/s60imagecapturesession.cpp | 1884 ++++++++++++ src/plugins/symbian/ecam/s60imagecapturesession.h | 359 +++ .../symbian/ecam/s60imageencodercontrol.cpp | 128 + src/plugins/symbian/ecam/s60imageencodercontrol.h | 84 + .../symbian/ecam/s60mediacontainercontrol.cpp | 97 + .../symbian/ecam/s60mediacontainercontrol.h | 82 + .../symbian/ecam/s60mediarecordercontrol.cpp | 187 ++ src/plugins/symbian/ecam/s60mediarecordercontrol.h | 118 + .../symbian/ecam/s60videocapturesession.cpp | 2995 ++++++++++++++++++++ src/plugins/symbian/ecam/s60videocapturesession.h | 414 +++ src/plugins/symbian/ecam/s60videodevicecontrol.cpp | 108 + src/plugins/symbian/ecam/s60videodevicecontrol.h | 95 + .../symbian/ecam/s60videoencodercontrol.cpp | 204 ++ src/plugins/symbian/ecam/s60videoencodercontrol.h | 94 + .../symbian/ecam/s60videorenderercontrol.cpp | 78 + src/plugins/symbian/ecam/s60videorenderercontrol.h | 76 + .../symbian/mmf/audiosource/audiosource_s60.pri | 31 + .../mmf/audiosource/s60audiocaptureservice.cpp | 98 + .../mmf/audiosource/s60audiocaptureservice.h | 75 + .../mmf/audiosource/s60audiocapturesession.cpp | 937 ++++++ .../mmf/audiosource/s60audiocapturesession.h | 193 ++ .../mmf/audiosource/s60audiocontainercontrol.cpp | 96 + .../mmf/audiosource/s60audiocontainercontrol.h | 70 + .../mmf/audiosource/s60audioencodercontrol.cpp | 235 ++ .../mmf/audiosource/s60audioencodercontrol.h | 82 + .../mmf/audiosource/s60audioendpointselector.cpp | 100 + .../mmf/audiosource/s60audioendpointselector.h | 76 + .../audiosource/s60audiomediarecordercontrol.cpp | 180 ++ .../mmf/audiosource/s60audiomediarecordercontrol.h | 92 + src/plugins/symbian/mmf/inc/DebugMacros.h | 66 + .../symbian/mmf/mediaplayer/mediaplayer_s60.pri | 92 + .../mmf/mediaplayer/ms60mediaplayerresolver.h | 54 + .../mmf/mediaplayer/s60audioplayersession.cpp | 577 ++++ .../mmf/mediaplayer/s60audioplayersession.h | 136 + .../mmf/mediaplayer/s60mediametadataprovider.cpp | 146 + .../mmf/mediaplayer/s60mediametadataprovider.h | 72 + .../mediaplayer/s60medianetworkaccesscontrol.cpp | 144 + .../mmf/mediaplayer/s60medianetworkaccesscontrol.h | 89 + .../s60mediaplayeraudioendpointselector.cpp | 182 ++ .../s60mediaplayeraudioendpointselector.h | 77 + .../mmf/mediaplayer/s60mediaplayercontrol.cpp | 518 ++++ .../mmf/mediaplayer/s60mediaplayercontrol.h | 148 + .../mmf/mediaplayer/s60mediaplayerservice.cpp | 326 +++ .../mmf/mediaplayer/s60mediaplayerservice.h | 97 + .../mmf/mediaplayer/s60mediaplayersession.cpp | 1054 +++++++ .../mmf/mediaplayer/s60mediaplayersession.h | 187 ++ .../symbian/mmf/mediaplayer/s60mediarecognizer.cpp | 167 ++ .../symbian/mmf/mediaplayer/s60mediarecognizer.h | 79 + .../mmf/mediaplayer/s60mediastreamcontrol.cpp | 201 ++ .../mmf/mediaplayer/s60mediastreamcontrol.h | 79 + .../mmf/mediaplayer/s60videooutputinterface.h | 62 + .../mmf/mediaplayer/s60videoplayersession.cpp | 1124 ++++++++ .../mmf/mediaplayer/s60videoplayersession.h | 218 ++ .../symbian/mmf/mediaplayer/s60videorenderer.cpp | 95 + .../symbian/mmf/mediaplayer/s60videorenderer.h | 66 + .../symbian/mmf/mediaplayer/s60videosurface.cpp | 372 +++ .../symbian/mmf/mediaplayer/s60videosurface.h | 106 + src/plugins/symbian/mmf/mmf.pro | 58 + src/plugins/symbian/mmf/radio/radio.pri | 24 + .../symbian/mmf/radio/s60radiotunercontrol_31.cpp | 603 ++++ .../symbian/mmf/radio/s60radiotunercontrol_31.h | 161 ++ .../mmf/radio/s60radiotunercontrol_since32.cpp | 685 +++++ .../mmf/radio/s60radiotunercontrol_since32.h | 296 ++ .../symbian/mmf/radio/s60radiotunerservice.cpp | 83 + .../symbian/mmf/radio/s60radiotunerservice.h | 71 + src/plugins/symbian/mmf/s60formatsupported.cpp | 121 + src/plugins/symbian/mmf/s60formatsupported.h | 65 + src/plugins/symbian/mmf/s60mediaserviceplugin.cpp | 115 + src/plugins/symbian/mmf/s60mediaserviceplugin.h | 69 + .../symbian/openmaxal/mediaplayer/mediaplayer.pri | 36 + .../mediaplayer/qxamediaplayercontrol.cpp | 288 ++ .../openmaxal/mediaplayer/qxamediaplayercontrol.h | 99 + .../mediaplayer/qxamediastreamscontrol.cpp | 98 + .../openmaxal/mediaplayer/qxamediastreamscontrol.h | 77 + .../openmaxal/mediaplayer/qxametadatacontrol.cpp | 131 + .../openmaxal/mediaplayer/qxametadatacontrol.h | 78 + .../openmaxal/mediaplayer/qxaplaymediaservice.cpp | 117 + .../openmaxal/mediaplayer/qxaplaymediaservice.h | 74 + .../openmaxal/mediaplayer/qxaplaysession.cpp | 610 ++++ .../symbian/openmaxal/mediaplayer/qxaplaysession.h | 192 ++ .../mediaplayer/qxavideowidgetcontrol.cpp | 182 ++ .../openmaxal/mediaplayer/qxavideowidgetcontrol.h | 93 + .../mediaplayer/qxavideowindowcontrol.cpp | 222 ++ .../openmaxal/mediaplayer/qxavideowindowcontrol.h | 105 + .../symbian/openmaxal/mediaplayer/qxawidget.cpp | 64 + .../symbian/openmaxal/mediaplayer/qxawidget.h | 63 + .../openmaxal/mediaplayer/xaplaysessioncommon.h | 58 + .../openmaxal/mediaplayer/xaplaysessionimpl.cpp | 1259 ++++++++ .../openmaxal/mediaplayer/xaplaysessionimpl.h | 210 ++ .../openmaxal/mediarecorder/mediarecorder.pri | 24 + .../mediarecorder/qxaaudioencodercontrol.cpp | 111 + .../mediarecorder/qxaaudioencodercontrol.h | 79 + .../mediarecorder/qxaaudioendpointselector.cpp | 98 + .../mediarecorder/qxaaudioendpointselector.h | 77 + .../mediarecorder/qxamediacontainercontrol.cpp | 81 + .../mediarecorder/qxamediacontainercontrol.h | 71 + .../mediarecorder/qxamediarecordercontrol.cpp | 122 + .../mediarecorder/qxamediarecordercontrol.h | 83 + .../mediarecorder/qxarecordmediaservice.cpp | 86 + .../mediarecorder/qxarecordmediaservice.h | 78 + .../openmaxal/mediarecorder/qxarecordsession.cpp | 766 +++++ .../openmaxal/mediarecorder/qxarecordsession.h | 144 + .../mediarecorder/xarecordsessioncommon.h | 67 + .../mediarecorder/xarecordsessionimpl.cpp | 1378 +++++++++ .../openmaxal/mediarecorder/xarecordsessionimpl.h | 179 ++ src/plugins/symbian/openmaxal/openmaxal.pro | 58 + src/plugins/symbian/openmaxal/qxacommon.h | 203 ++ .../openmaxal/qxamediaserviceproviderplugin.cpp | 87 + .../openmaxal/qxamediaserviceproviderplugin.h | 60 + .../openmaxal/radiotuner/qxaradiocontrol.cpp | 202 ++ .../symbian/openmaxal/radiotuner/qxaradiocontrol.h | 95 + .../openmaxal/radiotuner/qxaradiomediaservice.cpp | 72 + .../openmaxal/radiotuner/qxaradiomediaservice.h | 66 + .../openmaxal/radiotuner/qxaradiosession.cpp | 323 +++ .../symbian/openmaxal/radiotuner/qxaradiosession.h | 118 + .../symbian/openmaxal/radiotuner/radiotuner.pri | 18 + .../openmaxal/radiotuner/xaradiosessionimpl.cpp | 715 +++++ .../openmaxal/radiotuner/xaradiosessionimpl.h | 128 + .../radiotuner/xaradiosessionimplobserver.h | 64 + src/plugins/symbian/openmaxal/xacommon.h | 79 + src/plugins/symbian/symbian.pro | 23 + .../symbian/videooutput/s60videodisplay.cpp | 179 ++ src/plugins/symbian/videooutput/s60videodisplay.h | 188 ++ .../symbian/videooutput/s60videooutpututils.cpp | 119 + .../symbian/videooutput/s60videooutpututils.h | 71 + src/plugins/symbian/videooutput/s60videowidget.cpp | 237 ++ src/plugins/symbian/videooutput/s60videowidget.h | 97 + .../symbian/videooutput/s60videowidgetcontrol.cpp | 171 ++ .../symbian/videooutput/s60videowidgetcontrol.h | 131 + .../symbian/videooutput/s60videowidgetdisplay.cpp | 174 ++ .../symbian/videooutput/s60videowidgetdisplay.h | 85 + .../symbian/videooutput/s60videowindowcontrol.cpp | 178 ++ .../symbian/videooutput/s60videowindowcontrol.h | 102 + .../symbian/videooutput/s60videowindowdisplay.cpp | 140 + .../symbian/videooutput/s60videowindowdisplay.h | 73 + src/plugins/symbian/videooutput/videooutput.pri | 37 + src/plugins/v4l/radio/radio.pri | 29 + src/plugins/v4l/radio/v4lradiocontrol.cpp | 538 ++++ src/plugins/v4l/radio/v4lradiocontrol.h | 134 + src/plugins/v4l/radio/v4lradiocontrol_maemo5.cpp | 755 +++++ src/plugins/v4l/radio/v4lradiocontrol_maemo5.h | 144 + src/plugins/v4l/radio/v4lradioservice.cpp | 71 + src/plugins/v4l/radio/v4lradioservice.h | 67 + src/plugins/v4l/v4l.pro | 13 + src/plugins/v4l/v4lserviceplugin.cpp | 84 + src/plugins/v4l/v4lserviceplugin.h | 63 + src/plugins/wmp/qevrvideooverlay.cpp | 357 +++ src/plugins/wmp/qevrvideooverlay.h | 119 + src/plugins/wmp/qmfactivate.cpp | 296 ++ src/plugins/wmp/qmfactivate.h | 90 + src/plugins/wmp/qwmpevents.cpp | 114 + src/plugins/wmp/qwmpevents.h | 222 ++ src/plugins/wmp/qwmpglobal.cpp | 68 + src/plugins/wmp/qwmpglobal.h | 83 + src/plugins/wmp/qwmpmetadata.cpp | 442 +++ src/plugins/wmp/qwmpmetadata.h | 88 + src/plugins/wmp/qwmpplayercontrol.cpp | 465 +++ src/plugins/wmp/qwmpplayercontrol.h | 141 + src/plugins/wmp/qwmpplayerservice.cpp | 355 +++ src/plugins/wmp/qwmpplayerservice.h | 125 + src/plugins/wmp/qwmpplaylist.cpp | 296 ++ src/plugins/wmp/qwmpplaylist.h | 94 + src/plugins/wmp/qwmpplaylistcontrol.cpp | 153 + src/plugins/wmp/qwmpplaylistcontrol.h | 85 + src/plugins/wmp/qwmpserviceprovider.cpp | 74 + src/plugins/wmp/qwmpserviceprovider.h | 58 + src/plugins/wmp/qwmpvideooverlay.cpp | 462 +++ src/plugins/wmp/qwmpvideooverlay.h | 145 + src/plugins/wmp/wmp.pro | 47 + src/s60installs/backup_registration.xml | 8 + src/s60installs/bwins/QtMultimediaKitu.def | 1624 +++++++++++ src/s60installs/deviceconfiguration/.gitignore | 11 + .../deviceconfiguration/QtBearer{000a0000}.dll | Bin 0 -> 28061 bytes src/s60installs/deviceconfiguration/bld.inf | 57 + .../deviceconfiguration/mobilityconfig.prf | 5 + .../deviceconfiguration/qtmobility.confml | 16 + src/s60installs/deviceconfiguration/qtmobility.iby | 134 + .../deviceconfiguration/qtmobility.sisx | 1 + .../deviceconfiguration/qtmobility_copy.implml | 10 + .../deviceconfiguration/qtmobility_stub.pkg | 12 + .../deviceconfiguration/qtmobility_stub.sis | Bin 0 -> 324 bytes .../deviceconfiguration/qtmobilityconfig.xml | 13 + .../deviceconfiguration/qtmobilityexampleapps.pkg | 111 + .../deviceconfiguration/qtmobilityexamples.iby | 128 + .../deviceconfiguration/qtmobilityheaders.flm | 146 + .../deviceconfiguration/qtmobilitytests.iby | 47 + .../deviceconfiguration/symbian3_config.pri | 50 + .../deviceconfiguration/symbian3_qtmobility.pkg | 128 + src/s60installs/eabi/QtMultimediaKitu.def | 1640 +++++++++++ src/s60installs/s60installs.pro | 514 ++++ src/src.pro | 12 + 725 files changed, 157687 insertions(+) create mode 100644 src/harmattaninstalls/README create mode 100644 src/harmattaninstalls/api create mode 100644 src/harmattaninstalls/changelog create mode 100644 src/harmattaninstalls/compat create mode 100644 src/harmattaninstalls/control create mode 100644 src/harmattaninstalls/docs create mode 100644 src/harmattaninstalls/libqtm-contacts-tests.aegis create mode 100644 src/harmattaninstalls/libqtm-doc.install create mode 100644 src/harmattaninstalls/libqtm-examples.aegis create mode 100644 src/harmattaninstalls/libqtm-examples.install create mode 100644 src/harmattaninstalls/libqtm-multimedia-dev.install create mode 100644 src/harmattaninstalls/libqtm-multimedia-tests.install create mode 100644 src/harmattaninstalls/libqtm-multimedia.install create mode 100644 src/harmattaninstalls/libqtm-systeminfo-tests.aegis create mode 100644 src/harmattaninstalls/patches/series create mode 100755 src/harmattaninstalls/rules create mode 100755 src/harmattaninstalls/tests/install_tests create mode 100644 src/harmattaninstalls/tests/testset.txt create mode 100644 src/harmattaninstalls/tests/testsuite_footer.txt create mode 100644 src/harmattaninstalls/tests/testsuite_header.txt create mode 100644 src/imports/imports.pro create mode 100644 src/imports/multimedia/multimedia.cpp create mode 100644 src/imports/multimedia/multimedia.pro create mode 100644 src/imports/multimedia/qdeclarativeaudio.cpp create mode 100644 src/imports/multimedia/qdeclarativeaudio_p.h create mode 100644 src/imports/multimedia/qdeclarativecamera.cpp create mode 100644 src/imports/multimedia/qdeclarativecamera_p.h create mode 100644 src/imports/multimedia/qdeclarativecamerapreviewprovider.cpp create mode 100644 src/imports/multimedia/qdeclarativecamerapreviewprovider_p.h create mode 100644 src/imports/multimedia/qdeclarativemediabase.cpp create mode 100644 src/imports/multimedia/qdeclarativemediabase_p.h create mode 100644 src/imports/multimedia/qdeclarativemediametadata_p.h create mode 100644 src/imports/multimedia/qdeclarativevideo.cpp create mode 100644 src/imports/multimedia/qdeclarativevideo_p.h create mode 100644 src/imports/multimedia/qmldir create mode 100644 src/imports/qimportbase.pri create mode 100644 src/meegoinstalls/Makefile create mode 100644 src/meegoinstalls/README create mode 100644 src/meegoinstalls/qt-mobility.spec create mode 100644 src/meegoinstalls/qt-mobility.yaml create mode 100644 src/multimediakit/audio/audio.pri create mode 100644 src/multimediakit/audio/qaudio.cpp create mode 100644 src/multimediakit/audio/qaudio.h create mode 100644 src/multimediakit/audio/qaudio_mac.cpp create mode 100644 src/multimediakit/audio/qaudio_mac_p.h create mode 100644 src/multimediakit/audio/qaudio_symbian_p.cpp create mode 100644 src/multimediakit/audio/qaudio_symbian_p.h create mode 100644 src/multimediakit/audio/qaudiodevicefactory.cpp create mode 100644 src/multimediakit/audio/qaudiodevicefactory_p.h create mode 100644 src/multimediakit/audio/qaudiodeviceinfo.cpp create mode 100644 src/multimediakit/audio/qaudiodeviceinfo.h create mode 100644 src/multimediakit/audio/qaudiodeviceinfo_alsa_p.cpp create mode 100644 src/multimediakit/audio/qaudiodeviceinfo_alsa_p.h create mode 100644 src/multimediakit/audio/qaudiodeviceinfo_mac_p.cpp create mode 100644 src/multimediakit/audio/qaudiodeviceinfo_mac_p.h create mode 100644 src/multimediakit/audio/qaudiodeviceinfo_symbian_p.cpp create mode 100644 src/multimediakit/audio/qaudiodeviceinfo_symbian_p.h create mode 100644 src/multimediakit/audio/qaudiodeviceinfo_win32_p.cpp create mode 100644 src/multimediakit/audio/qaudiodeviceinfo_win32_p.h create mode 100644 src/multimediakit/audio/qaudioformat.cpp create mode 100644 src/multimediakit/audio/qaudioformat.h create mode 100644 src/multimediakit/audio/qaudioinput.cpp create mode 100644 src/multimediakit/audio/qaudioinput.h create mode 100644 src/multimediakit/audio/qaudioinput_alsa_p.cpp create mode 100644 src/multimediakit/audio/qaudioinput_alsa_p.h create mode 100644 src/multimediakit/audio/qaudioinput_mac_p.cpp create mode 100644 src/multimediakit/audio/qaudioinput_mac_p.h create mode 100644 src/multimediakit/audio/qaudioinput_symbian_p.cpp create mode 100644 src/multimediakit/audio/qaudioinput_symbian_p.h create mode 100644 src/multimediakit/audio/qaudioinput_win32_p.cpp create mode 100644 src/multimediakit/audio/qaudioinput_win32_p.h create mode 100644 src/multimediakit/audio/qaudiooutput.cpp create mode 100644 src/multimediakit/audio/qaudiooutput.h create mode 100644 src/multimediakit/audio/qaudiooutput_alsa_p.cpp create mode 100644 src/multimediakit/audio/qaudiooutput_alsa_p.h create mode 100644 src/multimediakit/audio/qaudiooutput_mac_p.cpp create mode 100644 src/multimediakit/audio/qaudiooutput_mac_p.h create mode 100644 src/multimediakit/audio/qaudiooutput_symbian_p.cpp create mode 100644 src/multimediakit/audio/qaudiooutput_symbian_p.h create mode 100644 src/multimediakit/audio/qaudiooutput_win32_p.cpp create mode 100644 src/multimediakit/audio/qaudiooutput_win32_p.h create mode 100644 src/multimediakit/audio/qaudiopluginloader.cpp create mode 100644 src/multimediakit/audio/qaudiopluginloader_p.h create mode 100644 src/multimediakit/audio/qaudiosystem.cpp create mode 100644 src/multimediakit/audio/qaudiosystem.h create mode 100644 src/multimediakit/audio/qaudiosystemplugin.cpp create mode 100644 src/multimediakit/audio/qaudiosystemplugin.h create mode 100644 src/multimediakit/effects/effects.pri create mode 100644 src/multimediakit/effects/qsamplecache_p.cpp create mode 100644 src/multimediakit/effects/qsamplecache_p.h create mode 100644 src/multimediakit/effects/qsoundeffect.cpp create mode 100644 src/multimediakit/effects/qsoundeffect_p.h create mode 100644 src/multimediakit/effects/qsoundeffect_pulse_p.cpp create mode 100644 src/multimediakit/effects/qsoundeffect_pulse_p.h create mode 100644 src/multimediakit/effects/qsoundeffect_qmedia_p.cpp create mode 100644 src/multimediakit/effects/qsoundeffect_qmedia_p.h create mode 100644 src/multimediakit/effects/qsoundeffect_qsound_p.cpp create mode 100644 src/multimediakit/effects/qsoundeffect_qsound_p.h create mode 100644 src/multimediakit/effects/qwavedecoder_p.cpp create mode 100644 src/multimediakit/effects/qwavedecoder_p.h create mode 100644 src/multimediakit/multimediakit.pro create mode 100644 src/multimediakit/qaudiocapturesource.cpp create mode 100644 src/multimediakit/qaudiocapturesource.h create mode 100644 src/multimediakit/qaudioencodercontrol.cpp create mode 100644 src/multimediakit/qaudioencodercontrol.h create mode 100644 src/multimediakit/qaudioendpointselector.cpp create mode 100644 src/multimediakit/qaudioendpointselector.h create mode 100644 src/multimediakit/qaudionamespace.qdoc create mode 100644 src/multimediakit/qcamera.cpp create mode 100644 src/multimediakit/qcamera.h create mode 100644 src/multimediakit/qcameracapturebufferformatcontrol.cpp create mode 100644 src/multimediakit/qcameracapturebufferformatcontrol.h create mode 100644 src/multimediakit/qcameracapturedestinationcontrol.cpp create mode 100644 src/multimediakit/qcameracapturedestinationcontrol.h create mode 100644 src/multimediakit/qcameracontrol.cpp create mode 100644 src/multimediakit/qcameracontrol.h create mode 100644 src/multimediakit/qcameraexposure.cpp create mode 100644 src/multimediakit/qcameraexposure.h create mode 100644 src/multimediakit/qcameraexposurecontrol.cpp create mode 100644 src/multimediakit/qcameraexposurecontrol.h create mode 100644 src/multimediakit/qcameraflashcontrol.cpp create mode 100644 src/multimediakit/qcameraflashcontrol.h create mode 100644 src/multimediakit/qcamerafocus.cpp create mode 100644 src/multimediakit/qcamerafocus.h create mode 100644 src/multimediakit/qcamerafocuscontrol.cpp create mode 100644 src/multimediakit/qcamerafocuscontrol.h create mode 100644 src/multimediakit/qcameraimagecapture.cpp create mode 100644 src/multimediakit/qcameraimagecapture.h create mode 100644 src/multimediakit/qcameraimagecapturecontrol.cpp create mode 100644 src/multimediakit/qcameraimagecapturecontrol.h create mode 100644 src/multimediakit/qcameraimageprocessing.cpp create mode 100644 src/multimediakit/qcameraimageprocessing.h create mode 100644 src/multimediakit/qcameraimageprocessingcontrol.cpp create mode 100644 src/multimediakit/qcameraimageprocessingcontrol.h create mode 100644 src/multimediakit/qcameralockscontrol.cpp create mode 100644 src/multimediakit/qcameralockscontrol.h create mode 100644 src/multimediakit/qcameraviewfinder.cpp create mode 100644 src/multimediakit/qcameraviewfinder.h create mode 100644 src/multimediakit/qeglimagetexturesurface.cpp create mode 100644 src/multimediakit/qeglimagetexturesurface_p.h create mode 100644 src/multimediakit/qgraphicsvideoitem.cpp create mode 100644 src/multimediakit/qgraphicsvideoitem.h create mode 100644 src/multimediakit/qgraphicsvideoitem_maemo5.cpp create mode 100644 src/multimediakit/qgraphicsvideoitem_maemo6.cpp create mode 100644 src/multimediakit/qgraphicsvideoitem_overlay.cpp create mode 100644 src/multimediakit/qgraphicsvideoitem_symbian.cpp create mode 100644 src/multimediakit/qimageencodercontrol.cpp create mode 100644 src/multimediakit/qimageencodercontrol.h create mode 100644 src/multimediakit/qlocalmediaplaylistprovider.cpp create mode 100644 src/multimediakit/qlocalmediaplaylistprovider.h create mode 100644 src/multimediakit/qmediabindableinterface.cpp create mode 100644 src/multimediakit/qmediabindableinterface.h create mode 100644 src/multimediakit/qmediacontainercontrol.cpp create mode 100644 src/multimediakit/qmediacontainercontrol.h create mode 100644 src/multimediakit/qmediacontent.cpp create mode 100644 src/multimediakit/qmediacontent.h create mode 100644 src/multimediakit/qmediacontrol.cpp create mode 100644 src/multimediakit/qmediacontrol.h create mode 100644 src/multimediakit/qmediacontrol_p.h create mode 100644 src/multimediakit/qmediaencodersettings.cpp create mode 100644 src/multimediakit/qmediaencodersettings.h create mode 100644 src/multimediakit/qmediaenumdebug.h create mode 100644 src/multimediakit/qmediaimageviewer.cpp create mode 100644 src/multimediakit/qmediaimageviewer.h create mode 100644 src/multimediakit/qmediaimageviewerservice.cpp create mode 100644 src/multimediakit/qmediaimageviewerservice_p.h create mode 100644 src/multimediakit/qmedianetworkaccesscontrol.cpp create mode 100644 src/multimediakit/qmedianetworkaccesscontrol.h create mode 100644 src/multimediakit/qmediaobject.cpp create mode 100644 src/multimediakit/qmediaobject.h create mode 100644 src/multimediakit/qmediaobject_p.h create mode 100644 src/multimediakit/qmediaplayer.cpp create mode 100644 src/multimediakit/qmediaplayer.h create mode 100644 src/multimediakit/qmediaplayercontrol.cpp create mode 100644 src/multimediakit/qmediaplayercontrol.h create mode 100644 src/multimediakit/qmediaplaylist.cpp create mode 100644 src/multimediakit/qmediaplaylist.h create mode 100644 src/multimediakit/qmediaplaylist_p.h create mode 100644 src/multimediakit/qmediaplaylistcontrol.cpp create mode 100644 src/multimediakit/qmediaplaylistcontrol.h create mode 100644 src/multimediakit/qmediaplaylistioplugin.cpp create mode 100644 src/multimediakit/qmediaplaylistioplugin.h create mode 100644 src/multimediakit/qmediaplaylistnavigator.cpp create mode 100644 src/multimediakit/qmediaplaylistnavigator.h create mode 100644 src/multimediakit/qmediaplaylistprovider.cpp create mode 100644 src/multimediakit/qmediaplaylistprovider.h create mode 100644 src/multimediakit/qmediaplaylistprovider_p.h create mode 100644 src/multimediakit/qmediaplaylistsourcecontrol.cpp create mode 100644 src/multimediakit/qmediaplaylistsourcecontrol.h create mode 100644 src/multimediakit/qmediapluginloader.cpp create mode 100644 src/multimediakit/qmediapluginloader_p.h create mode 100644 src/multimediakit/qmediarecorder.cpp create mode 100644 src/multimediakit/qmediarecorder.h create mode 100644 src/multimediakit/qmediarecordercontrol.cpp create mode 100644 src/multimediakit/qmediarecordercontrol.h create mode 100644 src/multimediakit/qmediaresource.cpp create mode 100644 src/multimediakit/qmediaresource.h create mode 100644 src/multimediakit/qmediaservice.cpp create mode 100644 src/multimediakit/qmediaservice.h create mode 100644 src/multimediakit/qmediaservice_p.h create mode 100644 src/multimediakit/qmediaserviceprovider.cpp create mode 100644 src/multimediakit/qmediaserviceprovider.h create mode 100644 src/multimediakit/qmediaserviceproviderplugin.h create mode 100644 src/multimediakit/qmediastreamscontrol.cpp create mode 100644 src/multimediakit/qmediastreamscontrol.h create mode 100644 src/multimediakit/qmediatimerange.cpp create mode 100644 src/multimediakit/qmediatimerange.h create mode 100644 src/multimediakit/qmetadatareadercontrol.cpp create mode 100644 src/multimediakit/qmetadatareadercontrol.h create mode 100644 src/multimediakit/qmetadatawritercontrol.cpp create mode 100644 src/multimediakit/qmetadatawritercontrol.h create mode 100644 src/multimediakit/qmobilityglobal.h create mode 100644 src/multimediakit/qpaintervideosurface.cpp create mode 100644 src/multimediakit/qpaintervideosurface_mac.mm create mode 100644 src/multimediakit/qpaintervideosurface_mac_p.h create mode 100644 src/multimediakit/qpaintervideosurface_p.h create mode 100644 src/multimediakit/qradiotuner.cpp create mode 100644 src/multimediakit/qradiotuner.h create mode 100644 src/multimediakit/qradiotunercontrol.cpp create mode 100644 src/multimediakit/qradiotunercontrol.h create mode 100644 src/multimediakit/qtmedianamespace.h create mode 100644 src/multimediakit/qtmedianamespace.qdoc create mode 100644 src/multimediakit/qvideodevicecontrol.cpp create mode 100644 src/multimediakit/qvideodevicecontrol.h create mode 100644 src/multimediakit/qvideoencodercontrol.cpp create mode 100644 src/multimediakit/qvideoencodercontrol.h create mode 100644 src/multimediakit/qvideorenderercontrol.cpp create mode 100644 src/multimediakit/qvideorenderercontrol.h create mode 100644 src/multimediakit/qvideosurfaceoutput.cpp create mode 100644 src/multimediakit/qvideosurfaceoutput_p.h create mode 100644 src/multimediakit/qvideowidget.cpp create mode 100644 src/multimediakit/qvideowidget.h create mode 100644 src/multimediakit/qvideowidget_p.h create mode 100644 src/multimediakit/qvideowidgetcontrol.cpp create mode 100644 src/multimediakit/qvideowidgetcontrol.h create mode 100644 src/multimediakit/qvideowindowcontrol.cpp create mode 100644 src/multimediakit/qvideowindowcontrol.h create mode 100644 src/multimediakit/qxvideosurface_maemo5.cpp create mode 100644 src/multimediakit/qxvideosurface_maemo5_p.h create mode 100644 src/multimediakit/video/qabstractvideobuffer.cpp create mode 100644 src/multimediakit/video/qabstractvideobuffer.h create mode 100644 src/multimediakit/video/qabstractvideobuffer_p.h create mode 100644 src/multimediakit/video/qabstractvideosurface.cpp create mode 100644 src/multimediakit/video/qabstractvideosurface.h create mode 100644 src/multimediakit/video/qimagevideobuffer.cpp create mode 100644 src/multimediakit/video/qimagevideobuffer_p.h create mode 100644 src/multimediakit/video/qmemoryvideobuffer.cpp create mode 100644 src/multimediakit/video/qmemoryvideobuffer_p.h create mode 100644 src/multimediakit/video/qvideoframe.cpp create mode 100644 src/multimediakit/video/qvideoframe.h create mode 100644 src/multimediakit/video/qvideosurfaceformat.cpp create mode 100644 src/multimediakit/video/qvideosurfaceformat.h create mode 100644 src/multimediakit/video/video.pri create mode 100644 src/plugins/audiocapture/audiocapture.pro create mode 100644 src/plugins/audiocapture/audiocaptureservice.cpp create mode 100644 src/plugins/audiocapture/audiocaptureservice.h create mode 100644 src/plugins/audiocapture/audiocaptureserviceplugin.cpp create mode 100644 src/plugins/audiocapture/audiocaptureserviceplugin.h create mode 100644 src/plugins/audiocapture/audiocapturesession.cpp create mode 100644 src/plugins/audiocapture/audiocapturesession.h create mode 100644 src/plugins/audiocapture/audiocontainercontrol.cpp create mode 100644 src/plugins/audiocapture/audiocontainercontrol.h create mode 100644 src/plugins/audiocapture/audioencodercontrol.cpp create mode 100644 src/plugins/audiocapture/audioencodercontrol.h create mode 100644 src/plugins/audiocapture/audioendpointselector.cpp create mode 100644 src/plugins/audiocapture/audioendpointselector.h create mode 100644 src/plugins/audiocapture/audiomediarecordercontrol.cpp create mode 100644 src/plugins/audiocapture/audiomediarecordercontrol.h create mode 100644 src/plugins/directshow/camera/camera.pri create mode 100644 src/plugins/directshow/camera/directshowglobal.h create mode 100644 src/plugins/directshow/camera/dscameracontrol.cpp create mode 100644 src/plugins/directshow/camera/dscameracontrol.h create mode 100644 src/plugins/directshow/camera/dscameraservice.cpp create mode 100644 src/plugins/directshow/camera/dscameraservice.h create mode 100644 src/plugins/directshow/camera/dscamerasession.cpp create mode 100644 src/plugins/directshow/camera/dscamerasession.h create mode 100644 src/plugins/directshow/camera/dsimagecapturecontrol.cpp create mode 100644 src/plugins/directshow/camera/dsimagecapturecontrol.h create mode 100644 src/plugins/directshow/camera/dsvideodevicecontrol.cpp create mode 100644 src/plugins/directshow/camera/dsvideodevicecontrol.h create mode 100644 src/plugins/directshow/camera/dsvideorenderer.cpp create mode 100644 src/plugins/directshow/camera/dsvideorenderer.h create mode 100644 src/plugins/directshow/camera/dsvideowidgetcontrol.cpp create mode 100644 src/plugins/directshow/camera/dsvideowidgetcontrol.h create mode 100644 src/plugins/directshow/directshow.pro create mode 100644 src/plugins/directshow/dsserviceplugin.cpp create mode 100644 src/plugins/directshow/dsserviceplugin.h create mode 100644 src/plugins/directshow/player/directshowaudioendpointcontrol.cpp create mode 100644 src/plugins/directshow/player/directshowaudioendpointcontrol.h create mode 100644 src/plugins/directshow/player/directshoweventloop.cpp create mode 100644 src/plugins/directshow/player/directshoweventloop.h create mode 100644 src/plugins/directshow/player/directshowglobal.h create mode 100644 src/plugins/directshow/player/directshowioreader.cpp create mode 100644 src/plugins/directshow/player/directshowioreader.h create mode 100644 src/plugins/directshow/player/directshowiosource.cpp create mode 100644 src/plugins/directshow/player/directshowiosource.h create mode 100644 src/plugins/directshow/player/directshowmediatype.cpp create mode 100644 src/plugins/directshow/player/directshowmediatype.h create mode 100644 src/plugins/directshow/player/directshowmediatypelist.cpp create mode 100644 src/plugins/directshow/player/directshowmediatypelist.h create mode 100644 src/plugins/directshow/player/directshowmetadatacontrol.cpp create mode 100644 src/plugins/directshow/player/directshowmetadatacontrol.h create mode 100644 src/plugins/directshow/player/directshowpinenum.cpp create mode 100644 src/plugins/directshow/player/directshowpinenum.h create mode 100644 src/plugins/directshow/player/directshowplayercontrol.cpp create mode 100644 src/plugins/directshow/player/directshowplayercontrol.h create mode 100644 src/plugins/directshow/player/directshowplayerservice.cpp create mode 100644 src/plugins/directshow/player/directshowplayerservice.h create mode 100644 src/plugins/directshow/player/directshowsamplescheduler.cpp create mode 100644 src/plugins/directshow/player/directshowsamplescheduler.h create mode 100644 src/plugins/directshow/player/directshowvideorenderercontrol.cpp create mode 100644 src/plugins/directshow/player/directshowvideorenderercontrol.h create mode 100644 src/plugins/directshow/player/mediasamplevideobuffer.cpp create mode 100644 src/plugins/directshow/player/mediasamplevideobuffer.h create mode 100644 src/plugins/directshow/player/player.pri create mode 100644 src/plugins/directshow/player/videosurfacefilter.cpp create mode 100644 src/plugins/directshow/player/videosurfacefilter.h create mode 100644 src/plugins/directshow/player/vmr9videowindowcontrol.cpp create mode 100644 src/plugins/directshow/player/vmr9videowindowcontrol.h create mode 100644 src/plugins/gstreamer/camerabin/camerabin.pri create mode 100644 src/plugins/gstreamer/camerabin/camerabinaudioencoder.cpp create mode 100644 src/plugins/gstreamer/camerabin/camerabinaudioencoder.h create mode 100644 src/plugins/gstreamer/camerabin/camerabincapturebufferformat.cpp create mode 100644 src/plugins/gstreamer/camerabin/camerabincapturebufferformat.h create mode 100644 src/plugins/gstreamer/camerabin/camerabincapturedestination.cpp create mode 100644 src/plugins/gstreamer/camerabin/camerabincapturedestination.h create mode 100644 src/plugins/gstreamer/camerabin/camerabincontainer.cpp create mode 100644 src/plugins/gstreamer/camerabin/camerabincontainer.h create mode 100644 src/plugins/gstreamer/camerabin/camerabincontrol.cpp create mode 100644 src/plugins/gstreamer/camerabin/camerabincontrol.h create mode 100644 src/plugins/gstreamer/camerabin/camerabinexposure.cpp create mode 100644 src/plugins/gstreamer/camerabin/camerabinexposure.h create mode 100644 src/plugins/gstreamer/camerabin/camerabinflash.cpp create mode 100644 src/plugins/gstreamer/camerabin/camerabinflash.h create mode 100644 src/plugins/gstreamer/camerabin/camerabinfocus.cpp create mode 100644 src/plugins/gstreamer/camerabin/camerabinfocus.h create mode 100644 src/plugins/gstreamer/camerabin/camerabinimagecapture.cpp create mode 100644 src/plugins/gstreamer/camerabin/camerabinimagecapture.h create mode 100644 src/plugins/gstreamer/camerabin/camerabinimageencoder.cpp create mode 100644 src/plugins/gstreamer/camerabin/camerabinimageencoder.h create mode 100644 src/plugins/gstreamer/camerabin/camerabinimageprocessing.cpp create mode 100644 src/plugins/gstreamer/camerabin/camerabinimageprocessing.h create mode 100644 src/plugins/gstreamer/camerabin/camerabinlocks.cpp create mode 100644 src/plugins/gstreamer/camerabin/camerabinlocks.h create mode 100644 src/plugins/gstreamer/camerabin/camerabinmetadata.cpp create mode 100644 src/plugins/gstreamer/camerabin/camerabinmetadata.h create mode 100644 src/plugins/gstreamer/camerabin/camerabinrecorder.cpp create mode 100644 src/plugins/gstreamer/camerabin/camerabinrecorder.h create mode 100644 src/plugins/gstreamer/camerabin/camerabinresourcepolicy.cpp create mode 100644 src/plugins/gstreamer/camerabin/camerabinresourcepolicy.h create mode 100644 src/plugins/gstreamer/camerabin/camerabinservice.cpp create mode 100644 src/plugins/gstreamer/camerabin/camerabinservice.h create mode 100644 src/plugins/gstreamer/camerabin/camerabinsession.cpp create mode 100644 src/plugins/gstreamer/camerabin/camerabinsession.h create mode 100644 src/plugins/gstreamer/camerabin/camerabinvideoencoder.cpp create mode 100644 src/plugins/gstreamer/camerabin/camerabinvideoencoder.h create mode 100644 src/plugins/gstreamer/camerabuttonlistener_maemo.cpp create mode 100644 src/plugins/gstreamer/camerabuttonlistener_maemo.h create mode 100644 src/plugins/gstreamer/camerabuttonlistener_meego.cpp create mode 100644 src/plugins/gstreamer/camerabuttonlistener_meego.h create mode 100644 src/plugins/gstreamer/gstreamer.pro create mode 100644 src/plugins/gstreamer/gstvideoconnector.c create mode 100644 src/plugins/gstreamer/gstvideoconnector.h create mode 100644 src/plugins/gstreamer/mediacapture/mediacapture.pri create mode 100644 src/plugins/gstreamer/mediacapture/qgstreameraudioencode.cpp create mode 100644 src/plugins/gstreamer/mediacapture/qgstreameraudioencode.h create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamercameracontrol.cpp create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamercameracontrol.h create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamercapturemetadatacontrol.cpp create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamercapturemetadatacontrol.h create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.cpp create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.h create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamercapturesession.h create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamerimagecapturecontrol.cpp create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamerimagecapturecontrol.h create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamerimageencode.cpp create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamerimageencode.h create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamermediacontainercontrol.cpp create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamermediacontainercontrol.h create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamerrecordercontrol.h create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamerv4l2input.cpp create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamerv4l2input.h create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamervideoencode.cpp create mode 100644 src/plugins/gstreamer/mediacapture/qgstreamervideoencode.h create mode 100644 src/plugins/gstreamer/mediaplayer/mediaplayer.pri create mode 100644 src/plugins/gstreamer/mediaplayer/playerresourcepolicy.cpp create mode 100644 src/plugins/gstreamer/mediaplayer/playerresourcepolicy.h create mode 100644 src/plugins/gstreamer/mediaplayer/qgstappsrc.cpp create mode 100644 src/plugins/gstreamer/mediaplayer/qgstappsrc.h create mode 100644 src/plugins/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp create mode 100644 src/plugins/gstreamer/mediaplayer/qgstreamermetadataprovider.h create mode 100644 src/plugins/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp create mode 100644 src/plugins/gstreamer/mediaplayer/qgstreamerplayercontrol.h create mode 100644 src/plugins/gstreamer/mediaplayer/qgstreamerplayerservice.cpp create mode 100644 src/plugins/gstreamer/mediaplayer/qgstreamerplayerservice.h create mode 100644 src/plugins/gstreamer/mediaplayer/qgstreamerplayersession.cpp create mode 100644 src/plugins/gstreamer/mediaplayer/qgstreamerplayersession.h create mode 100644 src/plugins/gstreamer/mediaplayer/qgstreamerstreamscontrol.cpp create mode 100644 src/plugins/gstreamer/mediaplayer/qgstreamerstreamscontrol.h create mode 100644 src/plugins/gstreamer/qabstractgstbufferpool.h create mode 100644 src/plugins/gstreamer/qgstreameraudioinputendpointselector.cpp create mode 100644 src/plugins/gstreamer/qgstreameraudioinputendpointselector.h create mode 100644 src/plugins/gstreamer/qgstreamerbushelper.cpp create mode 100644 src/plugins/gstreamer/qgstreamerbushelper.h create mode 100644 src/plugins/gstreamer/qgstreamergltexturerenderer.cpp create mode 100644 src/plugins/gstreamer/qgstreamergltexturerenderer.h create mode 100644 src/plugins/gstreamer/qgstreamermessage.cpp create mode 100644 src/plugins/gstreamer/qgstreamermessage.h create mode 100644 src/plugins/gstreamer/qgstreamerserviceplugin.cpp create mode 100644 src/plugins/gstreamer/qgstreamerserviceplugin.h create mode 100644 src/plugins/gstreamer/qgstreamervideoinputdevicecontrol.cpp create mode 100644 src/plugins/gstreamer/qgstreamervideoinputdevicecontrol.h create mode 100644 src/plugins/gstreamer/qgstreamervideooverlay.cpp create mode 100644 src/plugins/gstreamer/qgstreamervideooverlay.h create mode 100644 src/plugins/gstreamer/qgstreamervideorenderer.cpp create mode 100644 src/plugins/gstreamer/qgstreamervideorenderer.h create mode 100644 src/plugins/gstreamer/qgstreamervideorendererinterface.cpp create mode 100644 src/plugins/gstreamer/qgstreamervideorendererinterface.h create mode 100644 src/plugins/gstreamer/qgstreamervideowidget.cpp create mode 100644 src/plugins/gstreamer/qgstreamervideowidget.h create mode 100644 src/plugins/gstreamer/qgstreamervideowindow.cpp create mode 100644 src/plugins/gstreamer/qgstreamervideowindow.h create mode 100644 src/plugins/gstreamer/qgstutils.cpp create mode 100644 src/plugins/gstreamer/qgstutils.h create mode 100644 src/plugins/gstreamer/qgstvideobuffer.cpp create mode 100644 src/plugins/gstreamer/qgstvideobuffer.h create mode 100644 src/plugins/gstreamer/qgstxvimagebuffer.cpp create mode 100644 src/plugins/gstreamer/qgstxvimagebuffer.h create mode 100644 src/plugins/gstreamer/qvideosurfacegstsink.cpp create mode 100644 src/plugins/gstreamer/qvideosurfacegstsink.h create mode 100644 src/plugins/gstreamer/qx11videosurface.cpp create mode 100644 src/plugins/gstreamer/qx11videosurface.h create mode 100644 src/plugins/m3u/m3u.pro create mode 100644 src/plugins/m3u/main.cpp create mode 100644 src/plugins/m3u/qm3uhandler.cpp create mode 100644 src/plugins/m3u/qm3uhandler.h create mode 100644 src/plugins/plugins.pro create mode 100644 src/plugins/pulseaudio/pulseaudio.pro create mode 100644 src/plugins/pulseaudio/qaudiodeviceinfo_pulse.cpp create mode 100644 src/plugins/pulseaudio/qaudiodeviceinfo_pulse.h create mode 100644 src/plugins/pulseaudio/qaudioinput_pulse.cpp create mode 100644 src/plugins/pulseaudio/qaudioinput_pulse.h create mode 100644 src/plugins/pulseaudio/qaudiooutput_pulse.cpp create mode 100644 src/plugins/pulseaudio/qaudiooutput_pulse.h create mode 100644 src/plugins/pulseaudio/qpulseaudioengine.cpp create mode 100644 src/plugins/pulseaudio/qpulseaudioengine.h create mode 100644 src/plugins/pulseaudio/qpulseaudioplugin.cpp create mode 100644 src/plugins/pulseaudio/qpulseaudioplugin.h create mode 100644 src/plugins/pulseaudio/qpulsehelpers.cpp create mode 100644 src/plugins/pulseaudio/qpulsehelpers.h create mode 100644 src/plugins/qt7/mediaplayer/mediaplayer.pri create mode 100644 src/plugins/qt7/mediaplayer/qt7playercontrol.h create mode 100644 src/plugins/qt7/mediaplayer/qt7playercontrol.mm create mode 100644 src/plugins/qt7/mediaplayer/qt7playermetadata.h create mode 100644 src/plugins/qt7/mediaplayer/qt7playermetadata.mm create mode 100644 src/plugins/qt7/mediaplayer/qt7playerservice.h create mode 100644 src/plugins/qt7/mediaplayer/qt7playerservice.mm create mode 100644 src/plugins/qt7/mediaplayer/qt7playersession.h create mode 100644 src/plugins/qt7/mediaplayer/qt7playersession.mm create mode 100644 src/plugins/qt7/qcvdisplaylink.h create mode 100644 src/plugins/qt7/qcvdisplaylink.mm create mode 100644 src/plugins/qt7/qt7.pro create mode 100644 src/plugins/qt7/qt7backend.h create mode 100644 src/plugins/qt7/qt7backend.mm create mode 100644 src/plugins/qt7/qt7ciimagevideobuffer.h create mode 100644 src/plugins/qt7/qt7ciimagevideobuffer.mm create mode 100644 src/plugins/qt7/qt7movierenderer.h create mode 100644 src/plugins/qt7/qt7movierenderer.mm create mode 100644 src/plugins/qt7/qt7movievideowidget.h create mode 100644 src/plugins/qt7/qt7movievideowidget.mm create mode 100644 src/plugins/qt7/qt7movieviewoutput.h create mode 100644 src/plugins/qt7/qt7movieviewoutput.mm create mode 100644 src/plugins/qt7/qt7movieviewrenderer.h create mode 100644 src/plugins/qt7/qt7movieviewrenderer.mm create mode 100644 src/plugins/qt7/qt7serviceplugin.h create mode 100644 src/plugins/qt7/qt7serviceplugin.mm create mode 100644 src/plugins/qt7/qt7videooutput.h create mode 100644 src/plugins/qt7/qt7videooutput.mm create mode 100644 src/plugins/simulator/camera/simulatorcamera.pri create mode 100644 src/plugins/simulator/camera/simulatorcameracontrol.cpp create mode 100644 src/plugins/simulator/camera/simulatorcameracontrol.h create mode 100644 src/plugins/simulator/camera/simulatorcameraexposurecontrol.cpp create mode 100644 src/plugins/simulator/camera/simulatorcameraexposurecontrol.h create mode 100644 src/plugins/simulator/camera/simulatorcameraimagecapturecontrol.cpp create mode 100644 src/plugins/simulator/camera/simulatorcameraimagecapturecontrol.h create mode 100644 src/plugins/simulator/camera/simulatorcameraservice.cpp create mode 100644 src/plugins/simulator/camera/simulatorcameraservice.h create mode 100644 src/plugins/simulator/camera/simulatorcamerasession.cpp create mode 100644 src/plugins/simulator/camera/simulatorcamerasession.h create mode 100644 src/plugins/simulator/camera/simulatorcamerasettings.cpp create mode 100644 src/plugins/simulator/camera/simulatorcamerasettings.h create mode 100644 src/plugins/simulator/camera/simulatorvideoinputdevicecontrol.cpp create mode 100644 src/plugins/simulator/camera/simulatorvideoinputdevicecontrol.h create mode 100644 src/plugins/simulator/camera/simulatorvideorenderercontrol.cpp create mode 100644 src/plugins/simulator/camera/simulatorvideorenderercontrol.h create mode 100644 src/plugins/simulator/qsimulatormultimediaconnection.cpp create mode 100644 src/plugins/simulator/qsimulatormultimediaconnection_p.h create mode 100644 src/plugins/simulator/qsimulatormultimediadata.cpp create mode 100644 src/plugins/simulator/qsimulatormultimediadata_p.h create mode 100644 src/plugins/simulator/qsimulatorserviceplugin.cpp create mode 100644 src/plugins/simulator/qsimulatorserviceplugin.h create mode 100644 src/plugins/simulator/simulator.pro create mode 100644 src/plugins/symbian/ecam/camera_s60.pri create mode 100644 src/plugins/symbian/ecam/ecam.pro create mode 100644 src/plugins/symbian/ecam/s60audioencodercontrol.cpp create mode 100644 src/plugins/symbian/ecam/s60audioencodercontrol.h create mode 100644 src/plugins/symbian/ecam/s60cameraconstants.h create mode 100644 src/plugins/symbian/ecam/s60cameracontrol.cpp create mode 100644 src/plugins/symbian/ecam/s60cameracontrol.h create mode 100644 src/plugins/symbian/ecam/s60cameraengine.cpp create mode 100644 src/plugins/symbian/ecam/s60cameraengine.h create mode 100644 src/plugins/symbian/ecam/s60cameraengineobserver.h create mode 100644 src/plugins/symbian/ecam/s60cameraexposurecontrol.cpp create mode 100644 src/plugins/symbian/ecam/s60cameraexposurecontrol.h create mode 100644 src/plugins/symbian/ecam/s60cameraflashcontrol.cpp create mode 100644 src/plugins/symbian/ecam/s60cameraflashcontrol.h create mode 100644 src/plugins/symbian/ecam/s60camerafocuscontrol.cpp create mode 100644 src/plugins/symbian/ecam/s60camerafocuscontrol.h create mode 100644 src/plugins/symbian/ecam/s60cameraimagecapturecontrol.cpp create mode 100644 src/plugins/symbian/ecam/s60cameraimagecapturecontrol.h create mode 100644 src/plugins/symbian/ecam/s60cameraimageprocessingcontrol.cpp create mode 100644 src/plugins/symbian/ecam/s60cameraimageprocessingcontrol.h create mode 100644 src/plugins/symbian/ecam/s60cameralockscontrol.cpp create mode 100644 src/plugins/symbian/ecam/s60cameralockscontrol.h create mode 100644 src/plugins/symbian/ecam/s60cameraservice.cpp create mode 100644 src/plugins/symbian/ecam/s60cameraservice.h create mode 100644 src/plugins/symbian/ecam/s60cameraserviceplugin.cpp create mode 100644 src/plugins/symbian/ecam/s60cameraserviceplugin.h create mode 100644 src/plugins/symbian/ecam/s60camerasettings.cpp create mode 100644 src/plugins/symbian/ecam/s60camerasettings.h create mode 100644 src/plugins/symbian/ecam/s60cameraviewfinderengine.cpp create mode 100644 src/plugins/symbian/ecam/s60cameraviewfinderengine.h create mode 100644 src/plugins/symbian/ecam/s60imagecapturesession.cpp create mode 100644 src/plugins/symbian/ecam/s60imagecapturesession.h create mode 100644 src/plugins/symbian/ecam/s60imageencodercontrol.cpp create mode 100644 src/plugins/symbian/ecam/s60imageencodercontrol.h create mode 100644 src/plugins/symbian/ecam/s60mediacontainercontrol.cpp create mode 100644 src/plugins/symbian/ecam/s60mediacontainercontrol.h create mode 100644 src/plugins/symbian/ecam/s60mediarecordercontrol.cpp create mode 100644 src/plugins/symbian/ecam/s60mediarecordercontrol.h create mode 100644 src/plugins/symbian/ecam/s60videocapturesession.cpp create mode 100644 src/plugins/symbian/ecam/s60videocapturesession.h create mode 100644 src/plugins/symbian/ecam/s60videodevicecontrol.cpp create mode 100644 src/plugins/symbian/ecam/s60videodevicecontrol.h create mode 100644 src/plugins/symbian/ecam/s60videoencodercontrol.cpp create mode 100644 src/plugins/symbian/ecam/s60videoencodercontrol.h create mode 100644 src/plugins/symbian/ecam/s60videorenderercontrol.cpp create mode 100644 src/plugins/symbian/ecam/s60videorenderercontrol.h create mode 100644 src/plugins/symbian/mmf/audiosource/audiosource_s60.pri create mode 100644 src/plugins/symbian/mmf/audiosource/s60audiocaptureservice.cpp create mode 100644 src/plugins/symbian/mmf/audiosource/s60audiocaptureservice.h create mode 100644 src/plugins/symbian/mmf/audiosource/s60audiocapturesession.cpp create mode 100644 src/plugins/symbian/mmf/audiosource/s60audiocapturesession.h create mode 100644 src/plugins/symbian/mmf/audiosource/s60audiocontainercontrol.cpp create mode 100644 src/plugins/symbian/mmf/audiosource/s60audiocontainercontrol.h create mode 100644 src/plugins/symbian/mmf/audiosource/s60audioencodercontrol.cpp create mode 100644 src/plugins/symbian/mmf/audiosource/s60audioencodercontrol.h create mode 100644 src/plugins/symbian/mmf/audiosource/s60audioendpointselector.cpp create mode 100644 src/plugins/symbian/mmf/audiosource/s60audioendpointselector.h create mode 100644 src/plugins/symbian/mmf/audiosource/s60audiomediarecordercontrol.cpp create mode 100644 src/plugins/symbian/mmf/audiosource/s60audiomediarecordercontrol.h create mode 100644 src/plugins/symbian/mmf/inc/DebugMacros.h create mode 100644 src/plugins/symbian/mmf/mediaplayer/mediaplayer_s60.pri create mode 100644 src/plugins/symbian/mmf/mediaplayer/ms60mediaplayerresolver.h create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60audioplayersession.cpp create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60audioplayersession.h create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60mediametadataprovider.cpp create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60mediametadataprovider.h create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60medianetworkaccesscontrol.cpp create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60medianetworkaccesscontrol.h create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60mediaplayeraudioendpointselector.cpp create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60mediaplayeraudioendpointselector.h create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60mediaplayercontrol.cpp create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60mediaplayercontrol.h create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60mediaplayerservice.cpp create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60mediaplayerservice.h create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60mediaplayersession.cpp create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60mediaplayersession.h create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60mediarecognizer.cpp create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60mediarecognizer.h create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60mediastreamcontrol.cpp create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60mediastreamcontrol.h create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60videooutputinterface.h create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60videoplayersession.cpp create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60videoplayersession.h create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60videorenderer.cpp create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60videorenderer.h create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60videosurface.cpp create mode 100644 src/plugins/symbian/mmf/mediaplayer/s60videosurface.h create mode 100644 src/plugins/symbian/mmf/mmf.pro create mode 100644 src/plugins/symbian/mmf/radio/radio.pri create mode 100644 src/plugins/symbian/mmf/radio/s60radiotunercontrol_31.cpp create mode 100644 src/plugins/symbian/mmf/radio/s60radiotunercontrol_31.h create mode 100644 src/plugins/symbian/mmf/radio/s60radiotunercontrol_since32.cpp create mode 100644 src/plugins/symbian/mmf/radio/s60radiotunercontrol_since32.h create mode 100644 src/plugins/symbian/mmf/radio/s60radiotunerservice.cpp create mode 100644 src/plugins/symbian/mmf/radio/s60radiotunerservice.h create mode 100644 src/plugins/symbian/mmf/s60formatsupported.cpp create mode 100644 src/plugins/symbian/mmf/s60formatsupported.h create mode 100644 src/plugins/symbian/mmf/s60mediaserviceplugin.cpp create mode 100644 src/plugins/symbian/mmf/s60mediaserviceplugin.h create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/mediaplayer.pri create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/qxamediaplayercontrol.cpp create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/qxamediaplayercontrol.h create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/qxamediastreamscontrol.cpp create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/qxamediastreamscontrol.h create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/qxametadatacontrol.cpp create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/qxametadatacontrol.h create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/qxaplaymediaservice.cpp create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/qxaplaymediaservice.h create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/qxaplaysession.cpp create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/qxaplaysession.h create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/qxavideowidgetcontrol.cpp create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/qxavideowidgetcontrol.h create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/qxavideowindowcontrol.cpp create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/qxavideowindowcontrol.h create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/qxawidget.cpp create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/qxawidget.h create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/xaplaysessioncommon.h create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/xaplaysessionimpl.cpp create mode 100644 src/plugins/symbian/openmaxal/mediaplayer/xaplaysessionimpl.h create mode 100644 src/plugins/symbian/openmaxal/mediarecorder/mediarecorder.pri create mode 100644 src/plugins/symbian/openmaxal/mediarecorder/qxaaudioencodercontrol.cpp create mode 100644 src/plugins/symbian/openmaxal/mediarecorder/qxaaudioencodercontrol.h create mode 100644 src/plugins/symbian/openmaxal/mediarecorder/qxaaudioendpointselector.cpp create mode 100644 src/plugins/symbian/openmaxal/mediarecorder/qxaaudioendpointselector.h create mode 100644 src/plugins/symbian/openmaxal/mediarecorder/qxamediacontainercontrol.cpp create mode 100644 src/plugins/symbian/openmaxal/mediarecorder/qxamediacontainercontrol.h create mode 100644 src/plugins/symbian/openmaxal/mediarecorder/qxamediarecordercontrol.cpp create mode 100644 src/plugins/symbian/openmaxal/mediarecorder/qxamediarecordercontrol.h create mode 100644 src/plugins/symbian/openmaxal/mediarecorder/qxarecordmediaservice.cpp create mode 100644 src/plugins/symbian/openmaxal/mediarecorder/qxarecordmediaservice.h create mode 100644 src/plugins/symbian/openmaxal/mediarecorder/qxarecordsession.cpp create mode 100644 src/plugins/symbian/openmaxal/mediarecorder/qxarecordsession.h create mode 100644 src/plugins/symbian/openmaxal/mediarecorder/xarecordsessioncommon.h create mode 100644 src/plugins/symbian/openmaxal/mediarecorder/xarecordsessionimpl.cpp create mode 100644 src/plugins/symbian/openmaxal/mediarecorder/xarecordsessionimpl.h create mode 100644 src/plugins/symbian/openmaxal/openmaxal.pro create mode 100644 src/plugins/symbian/openmaxal/qxacommon.h create mode 100644 src/plugins/symbian/openmaxal/qxamediaserviceproviderplugin.cpp create mode 100644 src/plugins/symbian/openmaxal/qxamediaserviceproviderplugin.h create mode 100644 src/plugins/symbian/openmaxal/radiotuner/qxaradiocontrol.cpp create mode 100644 src/plugins/symbian/openmaxal/radiotuner/qxaradiocontrol.h create mode 100644 src/plugins/symbian/openmaxal/radiotuner/qxaradiomediaservice.cpp create mode 100644 src/plugins/symbian/openmaxal/radiotuner/qxaradiomediaservice.h create mode 100644 src/plugins/symbian/openmaxal/radiotuner/qxaradiosession.cpp create mode 100644 src/plugins/symbian/openmaxal/radiotuner/qxaradiosession.h create mode 100644 src/plugins/symbian/openmaxal/radiotuner/radiotuner.pri create mode 100644 src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimpl.cpp create mode 100644 src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimpl.h create mode 100644 src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimplobserver.h create mode 100644 src/plugins/symbian/openmaxal/xacommon.h create mode 100644 src/plugins/symbian/symbian.pro create mode 100644 src/plugins/symbian/videooutput/s60videodisplay.cpp create mode 100644 src/plugins/symbian/videooutput/s60videodisplay.h create mode 100644 src/plugins/symbian/videooutput/s60videooutpututils.cpp create mode 100644 src/plugins/symbian/videooutput/s60videooutpututils.h create mode 100644 src/plugins/symbian/videooutput/s60videowidget.cpp create mode 100644 src/plugins/symbian/videooutput/s60videowidget.h create mode 100644 src/plugins/symbian/videooutput/s60videowidgetcontrol.cpp create mode 100644 src/plugins/symbian/videooutput/s60videowidgetcontrol.h create mode 100644 src/plugins/symbian/videooutput/s60videowidgetdisplay.cpp create mode 100644 src/plugins/symbian/videooutput/s60videowidgetdisplay.h create mode 100644 src/plugins/symbian/videooutput/s60videowindowcontrol.cpp create mode 100644 src/plugins/symbian/videooutput/s60videowindowcontrol.h create mode 100644 src/plugins/symbian/videooutput/s60videowindowdisplay.cpp create mode 100644 src/plugins/symbian/videooutput/s60videowindowdisplay.h create mode 100644 src/plugins/symbian/videooutput/videooutput.pri create mode 100644 src/plugins/v4l/radio/radio.pri create mode 100644 src/plugins/v4l/radio/v4lradiocontrol.cpp create mode 100644 src/plugins/v4l/radio/v4lradiocontrol.h create mode 100644 src/plugins/v4l/radio/v4lradiocontrol_maemo5.cpp create mode 100644 src/plugins/v4l/radio/v4lradiocontrol_maemo5.h create mode 100644 src/plugins/v4l/radio/v4lradioservice.cpp create mode 100644 src/plugins/v4l/radio/v4lradioservice.h create mode 100644 src/plugins/v4l/v4l.pro create mode 100644 src/plugins/v4l/v4lserviceplugin.cpp create mode 100644 src/plugins/v4l/v4lserviceplugin.h create mode 100644 src/plugins/wmp/qevrvideooverlay.cpp create mode 100644 src/plugins/wmp/qevrvideooverlay.h create mode 100644 src/plugins/wmp/qmfactivate.cpp create mode 100644 src/plugins/wmp/qmfactivate.h create mode 100644 src/plugins/wmp/qwmpevents.cpp create mode 100644 src/plugins/wmp/qwmpevents.h create mode 100644 src/plugins/wmp/qwmpglobal.cpp create mode 100644 src/plugins/wmp/qwmpglobal.h create mode 100644 src/plugins/wmp/qwmpmetadata.cpp create mode 100644 src/plugins/wmp/qwmpmetadata.h create mode 100644 src/plugins/wmp/qwmpplayercontrol.cpp create mode 100644 src/plugins/wmp/qwmpplayercontrol.h create mode 100644 src/plugins/wmp/qwmpplayerservice.cpp create mode 100644 src/plugins/wmp/qwmpplayerservice.h create mode 100644 src/plugins/wmp/qwmpplaylist.cpp create mode 100644 src/plugins/wmp/qwmpplaylist.h create mode 100644 src/plugins/wmp/qwmpplaylistcontrol.cpp create mode 100644 src/plugins/wmp/qwmpplaylistcontrol.h create mode 100644 src/plugins/wmp/qwmpserviceprovider.cpp create mode 100644 src/plugins/wmp/qwmpserviceprovider.h create mode 100644 src/plugins/wmp/qwmpvideooverlay.cpp create mode 100644 src/plugins/wmp/qwmpvideooverlay.h create mode 100644 src/plugins/wmp/wmp.pro create mode 100644 src/s60installs/backup_registration.xml create mode 100644 src/s60installs/bwins/QtMultimediaKitu.def create mode 100644 src/s60installs/deviceconfiguration/.gitignore create mode 100644 src/s60installs/deviceconfiguration/QtBearer{000a0000}.dll create mode 100644 src/s60installs/deviceconfiguration/bld.inf create mode 100644 src/s60installs/deviceconfiguration/mobilityconfig.prf create mode 100644 src/s60installs/deviceconfiguration/qtmobility.confml create mode 100644 src/s60installs/deviceconfiguration/qtmobility.iby create mode 100644 src/s60installs/deviceconfiguration/qtmobility.sisx create mode 100644 src/s60installs/deviceconfiguration/qtmobility_copy.implml create mode 100644 src/s60installs/deviceconfiguration/qtmobility_stub.pkg create mode 100644 src/s60installs/deviceconfiguration/qtmobility_stub.sis create mode 100644 src/s60installs/deviceconfiguration/qtmobilityconfig.xml create mode 100644 src/s60installs/deviceconfiguration/qtmobilityexampleapps.pkg create mode 100644 src/s60installs/deviceconfiguration/qtmobilityexamples.iby create mode 100644 src/s60installs/deviceconfiguration/qtmobilityheaders.flm create mode 100644 src/s60installs/deviceconfiguration/qtmobilitytests.iby create mode 100644 src/s60installs/deviceconfiguration/symbian3_config.pri create mode 100644 src/s60installs/deviceconfiguration/symbian3_qtmobility.pkg create mode 100644 src/s60installs/eabi/QtMultimediaKitu.def create mode 100644 src/s60installs/s60installs.pro create mode 100644 src/src.pro (limited to 'src') diff --git a/src/harmattaninstalls/README b/src/harmattaninstalls/README new file mode 100644 index 000000000..2712122ae --- /dev/null +++ b/src/harmattaninstalls/README @@ -0,0 +1,19 @@ +This directory contains the metadata for building and +packaging Qt Mobility on Harmattan. + + +HOW TO BUILD FOR HARMATTAN +========================== + +(note: this is a brief overview and many aspects are uncovered) + +From within Scratchbox, at the top level of the Mobility +source tree: + + $ ln -s src/harmattaninstalls debian + + $ dpkg-checkbuilddeps + $ fakeroot apt-get install (any missing dependencies mentioned above) + + $ dpkg-buildpackage -rfakeroot + diff --git a/src/harmattaninstalls/api b/src/harmattaninstalls/api new file mode 100644 index 000000000..adf69eedc --- /dev/null +++ b/src/harmattaninstalls/api @@ -0,0 +1,92 @@ +interface: QtContacts +type: library +scope: Nokia MeeGo +state: stable +libs-pkg: libqtm-contacts +dev-pkg: libqtm-common-dev libqtm-contacts-dev + +interface: QtFeedback +type: library +scope: Nokia MeeGo +state: stable +libs-pkg: libqtm-feedback +dev-pkg: libqtm-common-dev libqtm-feedback-dev + +interface: QtGallery +type: library +libs-pkg: libqtm-gallery +dev-pkg: libqtm-common-dev libqtm-gallery-dev +state: stable +scope: Nokia MeeGo + +interface: QtLocation +type: library +libs-pkg: libqtm-location +dev-pkg: libqtm-common-dev libqtm-location-dev +state: stable +scope: Nokia MeeGo + +interface: QtMessaging +type: library +libs-pkg: libqtm-messaging +dev-pkg: libqtm-common-dev libqtm-messaging-dev +state: stable +scope: Nokia MeeGo + +interface: QtMultimediaKit +type: library +libs-pkg: libqtm-multimedia +dev-pkg: libqtm-common-dev libqtm-multimedia-dev +state: stable +scope: Nokia MeeGo + + +interface: QtOrganizer +type: library +libs-pkg: libqtm-organizer +dev-pkg: libqtm-common-dev libqtm-organizer-dev +state: stable +scope: Nokia MeeGo + +interface: QtPublishSubscribe +type: library +libs-pkg: libqtm-publishsubscribe +dev-pkg: libqtm-common-dev libqtm-publishsubscribe-dev +state: stable +scope: Nokia MeeGo + +interface: QtSensors +type: library +libs-pkg: libqtm-sensors +dev-pkg: libqtm-common-dev libqtm-sensors-dev +state: stable +scope: Nokia MeeGo + +interface: QtServiceFramework +type: library +libs-pkg: libqtm-serviceframework +dev-pkg: libqtm-common-dev libqtm-serviceframework-dev +state: stable +scope: Nokia MeeGo + +interface: QtSystemInfo +type: library +libs-pkg: libqtm-systeminfo +dev-pkg: libqtm-common-dev libqtm-systeminfo-dev +state: stable +scope: Nokia MeeGo + +interface: QtVersit +type: library +libs-pkg: libqtm-versit +dev-pkg: libqtm-common-dev libqtm-versit-dev +state: stable +scope: Nokia MeeGo + +interface: QtVersitOrganizer +type: library +libs-pkg: libqtm-versitorganizer +dev-pkg: libqtm-common-dev libqtm-versitorganizer-dev +state: stable +scope: Nokia MeeGo + diff --git a/src/harmattaninstalls/changelog b/src/harmattaninstalls/changelog new file mode 100644 index 000000000..b88e2e473 --- /dev/null +++ b/src/harmattaninstalls/changelog @@ -0,0 +1,178 @@ +qt-mobility (1.2.0~git20110225) unstable; urgency=low + + * Bumped up the version + + -- Sunil Thaha Fri, 25 Feb 2011 13:59:48 +1000 + +qt-mobility (1.2.0~git20110210) unstable; urgency=low + + * Bump version to 1.2 + * Fixes: NB#206728 + + -- Sunil Thaha Wed, 10 Feb 2011 13:59:48 +1000 + +qt-mobility (1.1.1~git20110106) unstable; urgency=low + + * Fixes: NB#212701 : added the commit 95e140e7 as a patch + + -- Sunil Thaha Thu, 06 Jan 2011 10:02:05 +1000 + +qt-mobility (1.1.1~git20101224) unstable; urgency=low + + * Fixes: NB#212701 : added the commit feb61b9 as a patch + + -- Sunil Thaha Fri, 24 Dec 2010 17:30:55 +1000 + +qt-mobility (1.1.1~git20101217) unstable; urgency=low + + * Updated the code base to releases/1.1.1 + * Fixes: NB#212701 : added the commit feb61b9 as a patch + + -- Sunil Thaha Fri, 17 Dec 2010 17:30:55 +1000 + +qt-mobility (1.1.1~git20101207) unstable; urgency=low + + * Fixes: NB#209489 + + -- Sunil Thaha Tue, 07 Dec 2010 17:30:55 +1000 + +qt-mobility (1.1.1~git20101201) unstable; urgency=low + * Fixes: NB#189902 + * Fixes: NB#189902 + * Fixes: NB#199411 + * Fixes: NB#198751 + * Fixes: NB#201514 + * Fixes: NB#203941 + * Fixes: NB#208483 + + -- Qt Development Frameworks Wed, 01 Dec 2010 11:39:00 +1000 + +qt-mobility (1.1.1~git20101119-0maemo1) unstable; urgency=low + * Qt Organizer module + * Classes for calendar entries, todo tasks, journal entries and notes + * Qt Feedback module + * Classes for feedback (haptic/tactile feedback, general multimedia feedback) + * Initial release has limited multimedia support + * Qt Gallery module + * Classes for searching for documents, and viewing document meta-data. + * Qt Maps and Navigation API + Part of the Location module + * Class for routing, geocoding and reverse geocoding, and for displaying and interacting with maps. + * Qt Landmarks module + * Part of the Location module + * Classes for saving, retrieving and deleting landmarks + + -- Qt Development Frameworks Fri, 19 Oct 2010 11:39:00 +1000 + +qt-mobility (1.1.0~git20101026-0maemo1) unstable; urgency=low + * New Modules: + * Feedback + * + * Modules Changed: + * + * Bug Fixes: + * JIRA#MOBILITY-1780 + + -- Qt Development Frameworks Tue, 26 Oct 2010 11:39:00 +1000 + +qt-mobility (1.1.0~git20101005-0maemo1) unstable; urgency=low + * Modules Integrated: + * QtContacts + * QtLocation + * QtMessaging + * QtMultimedia + * QtOrganizer + * QtPublishsubscribe + * QtSensors + * QtServiceframework + * QtSysteminfo + * QtVersit + * Bug Fixes + * NB#189907 : QtPositionProvider has too slow initiation + * NB#195969 : libqtm-organizer depends on libextendedkcal and it is deprecated + + -- Qt Development Frameworks Tue, 05 Oct 2010 11:39:00 +1000 + +qt-mobility (1.1.0~git20100922-0maemo1) unstable; urgency=low + + * Updated base code 1.1 + + -- Qt Development Frameworks Wed, 22 Sep 2010 11:39:00 +1000 + +qt-mobility (1.1.0~git20100917-0maemo1) unstable; urgency=low + + * Updated base code 1.1 + + -- Qt Development Frameworks Fri, 17 Sep 2010 11:39:00 +1000 + +qt-mobility (1.1.0~git20100916-0maemo2) unstable; urgency=low + + * Updated base code 1.1 + + -- Qt Development Frameworks Thu, 16 Sep 2010 11:39:00 +1000 + +qt-mobility (1.1.0~git20100909-0maemo2) unstable; urgency=low + + * Updated base code 1.1 + * Fixes: NB#190298 - [METABUG] Upgrade Qt Mobility APIs to version 1.1 + + -- Qt Development Frameworks Tue, 10 Sep 2010 11:39:00 +1000 + +qt-mobility (1.1.0~git20100906-0maemo1) unstable; urgency=low + + * Updated base code 1.1 + + -- Qt Development Frameworks Tue, 06 Sep 2010 11:39:00 +1000 + +qt-mobility (1.1.0~git20100831-0maemo1) unstable; urgency=low + + * Updated base code 1.1 + + -- Qt Development Frameworks Tue, 31 Aug 2010 11:39:00 +1000 + +qt-mobility (1.1.0~git20100817-0maemo1) unstable; urgency=low + + * Updated base code 1.1 + + -- Qt Development Frameworks Fri, 20 Aug 2010 11:39:00 +1000 + +qt-mobility (1.0.2~git20100721-0maemo1) unstable; urgency=low + + * Move component headers to their specific dev packages. + * Add missing pkgconfig files. + * Fixes: NB#180932 - Missing QtLocation.pc. + + -- Qt Development Frameworks Wed, 21 Jul 2010 14:39:00 +1000 + +qt-mobility (1.0.2~git20100714-0maemo1) unstable; urgency=low + + * Pull from upstream (qtmobility-releases/1.0.2) + * Fixes: 173824 - [METABUG] Integrate Qt Mobility APIs (contacts, versit, location) + * Fixes: 172247 - Headers missing from libqtm-serviceframework-dev package and installation issues. + + -- Qt Development Frameworks Wed, 14 Jul 2010 17:00:00 +1000 + +qt-mobility (1.0.2~git20100623-0maemo1) unstable; urgency=low + + * Pull from upstream (qtmobility/1.0) + + -- Qt Development Frameworks Thu, 10 Jun 2010 13:50:00 +0200 + +qt-mobility (1.0.0~git20100429-0maemo1) unstable; urgency=low + + * Pull from upstream + + -- Qt Development Frameworks Fri, 30 Apr 2010 12:30:00 +1000 + +qt-mobility (1.0.0~git20100422-0maemo1) unstable; urgency=low + + * Pull from upstream + + -- Qt Development Frameworks Fri, 23 Apr 2010 15:10:00 +1000 + +qt-mobility (1.0.0~git20100304-0maemo1) unstable; urgency=low + + * Initial release + + -- Qt Development Frameworks Thu, 04 Mar 2010 15:52:12 +1000 + diff --git a/src/harmattaninstalls/compat b/src/harmattaninstalls/compat new file mode 100644 index 000000000..7ed6ff82d --- /dev/null +++ b/src/harmattaninstalls/compat @@ -0,0 +1 @@ +5 diff --git a/src/harmattaninstalls/control b/src/harmattaninstalls/control new file mode 100644 index 000000000..8cb347d44 --- /dev/null +++ b/src/harmattaninstalls/control @@ -0,0 +1,716 @@ +Source: qt-mobility +Section: libs +Priority: extra +Maintainer: Qt Development Frameworks +Build-Depends: libqt4-dev (>= 4.7.0), cdbs, debhelper (>= 5), quilt, aegis-builder (>= 1.4), + libicd-network-wlan-dev, libqt4-opengl-dev (>= 4.7.0), + libconninet0-dev, libcontextsubscriber-dev, libbluetooth3-dev, libcontextprovider-dev, + libx11-dev, libsensord-dev (>= 0.6.4), libqt4-declarative-dev (>= 4.7.0), + libxrandr-dev, gstreamer0.10-plugins-bad-dev, icd2-dev, libasound2-dev, + libconnsettings0-dev, libgstreamer-plugins-base0.10-dev, libgstreamer0.10-dev, libtelepathy-qt4-1-dev, + libxrandr-dev, libxv-dev, osso-wlan-dev, x11proto-video-dev, libqmf-dev, + libmessagingif-dev, libcommhistory-dev, libblkid-dev, pulseaudio-dev, libimmvibe-dev[armel], libqtsparql-dev, + libmkcal-dev, libkcalcoren-dev, libresourceqt-dev, libqmsystem2-dev, libqtsparql-tracker-extensions-dev, + libudev-dev, libiphb-dev, meego-gstreamer0.10-interfaces-dev[armel], libbmeipc-dev, libiphb-dev +Standards-Version: 3.8.0 + +Package: libqtm-examples +Architecture: any +Section: devel +Depends: qt4-declarative-qmlviewer, ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility examples package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-dev +Architecture: any +Section: devel +Depends: ${shlibs:Depends}, ${misc:Depends}, libqtm-common-dev(= ${binary:Version}), + libqtm-contacts-dev(= ${binary:Version}), libqtm-feedback-dev(= ${binary:Version}), + libqtm-gallery-dev(= ${binary:Version}), libqtm-location-dev(= ${binary:Version}), + libqtm-messaging-dev(= ${binary:Version}), libqtm-multimedia-dev(= ${binary:Version}), + libqtm-organizer-dev(= ${binary:Version}), libqtm-publishsubscribe-dev(= ${binary:Version}), + libqtm-sensors-dev(= ${binary:Version}), libqtm-serviceframework-dev(= ${binary:Version}), + libqtm-systeminfo-dev(= ${binary:Version}), libqtm-versit-dev(= ${binary:Version}), + libqtm-versitorganizer-dev(= ${binary:Version}), libqtm-connectivity-dev(= ${binary:Version}) +Description: Qt Mobility development package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + This package contains development headers of each Mobility component + +Package: libqtm-common-dev +Architecture: any +Section: devel +Depends: ${shlibs:Depends}, ${misc:Depends}, libqt4-dev, libqt4-declarative-dev +Description: Qt Mobility development package that contains the headers common to all modules + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + This package contains development headers common to each Mobility component + +#Package: libqtm-doc +#Architecture: any +#Section: devel +#Depends: ${shlibs:Depends}, ${misc:Depends} +#Description: Qt Mobility documentation package +# Qt Mobility Project delivers a set of new APIs to Qt with features that are +# well known from the mobile device world, in particular phones. However, +# these APIs allow the developer to use these features with ease from one +# framework and apply them to phones, netbooks and non-mobile personal +# computers. +# . +# This package contains documentation for all Mobility components + +Package: libqtm-multimedia +Architecture: any +Section: libs +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Multimedia module + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-multimedia-dbg +Architecture: any +Section: libdevel +Depends: libqtm-multimedia (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Multimedia debugging symbols + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-multimedia-dev +Architecture: any +Section: libs +Depends: libqtm-multimedia (= ${binary:Version}), libqtm-common-dev (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Multimedia development package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-multimedia-tests +Architecture: any +Section: libs +Depends: ci-testing, ${shlibs:Depends},${misc:Depends} +XB-Maemo-CI-Packages: libqtm-multimedia +XB-Maemo-CI-Stage: staging +Description: Qt Mobility Multimedia autotest package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-feedback +Architecture: any +Section: libs +Depends: immvibed[armel], libqtm-multimedia (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Feedback module + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-feedback-dbg +Architecture: any +Section: libdevel +Depends: libqtm-feedback (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Feedback debugging symbols + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-feedback-dev +Architecture: any +Section: libs +Depends: libqtm-feedback (= ${binary:Version}), libqtm-multimedia-dev (= ${binary:Version}), libqtm-common-dev (= ${binary:Version}), ${shlibs:Depends},${misc:Depends} +Description: Qt Mobility Feedback development package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-feedback-tests +Architecture: any +Section: libs +Depends: ci-testing, ${shlibs:Depends}, ${shlibs:Depends},${misc:Depends} +XB-Maemo-CI-Packages: libqtm-feedback +XB-Maemo-CI-Stage: staging +Description: Qt Mobility Feedback autotest package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-gallery +Architecture: any +Section: libs +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Gallery Framework module + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-gallery-dbg +Architecture: any +Section: libdevel +Depends: libqtm-gallery (= ${binary:Version}), ${shlibs:Depends},${misc:Depends} +Description: Qt Mobility Gallery Framework debugging symbols + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-gallery-dev +Architecture: any +Section: libs +Depends: libqtm-gallery (= ${binary:Version}), libqtm-common-dev (= ${binary:Version}), ${shlibs:Depends},${misc:Depends} +Description: Qt Mobility Gallery Framework development package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-gallery-tests +Architecture: any +Section: libs +Depends: ci-testing, ${shlibs:Depends}, ${shlibs:Depends},${misc:Depends} +XB-Maemo-CI-Packages: libqtm-gallery +XB-Maemo-CI-Stage: staging +Description: Qt Mobility Gallery autotest package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-serviceframework +Architecture: any +Section: libs +Depends: libqt4-sql (>= 4.6.0), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Service Framework module + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-serviceframework-dbg +Architecture: any +Section: libdevel +Depends: libqtm-serviceframework (= ${binary:Version}), ${shlibs:Depends},${misc:Depends} +Description: Qt Mobility Service Framework debugging symbols + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-serviceframework-dev +Architecture: any +Section: libs +Depends: libqtm-serviceframework (= ${binary:Version}), libqtm-common-dev (= ${binary:Version}), ${shlibs:Depends},${misc:Depends} +Description: Qt Mobility Service Framework development package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-serviceframework-tests +Architecture: any +Section: libs +Depends: ci-testing, ${shlibs:Depends},${misc:Depends} +XB-Maemo-CI-Packages: libqtm-serviceframework +XB-Maemo-CI-Stage: staging +Description: Qt Mobility Serviceframework autotest package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-messaging +Architecture: any +Section: libs +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Messaging module + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-messaging-dbg +Architecture: any +Section: libdevel +Depends: libqtm-messaging (= ${binary:Version}), ${shlibs:Depends},${misc:Depends} +Description: Qt Mobility Messaging debugging symbols + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-messaging-dev +Architecture: any +Section: libs +Depends: libqtm-messaging (= ${binary:Version}), libqtm-common-dev (= ${binary:Version}), ${shlibs:Depends},${misc:Depends} +Description: Qt Mobility Messaging development package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-messaging-tests +Architecture: any +Section: libs +Depends: ci-testing, ${shlibs:Depends},${misc:Depends} +XB-Maemo-CI-Packages: libqtm-messaging +XB-Maemo-CI-Stage: staging +Description: Qt Mobility Messaging autotest package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-contacts +Architecture: any +Section: libs +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Contacts module + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-contacts-dbg +Architecture: any +Section: libdevel +Depends: libqtm-contacts (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Contacts debugging symbols + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-contacts-dev +Architecture: any +Section: libs +Depends: libqtm-contacts (= ${binary:Version}), libqtm-common-dev (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Contacts development package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-contacts-tests +Architecture: any +Section: libs +Depends: ci-testing, ${shlibs:Depends}, ${misc:Depends} +XB-Maemo-CI-Packages: libqtm-contacts +XB-Maemo-CI-Stage: staging +Description: Qt Mobility Contacts autotest package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-versit +Architecture: any +Section: libs +Depends: libqtm-contacts (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Versit module + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-versit-dbg +Architecture: any +Section: libdevel +Depends: libqtm-versit (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Versit debugging symbols + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-versit-dev +Architecture: any +Section: libs +Depends: libqtm-versit (= ${binary:Version}), libqtm-contacts-dev (= ${binary:Version}), libqtm-common-dev (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Versit development package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-versit-tests +Architecture: any +Section: libs +Depends: ci-testing, ${shlibs:Depends}, ${misc:Depends} +XB-Maemo-CI-Packages: libqtm-versit +XB-Maemo-CI-Stage: staging +Description: Qt Mobility Versit autotest package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-organizer +Architecture: any +Section: libs +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Organizer module + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-organizer-dbg +Architecture: any +Section: libdevel +Depends: libqtm-organizer (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Organizer debugging symbols + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-organizer-dev +Architecture: any +Section: libs +Depends: libqtm-organizer (= ${binary:Version}), libqtm-common-dev (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Organizer development package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-organizer-tests +Architecture: any +Section: libs +Depends: ci-testing, ${shlibs:Depends}, ${misc:Depends} +XB-Maemo-CI-Packages: libqtm-organizer +XB-Maemo-CI-Stage: staging +Description: Qt Mobility Organizer autotest package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-versitorganizer +Architecture: any +Section: libs +Depends: libqtm-versit (= ${binary:Version}), libqtm-organizer (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Versit Organizer module + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-versitorganizer-dbg +Architecture: any +Section: libdevel +Depends: libqtm-versitorganizer (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Versit Organizer debugging symbols + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-versitorganizer-dev +Architecture: any +Section: libs +Depends: libqtm-versitorganizer (= ${binary:Version}), libqtm-common-dev (= ${binary:Version}), libqtm-versit-dev (= ${binary:Version}), + libqtm-organizer-dev (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Versit Organizer development package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +#Package: libqtm-versitorganizer-tests +#Architecture: any +#Section: libs +#Depends: ci-testing, ${shlibs:Depends} +#XB-Maemo-CI-Packages: libqtm-versitorganizer +#XB-Maemo-CI-Stage: staging +#Description: Qt Mobility Versit Organizer autotest package +# Qt Mobility Project delivers a set of new APIs to Qt with features that are +# well known from the mobile device world, in particular phones. However, +# these APIs allow the developer to use these features with ease from one +# framework and apply them to phones, netbooks and non-mobile personal +# computers. + +Package: libqtm-publishsubscribe +Architecture: any +Section: libs +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility PublishSubscribe module + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-publishsubscribe-dbg +Architecture: any +Section: libdevel +Depends: libqtm-publishsubscribe (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility PublishSubscribe debugging symbols + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-publishsubscribe-dev +Architecture: any +Section: libs +Depends: libqtm-publishsubscribe (= ${binary:Version}), libqtm-common-dev (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility PublishSubscribe development package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-publishsubscribe-tests +Architecture: any +Section: libs +Depends: ci-testing, ${shlibs:Depends}, ${misc:Depends} +XB-Maemo-CI-Packages: libqtm-publishsubscribe +XB-Maemo-CI-Stage: staging +Description: Qt Mobility PublishSubscribe autotest package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-location +Architecture: any +Section: libs +Depends: ${shlibs:Depends}, ${misc:Depends}, libqtsparql-tracker, tracker (>= 0.9.35) +Recommends: positioningd +Description: Qt Mobility Location module + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-location-dbg +Architecture: any +Section: libdevel +Depends: libqtm-location (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Location debugging symbols + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-location-dev +Architecture: any +Section: libs +Depends: libqtm-location (= ${binary:Version}), libqtm-common-dev (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Location development package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-location-tests +Architecture: any +Section: libs +Depends: ci-testing, ${shlibs:Depends}, ${misc:Depends} +XB-Maemo-CI-Packages: libqtm-location +XB-Maemo-CI-Stage: staging +Description: Qt Mobility Location autotest package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-sensors +Architecture: any +Section: libs +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Sensors module + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-sensors-dbg +Architecture: any +Section: libdevel +Depends: libqtm-sensors (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Sensors debugging symbols + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-sensors-dev +Architecture: any +Section: libs +Depends: libqtm-sensors (= ${binary:Version}), libqtm-common-dev (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Sensors development package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-sensors-tests +Architecture: any +Section: libs +Depends: ci-testing, ${shlibs:Depends}, ${misc:Depends} +XB-Maemo-CI-Packages: libqtm-sensors +XB-Maemo-CI-Stage: staging +Description: Qt Mobility Sensors autotest package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-systeminfo +Architecture: any +Section: libs +Depends: ${shlibs:Depends}, ${misc:Depends}, sysinfo-dbus +Description: Qt Mobility SystemInfo module + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-systeminfo-dbg +Architecture: any +Section: libdevel +Depends: libqtm-systeminfo (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility SystemInfo debugging symbols + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-systeminfo-dev +Architecture: any +Section: libs +Depends: libqtm-systeminfo (= ${binary:Version}), libqtm-common-dev (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility SystemInfo development package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-systeminfo-tests +Architecture: any +Section: libs +Depends: ci-testing, ${shlibs:Depends}, ${misc:Depends} +XB-Maemo-CI-Packages: libqtm-systeminfo +XB-Maemo-CI-Stage: staging +Description: Qt Mobility SystemInfo autotest package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-connectivity +Architecture: any +Section: libs +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Connectivity module + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-connectivity-dbg +Architecture: any +Section: libdevel +Depends: libqtm-connectivity (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Connectivity debugging symbols + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-connectivity-dev +Architecture: any +Section: libs +Depends: libqtm-connectivity (= ${binary:Version}), libqtm-common-dev (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Qt Mobility Connectivity development package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. + +Package: libqtm-connectivity-tests +Architecture: any +Section: libs +Depends: ci-testing, ${shlibs:Depends}, ${misc:Depends} +XB-Maemo-CI-Packages: libqtm-connectivity +XB-Maemo-CI-Stage: staging +Description: Qt Mobility Connectivity autotest package + Qt Mobility Project delivers a set of new APIs to Qt with features that are + well known from the mobile device world, in particular phones. However, + these APIs allow the developer to use these features with ease from one + framework and apply them to phones, netbooks and non-mobile personal + computers. diff --git a/src/harmattaninstalls/docs b/src/harmattaninstalls/docs new file mode 100644 index 000000000..11bffb5ba --- /dev/null +++ b/src/harmattaninstalls/docs @@ -0,0 +1,2 @@ +INSTALL.txt +LGPL_EXCEPTION.txt diff --git a/src/harmattaninstalls/libqtm-contacts-tests.aegis b/src/harmattaninstalls/libqtm-contacts-tests.aegis new file mode 100644 index 000000000..4f5fc8dca --- /dev/null +++ b/src/harmattaninstalls/libqtm-contacts-tests.aegis @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/harmattaninstalls/libqtm-doc.install b/src/harmattaninstalls/libqtm-doc.install new file mode 100644 index 000000000..a1c81d47c --- /dev/null +++ b/src/harmattaninstalls/libqtm-doc.install @@ -0,0 +1 @@ +usr/doc/html/* usr/share/qt4/QtMobility/doc/html diff --git a/src/harmattaninstalls/libqtm-examples.aegis b/src/harmattaninstalls/libqtm-examples.aegis new file mode 100644 index 000000000..21e8207d5 --- /dev/null +++ b/src/harmattaninstalls/libqtm-examples.aegis @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/harmattaninstalls/libqtm-examples.install b/src/harmattaninstalls/libqtm-examples.install new file mode 100644 index 000000000..dc9ddb19d --- /dev/null +++ b/src/harmattaninstalls/libqtm-examples.install @@ -0,0 +1,100 @@ +usr/lib/qt4/plugins/serviceframework/libserviceframework_bluetoothtransferplugin.so +usr/lib/qt4/plugins/serviceframework/libserviceframework_filemanagerplugin.so +usr/lib/qt4/plugins/serviceframework/libserviceframework_landlinedialerservice.so +usr/lib/qt4/plugins/serviceframework/libserviceframework_notesmanagerplugin.so +usr/lib/qt4/plugins/serviceframework/libserviceframework_voipdialerservice.so +usr/lib/qtmobility/demos/lightmaps_with_location +usr/lib/qtmobility/demos/nmealog.txt +usr/lib/qtmobility/demos/player +usr/lib/qtmobility/demos/qmlcontacts +usr/lib/qtmobility/demos/serviceactions +usr/lib/qtmobility/demos/smallsensors +usr/lib/qtmobility/demos/weatherinfo_with_location +usr/lib/qtmobility/examples/accel +usr/lib/qtmobility/examples/annotatedurl +usr/lib/qtmobility/examples/arrowkeys +usr/lib/qtmobility/examples/audiodevices +usr/lib/qtmobility/examples/audioinput +usr/lib/qtmobility/examples/audiooutput +usr/lib/qtmobility/examples/audiorecorder +usr/lib/qtmobility/examples/battery-publisher +usr/lib/qtmobility/examples/battery-subscriber/battery-subscriber.qml +usr/lib/qtmobility/examples/battery-subscriber/content/bubble.png +usr/lib/qtmobility/examples/btchat +usr/lib/qtmobility/examples/btfiletransfer +usr/lib/qtmobility/examples/btscanner +usr/lib/qtmobility/examples/bttennis +usr/lib/qtmobility/examples/calendardemo +usr/lib/qtmobility/examples/camera +usr/lib/qtmobility/examples/cubehouse +usr/lib/qtmobility/examples/declarative-music-browser +usr/lib/qtmobility/examples/dialer_service +usr/lib/qtmobility/examples/documentproperties +usr/lib/qtmobility/examples/flickrdemo +usr/lib/qtmobility/examples/grueapp +usr/lib/qtmobility/examples/hapticsplayer +usr/lib/qtmobility/examples/hapticsquare +usr/lib/qtmobility/examples/keepintouch +usr/lib/qtmobility/examples/landmarkbrowser +usr/lib/qtmobility/examples/logfilepositionsource +usr/lib/qtmobility/examples/mapsdemo +usr/lib/qtmobility/examples/mediabrowser +usr/lib/qtmobility/examples/metadata +usr/lib/qtmobility/examples/metadata2 +usr/lib/qtmobility/examples/moreplaces.lmx +usr/lib/qtmobility/examples/mylm.lmx +usr/lib/qtmobility/examples/ndefeditor +usr/lib/qtmobility/examples/nmealog.txt +usr/lib/qtmobility/examples/orientation +usr/lib/qtmobility/examples/places.gpx +usr/lib/qtmobility/examples/publish-subscribe +usr/lib/qtmobility/examples/qml_battery +usr/lib/qtmobility/examples/qml_battery2 +usr/lib/qtmobility/examples/qml_camera +usr/lib/qtmobility/examples/qml_device +usr/lib/qtmobility/examples/qmldialer +usr/lib/qtmobility/examples/qml_landmarkmap +usr/lib/qtmobility/examples/qml_location_flickr +usr/lib/qtmobility/examples/qml_mapviewer +usr/lib/qtmobility/examples/qml_networkinfo +usr/lib/qtmobility/examples/qmlnotes +usr/lib/qtmobility/examples/qmlorganizer +usr/lib/qtmobility/examples/qml_poster +usr/lib/qtmobility/examples/qml_scanner +usr/lib/qtmobility/examples/qml_storageinfo +usr/lib/qtmobility/examples/qml_tennis +usr/lib/qtmobility/examples/qsysinfo +usr/lib/qtmobility/examples/qsystemalignedtimer +usr/lib/qtmobility/examples/querymessages +usr/lib/qtmobility/examples/radio +usr/lib/qtmobility/examples/samplephonebook +usr/lib/qtmobility/examples/sensor_explorer +usr/lib/qtmobility/examples/servicebrowser +usr/lib/qtmobility/examples/sfwecho_client +usr/lib/qtmobility/examples/sfwecho_service +usr/lib/qtmobility/examples/sfw-notes +usr/lib/qtmobility/examples/show_acceleration +usr/lib/qtmobility/examples/show_als +usr/lib/qtmobility/examples/show_compass +usr/lib/qtmobility/examples/show_gyroscope +usr/lib/qtmobility/examples/show_light +usr/lib/qtmobility/examples/show_magneticflux +usr/lib/qtmobility/examples/show_orientation +usr/lib/qtmobility/examples/show_proximity +usr/lib/qtmobility/examples/show_reflectance +usr/lib/qtmobility/examples/show_rotation +usr/lib/qtmobility/examples/show_tap +usr/lib/qtmobility/examples/simplelog.txt +usr/lib/qtmobility/examples/slideshow +usr/lib/qtmobility/examples/todo +usr/lib/qtmobility/examples/videographicsitem +usr/lib/qtmobility/examples/videowidget +usr/lib/qtmobility/examples/writemessage +usr/lib/qtmobility/examples/xmldata/bluetoothtransferservice.xml +usr/lib/qtmobility/examples/xmldata/filemanagerservice.xml +usr/lib/qtmobility/examples/xmldata/landlinedialerservice.xml +usr/lib/qtmobility/examples/xmldata/notesmanagerservice.xml +usr/lib/qtmobility/examples/xmldata/remotedialerservice.xml +usr/lib/qtmobility/examples/xmldata/sfwechoservice.xml +usr/lib/qtmobility/examples/xmldata/voipdialerservice.xml +usr/lib/qtmobility/examples/qml_messages diff --git a/src/harmattaninstalls/libqtm-multimedia-dev.install b/src/harmattaninstalls/libqtm-multimedia-dev.install new file mode 100644 index 000000000..ec82185b5 --- /dev/null +++ b/src/harmattaninstalls/libqtm-multimedia-dev.install @@ -0,0 +1,145 @@ +usr/include/qt4/QtMultimediaKit/QAbstractAudioDeviceInfo +usr/include/qt4/QtMultimediaKit/QAbstractAudioInput +usr/include/qt4/QtMultimediaKit/QAbstractAudioOutput +usr/include/qt4/QtMultimediaKit/QAbstractVideoBuffer +usr/include/qt4/QtMultimediaKit/QAbstractVideoSurface +usr/include/qt4/QtMultimediaKit/QAudio +usr/include/qt4/QtMultimediaKit/QAudioCaptureSource +usr/include/qt4/QtMultimediaKit/QAudioDeviceInfo +usr/include/qt4/QtMultimediaKit/QAudioEncoderControl +usr/include/qt4/QtMultimediaKit/QAudioEncoderSettings +usr/include/qt4/QtMultimediaKit/QAudioEndpointSelector +usr/include/qt4/QtMultimediaKit/QAudioFormat +usr/include/qt4/QtMultimediaKit/QAudioInput +usr/include/qt4/QtMultimediaKit/QAudioOutput +usr/include/qt4/QtMultimediaKit/QAudioSystemPlugin +usr/include/qt4/QtMultimediaKit/QCamera +usr/include/qt4/QtMultimediaKit/QCameraControl +usr/include/qt4/QtMultimediaKit/QCameraExposure +usr/include/qt4/QtMultimediaKit/QCameraExposureControl +usr/include/qt4/QtMultimediaKit/QCameraFlashControl +usr/include/qt4/QtMultimediaKit/QCameraFocus +usr/include/qt4/QtMultimediaKit/QCameraFocusControl +usr/include/qt4/QtMultimediaKit/QCameraFocusZone +usr/include/qt4/QtMultimediaKit/QCameraImageCapture +usr/include/qt4/QtMultimediaKit/QCameraImageCaptureControl +usr/include/qt4/QtMultimediaKit/QCameraCaptureBufferFormatControl +usr/include/qt4/QtMultimediaKit/QCameraCaptureDestinationControl +usr/include/qt4/QtMultimediaKit/QCameraImageProcessing +usr/include/qt4/QtMultimediaKit/QCameraImageProcessingControl +usr/include/qt4/QtMultimediaKit/QCameraLocksControl +usr/include/qt4/QtMultimediaKit/QCameraViewfinder +usr/include/qt4/QtMultimediaKit/QGraphicsVideoItem +usr/include/qt4/QtMultimediaKit/QImageEncoderControl +usr/include/qt4/QtMultimediaKit/QImageEncoderSettings +usr/include/qt4/QtMultimediaKit/QLocalMediaPlaylistProvider +usr/include/qt4/QtMultimediaKit/QMediaBindableInterface +usr/include/qt4/QtMultimediaKit/QMediaContainerControl +usr/include/qt4/QtMultimediaKit/QMediaContent +usr/include/qt4/QtMultimediaKit/QMediaControl +usr/include/qt4/QtMultimediaKit/QMediaImageViewer +usr/include/qt4/QtMultimediaKit/QMediaNetworkAccessControl +usr/include/qt4/QtMultimediaKit/QMediaObject +usr/include/qt4/QtMultimediaKit/QMediaPlayer +usr/include/qt4/QtMultimediaKit/QMediaPlayerControl +usr/include/qt4/QtMultimediaKit/QMediaPlaylist +usr/include/qt4/QtMultimediaKit/QMediaPlaylistControl +usr/include/qt4/QtMultimediaKit/QMediaPlaylistIOPlugin +usr/include/qt4/QtMultimediaKit/QMediaPlaylistNavigator +usr/include/qt4/QtMultimediaKit/QMediaPlaylistProvider +usr/include/qt4/QtMultimediaKit/QMediaPlaylistReader +usr/include/qt4/QtMultimediaKit/QMediaPlaylistSourceControl +usr/include/qt4/QtMultimediaKit/QMediaPlaylistWriter +usr/include/qt4/QtMultimediaKit/QMediaRecorder +usr/include/qt4/QtMultimediaKit/QMediaRecorderControl +usr/include/qt4/QtMultimediaKit/QMediaResource +usr/include/qt4/QtMultimediaKit/QMediaService +usr/include/qt4/QtMultimediaKit/QMediaServiceProvider +usr/include/qt4/QtMultimediaKit/QMediaServiceProviderHint +usr/include/qt4/QtMultimediaKit/QMediaServiceProviderPlugin +usr/include/qt4/QtMultimediaKit/QMediaStreamsControl +usr/include/qt4/QtMultimediaKit/QMediaTimeInterval +usr/include/qt4/QtMultimediaKit/QMediaTimeRange +usr/include/qt4/QtMultimediaKit/QMetaDataReaderControl +usr/include/qt4/QtMultimediaKit/QMetaDataWriterControl +usr/include/qt4/QtMultimediaKit/QRadioTuner +usr/include/qt4/QtMultimediaKit/QRadioTunerControl +usr/include/qt4/QtMultimediaKit/QVideoDeviceControl +usr/include/qt4/QtMultimediaKit/QVideoEncoderControl +usr/include/qt4/QtMultimediaKit/QVideoEncoderSettings +usr/include/qt4/QtMultimediaKit/QVideoFrame +usr/include/qt4/QtMultimediaKit/QVideoRendererControl +usr/include/qt4/QtMultimediaKit/QVideoSurfaceFormat +usr/include/qt4/QtMultimediaKit/QVideoWidget +usr/include/qt4/QtMultimediaKit/QVideoWidgetControl +usr/include/qt4/QtMultimediaKit/QVideoWindowControl +usr/include/qt4/QtMultimediaKit/qabstractvideobuffer.h +usr/include/qt4/QtMultimediaKit/qabstractvideosurface.h +usr/include/qt4/QtMultimediaKit/qaudio.h +usr/include/qt4/QtMultimediaKit/qaudiocapturesource.h +usr/include/qt4/QtMultimediaKit/qaudiodeviceinfo.h +usr/include/qt4/QtMultimediaKit/qaudioencodercontrol.h +usr/include/qt4/QtMultimediaKit/qaudioendpointselector.h +usr/include/qt4/QtMultimediaKit/qaudioformat.h +usr/include/qt4/QtMultimediaKit/qaudioinput.h +usr/include/qt4/QtMultimediaKit/qaudiooutput.h +usr/include/qt4/QtMultimediaKit/qaudiosystem.h +usr/include/qt4/QtMultimediaKit/qaudiosystemplugin.h +usr/include/qt4/QtMultimediaKit/qcamera.h +usr/include/qt4/QtMultimediaKit/qcameracontrol.h +usr/include/qt4/QtMultimediaKit/qcameraexposure.h +usr/include/qt4/QtMultimediaKit/qcameraexposurecontrol.h +usr/include/qt4/QtMultimediaKit/qcameraflashcontrol.h +usr/include/qt4/QtMultimediaKit/qcamerafocus.h +usr/include/qt4/QtMultimediaKit/qcamerafocuscontrol.h +usr/include/qt4/QtMultimediaKit/qcameraimagecapture.h +usr/include/qt4/QtMultimediaKit/qcameraimagecapturecontrol.h +usr/include/qt4/QtMultimediaKit/qcameracapturedestinationcontrol.h +usr/include/qt4/QtMultimediaKit/qcameracapturebufferformatcontrol.h +usr/include/qt4/QtMultimediaKit/qcameraimageprocessing.h +usr/include/qt4/QtMultimediaKit/qcameraimageprocessingcontrol.h +usr/include/qt4/QtMultimediaKit/qcameralockscontrol.h +usr/include/qt4/QtMultimediaKit/qcameraviewfinder.h +usr/include/qt4/QtMultimediaKit/qgraphicsvideoitem.h +usr/include/qt4/QtMultimediaKit/qimageencodercontrol.h +usr/include/qt4/QtMultimediaKit/qlocalmediaplaylistprovider.h +usr/include/qt4/QtMultimediaKit/qmediabindableinterface.h +usr/include/qt4/QtMultimediaKit/qmediacontainercontrol.h +usr/include/qt4/QtMultimediaKit/qmediacontent.h +usr/include/qt4/QtMultimediaKit/qmediacontrol.h +usr/include/qt4/QtMultimediaKit/qmediaencodersettings.h +usr/include/qt4/QtMultimediaKit/qmediaenumdebug.h +usr/include/qt4/QtMultimediaKit/qmediaimageviewer.h +usr/include/qt4/QtMultimediaKit/qmedianetworkaccesscontrol.h +usr/include/qt4/QtMultimediaKit/qmediaobject.h +usr/include/qt4/QtMultimediaKit/qmediaplayer.h +usr/include/qt4/QtMultimediaKit/qmediaplayercontrol.h +usr/include/qt4/QtMultimediaKit/qmediaplaylist.h +usr/include/qt4/QtMultimediaKit/qmediaplaylistcontrol.h +usr/include/qt4/QtMultimediaKit/qmediaplaylistioplugin.h +usr/include/qt4/QtMultimediaKit/qmediaplaylistnavigator.h +usr/include/qt4/QtMultimediaKit/qmediaplaylistprovider.h +usr/include/qt4/QtMultimediaKit/qmediaplaylistsourcecontrol.h +usr/include/qt4/QtMultimediaKit/qmediarecorder.h +usr/include/qt4/QtMultimediaKit/qmediarecordercontrol.h +usr/include/qt4/QtMultimediaKit/qmediaresource.h +usr/include/qt4/QtMultimediaKit/qmediaservice.h +usr/include/qt4/QtMultimediaKit/qmediaserviceprovider.h +usr/include/qt4/QtMultimediaKit/qmediaserviceproviderplugin.h +usr/include/qt4/QtMultimediaKit/qmediastreamscontrol.h +usr/include/qt4/QtMultimediaKit/qmediatimerange.h +usr/include/qt4/QtMultimediaKit/qmetadatareadercontrol.h +usr/include/qt4/QtMultimediaKit/qmetadatawritercontrol.h +usr/include/qt4/QtMultimediaKit/qradiotuner.h +usr/include/qt4/QtMultimediaKit/qradiotunercontrol.h +usr/include/qt4/QtMultimediaKit/qtmedianamespace.h +usr/include/qt4/QtMultimediaKit/qvideodevicecontrol.h +usr/include/qt4/QtMultimediaKit/qvideoencodercontrol.h +usr/include/qt4/QtMultimediaKit/qvideoframe.h +usr/include/qt4/QtMultimediaKit/qvideorenderercontrol.h +usr/include/qt4/QtMultimediaKit/qvideosurfaceformat.h +usr/include/qt4/QtMultimediaKit/qvideowidget.h +usr/include/qt4/QtMultimediaKit/qvideowidgetcontrol.h +usr/include/qt4/QtMultimediaKit/qvideowindowcontrol.h +usr/lib/libQtMultimediaKit.so +usr/lib/pkgconfig/QtMultimediaKit.pc diff --git a/src/harmattaninstalls/libqtm-multimedia-tests.install b/src/harmattaninstalls/libqtm-multimedia-tests.install new file mode 100644 index 000000000..966d6e7db --- /dev/null +++ b/src/harmattaninstalls/libqtm-multimedia-tests.install @@ -0,0 +1,32 @@ +usr/tests/qtm/tst_qmediaresource +usr/tests/qtm/tst_qmediatimerange +usr/tests/qtm/tst_qaudiooutput +usr/tests/qtm/tst_qabstractvideosurface +usr/tests/qtm/tst_qmediaimageviewer +usr/tests/qtm/tst_qcamera +usr/tests/qtm/tst_qmediaplayerbackend +usr/tests/qtm/tst_qvideoframe +usr/tests/qtm/tst_qabstractvideobuffer +usr/tests/qtm/tst_qdeclarativevideo +usr/tests/qtm/tst_qmediapluginloader +usr/tests/qtm/tst_qmediaplaylist +usr/tests/qtm/tst_qaudiocapturesource +usr/tests/qtm/tst_qmediarecorder +usr/tests/qtm/tst_qmediaserviceprovider +usr/tests/qtm/tst_qvideowidget +usr/tests/qtm/tst_qaudioinput +usr/tests/qtm/tst_qmediacontent +usr/tests/qtm/tst_qmediaplayer +usr/tests/qtm/tst_qpaintervideosurface +usr/tests/qtm/tst_qmediaplaylistnavigator +usr/tests/qtm/tst_qradiotuner +usr/tests/qtm/tst_qaudioformat +usr/tests/qtm/tst_qmediaservice +usr/tests/qtm/tst_qaudiodeviceinfo +usr/tests/qtm/tst_qsoundeffect +usr/tests/qtm/tst_qvideosurfaceformat +usr/tests/qtm/tst_qgraphicsvideoitem +usr/tests/qtm/tst_qdeclarativeaudio +usr/tests/qtm/tst_qmediaobject +usr/tests/qtm/tst_qcamerabackend +usr/share/libqtm-multimedia-tests/tests.xml diff --git a/src/harmattaninstalls/libqtm-multimedia.install b/src/harmattaninstalls/libqtm-multimedia.install new file mode 100644 index 000000000..b8a1fb7c6 --- /dev/null +++ b/src/harmattaninstalls/libqtm-multimedia.install @@ -0,0 +1,8 @@ +usr/lib/libQtMultimediaKit.so.1.2.0 +usr/lib/libQtMultimediaKit.so.1.2 +usr/lib/libQtMultimediaKit.so.1 +usr/lib/qt4/imports/QtMultimediaKit/libdeclarative_multimedia.so +usr/lib/qt4/imports/QtMultimediaKit/qmldir +usr/lib/qt4/plugins/audio/libqtmedia_pulse.so +usr/lib/qt4/plugins/mediaservice/libqgstengine.so +usr/lib/qt4/plugins/playlistformats/libqtmultimediakit_m3u.so diff --git a/src/harmattaninstalls/libqtm-systeminfo-tests.aegis b/src/harmattaninstalls/libqtm-systeminfo-tests.aegis new file mode 100644 index 000000000..599c7818b --- /dev/null +++ b/src/harmattaninstalls/libqtm-systeminfo-tests.aegis @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/harmattaninstalls/patches/series b/src/harmattaninstalls/patches/series new file mode 100644 index 000000000..e69de29bb diff --git a/src/harmattaninstalls/rules b/src/harmattaninstalls/rules new file mode 100755 index 000000000..75c2f13fe --- /dev/null +++ b/src/harmattaninstalls/rules @@ -0,0 +1,110 @@ +#!/usr/bin/make -f + +#export DH_VERBOSE=1 +# set MOBILITY_ENABLE_STATIC_CONFIG to 0 to disable using staticconfig in configure +MOBILITY_ENABLE_STATIC_CONFIG=1 + + +include /usr/share/cdbs/1/rules/debhelper.mk +include /usr/share/cdbs/1/rules/utils.mk +include /usr/share/cdbs/1/rules/patchsys-quilt.mk +include /usr/share/cdbs/1/class/autotools.mk + +# Find out how many parallel threads to run +TMP_BUILD_OPTS = $(subst $(comma),$(space),$(DEB_BUILD_OPTIONS)) +ifneq (,$(filter parallel=%,$(TMP_BUILD_OPTS))) + NUMJOBS = $(patsubst parallel=%,%,$(filter parallel=%,$(TMP_BUILD_OPTS))) + PARALLEL_MAKEFLAGS += -j$(NUMJOBS) +endif + +DEB_MAKE_INVOKE := $(MAKE) $(PARALLEL_MAKEFLAGS) +DEB_MAKE_INSTALL_TARGET := INSTALL_ROOT=$(DEB_DESTDIR) install +DEB_DH_INSTALL_SOURCEDIR := debian/tmp +# DEB_DH_INSTALL_ARGS ensures that the build breaks if a file installed +# to DEB_DH_INSTALL_SOURCEDIR is not listed in any of the libqtm*.install files +# except the *.prl files (-X.prl) +DEB_DH_INSTALL_ARGS := --fail-missing -X.prl + +# bearer location contacts multimedia publishsubscribe versit messaging systeminfo serviceframework sensors gallery organizer feedback connectivity +QTM_MODULES += connectivity +QTM_MODULES += contacts +QTM_MODULES += feedback +QTM_MODULES += gallery +QTM_MODULES += location +QTM_MODULES += messaging +QTM_MODULES += multimedia +QTM_MODULES += organizer +QTM_MODULES += publishsubscribe +QTM_MODULES += sensors +QTM_MODULES += serviceframework +QTM_MODULES += systeminfo +QTM_MODULES += versit + +# Add here any variable or target overrides you need. +# Arguments to configure +DEB_CONFIGURE_NORMAL_ARGS := -maemo6 -prefix /usr -headerdir /usr/include/qt4 \ + -plugindir /usr/lib/qt4/plugins -modules "$(QTM_MODULES)" \ + -examples -examplesdir /usr/lib/qtmobility/examples \ + -demos -demosdir /usr/lib/qtmobility/demos \ + -silent -release -tests + +# enable static config if set +ifeq ($(MOBILITY_ENABLE_STATIC_CONFIG),1) + TARGET_BUILD=x86 + ifeq ($(DEB_HOST_ARCH),arm) + TARGET_BUILD=arm + endif + ifeq ($(DEB_HOST_ARCH),armel) + TARGET_BUILD=arm + endif + DEB_CONFIGURE_EXTRA_FLAGS := -staticconfig harmattan_$(TARGET_BUILD) +endif + +common-install-arch:: install-autotests + +#List of auto tests +QTM_MAEMO_TESTDIR := debian/tests + +QTM_AUTOTESTS_SIMPLE := debian/libqtm-connectivity-tests.install \ + debian/libqtm-contacts-tests.install \ + debian/libqtm-feedback-tests.install \ + debian/libqtm-gallery-tests.install \ + debian/libqtm-location-tests.install \ + debian/libqtm-messaging-tests.install \ + debian/libqtm-multimedia-tests.install \ + debian/libqtm-organizer-tests.install \ + debian/libqtm-publishsubscribe-tests.install \ + debian/libqtm-sensors-tests.install \ + debian/libqtm-serviceframework-tests.install \ + debian/libqtm-systeminfo-tests.install \ + debian/libqtm-versit-tests.install + + +export QTM_TEST_INSTALL_FILE=$(CURDIR)/debian/pkg.install + +#installation +install-autotests: + $(DEB_MAKE_INVOKE) -C tests INSTALL_ROOT=$(DEB_DESTDIR) installtests + $(QTM_MAEMO_TESTDIR)/install_tests -d debian -t $(QTM_MAEMO_TESTDIR) \ + -i $(DEB_DESTDIR) -c -xml $(QTM_AUTOTESTS_SIMPLE) + +PACKAGE_TARGETS := $(foreach pkg,$(DEB_ALL_PACKAGES),binary/$(pkg)) + +$(PACKAGE_TARGETS):: + [ ! -f debian/$(notdir $@).aegis ] || aegis-deb-add -control debian/$(notdir $@)/DEBIAN/control .. debian/$(notdir $@).aegis=_aegis + +clean:: + find \( -false \ + -o -type f -name mobility*.prf \ + \) -delete + rm -rf include build lib patches + # Delete the config tests and + rm -f \ + config.tests/maemo-icd-network-wlan/maemo-icd-network-wlan \ + config.tests/maemo-icd/maemo-icd \ + config.tests/sensord/sensord \ + config.tests/gstreamer-photography/gstreamer-photography \ + config.tests/immersion/immersion \ + config.tests/maemo6-landmarks/maemo6-landmarks \ + config.tests/pulseaudio/pulseaudio + diff --git a/src/harmattaninstalls/tests/install_tests b/src/harmattaninstalls/tests/install_tests new file mode 100755 index 000000000..05fbc232b --- /dev/null +++ b/src/harmattaninstalls/tests/install_tests @@ -0,0 +1,201 @@ +#!/bin/sh + +############################################################################# +## +## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +## All rights reserved. +## Contact: Nokia Corporation (qt-info@nokia.com) +## +## This file is the build configuration utility of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:LGPL$ +## GNU Lesser General Public License Usage +## This file may be used under the terms of the GNU Lesser General Public +## License version 2.1 as published by the Free Software Foundation and +## appearing in the file LICENSE.LGPL included in the packaging of this +## file. Please review the following information to ensure the GNU Lesser +## General Public License version 2.1 requirements will be met: +## http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +## +## In addition, as a special exception, Nokia gives you certain additional +## rights. These rights are described in the Nokia Qt LGPL Exception +## version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU General +## Public License version 3.0 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 3.0 requirements will be met: +## http://www.gnu.org/copyleft/gpl.html. +## +## Other Usage +## Alternatively, this file may be used in accordance with the terms and +## conditions contained in a signed written agreement between you and Nokia. +## +## +## +## +## +## $QT_END_LICENSE$ +## +############################################################################# + + +set -e + +#------------------------------------------------------------------------------- +#Design assumptions: +## The name of the test application binary is tst_ +## The name of the project file passed to the scrpt is . +## The extension string is not relevant. Typical values: .pri, .pro, .conf +#------------------------------------------------------------------------------- + + +xmlInstallDir="usr/share" + +testSuiteHeader="testsuite_header.txt" +testSuiteFooter="testsuite_footer.txt" +testSetTemplate="testset.txt" + +#------------------------------------------------------------------------------- +#Parameters: $1 the project file where the tests are defined +#------------------------------------------------------------------------------- +install_tests() +{ + #derive the package name from the file name + extension=".$(echo $1 | awk -F"." '{print $NF}')" + packageName=$(basename "$1" "$extension") + installFile="$packageDir/${packageName}.install" + + mkdir -p $installDir/$xmlInstallDir/$packageName + xmlFile="$installDir/$xmlInstallDir/$packageName/tests.xml" + + begin_test_suite $xmlFile + + # only run applications, not test data or plugins (which will have a '.' in the name) + grep -v -F . "$installFile" | while read testApp; do + add_test_set "$testApp" "$xmlFile" + done + + end_test_suite $xmlFile +} + +#------------------------------------------------------------------------------- +#Parameters: $1 the xml output file' +#------------------------------------------------------------------------------- +begin_test_suite() +{ + optstr="/ "$1" +} + +#Parameters: $1 the xml output file +end_test_suite() +{ + cat "$templateDir/$testSuiteFooter" >> "$1" +} + +#------------------------------------------------------------------------------- +#Parameters: $1 the name of the test application +#Parameters: $2 the xml output file +#------------------------------------------------------------------------------- +add_test_set() +{ + templateSetFile="$templateDir/$testSetTemplate" + testSuiteName=$(basename $1) + insignificantTest="false" + # *.insignificant_test files indicate that the test should be marked as insignificant - run but not counted + if [ -e "$installDir/$1.insignificant_test" ]; then + insignificantTest="true" + rm "$installDir/$1.insignificant_test" + fi + # *.manual_test files indicate that the test is not to be run in CITA + if [ ! -e "$installDir/$1.manual_test" ]; then + add_set_name "$testSuiteName" "$templateSetFile" |add_description "$testSuiteName" |add_case_name "$testSuiteName" |add_insignificant_test "$insignificantTest" | add_step "$1" >> "$2" + else + rm "$installDir/$1.manual_test" + fi +} + +add_set_name() +{ + optstr="/&2 + exit 1 +fi + +while [ $# -gt 0 ]; do + case "$1" in + -t) templateDir=$(cd "$2"; pwd) + shift + ;; + -d) packageDir=$(cd "$2"; pwd) + shift + ;; + -i) installDir=$(cd "$2"; pwd) + shift + ;; + -c) testCliOptions="$2" + shift + ;; + *) projFileList="$projFileList $1";; + esac + shift +done + +if [ -z "$templateDir" ]|| [ -z "$packageDir" ] || [ -z "$installDir" ]; then + echo "$usage" 1>&2 + exit 1 +fi + +for projFile in $projFileList; do + install_tests $projFile +done diff --git a/src/harmattaninstalls/tests/testset.txt b/src/harmattaninstalls/tests/testset.txt new file mode 100644 index 000000000..e741a4d25 --- /dev/null +++ b/src/harmattaninstalls/tests/testset.txt @@ -0,0 +1,11 @@ + + ##Package-name:test_name## + + ##Package-name:test_name## + /usr/tests/qtm/tst_foo + + + true + true + + diff --git a/src/harmattaninstalls/tests/testsuite_footer.txt b/src/harmattaninstalls/tests/testsuite_footer.txt new file mode 100644 index 000000000..8c71c93a4 --- /dev/null +++ b/src/harmattaninstalls/tests/testsuite_footer.txt @@ -0,0 +1,2 @@ + + diff --git a/src/harmattaninstalls/tests/testsuite_header.txt b/src/harmattaninstalls/tests/testsuite_header.txt new file mode 100644 index 000000000..4c57f766d --- /dev/null +++ b/src/harmattaninstalls/tests/testsuite_header.txt @@ -0,0 +1,4 @@ + + + + diff --git a/src/imports/imports.pro b/src/imports/imports.pro new file mode 100644 index 000000000..669064baa --- /dev/null +++ b/src/imports/imports.pro @@ -0,0 +1,5 @@ + +TEMPLATE = subdirs + +SUBDIRS += multimedia + diff --git a/src/imports/multimedia/multimedia.cpp b/src/imports/multimedia/multimedia.cpp new file mode 100644 index 000000000..59137390b --- /dev/null +++ b/src/imports/multimedia/multimedia.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include "private/qsoundeffect_p.h" + +#include "qdeclarativevideo_p.h" +#include "qdeclarativeaudio_p.h" +#include "qdeclarativemediametadata_p.h" +#include "qdeclarativecamera_p.h" +#include "qdeclarativecamerapreviewprovider_p.h" + +QML_DECLARE_TYPE(QSoundEffect) + +QT_BEGIN_NAMESPACE + +class QMultimediaDeclarativeModule : public QDeclarativeExtensionPlugin +{ + Q_OBJECT +public: + virtual void registerTypes(const char *uri) + { + Q_ASSERT(QLatin1String(uri) == QLatin1String("QtMultimediaKit")); + + qmlRegisterType(uri, 1, 1, "SoundEffect"); + qmlRegisterType(uri, 1, 1, "Audio"); + qmlRegisterType(uri, 1, 1, "Video"); + qmlRegisterType(uri, 1, 1, "Camera"); + qmlRegisterType(); + } + + void initializeEngine(QDeclarativeEngine *engine, const char *uri) + { + Q_UNUSED(uri); + engine->addImageProvider("camera", new QDeclarativeCameraPreviewProvider); + } +}; + +QT_END_NAMESPACE + +#include "multimedia.moc" + +Q_EXPORT_PLUGIN2(qmultimediadeclarativemodule, QT_PREPEND_NAMESPACE(QMultimediaDeclarativeModule)); + diff --git a/src/imports/multimedia/multimedia.pro b/src/imports/multimedia/multimedia.pro new file mode 100644 index 000000000..c3874d3ba --- /dev/null +++ b/src/imports/multimedia/multimedia.pro @@ -0,0 +1,41 @@ +TARGET = declarative_multimedia +TARGETPATH = Qt/multimediakit + +include(../qimportbase.pri) + +QT += declarative network multimediakit-private + +DESTDIR = $$QT.multimediakit.imports/$$TARGETPATH +target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH + +HEADERS += \ + qdeclarativeaudio_p.h \ + qdeclarativemediabase_p.h \ + qdeclarativemediametadata_p.h \ + qdeclarativevideo_p.h \ + qdeclarativecamera_p.h \ + qdeclarativecamerapreviewprovider_p.h + +SOURCES += \ + multimedia.cpp \ + qdeclarativeaudio.cpp \ + qdeclarativemediabase.cpp \ + qdeclarativevideo.cpp \ + qdeclarativecamera.cpp \ + qdeclarativecamerapreviewprovider.cpp + +qmldir.files += $$PWD/qmldir +qmldir.path += $$[QT_INSTALL_IMPORTS]/$$TARGETPATH + +INSTALLS += target qmldir + +symbian { + # In Symbian, a library should enjoy _largest_ possible capability set. + TARGET.CAPABILITY = ALL -TCB + TARGET.UID3 = 0x20021313 + TARGET.EPOCALLOWDLLDATA=1 + # Specifies what files shall be deployed: the plugin itself and the qmldir file. + importFiles.sources = $$DESTDIR/declarative_multimedia$${QT_LIBINFIX}.dll qmldir + importFiles.path = $$QT_IMPORTS_BASE_DIR/$$TARGETPATH + DEPLOYMENT = importFiles +} diff --git a/src/imports/multimedia/qdeclarativeaudio.cpp b/src/imports/multimedia/qdeclarativeaudio.cpp new file mode 100644 index 000000000..6ba8b39de --- /dev/null +++ b/src/imports/multimedia/qdeclarativeaudio.cpp @@ -0,0 +1,698 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativeaudio_p.h" + +#include + +QT_BEGIN_NAMESPACE + + +/*! + \qmlclass Audio QDeclarativeAudio + \brief The Audio element allows you to add audio playback to a scene. + + \ingroup qml-multimedia + + This element is part of the \bold{QtMultimediaKit 1.1} module. + + \qml + import Qt 4.7 + import QtMultimediaKit 1.1 + + Text { + text: "Click Me!"; + font.pointSize: 24; + width: 150; height: 50; + + Audio { + id: playMusic + source: "music.wav" + } + MouseArea { + id: playArea + anchors.fill: parent + onPressed: { playMusic.play() } + } + } + \endqml + + \sa Video +*/ + +/*! + \internal + \class QDeclarativeAudio + \brief The QDeclarativeAudio class provides an audio item that you can add to a QDeclarativeView. +*/ + +void QDeclarativeAudio::_q_error(int errorCode, const QString &errorString) +{ + m_error = QMediaPlayer::Error(errorCode); + m_errorString = errorString; + + emit error(Error(errorCode), errorString); + emit errorChanged(); +} + + +QDeclarativeAudio::QDeclarativeAudio(QObject *parent) + : QObject(parent) +{ +} + +QDeclarativeAudio::~QDeclarativeAudio() +{ + shutdown(); +} + +/*! + \qmlmethod Audio::play() + + Starts playback of the media. + + Sets the \l playing property to true, and the \l paused property to false. +*/ + +void QDeclarativeAudio::play() +{ + if (!m_complete) + return; + + setPaused(false); + setPlaying(true); +} + +/*! + \qmlmethod Audio::pause() + + Pauses playback of the media. + + Sets the \l playing and \l paused properties to true. +*/ + +void QDeclarativeAudio::pause() +{ + if (!m_complete) + return; + + setPaused(true); + setPlaying(true); +} + +/*! + \qmlmethod Audio::stop() + + Stops playback of the media. + + Sets the \l playing and \l paused properties to false. +*/ + +void QDeclarativeAudio::stop() +{ + if (!m_complete) + return; + + setPlaying(false); + setPaused(false); +} + +/*! + \qmlproperty url Audio::source + + This property holds the source URL of the media. +*/ + +/*! + \qmlproperty url Audio::autoLoad + + This property indicates if loading of media should begin immediately. + + Defaults to true, if false media will not be loaded until playback is started. +*/ + +/*! + \qmlproperty bool Audio::playing + + This property holds whether the media is playing. + + Defaults to false, and can be set to true to start playback. +*/ + +/*! + \qmlproperty bool Audio::paused + + This property holds whether the media is paused. + + Defaults to false, and can be set to true to pause playback. +*/ + +/*! + \qmlsignal Audio::onStarted() + + This handler is called when playback is started. +*/ + +/*! + \qmlsignal Audio::onResumed() + + This handler is called when playback is resumed from the paused state. +*/ + +/*! + \qmlsignal Audio::onPaused() + + This handler is called when playback is paused. +*/ + +/*! + \qmlsignal Audio::onStopped() + + This handler is called when playback is stopped. +*/ + +/*! + \qmlproperty enumeration Audio::status + + This property holds the status of media loading. It can be one of: + + \list + \o NoMedia - no media has been set. + \o Loading - the media is currently being loaded. + \o Loaded - the media has been loaded. + \o Buffering - the media is buffering data. + \o Stalled - playback has been interrupted while the media is buffering data. + \o Buffered - the media has buffered data. + \o EndOfMedia - the media has played to the end. + \o InvalidMedia - the media cannot be played. + \o UnknownStatus - the status of the media is unknown. + \endlist +*/ + +QDeclarativeAudio::Status QDeclarativeAudio::status() const +{ + return Status(m_status); +} + +/*! + \qmlproperty int Audio::duration + + This property holds the duration of the media in milliseconds. + + If the media doesn't have a fixed duration (a live stream for example) this will be 0. +*/ + +/*! + \qmlproperty int Audio::position + + This property holds the current playback position in milliseconds. + + If the \l seekable property is true, this property can be set to seek to a new position. +*/ + +/*! + \qmlproperty real Audio::volume + + This property holds the volume of the audio output, from 0.0 (silent) to 1.0 (maximum volume). +*/ + +/*! + \qmlproperty bool Audio::muted + + This property holds whether the audio output is muted. +*/ + +/*! + \qmlproperty real Audio::bufferProgress + + This property holds how much of the data buffer is currently filled, from 0.0 (empty) to 1.0 + (full). +*/ + +/*! + \qmlproperty bool Audio::seekable + + This property holds whether position of the audio can be changed. + + If true; setting a \l position value will cause playback to seek to the new position. +*/ + +/*! + \qmlproperty real Audio::playbackRate + + This property holds the rate at which audio is played at as a multiple of the normal rate. +*/ + +/*! + \qmlproperty enumeration Audio::error + + This property holds the error state of the audio. It can be one of: + + \list + \o NoError - there is no current error. + \o ResourceError - the audio cannot be played due to a problem allocating resources. + \o FormatError - the audio format is not supported. + \o NetworkError - the audio cannot be played due to network issues. + \o AccessDenied - the audio cannot be played due to insufficient permissions. + \o ServiceMissing - the audio cannot be played because the media service could not be + instantiated. + \endlist +*/ + +QDeclarativeAudio::Error QDeclarativeAudio::error() const +{ + return Error(m_error); +} + +void QDeclarativeAudio::classBegin() +{ + setObject(this); +} + +void QDeclarativeAudio::componentComplete() +{ + QDeclarativeMediaBase::componentComplete(); +} + + +/*! + \qmlproperty string Audio::errorString + + This property holds a string describing the current error condition in more detail. +*/ + +/*! + \qmlsignal Audio::onError(error, errorString) + + This handler is called when an \l {QMediaPlayer::Error}{error} has + occurred. The errorString parameter may contain more detailed + information about the error. +*/ + +/*! + \qmlproperty variant Audio::metaData.title + + This property holds the tile of the media. + + \sa {QtMultimediaKit::Title} +*/ + +/*! + \qmlproperty variant Audio::metaData.subTitle + + This property holds the sub-title of the media. + + \sa {QtMultimediaKit::SubTitle} +*/ + +/*! + \qmlproperty variant Audio::metaData.author + + This property holds the author of the media. + + \sa {QtMultimediaKit::Author} +*/ + +/*! + \qmlproperty variant Audio::metaData.comment + + This property holds a user comment about the media. + + \sa {QtMultimediaKit::Comment} +*/ + +/*! + \qmlproperty variant Audio::metaData.description + + This property holds a description of the media. + + \sa {QtMultimediaKit::Description} +*/ + +/*! + \qmlproperty variant Audio::metaData.category + + This property holds the category of the media + + \sa {QtMultimediaKit::Category} +*/ + +/*! + \qmlproperty variant Audio::metaData.genre + + This property holds the genre of the media. + + \sa {QtMultimediaKit::Genre} +*/ + +/*! + \qmlproperty variant Audio::metaData.year + + This property holds the year of release of the media. + + \sa {QtMultimediaKit::Year} +*/ + +/*! + \qmlproperty variant Audio::metaData.date + + This property holds the date of the media. + + \sa {QtMultimediaKit::Date} +*/ + +/*! + \qmlproperty variant Audio::metaData.userRating + + This property holds a user rating of the media in the range of 0 to 100. + + \sa {QtMultimediaKit::UserRating} +*/ + +/*! + \qmlproperty variant Audio::metaData.keywords + + This property holds a list of keywords describing the media. + + \sa {QtMultimediaKit::Keywords} +*/ + +/*! + \qmlproperty variant Audio::metaData.language + + This property holds the language of the media, as an ISO 639-2 code. + + \sa {QtMultimediaKit::Language} +*/ + +/*! + \qmlproperty variant Audio::metaData.publisher + + This property holds the publisher of the media. + + \sa {QtMultimediaKit::Publisher} +*/ + +/*! + \qmlproperty variant Audio::metaData.copyright + + This property holds the media's copyright notice. + + \sa {QtMultimediaKit::Copyright} +*/ + +/*! + \qmlproperty variant Audio::metaData.parentalRating + + This property holds the parental rating of the media. + + \sa {QtMultimediaKit::ParentalRating} +*/ + +/*! + \qmlproperty variant Audio::metaData.ratingOrganisation + + This property holds the name of the rating organisation responsible for the + parental rating of the media. + + \sa {QtMultimediaKit::RatingOrganisation} +*/ + +/*! + \qmlproperty variant Audio::metaData.size + + This property property holds the size of the media in bytes. + + \sa {QtMultimediaKit::Size} +*/ + +/*! + \qmlproperty variant Audio::metaData.mediaType + + This property holds the type of the media. + + \sa {QtMultimediaKit::MediaType} +*/ + +/*! + \qmlproperty variant Audio::metaData.audioBitRate + + This property holds the bit rate of the media's audio stream ni bits per + second. + + \sa {QtMultimediaKit::AudioBitRate} +*/ + +/*! + \qmlproperty variant Audio::metaData.audioCodec + + This property holds the encoding of the media audio stream. + + \sa {QtMultimediaKit::AudioCodec} +*/ + +/*! + \qmlproperty variant Audio::metaData.averageLevel + + This property holds the average volume level of the media. + + \sa {QtMultimediaKit::AverageLevel} +*/ + +/*! + \qmlproperty variant Audio::metaData.channelCount + + This property holds the number of channels in the media's audio stream. + + \sa {QtMultimediaKit::ChannelCount} +*/ + +/*! + \qmlproperty variant Audio::metaData.peakValue + + This property holds the peak volume of media's audio stream. + + \sa {QtMultimediaKit::PeakValue} +*/ + +/*! + \qmlproperty variant Audio::metaData.sampleRate + + This property holds the sample rate of the media's audio stream in hertz. + + \sa {QtMultimediaKit::SampleRate} +*/ + +/*! + \qmlproperty variant Audio::metaData.albumTitle + + This property holds the title of the album the media belongs to. + + \sa {QtMultimediaKit::AlbumTitle} +*/ + +/*! + \qmlproperty variant Audio::metaData.albumArtist + + This property holds the name of the principal artist of the album the media + belongs to. + + \sa {QtMultimediaKit::AlbumArtist} +*/ + +/*! + \qmlproperty variant Audio::metaData.contributingArtist + + This property holds the names of artists contributing to the media. + + \sa {QtMultimediaKit::ContributingArtist} +*/ + +/*! + \qmlproperty variant Audio::metaData.composer + + This property holds the composer of the media. + + \sa {QtMultimediaKit::Composer} +*/ + +/*! + \qmlproperty variant Audio::metaData.conductor + + This property holds the conductor of the media. + + \sa {QtMultimediaKit::Conductor} +*/ + +/*! + \qmlproperty variant Audio::metaData.lyrics + + This property holds the lyrics to the media. + + \sa {QtMultimediaKit::Lyrics} +*/ + +/*! + \qmlproperty variant Audio::metaData.mood + + This property holds the mood of the media. + + \sa {QtMultimediaKit::Mood} +*/ + +/*! + \qmlproperty variant Audio::metaData.trackNumber + + This property holds the track number of the media. + + \sa {QtMultimediaKit::TrackNumber} +*/ + +/*! + \qmlproperty variant Audio::metaData.trackCount + + This property holds the number of track on the album containing the media. + + \sa {QtMultimediaKit::TrackNumber} +*/ + +/*! + \qmlproperty variant Audio::metaData.coverArtUrlSmall + + This property holds the URL of a small cover art image. + + \sa {QtMultimediaKit::CoverArtUrlSmall} +*/ + +/*! + \qmlproperty variant Audio::metaData.coverArtUrlLarge + + This property holds the URL of a large cover art image. + + \sa {QtMultimediaKit::CoverArtUrlLarge} +*/ + +/*! + \qmlproperty variant Audio::metaData.resolution + + This property holds the dimension of an image or video. + + \sa {QtMultimediaKit::Resolution} +*/ + +/*! + \qmlproperty variant Audio::metaData.pixelAspectRatio + + This property holds the pixel aspect ratio of an image or video. + + \sa {QtMultimediaKit::PixelAspectRatio} +*/ + +/*! + \qmlproperty variant Audio::metaData.videoFrameRate + + This property holds the frame rate of the media's video stream. + + \sa {QtMultimediaKit::VideoFrameRate} +*/ + +/*! + \qmlproperty variant Audio::metaData.videoBitRate + + This property holds the bit rate of the media's video stream in bits per + second. + + \sa {QtMultimediaKit::VideoBitRate} +*/ + +/*! + \qmlproperty variant Audio::metaData.videoCodec + + This property holds the encoding of the media's video stream. + + \sa {QtMultimediaKit::VideoCodec} +*/ + +/*! + \qmlproperty variant Audio::metaData.posterUrl + + This property holds the URL of a poster image. + + \sa {QtMultimediaKit::PosterUrl} +*/ + +/*! + \qmlproperty variant Audio::metaData.chapterNumber + + This property holds the chapter number of the media. + + \sa {QtMultimediaKit::ChapterNumber} +*/ + +/*! + \qmlproperty variant Audio::metaData.director + + This property holds the director of the media. + + \sa {QtMultimediaKit::Director} +*/ + +/*! + \qmlproperty variant Audio::metaData.leadPerformer + + This property holds the lead performer in the media. + + \sa {QtMultimediaKit::LeadPerformer} +*/ + +/*! + \qmlproperty variant Audio::metaData.writer + + This property holds the writer of the media. + + \sa {QtMultimediaKit::Writer} +*/ + +QT_END_NAMESPACE + +#include "moc_qdeclarativeaudio_p.cpp" + + diff --git a/src/imports/multimedia/qdeclarativeaudio_p.h b/src/imports/multimedia/qdeclarativeaudio_p.h new file mode 100644 index 000000000..6b7c64453 --- /dev/null +++ b/src/imports/multimedia/qdeclarativeaudio_p.h @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEAUDIO_P_H +#define QDECLARATIVEAUDIO_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 "qdeclarativemediabase_p.h" + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QTimerEvent; + +class QDeclarativeAudio : public QObject, public QDeclarativeMediaBase, public QDeclarativeParserStatus +{ + Q_OBJECT + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(bool autoLoad READ isAutoLoad WRITE setAutoLoad NOTIFY autoLoadChanged) + Q_PROPERTY(bool playing READ isPlaying WRITE setPlaying NOTIFY playingChanged) + Q_PROPERTY(int loops READ loopCount WRITE setLoopCount NOTIFY loopCountChanged) + Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) + Q_PROPERTY(int duration READ duration NOTIFY durationChanged) + Q_PROPERTY(int position READ position WRITE setPosition NOTIFY positionChanged) + Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) + Q_PROPERTY(int bufferProgress READ bufferProgress NOTIFY bufferProgressChanged) + Q_PROPERTY(bool seekable READ isSeekable NOTIFY seekableChanged) + Q_PROPERTY(qreal playbackRate READ playbackRate WRITE setPlaybackRate NOTIFY playbackRateChanged) + Q_PROPERTY(Error error READ error NOTIFY errorChanged) + Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged) + Q_PROPERTY(QDeclarativeMediaMetaData *metaData READ metaData CONSTANT) + Q_ENUMS(Status) + Q_ENUMS(Error) + Q_ENUMS(Loop) + Q_INTERFACES(QDeclarativeParserStatus) +public: + enum Status + { + UnknownStatus = QMediaPlayer::UnknownMediaStatus, + NoMedia = QMediaPlayer::NoMedia, + Loading = QMediaPlayer::LoadingMedia, + Loaded = QMediaPlayer::LoadedMedia, + Stalled = QMediaPlayer::StalledMedia, + Buffering = QMediaPlayer::BufferingMedia, + Buffered = QMediaPlayer::BufferedMedia, + EndOfMedia = QMediaPlayer::EndOfMedia, + InvalidMedia = QMediaPlayer::InvalidMedia + }; + + enum Error + { + NoError = QMediaPlayer::NoError, + ResourceError = QMediaPlayer::ResourceError, + FormatError = QMediaPlayer::FormatError, + NetworkError = QMediaPlayer::NetworkError, + AccessDenied = QMediaPlayer::AccessDeniedError, + ServiceMissing = QMediaPlayer::ServiceMissingError + }; + + enum Loop + { + Infinite = QDeclarativeMediaBase::INFINITE + }; + + QDeclarativeAudio(QObject *parent = 0); + ~QDeclarativeAudio(); + + Status status() const; + Error error() const; + + void classBegin(); + void componentComplete(); + +public Q_SLOTS: + void play(); + void pause(); + void stop(); + +Q_SIGNALS: + void sourceChanged(); + void autoLoadChanged(); + void playingChanged(); + void pausedChanged(); + void loopCountChanged(); + + void started(); + void resumed(); + void paused(); + void stopped(); + + void statusChanged(); + + void durationChanged(); + void positionChanged(); + + void volumeChanged(); + void mutedChanged(); + + void bufferProgressChanged(); + + void seekableChanged(); + void playbackRateChanged(); + + void errorChanged(); + void error(QDeclarativeAudio::Error error, const QString &errorString); + +private Q_SLOTS: + void _q_error(int, const QString &); + +private: + Q_DISABLE_COPY(QDeclarativeAudio) + Q_PRIVATE_SLOT(mediaBase(), void _q_statusChanged()) + + inline QDeclarativeMediaBase *mediaBase() { return this; } +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QT_PREPEND_NAMESPACE(QDeclarativeAudio)) + +QT_END_HEADER + +#endif diff --git a/src/imports/multimedia/qdeclarativecamera.cpp b/src/imports/multimedia/qdeclarativecamera.cpp new file mode 100644 index 000000000..08562dd76 --- /dev/null +++ b/src/imports/multimedia/qdeclarativecamera.cpp @@ -0,0 +1,1342 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativecamera_p.h" +#include "qdeclarativecamerapreviewprovider_p.h" + +#include +#include +#include +#include +#include + +#include +#include + + +QT_BEGIN_NAMESPACE + +class FocusZoneItem : public QGraphicsItem { +public: + FocusZoneItem(const QCameraFocusZone & zone, const QColor &color, QGraphicsItem *parent = 0) + :QGraphicsItem(parent),m_zone(zone), m_color(color) + {} + + virtual ~FocusZoneItem() {} + void paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *widget = 0) + { + Q_UNUSED(widget); + Q_UNUSED(option); + + painter->setPen(QPen(QBrush(m_color), 2.5)); + QRectF r = boundingRect(); + QPointF dw(r.width()/10, 0); + QPointF dh(0, r.width()/10); + + painter->drawLine(r.topLeft(), r.topLeft()+dw); + painter->drawLine(r.topLeft(), r.topLeft()+dh); + + painter->drawLine(r.topRight(), r.topRight()-dw); + painter->drawLine(r.topRight(), r.topRight()+dh); + + painter->drawLine(r.bottomLeft(), r.bottomLeft()+dw); + painter->drawLine(r.bottomLeft(), r.bottomLeft()-dh); + + painter->drawLine(r.bottomRight(), r.bottomRight()-dw); + painter->drawLine(r.bottomRight(), r.bottomRight()-dh); + } + + QRectF boundingRect() const { + if (!parentItem()) + return QRectF(); + + QRectF p = parentItem()->boundingRect(); + QRectF zone = m_zone.area(); + + return QRectF(p.left() + zone.left()*p.width(), + p.top() + zone.top()*p.height(), + p.width()*zone.width(), + p.height()*zone.height()); + } + + + QCameraFocusZone m_zone; + QColor m_color; +}; + + +void QDeclarativeCamera::_q_nativeSizeChanged(const QSizeF &size) +{ + setImplicitWidth(size.width()); + setImplicitHeight(size.height()); +} + +void QDeclarativeCamera::_q_error(int errorCode, const QString &errorString) +{ + emit error(Error(errorCode), errorString); + emit errorChanged(); +} + +void QDeclarativeCamera::_q_imageCaptured(int id, const QImage &preview) +{ + m_capturedImagePreview = preview; + QString previewId = QString("preview_%1").arg(id); + QDeclarativeCameraPreviewProvider::registerPreview(previewId, preview); + + emit imageCaptured(QLatin1String("image://camera/")+previewId); +} + +void QDeclarativeCamera::_q_imageSaved(int id, const QString &fileName) +{ + Q_UNUSED(id); + m_capturedImagePath = fileName; + emit imageSaved(fileName); +} + +void QDeclarativeCamera::_q_updateState(QCamera::State state) +{ + emit cameraStateChanged(QDeclarativeCamera::State(state)); +} + +void QDeclarativeCamera::_q_updateLockStatus(QCamera::LockType type, + QCamera::LockStatus status, + QCamera::LockChangeReason reason) +{ + if (type == QCamera::LockFocus) { + if (status == QCamera::Unlocked && reason == QCamera::LockFailed) { + //display failed focus points in red for 1 second + m_focusFailedTime = QTime::currentTime(); + QTimer::singleShot(1000, this, SLOT(_q_updateFocusZones())); + } else { + m_focusFailedTime = QTime(); + } + _q_updateFocusZones(); + } +} + +void QDeclarativeCamera::_q_updateFocusZones() +{ + qDeleteAll(m_focusZones); + m_focusZones.clear(); + + foreach(const QCameraFocusZone &zone, m_camera->focus()->focusZones()) { + QColor c; + QCamera::LockStatus lockStatus = m_camera->lockStatus(QCamera::LockFocus); + + if (lockStatus == QCamera::Unlocked) { + //display failed focus points in red for 1 second + if (zone.status() == QCameraFocusZone::Selected && + m_focusFailedTime.msecsTo(QTime::currentTime()) < 500) { + c = Qt::red; + } + } else { + switch (zone.status()) { + case QCameraFocusZone::Focused: + c = Qt::green; + break; + case QCameraFocusZone::Selected: + c = lockStatus == QCamera::Searching ? Qt::yellow : Qt::black; + break; + default: + c= QColor::Invalid; + break; + } + } + + if (c.isValid()) + m_focusZones.append(new FocusZoneItem(zone, c, m_viewfinderItem)); + } +} + +void QDeclarativeCamera::_q_updateImageSettings() +{ + if (m_imageSettingsChanged) { + m_imageSettingsChanged = false; + m_capture->setEncodingSettings(m_imageSettings); + } +} + +void QDeclarativeCamera::_q_applyPendingState() +{ + if (!m_isStateSet) { + m_isStateSet = true; + setCameraState(m_pendingState); + } +} + +void QDeclarativeCamera::_q_captureFailed(int id, QCameraImageCapture::Error error, const QString &message) +{ + Q_UNUSED(id); + Q_UNUSED(error); + emit captureFailed(message); +} + + +/*! + \qmlclass Camera QDeclarativeCamera + \since 4.7 + \brief The Camera element allows you to add camera viewfinder to a scene. + \ingroup qml-multimedia + \inherits Item + + This element is part of the \bold{QtMultimediaKit 1.1} module. + + \qml + import Qt 4.7 + import QtMultimediaKit 1.1 + + Camera { + focus : visible // to receive focus and capture key events when visible + + flashMode: Camera.FlashRedEyeReduction + whiteBalanceMode: Camera.WhiteBalanceFlash + exposureCompensation: -1.0 + + onImageCaptured : { + photoPreview.source = preview // Show the preview in an Image element + } + + } + \endqml + + You can use the \c Camera element to capture images from a camera, and manipulate the capture and + processing settings that get applied to the image. + + \note On Symbian, your process requires the \c UserEnvironment capability to use this element. +*/ + +/*! + \class QDeclarativeCamera + \brief The QDeclarativeCamera class provides a camera item that you can add to a QDeclarativeView. +*/ + +/*! + Construct a declarative camera object using \a parent object. + */ +QDeclarativeCamera::QDeclarativeCamera(QDeclarativeItem *parent) : + QDeclarativeItem(parent), + m_camera(0), + m_viewfinderItem(0), + m_imageSettingsChanged(false), + m_pendingState(ActiveState), + m_isStateSet(false), + m_isValid(true) +{ +#if defined(Q_OS_SYMBIAN) + RProcess thisProcess; + if (!thisProcess.HasCapability(ECapabilityUserEnvironment)) { + qmlInfo(this) << "Camera Element requires UserEnvironment Capability to be successfully used on Symbian"; + m_isValid = false; + return; + } +#endif + m_camera = new QCamera(this); + m_viewfinderItem = new QGraphicsVideoItem(this); + m_camera->setViewfinder(m_viewfinderItem); + m_exposure = m_camera->exposure(); + m_focus = m_camera->focus(); + + connect(m_viewfinderItem, SIGNAL(nativeSizeChanged(QSizeF)), + this, SLOT(_q_nativeSizeChanged(QSizeF))); + + connect(m_camera, SIGNAL(lockStatusChanged(QCamera::LockStatus,QCamera::LockChangeReason)), this, SIGNAL(lockStatusChanged())); + connect(m_camera, SIGNAL(stateChanged(QCamera::State)), this, SLOT(_q_updateState(QCamera::State))); + + m_capture = new QCameraImageCapture(m_camera, this); + + connect(m_capture, SIGNAL(imageCaptured(int,QImage)), this, SLOT(_q_imageCaptured(int, QImage))); + connect(m_capture, SIGNAL(imageSaved(int,QString)), this, SLOT(_q_imageSaved(int, QString))); + connect(m_capture, SIGNAL(error(int,QCameraImageCapture::Error,QString)), + this, SLOT(_q_captureFailed(int,QCameraImageCapture::Error,QString))); + + connect(m_focus, SIGNAL(focusZonesChanged()), this, SLOT(_q_updateFocusZones())); + connect(m_camera, SIGNAL(lockStatusChanged(QCamera::LockType,QCamera::LockStatus,QCamera::LockChangeReason)), + this, SLOT(_q_updateLockStatus(QCamera::LockType,QCamera::LockStatus,QCamera::LockChangeReason))); + + connect(m_exposure, SIGNAL(isoSensitivityChanged(int)), this, SIGNAL(isoSensitivityChanged(int))); + connect(m_exposure, SIGNAL(apertureChanged(qreal)), this, SIGNAL(apertureChanged(qreal))); + connect(m_exposure, SIGNAL(shutterSpeedChanged(qreal)), this, SIGNAL(shutterSpeedChanged(qreal))); + + //connect(m_exposure, SIGNAL(exposureCompensationChanged(qreal)), this, SIGNAL(exposureCompensationChanged(qreal))); + + connect(m_focus, SIGNAL(opticalZoomChanged(qreal)), this, SIGNAL(opticalZoomChanged(qreal))); + connect(m_focus, SIGNAL(digitalZoomChanged(qreal)), this, SIGNAL(digitalZoomChanged(qreal))); + connect(m_focus, SIGNAL(maximumOpticalZoomChanged(qreal)), this, SIGNAL(maximumOpticalZoomChanged(qreal))); + connect(m_focus, SIGNAL(maximumDigitalZoomChanged(qreal)), this, SIGNAL(maximumDigitalZoomChanged(qreal))); + + //delayed start to evoid stopping the cammera immediately if + //stop() is called after constructor, + //or to set the rest of camera settings before starting the camera + QMetaObject::invokeMethod(this, "_q_applyPendingState", Qt::QueuedConnection); + +} + +/*! Destructor, clean up memory */ +QDeclarativeCamera::~QDeclarativeCamera() +{ + if (m_isValid) { + m_camera->unload(); + + delete m_viewfinderItem; + delete m_capture; + delete m_camera; + } +} + +/*! + Returns any camera error. + \sa QDeclarativeError::Error +*/ +QDeclarativeCamera::Error QDeclarativeCamera::error() const +{ + if (!m_isValid) + return QDeclarativeCamera::CameraError; + + return QDeclarativeCamera::Error(m_camera->error()); +} + +/*! + \qmlproperty string Camera::errorString + + A description of the current error, if any. +*/ +/*! + \property QDeclarativeCamera::errorString + + A description of the current error, if any. +*/ +QString QDeclarativeCamera::errorString() const +{ + if (!m_isValid) + return QString(); + + return m_camera->errorString(); +} + +/*! + \qmlproperty enumeration Camera::cameraState + + The current state of the camera object. + + \table + \header \o Value \o Description + \row \o UnloadedState + \o The initial camera state, with camera not loaded, + the camera capabilities except of supported capture modes + are unknown. + While the supported settings are unknown in this state, + it's allowed to set the camera capture settings like codec, + resolution, or frame rate. + + \row \o LoadedState + \o The camera is loaded and ready to be configured. + + In the Idle state it's allowed to query camera capabilities, + set capture resolution, codecs, etc. + + The viewfinder is not active in the loaded state. + + \row \o ActiveState + \o In the active state as soon as camera is started + the viewfinder displays video frames and the + camera is ready for capture. + \endtable +*/ +/*! + \property QDeclarativeCamera::cameraState + + The current state of the camera object. + + \table + \header \o Value \o Description + \row \o UnloadedState + \o The initial camera state, with camera not loaded, + the camera capabilities except of supported capture modes + are unknown. + While the supported settings are unknown in this state, + it's allowed to set the camera capture settings like codec, + resolution, or frame rate. + + \row \o LoadedState + \o The camera is loaded and ready to be configured. + + In the Idle state it's allowed to query camera capabilities, + set capture resolution, codecs, etc. + + The viewfinder is not active in the loaded state. + + \row \o ActiveState + \o In the active state as soon as camera is started + the viewfinder displays video frames and the + camera is ready for capture. + \endtable +*/ +/*! + \enum QDeclarativeCamera::State + \value UnloadedState + The initial camera state, with camera not loaded, + the camera capabilities except of supported capture modes + are unknown. + While the supported settings are unknown in this state, + it's allowed to set the camera capture settings like codec, + resolution, or frame rate. + + \value LoadedState + The camera is loaded and ready to be configured. + In the Idle state it's allowed to query camera capabilities, + set capture resolution, codecs, etc. + The viewfinder is not active in the loaded state. + + \value ActiveState + In the active state as soon as camera is started + the viewfinder displays video frames and the + camera is ready for capture. + + + The default camera state is ActiveState. +*/ + +QDeclarativeCamera::State QDeclarativeCamera::cameraState() const +{ + if (!m_isValid) + return QDeclarativeCamera::UnloadedState; + + return m_isStateSet ? QDeclarativeCamera::State(m_camera->state()) : m_pendingState; +} + +void QDeclarativeCamera::setCameraState(QDeclarativeCamera::State state) +{ + if (!m_isValid) + return; + + if (!m_isStateSet) { + m_pendingState = state; + return; + } + + switch (state) { + case QDeclarativeCamera::ActiveState: + m_camera->start(); + break; + case QDeclarativeCamera::UnloadedState: + m_camera->unload(); + break; + case QDeclarativeCamera::LoadedState: + m_camera->load(); + break; + } +} + +/*! + \qmlmethod Camera::start() + \fn QDeclarativeCamera::start() + + Starts the camera. +*/ +void QDeclarativeCamera::start() +{ + if (m_isValid) + m_camera->start(); +} + +/*! + \qmlmethod Camera::stop() + \fn QDeclarativeCamera::stop() + + Stops the camera. +*/ +void QDeclarativeCamera::stop() +{ + if (m_isValid) + m_camera->stop(); +} + + +/*! + \qmlproperty enumeration Camera::lockStatus + + The overall status for all the requested camera locks. + + \table + \header \o Value \o Description + \row \o Unlocked + \o The application is not interested in camera settings value. + The camera may keep this parameter without changes, this is common with camera focus, + or adjust exposure and white balance constantly to keep the viewfinder image nice. + + \row \o Searching + \o The application has requested the camera focus, exposure or white balance lock with + searchAndLock(). This state indicates the camera is focusing or calculating exposure and white balance. + + \row \o Locked + \o The camera focus, exposure or white balance is locked. + The camera is ready to capture, application may check the exposure parameters. + + The locked state usually means the requested parameter stays the same, + except in the cases when the parameter is requested to be constantly updated. + For example in continuous focusing mode, the focus is considered locked as long + and the object is in focus, even while the actual focusing distance may be constantly changing. + \endtable +*/ +/*! + \property QDeclarativeCamera::lockStatus + + The overall status for all the requested camera locks. + + \table + \header \o Value \o Description + \row \o Unlocked + \o The application is not interested in camera settings value. + The camera may keep this parameter without changes, this is common with camera focus, + or adjust exposure and white balance constantly to keep the viewfinder image nice. + + \row \o Searching + \o The application has requested the camera focus, exposure or white balance lock with + searchAndLock(). This state indicates the camera is focusing or calculating exposure and white balance. + + \row \o Locked + \o The camera focus, exposure or white balance is locked. + The camera is ready to capture, application may check the exposure parameters. + + The locked state usually means the requested parameter stays the same, + except in the cases when the parameter is requested to be constantly updated. + For example in continuous focusing mode, the focus is considered locked as long + and the object is in focus, even while the actual focusing distance may be constantly changing. + \endtable +*/ +/*! + \enum QDeclarativeCamera::LockStatus + \value Unlocked + The application is not interested in camera settings value. + The camera may keep this parameter without changes, this is common with camera focus, + or adjust exposure and white balance constantly to keep the viewfinder image nice. + + \value Searching + The application has requested the camera focus, exposure or white balance lock with + searchAndLock(). This state indicates the camera is focusing or calculating exposure and white balance. + + \value Locked + The camera focus, exposure or white balance is locked. + The camera is ready to capture, application may check the exposure parameters. + + The locked state usually means the requested parameter stays the same, + except in the cases when the parameter is requested to be constantly updated. + For example in continuous focusing mode, the focus is considered locked as long + and the object is in focus, even while the actual focusing distance may be constantly changing. +*/ +QDeclarativeCamera::LockStatus QDeclarativeCamera::lockStatus() const +{ + if (!m_isValid) + return QDeclarativeCamera::Unlocked; + + return QDeclarativeCamera::LockStatus(m_camera->lockStatus()); +} + +/*! + \qmlmethod Camera::searchAndLock() + \fn QDeclarativeCamera::searchAndLock() + + Start focusing, exposure and white balance calculation. + If the camera has keyboard focus, searchAndLock() is called + automatically when the camera focus button is pressed. +*/ +void QDeclarativeCamera::searchAndLock() +{ + if (m_isValid) + m_camera->searchAndLock(); +} + +/*! + \qmlmethod Camera::unlock() + \fn QDeclarativeCamera::unlock() + + Unlock focus. + + If the camera has keyboard focus, unlock() is called automatically + when the camera focus button is released. + */ +void QDeclarativeCamera::unlock() +{ + if (m_isValid) + m_camera->unlock(); +} + +/*! + \qmlmethod Camera::captureImage() + \fn QDeclarativeCamera::captureImage() + + Start image capture. The \l onImageCaptured() and \l onImageSaved() signals will + be emitted when the capture is complete. +*/ +void QDeclarativeCamera::captureImage() +{ + if (m_isValid) + m_capture->capture(); +} + +// XXX this doesn't seem to be used +/*! + \fn QDeclarativeCamera::capturedImagePreview() const +*/ +QImage QDeclarativeCamera::capturedImagePreview() const +{ + return m_capturedImagePreview; +} + +/*! + \qmlproperty string Camera::capturedImagePath + + The path to the captured image. +*/ +/*! + \property QDeclarativeCamera::capturedImagePath + + The path to the captured image. +*/ +QString QDeclarativeCamera::capturedImagePath() const +{ + return m_capturedImagePath; +} + +/*! + Paint method. +*/ +void QDeclarativeCamera::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) +{ +} + +/*! + Change viewfinder size to \a newGeometry and returning the \a oldGeometry +*/ +void QDeclarativeCamera::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + m_viewfinderItem->setSize(newGeometry.size()); + _q_updateFocusZones(); + + QDeclarativeItem::geometryChanged(newGeometry, oldGeometry); +} + +void QDeclarativeCamera::keyPressEvent(QKeyEvent * event) +{ + if (!m_isValid || event->isAutoRepeat()) + return; + + switch (event->key()) { + case Qt::Key_CameraFocus: + m_camera->searchAndLock(); + event->accept(); + break; + case Qt::Key_Camera: + if (m_camera->captureMode() == QCamera::CaptureStillImage) + captureImage(); + //else + // m_recorder->record(); + event->accept(); + break; + default: + QDeclarativeItem::keyPressEvent(event); + } +} + +/*! + Handle the release of a key in \a event and take action if needed. +*/ +void QDeclarativeCamera::keyReleaseEvent(QKeyEvent * event) +{ + if (!m_isValid || event->isAutoRepeat()) + return; + + switch (event->key()) { + case Qt::Key_CameraFocus: + m_camera->unlock(); + event->accept(); + break; + case Qt::Key_Camera: + //if (m_camera->captureMode() == QCamera::CaptureVideo) + // m_recorder->stop(); + event->accept(); + break; + default: + QDeclarativeItem::keyReleaseEvent(event); + } +} + + +/*! + \qmlproperty enumeration Camera::flashMode + + \table + \header \o Value \o Description + \row \o FlashOff \o Flash is Off. + \row \o FlashOn \o Flash is On. + \row \o FlashAuto \o Automatic flash. + \row \o FlashRedEyeReduction \o Red eye reduction flash. + \row \o FlashFill \o Use flash to fillin shadows. + \row \o FlashTorch \o Constant light source, useful for focusing and video capture. + \row \o FlashSlowSyncFrontCurtain + \o Use the flash in conjunction with a slow shutter speed. + This mode allows better exposure of distant objects and/or motion blur effect. + \row \o FlashSlowSyncRearCurtain + \o The similar mode to FlashSlowSyncFrontCurtain but flash is fired at the end of exposure. + \row \o FlashManual \o Flash power is manually set. + \endtable + +*/ +/*! + \property QDeclarativeCamera::flashMode + + \table + \header \o Value \o Description + \row \o FlashOff \o Flash is Off. + \row \o FlashOn \o Flash is On. + \row \o FlashAuto \o Automatic flash. + \row \o FlashRedEyeReduction \o Red eye reduction flash. + \row \o FlashFill \o Use flash to fillin shadows. + \row \o FlashTorch \o Constant light source, useful for focusing and video capture. + \row \o FlashSlowSyncFrontCurtain + \o Use the flash in conjunction with a slow shutter speed. + This mode allows better exposure of distant objects and/or motion blur effect. + \row \o FlashSlowSyncRearCurtain + \o The similar mode to FlashSlowSyncFrontCurtain but flash is fired at the end of exposure. + \row \o FlashManual \o Flash power is manually set. + \endtable + +*/ +/*! + \enum QDeclarativeCamera::FlashMode + \value FlashOff Flash is Off. + \value FlashOn Flash is On. + \value FlashAuto Automatic flash. + \value FlashRedEyeReduction Red eye reduction flash. + \value FlashFill Use flash to fillin shadows. + \value FlashTorch Constant light source, useful for focusing and video capture. + \value FlashSlowSyncFrontCurtain + Use the flash in conjunction with a slow shutter speed. + This mode allows better exposure of distant objects and/or motion blur effect. + \value FlashSlowSyncRearCurtain + The similar mode to FlashSlowSyncFrontCurtain but flash is fired at the end of exposure. + \value FlashManual Flash power is manually set. + +*/ +int QDeclarativeCamera::flashMode() const +{ + if (!m_isValid) + return 0; + + return m_exposure->flashMode(); +} + +void QDeclarativeCamera::setFlashMode(int mode) +{ + if (m_isValid && m_exposure->flashMode() != mode) { + m_exposure->setFlashMode(QCameraExposure::FlashModes(mode)); + emit flashModeChanged(mode); + } +} + +/*! + \qmlproperty real Camera::exposureCompensation + + Adjustment for the automatically calculated exposure. The value is + in EV units. + */ +/*! + \property QDeclarativeCamera::exposureCompensation + + Adjustment for the automatically calculated exposure. The value is + in EV units. + */ +qreal QDeclarativeCamera::exposureCompensation() const +{ + if (!m_isValid) + return 0.0; + + return m_exposure->exposureCompensation(); +} + +void QDeclarativeCamera::setExposureCompensation(qreal ev) +{ + if (m_isValid) + m_exposure->setExposureCompensation(ev); +} + +/*! + \qmlproperty real Camera::isoSensitivity + + The sensor's ISO sensitivity. + */ +/*! + \property QDeclarativeCamera::iso + + The sensor's ISO sensitivity. + */ +int QDeclarativeCamera::isoSensitivity() const +{ + if (!m_isValid) + return 0; + + return m_exposure->isoSensitivity(); +} + +void QDeclarativeCamera::setManualIsoSensitivity(int iso) +{ + if (!m_isValid) + return; + + m_exposure->setManualIsoSensitivity(iso); +} + +/*! + \qmlproperty real Camera::shutterSpeed + + The camera's shutter speed, in seconds. +*/ +/*! + \property QDeclarativeCamera::shutterSpeed + + The camera's shutter speed, in seconds. +*/ +qreal QDeclarativeCamera::shutterSpeed() const +{ + if (!m_isValid) + return 0.0; + + return m_exposure->shutterSpeed(); +} + +/*! + \qmlproperty real Camera::aperture + + The lens aperture as an F number (the ratio of the focal length to effective aperture diameter). +*/ +/*! + \property QDeclarativeCamera::aperture + + The lens aperture as an F number (the ratio of the focal length to effective aperture diameter). +*/ +qreal QDeclarativeCamera::aperture() const +{ + if (!m_isValid) + return 0.0; + + return m_exposure->aperture(); +} + +/*! + \qmlproperty enumeration Camera::exposureMode + + \table + \header \o Value \o Description + \row \o ExposureManual \o Manual mode. + \row \o ExposureAuto \o Automatic mode. + \row \o ExposureNight \o Night mode. + \row \o ExposureBacklight \o Backlight exposure mode. + \row \o ExposureSpotlight \o Spotlight exposure mode. + \row \o ExposureSports \o Spots exposure mode. + \row \o ExposureSnow \o Snow exposure mode. + \row \o ExposureBeach \o Beach exposure mode. + \row \o ExposureLargeAperture \o Use larger aperture with small depth of field. + \row \o ExposureSmallAperture \o Use smaller aperture. + \row \o ExposurePortrait \o Portrait exposure mode. + \row \o ExposureModeVendor \o The base value for device specific exposure modes. + \endtable + +*/ +/*! + \enum QDeclarativeCamera::ExposureMode + \value ExposureManual Manual mode. + \value ExposureAuto Automatic mode. + \value ExposureNight Night mode. + \value ExposureBacklight Backlight exposure mode. + \value ExposureSpotlight Spotlight exposure mode. + \value ExposureSports Spots exposure mode. + \value ExposureSnow Snow exposure mode. + \value ExposureBeach Beach exposure mode. + \value ExposureLargeAperture Use larger aperture with small depth of field. + \value ExposureSmallAperture Use smaller aperture. + \value ExposurePortrait Portrait exposure mode. + \value ExposureModeVendor The base value for device specific exposure modes. + +*/ +/*! + \property QDeclarativeCamera::exposureMode + + Camera exposure modes. +*/ +QDeclarativeCamera::ExposureMode QDeclarativeCamera::exposureMode() const +{ + if (!m_isValid) + return QDeclarativeCamera::ExposureAuto; + + return ExposureMode(m_exposure->exposureMode()); +} + +void QDeclarativeCamera::setExposureMode(QDeclarativeCamera::ExposureMode mode) +{ + if (!m_isValid) + return; + + if (exposureMode() != mode) { + m_exposure->setExposureMode(QCameraExposure::ExposureMode(mode)); + emit exposureModeChanged(exposureMode()); + } +} + +/*! + \qmlproperty size Camera::captureResolution + + The resolution to capture the image at. If empty, the system will pick + a good size. +*/ +/*! + \property QDeclarativeCamera::captureResolution + + The resolution to capture the image at. If empty, the system will pick + a good size. +*/ +QSize QDeclarativeCamera::captureResolution() const +{ + if (!m_isValid) + return QSize(); + + return m_imageSettings.resolution(); +} + +void QDeclarativeCamera::setCaptureResolution(const QSize &resolution) +{ + if (m_isValid && m_imageSettings.resolution() != resolution) { + m_imageSettings.setResolution(resolution); + + if (!m_imageSettingsChanged) { + m_imageSettingsChanged = true; + QMetaObject::invokeMethod(this, "_q_updateImageSettings", Qt::QueuedConnection); + } + + emit captureResolutionChanged(resolution); + } +} + +/*! + \qmlproperty real Camera::maximumOpticalZoom + + The maximum optical zoom factor, or 1.0 if optical zoom is not supported. +*/ +/*! + \property QDeclarativeCamera::maximumOpticalZoom + + The maximum optical zoom factor, or 1.0 if optical zoom is not supported. +*/ +qreal QDeclarativeCamera::maximumOpticalZoom() const +{ + if (!m_isValid) + return 0.0; + + return m_focus->maximumOpticalZoom(); +} + +/*! + \qmlproperty real Camera::maximumDigitalZoom + + The maximum digital zoom factor, or 1.0 if digital zoom is not supported. +*/ +/*! + \property QDeclarativeCamera::maximumDigitalZoom + + The maximum digital zoom factor, or 1.0 if digital zoom is not supported. +*/ +qreal QDeclarativeCamera::maximumDigitalZoom() const +{ + if (!m_isValid) + return 0.0; + + return m_focus->maximumDigitalZoom(); +} + +/*! + \qmlproperty real Camera::opticalZoom + + The current optical zoom factor. +*/ +/*! + \property QDeclarativeCamera::opticalZoom + + The current optical zoom factor. +*/ +qreal QDeclarativeCamera::opticalZoom() const +{ + if (!m_isValid) + return 0.0; + + return m_focus->opticalZoom(); +} + +void QDeclarativeCamera::setOpticalZoom(qreal value) +{ + if (m_isValid) + m_focus->zoomTo(value, digitalZoom()); +} + +/*! + \qmlproperty real Camera::digitalZoom + + The current digital zoom factor. +*/ +/*! + \property QDeclarativeCamera::digitalZoom + + The current digital zoom factor. +*/ +qreal QDeclarativeCamera::digitalZoom() const +{ + if (!m_isValid) + return 0.0; + + return m_focus->digitalZoom(); +} + +void QDeclarativeCamera::setDigitalZoom(qreal value) +{ + if (m_isValid) + m_focus->zoomTo(opticalZoom(), value); +} + +/*! + \enum QDeclarativeCamera::WhiteBalanceMode + \value WhiteBalanceManual Manual white balance. In this mode the manual white balance property value is used. + \value WhiteBalanceAuto Auto white balance mode. + \value WhiteBalanceSunlight Sunlight white balance mode. + \value WhiteBalanceCloudy Cloudy white balance mode. + \value WhiteBalanceShade Shade white balance mode. + \value WhiteBalanceTungsten Tungsten white balance mode. + \value WhiteBalanceFluorescent Fluorescent white balance mode. + \value WhiteBalanceIncandescent Incandescent white balance mode. + \value WhiteBalanceFlash Flash white balance mode. + \value WhiteBalanceSunset Sunset white balance mode. + \value WhiteBalanceVendor Vendor defined white balance mode. +*/ +/*! + \qmlproperty enumeration Camera::whiteBalanceMode + + \table + \header \o Value \o Description + \row \o WhiteBalanceManual \o Manual white balance. In this mode the manual white balance property value is used. + \row \o WhiteBalanceAuto \o Auto white balance mode. + \row \o WhiteBalanceSunlight \o Sunlight white balance mode. + \row \o WhiteBalanceCloudy \o Cloudy white balance mode. + \row \o WhiteBalanceShade \o Shade white balance mode. + \row \o WhiteBalanceTungsten \o Tungsten white balance mode. + \row \o WhiteBalanceFluorescent \o Fluorescent white balance mode. + \row \o WhiteBalanceIncandescent \o Incandescent white balance mode. + \row \o WhiteBalanceFlash \o Flash white balance mode. + \row \o WhiteBalanceSunset \o Sunset white balance mode. + \row \o WhiteBalanceVendor \o Vendor defined white balance mode. + \endtable + + \sa manualWhiteBalance +*/ +/*! + \property QDeclarativeCamera::whiteBalanceMode + + \sa WhiteBalanceMode +*/ +QDeclarativeCamera::WhiteBalanceMode QDeclarativeCamera::whiteBalanceMode() const +{ + if (!m_isValid) + return QDeclarativeCamera::WhiteBalanceAuto; + + return WhiteBalanceMode(m_camera->imageProcessing()->whiteBalanceMode()); +} + +void QDeclarativeCamera::setWhiteBalanceMode(QDeclarativeCamera::WhiteBalanceMode mode) const +{ + if (m_isValid && whiteBalanceMode() != mode) { + m_camera->imageProcessing()->setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode(mode)); + emit whiteBalanceModeChanged(whiteBalanceMode()); + } +} + +/*! + \qmlproperty int Camera::manualWhiteBalance + + The color temperature used when in manual white balance mode (WhiteBalanceManual). + + \sa whiteBalanceMode +*/ +/*! + \property QDeclarativeCamera::manualWhiteBalance + + The color temperature used when in manual white balance mode (WhiteBalanceManual). + + \sa whiteBalanceMode +*/ +int QDeclarativeCamera::manualWhiteBalance() const +{ + if (!m_isValid) + return 0; + + return m_camera->imageProcessing()->manualWhiteBalance(); +} + +void QDeclarativeCamera::setManualWhiteBalance(int colorTemp) const +{ + if (m_isValid && manualWhiteBalance() != colorTemp) { + m_camera->imageProcessing()->setManualWhiteBalance(colorTemp); + emit manualWhiteBalanceChanged(manualWhiteBalance()); + } +} + +/*! + \qmlsignal Camera::onError(error, errorString) + + + This handler is called when an error occurs. The enumeration value \a error is one of the + values defined below, and a descriptive string value is available in \a errorString. + + \table + \header \o Value \o Description + \row \o NoError \o No errors have occurred. + \row \o CameraError \o An error has occurred. + \row \o InvalidRequestError \o System resource doesn't support requested functionality. + \row \o ServiceMissingError \o No camera service available. + \row \o NotSupportedFeatureError \o The feature is not supported. + \endtable +*/ +/*! + \qmlsignal Camera::onError(error, errorString) + + + This handler is called when an error occurs. The enumeration value \a error is one of the + values defined below, and a descriptive string value is available in \a errorString. +*/ +/*! + \enum QDeclarativeCamera::Error + \value NoError No errors have occurred. + \value CameraError An error has occurred. + \value InvalidRequestError System resource doesn't support requested functionality. + \value ServiceMissingError No camera service available. + \value NotSupportedFeatureError The feature is not supported. +*/ + + +/*! + \qmlsignal Camera::onCaptureFailed(message) + + This handler is called when an error occurs during capture. A descriptive message is available in \a message. +*/ +/*! + \fn QDeclarativeCamera::captureFailed(const QString &message) + + This handler is called when an error occurs during capture. A descriptive message is available in \a message. +*/ + +/*! + \qmlsignal Camera::onImageCaptured(preview) + + This handler is called when an image has been captured but not yet saved to the filesystem. The \a preview + parameter can be used as the URL supplied to an Image element. + + \sa onImageSaved +*/ +/*! + \fn QDeclarativeCamera::imageCaptured(const QString &preview) + + This handler is called when an image has been captured but not yet saved to the filesystem. The \a preview + parameter can be used as the URL supplied to an Image element. + + \sa imageSaved() +*/ + +/*! + \qmlsignal Camera::onImageSaved(path) + + This handler is called after the image has been written to the filesystem. The \a path is a local file path, not a URL. + + \sa onImageCaptured +*/ +/*! + \fn QDeclarativeCamera::imageSaved(const QString &path) + + This handler is called after the image has been written to the filesystem. The \a path is a local file path, not a URL. + + \sa imageCaptured() +*/ + + +/*! + \fn void QDeclarativeCamera::lockStatusChanged() + + \qmlsignal Camera::lockStatusChanged() +*/ + +/*! + \fn void QDeclarativeCamera::stateChanged(QDeclarativeCamera::State) + + \qmlsignal Camera::stateChanged(Camera::State) +*/ + +/*! + \fn void QDeclarativeCamera::imageCaptured(const QString &) + + \qmlsignal Camera::imageCaptured(string) +*/ + +/*! + \fn void QDeclarativeCamera::imageSaved(const QString &) + + \qmlsignal Camera::imageSaved(string) +*/ + +/*! + \fn void QDeclarativeCamera::error(QDeclarativeCamera::Error , const QString &) + + \qmlsignal Camera::error(Camera::Error, string) +*/ + +/*! + \fn void QDeclarativeCamera::errorChanged() + +*/ +/*! + \qmlsignal Camera::errorChanged() +*/ + +/*! + \fn void QDeclarativeCamera::isoSensitivityChanged(int) +*/ +/*! + \qmlsignal Camera::isoSensitivityChanged(int) +*/ + +/*! + \fn void QDeclarativeCamera::apertureChanged(qreal) + + \qmlsignal Camera::apertureChanged(real) +*/ + +/*! + \fn void QDeclarativeCamera::shutterSpeedChanged(qreal) + +*/ +/*! + \qmlsignal Camera::shutterSpeedChanged(real) +*/ + +/*! + \fn void QDeclarativeCamera::exposureCompensationChanged(qreal) + +*/ +/*! + \qmlsignal Camera::exposureCompensationChanged(real) +*/ + +/*! + \fn void QDeclarativeCamera:opticalZoomChanged(qreal zoom) + + Optical zoom changed to \a zoom. +*/ +/*! + \qmlsignal Camera::opticalZoomChanged(real) +*/ + +/*! + \fn void QDeclarativeCamera::digitalZoomChanged(qreal) + + \qmlsignal Camera::digitalZoomChanged(real) +*/ + +/*! + \fn void QDeclarativeCamera::maximumOpticalZoomChanged(qreal) + + \qmlsignal Camera::maximumOpticalZoomChanged(real) +*/ + +/*! + \fn void QDeclarativeCamera::maximumDigitalZoomChanged(qreal) + + \qmlsignal Camera::maximumDigitalZoomChanged(real) +*/ + + +/*! + \fn void QDeclarativeCamera::exposureModeChanged(QDeclarativeCamera::ExposureMode) + + \qmlsignal Camera::exposureModeChanged(Camera::ExposureMode) +*/ + +/*! + \fn void QDeclarativeCamera::flashModeChanged(int) +*/ +/*! + \qmlsignal Camera::flashModeChanged(int) +*/ + +/*! + \fn void QDeclarativeCamera::whiteBalanceModeChanged(QDeclarativeCamera::WhiteBalanceMode) const + +*/ +/*! + \qmlsignal Camera::whiteBalanceModeChanged(Camera::WhiteBalanceMode) +*/ + +/*! + \fn void QDeclarativeCamera::manualWhiteBalanceChanged(int) const +*/ +/*! + \qmlsignal Camera::manualWhiteBalanceChanged(int) +*/ + +/*! + \fn void QDeclarativeCamera::captureResolutionChanged(const QSize &) + + \qmlsignal Camera::captureResolutionChanged(Item) +*/ + +/*! + \fn QDeclarativeCamera::cameraStateChanged(QDeclarativeCamera::State) + +*/ + + +QT_END_NAMESPACE + +#include "moc_qdeclarativecamera_p.cpp" diff --git a/src/imports/multimedia/qdeclarativecamera_p.h b/src/imports/multimedia/qdeclarativecamera_p.h new file mode 100644 index 000000000..e477538b2 --- /dev/null +++ b/src/imports/multimedia/qdeclarativecamera_p.h @@ -0,0 +1,302 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVECAMERA_H +#define QDECLARATIVECAMERA_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 "qgraphicsvideoitem.h" +#include +#include +#include + +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QTimerEvent; +class QVideoSurfaceFormat; + + +class QDeclarativeCamera : public QDeclarativeItem +{ + Q_OBJECT + Q_PROPERTY(State cameraState READ cameraState WRITE setCameraState NOTIFY cameraStateChanged) + Q_PROPERTY(LockStatus lockStatus READ lockStatus NOTIFY lockStatusChanged) + Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged) + + Q_PROPERTY(QString capturedImagePath READ capturedImagePath NOTIFY imageSaved) + + Q_PROPERTY(int iso READ isoSensitivity WRITE setManualIsoSensitivity NOTIFY isoSensitivityChanged) + Q_PROPERTY(qreal shutterSpeed READ shutterSpeed NOTIFY shutterSpeedChanged) + Q_PROPERTY(qreal aperture READ aperture NOTIFY apertureChanged) + Q_PROPERTY(qreal exposureCompensation READ exposureCompensation WRITE setExposureCompensation NOTIFY exposureCompensationChanged) + + Q_PROPERTY(ExposureMode exposureMode READ exposureMode WRITE setExposureMode NOTIFY exposureModeChanged) + Q_PROPERTY(int flashMode READ flashMode WRITE setFlashMode NOTIFY flashModeChanged) + Q_PROPERTY(WhiteBalanceMode whiteBalanceMode READ whiteBalanceMode WRITE setWhiteBalanceMode NOTIFY whiteBalanceModeChanged) + Q_PROPERTY(int manualWhiteBalance READ manualWhiteBalance WRITE setManualWhiteBalance NOTIFY manualWhiteBalanceChanged) + + Q_PROPERTY(QSize captureResolution READ captureResolution WRITE setCaptureResolution NOTIFY captureResolutionChanged) + + Q_PROPERTY(qreal opticalZoom READ opticalZoom WRITE setOpticalZoom NOTIFY opticalZoomChanged) + Q_PROPERTY(qreal maximumOpticalZoom READ maximumOpticalZoom NOTIFY maximumOpticalZoomChanged) + Q_PROPERTY(qreal digitalZoom READ digitalZoom WRITE setDigitalZoom NOTIFY digitalZoomChanged) + Q_PROPERTY(qreal maximumDigitalZoom READ maximumDigitalZoom NOTIFY maximumDigitalZoomChanged) + + Q_ENUMS(State) + Q_ENUMS(LockStatus) + Q_ENUMS(Error) + Q_ENUMS(FlashMode) + Q_ENUMS(ExposureMode) + Q_ENUMS(WhiteBalanceMode) +public: + enum State + { + ActiveState = QCamera::ActiveState, + LoadedState = QCamera::LoadedState, + UnloadedState = QCamera::UnloadedState + }; + + enum LockStatus + { + Unlocked = QCamera::Unlocked, + Searching = QCamera::Searching, + Locked = QCamera::Locked + }; + + enum Error + { + NoError = QCamera::NoError, + CameraError = QCamera::CameraError, + InvalidRequestError = QCamera::InvalidRequestError, + ServiceMissingError = QCamera::ServiceMissingError, + NotSupportedFeatureError = QCamera::NotSupportedFeatureError + }; + + enum FlashMode { + FlashAuto = 0x1, + FlashOff = 0x2, + FlashOn = 0x4, + FlashRedEyeReduction = 0x8, + FlashFill = 0x10, + FlashTorch = 0x20, + FlashSlowSyncFrontCurtain = 0x40, + FlashSlowSyncRearCurtain = 0x80, + FlashManual = 0x100 + }; + + enum ExposureMode { + ExposureAuto = 0, + ExposureManual = 1, + ExposurePortrait = 2, + ExposureNight = 3, + ExposureBacklight = 4, + ExposureSpotlight = 5, + ExposureSports = 6, + ExposureSnow = 7, + ExposureBeach = 8, + ExposureLargeAperture = 9, + ExposureSmallAperture = 10, + ExposureModeVendor = 1000 + }; + + enum WhiteBalanceMode { + WhiteBalanceAuto = 0, + WhiteBalanceManual = 1, + WhiteBalanceSunlight = 2, + WhiteBalanceCloudy = 3, + WhiteBalanceShade = 4, + WhiteBalanceTungsten = 5, + WhiteBalanceFluorescent = 6, + WhiteBalanceIncandescent = 7, + WhiteBalanceFlash = 8, + WhiteBalanceSunset = 9, + WhiteBalanceVendor = 1000 + }; + + QDeclarativeCamera(QDeclarativeItem *parent = 0); + ~QDeclarativeCamera(); + + State cameraState() const; + + Error error() const; + QString errorString() const; + + LockStatus lockStatus() const; + + QImage capturedImagePreview() const; + QString capturedImagePath() const; + + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); + + int flashMode() const; + ExposureMode exposureMode() const; + qreal exposureCompensation() const; + int isoSensitivity() const; + qreal shutterSpeed() const; + qreal aperture() const; + + WhiteBalanceMode whiteBalanceMode() const; + int manualWhiteBalance() const; + + QSize captureResolution() const; + + qreal maximumOpticalZoom() const; + qreal maximumDigitalZoom() const; + + qreal opticalZoom() const; + qreal digitalZoom() const; + +public Q_SLOTS: + void start(); + void stop(); + + void setCameraState(State state); + + void searchAndLock(); + void unlock(); + + void captureImage(); + + void setFlashMode(int); + void setExposureMode(QDeclarativeCamera::ExposureMode); + void setExposureCompensation(qreal ev); + void setManualIsoSensitivity(int iso); + + void setWhiteBalanceMode(QDeclarativeCamera::WhiteBalanceMode mode) const; + void setManualWhiteBalance(int colorTemp) const; + + void setCaptureResolution(const QSize &size); + + void setOpticalZoom(qreal); + void setDigitalZoom(qreal); + +Q_SIGNALS: + void errorChanged(); + void error(QDeclarativeCamera::Error error, const QString &errorString); + + void cameraStateChanged(QDeclarativeCamera::State); + + void lockStatusChanged(); + + void imageCaptured(const QString &preview); + void imageSaved(const QString &path); + void captureFailed(const QString &message); + + void isoSensitivityChanged(int); + void apertureChanged(qreal); + void shutterSpeedChanged(qreal); + void exposureCompensationChanged(qreal); + void exposureModeChanged(QDeclarativeCamera::ExposureMode); + void flashModeChanged(int); + + void whiteBalanceModeChanged(QDeclarativeCamera::WhiteBalanceMode) const; + void manualWhiteBalanceChanged(int) const; + + void captureResolutionChanged(const QSize&); + + void opticalZoomChanged(qreal); + void digitalZoomChanged(qreal); + void maximumOpticalZoomChanged(qreal); + void maximumDigitalZoomChanged(qreal); + +protected: + void geometryChanged(const QRectF &geometry, const QRectF &); + void keyPressEvent(QKeyEvent * event); + void keyReleaseEvent(QKeyEvent * event); + +private Q_SLOTS: + void _q_updateState(QCamera::State); + void _q_nativeSizeChanged(const QSizeF &size); + void _q_error(int, const QString &); + void _q_imageCaptured(int, const QImage&); + void _q_imageSaved(int, const QString&); + void _q_captureFailed(int, QCameraImageCapture::Error, const QString&); + void _q_updateFocusZones(); + void _q_updateLockStatus(QCamera::LockType, QCamera::LockStatus, QCamera::LockChangeReason); + void _q_updateImageSettings(); + void _q_applyPendingState(); + +private: + Q_DISABLE_COPY(QDeclarativeCamera) + QCamera *m_camera; + QGraphicsVideoItem *m_viewfinderItem; + + QCameraExposure *m_exposure; + QCameraFocus *m_focus; + QCameraImageCapture *m_capture; + + QImage m_capturedImagePreview; + QString m_capturedImagePath; + QList m_focusZones; + QTime m_focusFailedTime; + + QImageEncoderSettings m_imageSettings; + bool m_imageSettingsChanged; + + State m_pendingState; + bool m_isStateSet; + bool m_isValid; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QT_PREPEND_NAMESPACE(QDeclarativeCamera)) + +QT_END_HEADER + +#endif diff --git a/src/imports/multimedia/qdeclarativecamerapreviewprovider.cpp b/src/imports/multimedia/qdeclarativecamerapreviewprovider.cpp new file mode 100644 index 000000000..293120eda --- /dev/null +++ b/src/imports/multimedia/qdeclarativecamerapreviewprovider.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativecamerapreviewprovider_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +struct QDeclarativeCameraPreviewProviderPrivate +{ + QString id; + QImage image; + QMutex mutex; +}; + +Q_GLOBAL_STATIC(QDeclarativeCameraPreviewProviderPrivate, qDeclarativeCameraPreviewProviderPrivate) + +QDeclarativeCameraPreviewProvider::QDeclarativeCameraPreviewProvider() +: QDeclarativeImageProvider(QDeclarativeImageProvider::Image) +{ +} + +QDeclarativeCameraPreviewProvider::~QDeclarativeCameraPreviewProvider() +{ + QDeclarativeCameraPreviewProviderPrivate *d = qDeclarativeCameraPreviewProviderPrivate(); + QMutexLocker lock(&d->mutex); + d->id.clear(); + d->image = QImage(); +} + +QImage QDeclarativeCameraPreviewProvider::requestImage(const QString &id, QSize *size, const QSize& requestedSize) +{ + QDeclarativeCameraPreviewProviderPrivate *d = qDeclarativeCameraPreviewProviderPrivate(); + QMutexLocker lock(&d->mutex); + + if (d->id != id) + return QImage(); + + QImage res = d->image; + if (!requestedSize.isEmpty()) + res = res.scaled(requestedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + + if (size) + *size = res.size(); + + return res; +} + +void QDeclarativeCameraPreviewProvider::registerPreview(const QString &id, const QImage &preview) +{ + //only the last preview is kept + QDeclarativeCameraPreviewProviderPrivate *d = qDeclarativeCameraPreviewProviderPrivate(); + QMutexLocker lock(&d->mutex); + d->id = id; + d->image = preview; +} + +QT_END_NAMESPACE diff --git a/src/imports/multimedia/qdeclarativecamerapreviewprovider_p.h b/src/imports/multimedia/qdeclarativecamerapreviewprovider_p.h new file mode 100644 index 000000000..44a47e781 --- /dev/null +++ b/src/imports/multimedia/qdeclarativecamerapreviewprovider_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVECAMERAPREVIEWPROVIDER_H +#define QDECLARATIVECAMERAPREVIEWPROVIDER_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 + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QDeclarativeCameraPreviewProvider : public QDeclarativeImageProvider +{ +public: + QDeclarativeCameraPreviewProvider(); + ~QDeclarativeCameraPreviewProvider(); + + virtual QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize); + static void registerPreview(const QString &id, const QImage &preview); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/imports/multimedia/qdeclarativemediabase.cpp b/src/imports/multimedia/qdeclarativemediabase.cpp new file mode 100644 index 000000000..68552ed6a --- /dev/null +++ b/src/imports/multimedia/qdeclarativemediabase.cpp @@ -0,0 +1,567 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativemediabase_p.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "qdeclarativemediametadata_p.h" + +QT_BEGIN_NAMESPACE + + +class QDeclarativeMediaBaseObject : public QMediaObject +{ +public: + QDeclarativeMediaBaseObject(QMediaService *service) + : QMediaObject(0, service) + { + } +}; + +class QDeclarativeMediaBasePlayerControl : public QMediaPlayerControl +{ +public: + QDeclarativeMediaBasePlayerControl(QObject *parent) + : QMediaPlayerControl(parent) + { + } + + QMediaPlayer::State state() const { return QMediaPlayer::StoppedState; } + QMediaPlayer::MediaStatus mediaStatus() const { return QMediaPlayer::NoMedia; } + + qint64 duration() const { return 0; } + qint64 position() const { return 0; } + void setPosition(qint64) {} + int volume() const { return 0; } + void setVolume(int) {} + bool isMuted() const { return false; } + void setMuted(bool) {} + int bufferStatus() const { return 0; } + bool isAudioAvailable() const { return false; } + bool isVideoAvailable() const { return false; } + bool isSeekable() const { return false; } + QMediaTimeRange availablePlaybackRanges() const { return QMediaTimeRange(); } + qreal playbackRate() const { return 1; } + void setPlaybackRate(qreal) {} + QMediaContent media() const { return QMediaContent(); } + const QIODevice *mediaStream() const { return 0; } + void setMedia(const QMediaContent &, QIODevice *) {} + + void play() {} + void pause() {} + void stop() {} +}; + + +class QDeclarativeMediaBaseMetaDataControl : public QMetaDataReaderControl +{ +public: + QDeclarativeMediaBaseMetaDataControl(QObject *parent) + : QMetaDataReaderControl(parent) + { + } + + bool isMetaDataAvailable() const { return false; } + + QVariant metaData(QtMultimediaKit::MetaData) const { return QVariant(); } + QList availableMetaData() const { + return QList(); } + + QVariant extendedMetaData(const QString &) const { return QVariant(); } + QStringList availableExtendedMetaData() const { return QStringList(); } +}; + +class QDeclarativeMediaBaseAnimation : public QObject +{ +public: + QDeclarativeMediaBaseAnimation(QDeclarativeMediaBase *media) + : m_media(media) + { + } + + void start() { if (!m_timer.isActive()) m_timer.start(500, this); } + void stop() { m_timer.stop(); } + +protected: + void timerEvent(QTimerEvent *event) + { + if (event->timerId() == m_timer.timerId()) { + event->accept(); + + if (m_media->m_playing && !m_media->m_paused) + emit m_media->positionChanged(); + if (m_media->m_status == QMediaPlayer::BufferingMedia || QMediaPlayer::StalledMedia) + emit m_media->bufferProgressChanged(); + } else { + QObject::timerEvent(event); + } + } + +private: + QDeclarativeMediaBase *m_media; + QBasicTimer m_timer; +}; + +void QDeclarativeMediaBase::_q_statusChanged() +{ + if (m_playerControl->mediaStatus() == QMediaPlayer::EndOfMedia && m_runningCount != 0) { + m_runningCount -= 1; + m_playerControl->play(); + } + + const QMediaPlayer::MediaStatus oldStatus = m_status; + const bool wasPlaying = m_playing; + const bool wasPaused = m_paused; + + const QMediaPlayer::State state = m_playerControl->state(); + + m_status = m_playerControl->mediaStatus(); + + if (m_complete) + m_playing = state != QMediaPlayer::StoppedState; + + if (state == QMediaPlayer::PausedState) + m_paused = true; + else if (state == QMediaPlayer::PlayingState) + m_paused = false; + + if (m_status != oldStatus) + emit statusChanged(); + + switch (state) { + case QMediaPlayer::StoppedState: + if (wasPlaying) { + emit stopped(); + + if (!m_playing) + emit playingChanged(); + } + break; + case QMediaPlayer::PausedState: + if (!wasPlaying) { + emit started(); + if (m_playing) + emit playingChanged(); + } + if ((!wasPaused || !wasPlaying) && m_paused) + emit paused(); + if (!wasPaused && m_paused) + emit pausedChanged(); + + break; + + case QMediaPlayer::PlayingState: + if (wasPaused && wasPlaying) + emit resumed(); + else + emit started(); + + if (wasPaused && !m_paused) + emit pausedChanged(); + if (!wasPlaying && m_playing) + emit playingChanged(); + break; + } + + // Check + if ((m_playing && !m_paused) + || m_status == QMediaPlayer::BufferingMedia + || m_status == QMediaPlayer::StalledMedia) { + m_animation->start(); + } + else { + m_animation->stop(); + } +} + +QDeclarativeMediaBase::QDeclarativeMediaBase() + : m_paused(false) + , m_playing(false) + , m_autoLoad(true) + , m_loaded(false) + , m_muted(false) + , m_complete(false) + , m_loopCount(1) + , m_runningCount(0) + , m_position(0) + , m_vol(1.0) + , m_playbackRate(1.0) + , m_mediaService(0) + , m_playerControl(0) + , m_qmlObject(0) + , m_mediaObject(0) + , m_mediaProvider(0) + , m_metaDataControl(0) + , m_animation(0) + , m_status(QMediaPlayer::NoMedia) + , m_error(QMediaPlayer::ServiceMissingError) +{ +} + +QDeclarativeMediaBase::~QDeclarativeMediaBase() +{ +} + +void QDeclarativeMediaBase::shutdown() +{ + delete m_mediaObject; + m_metaData.reset(); + + if (m_mediaProvider) + m_mediaProvider->releaseService(m_mediaService); + + delete m_animation; + +} + +void QDeclarativeMediaBase::setObject(QObject *object) +{ + m_qmlObject = object; + + if ((m_mediaProvider = QMediaServiceProvider::defaultServiceProvider()) != 0) { + if ((m_mediaService = m_mediaProvider->requestService(Q_MEDIASERVICE_MEDIAPLAYER)) != 0) { + m_playerControl = qobject_cast( + m_mediaService->requestControl(QMediaPlayerControl_iid)); + m_metaDataControl = qobject_cast( + m_mediaService->requestControl(QMetaDataReaderControl_iid)); + m_mediaObject = new QDeclarativeMediaBaseObject(m_mediaService); + } + } + + if (m_playerControl) { + QObject::connect(m_playerControl, SIGNAL(stateChanged(QMediaPlayer::State)), + object, SLOT(_q_statusChanged())); + QObject::connect(m_playerControl, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + object, SLOT(_q_statusChanged())); + QObject::connect(m_playerControl, SIGNAL(mediaChanged(QMediaContent)), + object, SIGNAL(sourceChanged())); + QObject::connect(m_playerControl, SIGNAL(durationChanged(qint64)), + object, SIGNAL(durationChanged())); + QObject::connect(m_playerControl, SIGNAL(positionChanged(qint64)), + object, SIGNAL(positionChanged())); + QObject::connect(m_playerControl, SIGNAL(volumeChanged(int)), + object, SIGNAL(volumeChanged())); + QObject::connect(m_playerControl, SIGNAL(mutedChanged(bool)), + object, SIGNAL(mutedChanged())); + QObject::connect(m_playerControl, SIGNAL(bufferStatusChanged(int)), + object, SIGNAL(bufferProgressChanged())); + QObject::connect(m_playerControl, SIGNAL(seekableChanged(bool)), + object, SIGNAL(seekableChanged())); + QObject::connect(m_playerControl, SIGNAL(playbackRateChanged(qreal)), + object, SIGNAL(playbackRateChanged())); + QObject::connect(m_playerControl, SIGNAL(error(int,QString)), + object, SLOT(_q_error(int,QString))); + + m_animation = new QDeclarativeMediaBaseAnimation(this); + m_error = QMediaPlayer::NoError; + } else { + m_playerControl = new QDeclarativeMediaBasePlayerControl(object); + } + + if (!m_metaDataControl) + m_metaDataControl = new QDeclarativeMediaBaseMetaDataControl(object); + + m_metaData.reset(new QDeclarativeMediaMetaData(m_metaDataControl)); + + QObject::connect(m_metaDataControl, SIGNAL(metaDataChanged()), + m_metaData.data(), SIGNAL(metaDataChanged())); +} + +void QDeclarativeMediaBase::componentComplete() +{ + m_playerControl->setVolume(m_vol * 100); + m_playerControl->setMuted(m_muted); + m_playerControl->setPlaybackRate(m_playbackRate); + + if (!m_source.isEmpty() && (m_autoLoad || m_playing)) // Override autoLoad if playing set + m_playerControl->setMedia(m_source, 0); + + m_complete = true; + + if (m_playing) { + if (m_position > 0) + m_playerControl->setPosition(m_position); + + if (m_source.isEmpty()) { + m_playing = false; + + emit playingChanged(); + } else if (m_paused) { + m_playerControl->pause(); + } else { + m_playerControl->play(); + } + } +} + +// Properties + +QUrl QDeclarativeMediaBase::source() const +{ + return m_source; +} + +void QDeclarativeMediaBase::setSource(const QUrl &url) +{ + if (url == m_source) + return; + + m_source = url; + m_loaded = false; + if (m_complete && (m_autoLoad || url.isEmpty())) { + if (m_error != QMediaPlayer::ServiceMissingError && m_error != QMediaPlayer::NoError) { + m_error = QMediaPlayer::NoError; + m_errorString = QString(); + + emit errorChanged(); + } + + m_playerControl->setMedia(m_source, 0); + m_loaded = true; + } + else + emit sourceChanged(); +} + +bool QDeclarativeMediaBase::isAutoLoad() const +{ + return m_autoLoad; +} + +void QDeclarativeMediaBase::setAutoLoad(bool autoLoad) +{ + if (m_autoLoad == autoLoad) + return; + + m_autoLoad = autoLoad; + emit autoLoadChanged(); +} + +int QDeclarativeMediaBase::loopCount() const +{ + return m_loopCount; +} + +void QDeclarativeMediaBase::setLoopCount(int loopCount) +{ + if (loopCount == 0) + loopCount = 1; + else if (loopCount < -1) + loopCount = -1; + + if (m_loopCount == loopCount) { + return; + } + m_loopCount = loopCount; + emit loopCountChanged(); +} + +bool QDeclarativeMediaBase::isPlaying() const +{ + return m_playing; +} + +void QDeclarativeMediaBase::setPlaying(bool playing) +{ + if (playing == m_playing) + return; + + if (m_complete) { + if (playing) { + if (!m_autoLoad && !m_loaded) { + m_playerControl->setMedia(m_source, 0); + m_playerControl->setPosition(m_position); + m_loaded = true; + } + + m_runningCount = m_loopCount - 1; + + if (!m_paused) + m_playerControl->play(); + else + m_playerControl->pause(); + } else { + m_playerControl->stop(); + } + } else { + m_playing = playing; + emit playingChanged(); + } +} + +bool QDeclarativeMediaBase::isPaused() const +{ + return m_paused; +} + +void QDeclarativeMediaBase::setPaused(bool paused) +{ + if (m_paused == paused) + return; + + if (m_complete && m_playing) { + if (!m_autoLoad && !m_loaded) { + m_playerControl->setMedia(m_source, 0); + m_playerControl->setPosition(m_position); + m_loaded = true; + } + + if (!paused) + m_playerControl->play(); + else + m_playerControl->pause(); + } else { + m_paused = paused; + emit pausedChanged(); + } +} + +int QDeclarativeMediaBase::duration() const +{ + return !m_complete ? 0 : m_playerControl->duration(); +} + +int QDeclarativeMediaBase::position() const +{ + return !m_complete ? m_position : m_playerControl->position(); +} + +void QDeclarativeMediaBase::setPosition(int position) +{ + if (this->position() == position) + return; + + m_position = position; + if (m_complete) + m_playerControl->setPosition(m_position); + else + emit positionChanged(); +} + +qreal QDeclarativeMediaBase::volume() const +{ + return !m_complete ? m_vol : qreal(m_playerControl->volume()) / 100; +} + +void QDeclarativeMediaBase::setVolume(qreal volume) +{ + if (volume < 0 || volume > 1) { + qmlInfo(m_qmlObject) << m_qmlObject->tr("volume should be between 0.0 and 1.0"); + return; + } + + if (m_vol == volume) + return; + + m_vol = volume; + + if (m_complete) + m_playerControl->setVolume(qRound(volume * 100)); + else + emit volumeChanged(); +} + +bool QDeclarativeMediaBase::isMuted() const +{ + return !m_complete ? m_muted : m_playerControl->isMuted(); +} + +void QDeclarativeMediaBase::setMuted(bool muted) +{ + if (m_muted == muted) + return; + + m_muted = muted; + + if (m_complete) + m_playerControl->setMuted(muted); + else + emit mutedChanged(); +} + +qreal QDeclarativeMediaBase::bufferProgress() const +{ + return !m_complete ? 0 : qreal(m_playerControl->bufferStatus()) / 100; +} + +bool QDeclarativeMediaBase::isSeekable() const +{ + return !m_complete ? false : m_playerControl->isSeekable(); +} + +qreal QDeclarativeMediaBase::playbackRate() const +{ + return m_playbackRate; +} + +void QDeclarativeMediaBase::setPlaybackRate(qreal rate) +{ + if (m_playbackRate == rate) + return; + + m_playbackRate = rate; + + if (m_complete) + m_playerControl->setPlaybackRate(m_playbackRate); + else + emit playbackRateChanged(); +} + +QString QDeclarativeMediaBase::errorString() const +{ + return m_errorString; +} + +QDeclarativeMediaMetaData *QDeclarativeMediaBase::metaData() const +{ + return m_metaData.data(); +} + +QT_END_NAMESPACE + diff --git a/src/imports/multimedia/qdeclarativemediabase_p.h b/src/imports/multimedia/qdeclarativemediabase_p.h new file mode 100644 index 000000000..ffe091614 --- /dev/null +++ b/src/imports/multimedia/qdeclarativemediabase_p.h @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEMEDIABASE_P_H +#define QDECLARATIVEMEDIABASE_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 +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMediaPlayerControl; +class QMediaService; +class QMediaServiceProvider; +class QMetaDataReaderControl; +class QDeclarativeMediaBaseAnimation; +class QDeclarativeMediaMetaData; + +class QDeclarativeMediaBase +{ +public: + enum Loop { + INFINITE = -1 + }; + + QDeclarativeMediaBase(); + virtual ~QDeclarativeMediaBase(); + + QUrl source() const; + void setSource(const QUrl &url); + + bool isAutoLoad() const; + void setAutoLoad(bool autoLoad); + + int loopCount() const; + void setLoopCount(int loopCount); + + bool isPlaying() const; + void setPlaying(bool playing); + + bool isPaused() const; + void setPaused(bool paused); + + int duration() const; + + int position() const; + void setPosition(int position); + + qreal volume() const; + void setVolume(qreal volume); + + bool isMuted() const; + void setMuted(bool muted); + + qreal bufferProgress() const; + + bool isSeekable() const; + + qreal playbackRate() const; + void setPlaybackRate(qreal rate); + + QString errorString() const; + + QDeclarativeMediaMetaData *metaData() const; + + void _q_statusChanged(); + + void _q_metaDataChanged(); + + void componentComplete(); + +protected: + void shutdown(); + + void setObject(QObject *object); + + virtual void sourceChanged() = 0; + virtual void autoLoadChanged() = 0; + virtual void playingChanged() = 0; + virtual void pausedChanged() = 0; + virtual void loopCountChanged() = 0; + + virtual void started() = 0; + virtual void resumed() = 0; + virtual void paused() = 0; + virtual void stopped() = 0; + + virtual void statusChanged() = 0; + + virtual void durationChanged() = 0; + virtual void positionChanged() = 0; + + virtual void volumeChanged() = 0; + virtual void mutedChanged() = 0; + + virtual void bufferProgressChanged() = 0; + + virtual void seekableChanged() = 0; + virtual void playbackRateChanged() = 0; + + virtual void errorChanged() = 0; + + bool m_paused; + bool m_playing; + bool m_autoLoad; + bool m_loaded; + bool m_muted; + bool m_complete; + int m_loopCount; + int m_runningCount; + int m_position; + qreal m_vol; + qreal m_playbackRate; + QMediaService *m_mediaService; + QMediaPlayerControl *m_playerControl; + + QObject *m_qmlObject; + QMediaObject *m_mediaObject; + QMediaServiceProvider *m_mediaProvider; + QMetaDataReaderControl *m_metaDataControl; + QDeclarativeMediaBaseAnimation *m_animation; + QScopedPointer m_metaData; + + QMediaPlayer::MediaStatus m_status; + QMediaPlayer::Error m_error; + QString m_errorString; + QUrl m_source; + + friend class QDeclarativeMediaBaseAnimation; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/imports/multimedia/qdeclarativemediametadata_p.h b/src/imports/multimedia/qdeclarativemediametadata_p.h new file mode 100644 index 000000000..ca28e6e07 --- /dev/null +++ b/src/imports/multimedia/qdeclarativemediametadata_p.h @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEMEDIAMETADATA_P_H +#define QDECLARATIVEMEDIAMETADATA_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 + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QDeclarativeMediaMetaData : public QObject +{ + Q_OBJECT + Q_PROPERTY(QVariant title READ title NOTIFY metaDataChanged) + Q_PROPERTY(QVariant subTitle READ subTitle NOTIFY metaDataChanged) + Q_PROPERTY(QVariant author READ author NOTIFY metaDataChanged) + Q_PROPERTY(QVariant comment READ comment NOTIFY metaDataChanged) + Q_PROPERTY(QVariant description READ description NOTIFY metaDataChanged) + Q_PROPERTY(QVariant category READ category NOTIFY metaDataChanged) + Q_PROPERTY(QVariant genre READ genre NOTIFY metaDataChanged) + Q_PROPERTY(QVariant year READ year NOTIFY metaDataChanged) + Q_PROPERTY(QVariant date READ date NOTIFY metaDataChanged) + Q_PROPERTY(QVariant userRating READ userRating NOTIFY metaDataChanged) + Q_PROPERTY(QVariant keywords READ keywords NOTIFY metaDataChanged) + Q_PROPERTY(QVariant language READ language NOTIFY metaDataChanged) + Q_PROPERTY(QVariant publisher READ publisher NOTIFY metaDataChanged) + Q_PROPERTY(QVariant copyright READ copyright NOTIFY metaDataChanged) + Q_PROPERTY(QVariant parentalRating READ parentalRating NOTIFY metaDataChanged) + Q_PROPERTY(QVariant ratingOrganisation READ ratingOrganisation NOTIFY metaDataChanged) + Q_PROPERTY(QVariant size READ size NOTIFY metaDataChanged) + Q_PROPERTY(QVariant mediaType READ mediaType NOTIFY metaDataChanged) + Q_PROPERTY(QVariant duration READ duration NOTIFY metaDataChanged) + Q_PROPERTY(QVariant audioBitRate READ audioBitRate NOTIFY metaDataChanged) + Q_PROPERTY(QVariant audioCodec READ audioCodec NOTIFY metaDataChanged) + Q_PROPERTY(QVariant averageLevel READ averageLevel NOTIFY metaDataChanged) + Q_PROPERTY(QVariant channelCount READ channelCount NOTIFY metaDataChanged) + Q_PROPERTY(QVariant peakValue READ peakValue NOTIFY metaDataChanged) + Q_PROPERTY(QVariant sampleRate READ sampleRate NOTIFY metaDataChanged) + Q_PROPERTY(QVariant albumTitle READ albumTitle NOTIFY metaDataChanged) + Q_PROPERTY(QVariant albumArtist READ albumArtist NOTIFY metaDataChanged) + Q_PROPERTY(QVariant contributingArtist READ contributingArtist NOTIFY metaDataChanged) + Q_PROPERTY(QVariant composer READ composer NOTIFY metaDataChanged) + Q_PROPERTY(QVariant conductor READ conductor NOTIFY metaDataChanged) + Q_PROPERTY(QVariant lyrics READ lyrics NOTIFY metaDataChanged) + Q_PROPERTY(QVariant mood READ mood NOTIFY metaDataChanged) + Q_PROPERTY(QVariant trackNumber READ trackNumber NOTIFY metaDataChanged) + Q_PROPERTY(QVariant trackCount READ trackCount NOTIFY metaDataChanged) + Q_PROPERTY(QVariant coverArtUrlSmall READ coverArtUrlSmall NOTIFY metaDataChanged) + Q_PROPERTY(QVariant coverArtUrlLarge READ coverArtUrlLarge NOTIFY metaDataChanged) + Q_PROPERTY(QVariant resolution READ resolution NOTIFY metaDataChanged) + Q_PROPERTY(QVariant pixelAspectRatio READ pixelAspectRatio NOTIFY metaDataChanged) + Q_PROPERTY(QVariant videoFrameRate READ videoFrameRate NOTIFY metaDataChanged) + Q_PROPERTY(QVariant videoBitRate READ videoBitRate NOTIFY metaDataChanged) + Q_PROPERTY(QVariant videoCodec READ videoCodec NOTIFY metaDataChanged) + Q_PROPERTY(QVariant posterUrl READ posterUrl NOTIFY metaDataChanged) + Q_PROPERTY(QVariant chapterNumber READ chapterNumber NOTIFY metaDataChanged) + Q_PROPERTY(QVariant director READ director NOTIFY metaDataChanged) + Q_PROPERTY(QVariant leadPerformer READ leadPerformer NOTIFY metaDataChanged) + Q_PROPERTY(QVariant writer READ writer NOTIFY metaDataChanged) +public: + QDeclarativeMediaMetaData(QMetaDataReaderControl *control, QObject *parent = 0) + : QObject(parent) + , m_control(control) + { + } + + QVariant title() const { return m_control->metaData(QtMultimediaKit::Title); } + QVariant subTitle() const { return m_control->metaData(QtMultimediaKit::SubTitle); } + QVariant author() const { return m_control->metaData(QtMultimediaKit::Author); } + QVariant comment() const { return m_control->metaData(QtMultimediaKit::Comment); } + QVariant description() const { return m_control->metaData(QtMultimediaKit::Description); } + QVariant category() const { return m_control->metaData(QtMultimediaKit::Category); } + QVariant genre() const { return m_control->metaData(QtMultimediaKit::Genre); } + QVariant year() const { return m_control->metaData(QtMultimediaKit::Year); } + QVariant date() const { return m_control->metaData(QtMultimediaKit::Date); } + QVariant userRating() const { return m_control->metaData(QtMultimediaKit::UserRating); } + QVariant keywords() const { return m_control->metaData(QtMultimediaKit::Keywords); } + QVariant language() const { return m_control->metaData(QtMultimediaKit::Language); } + QVariant publisher() const { return m_control->metaData(QtMultimediaKit::Publisher); } + QVariant copyright() const { return m_control->metaData(QtMultimediaKit::Copyright); } + QVariant parentalRating() const { return m_control->metaData(QtMultimediaKit::ParentalRating); } + QVariant ratingOrganisation() const { + return m_control->metaData(QtMultimediaKit::RatingOrganisation); } + QVariant size() const { return m_control->metaData(QtMultimediaKit::Size); } + QVariant mediaType() const { return m_control->metaData(QtMultimediaKit::MediaType); } + QVariant duration() const { return m_control->metaData(QtMultimediaKit::Duration); } + QVariant audioBitRate() const { return m_control->metaData(QtMultimediaKit::AudioBitRate); } + QVariant audioCodec() const { return m_control->metaData(QtMultimediaKit::AudioCodec); } + QVariant averageLevel() const { return m_control->metaData(QtMultimediaKit::AverageLevel); } + QVariant channelCount() const { return m_control->metaData(QtMultimediaKit::ChannelCount); } + QVariant peakValue() const { return m_control->metaData(QtMultimediaKit::PeakValue); } + QVariant sampleRate() const { return m_control->metaData(QtMultimediaKit::SampleRate); } + QVariant albumTitle() const { return m_control->metaData(QtMultimediaKit::AlbumTitle); } + QVariant albumArtist() const { return m_control->metaData(QtMultimediaKit::AlbumArtist); } + QVariant contributingArtist() const { + return m_control->metaData(QtMultimediaKit::ContributingArtist); } + QVariant composer() const { return m_control->metaData(QtMultimediaKit::Composer); } + QVariant conductor() const { return m_control->metaData(QtMultimediaKit::Conductor); } + QVariant lyrics() const { return m_control->metaData(QtMultimediaKit::Lyrics); } + QVariant mood() const { return m_control->metaData(QtMultimediaKit::Mood); } + QVariant trackNumber() const { return m_control->metaData(QtMultimediaKit::TrackNumber); } + QVariant trackCount() const { return m_control->metaData(QtMultimediaKit::TrackCount); } + QVariant coverArtUrlSmall() const { + return m_control->metaData(QtMultimediaKit::CoverArtUrlSmall); } + QVariant coverArtUrlLarge() const { + return m_control->metaData(QtMultimediaKit::CoverArtUrlLarge); } + QVariant resolution() const { return m_control->metaData(QtMultimediaKit::Resolution); } + QVariant pixelAspectRatio() const { + return m_control->metaData(QtMultimediaKit::PixelAspectRatio); } + QVariant videoFrameRate() const { return m_control->metaData(QtMultimediaKit::VideoFrameRate); } + QVariant videoBitRate() const { return m_control->metaData(QtMultimediaKit::VideoBitRate); } + QVariant videoCodec() const { return m_control->metaData(QtMultimediaKit::VideoCodec); } + QVariant posterUrl() const { return m_control->metaData(QtMultimediaKit::PosterUrl); } + QVariant chapterNumber() const { return m_control->metaData(QtMultimediaKit::ChapterNumber); } + QVariant director() const { return m_control->metaData(QtMultimediaKit::Director); } + QVariant leadPerformer() const { return m_control->metaData(QtMultimediaKit::LeadPerformer); } + QVariant writer() const { return m_control->metaData(QtMultimediaKit::Writer); } + +Q_SIGNALS: + void metaDataChanged(); + +private: + QMetaDataReaderControl *m_control; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QT_PREPEND_NAMESPACE(QDeclarativeMediaMetaData)) + +QT_END_HEADER + +#endif diff --git a/src/imports/multimedia/qdeclarativevideo.cpp b/src/imports/multimedia/qdeclarativevideo.cpp new file mode 100644 index 000000000..af87fe1bd --- /dev/null +++ b/src/imports/multimedia/qdeclarativevideo.cpp @@ -0,0 +1,951 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativevideo_p.h" + +#include +#include +#include +#include + + +QT_BEGIN_NAMESPACE + + +void QDeclarativeVideo::_q_nativeSizeChanged(const QSizeF &size) +{ + setImplicitWidth(size.width()); + setImplicitHeight(size.height()); +} + +void QDeclarativeVideo::_q_error(int errorCode, const QString &errorString) +{ + m_error = QMediaPlayer::Error(errorCode); + m_errorString = errorString; + + emit error(Error(errorCode), errorString); + emit errorChanged(); +} + + +/*! + \qmlclass Video QDeclarativeVideo + \brief The Video element allows you to add videos to a scene. + \inherits Item + \ingroup qml-multimedia + + This element is part of the \bold{QtMultimediaKit 1.1} module. + + \qml + import Qt 4.7 + import QtMultimediaKit 1.1 + + Video { + id: video + width : 800 + height : 600 + source: "video.avi" + + MouseArea { + anchors.fill: parent + onClicked: { + video.play() + } + } + + focus: true + Keys.onSpacePressed: video.paused = !video.paused + Keys.onLeftPressed: video.position -= 5000 + Keys.onRightPressed: video.position += 5000 + } + \endqml + + The Video item supports untransformed, stretched, and uniformly scaled video presentation. + For a description of stretched uniformly scaled presentation, see the \l fillMode property + description. + + The Video item is only visible when the \l hasVideo property is true and the video is playing. + + \sa Audio +*/ + +/*! + \internal + \class QDeclarativeVideo + \brief The QDeclarativeVideo class provides a video item that you can add to a QDeclarativeView. +*/ + +QDeclarativeVideo::QDeclarativeVideo(QDeclarativeItem *parent) + : QDeclarativeItem(parent) + , m_graphicsItem(0) + +{ +} + +QDeclarativeVideo::~QDeclarativeVideo() +{ + shutdown(); + + delete m_graphicsItem; +} + +/*! + \qmlproperty url Video::source + + This property holds the source URL of the media. +*/ + +/*! + \qmlproperty url Video::autoLoad + + This property indicates if loading of media should begin immediately. + + Defaults to true, if false media will not be loaded until playback is started. +*/ + +/*! + \qmlproperty bool Video::playing + + This property holds whether the media is playing. + + Defaults to false, and can be set to true to start playback. +*/ + +/*! + \qmlproperty bool Video::paused + + This property holds whether the media is paused. + + Defaults to false, and can be set to true to pause playback. +*/ + +/*! + \qmlsignal Video::onStarted() + + This handler is called when playback is started. +*/ + +/*! + \qmlsignal Video::onResumed() + + This handler is called when playback is resumed from the paused state. +*/ + +/*! + \qmlsignal Video::onPaused() + + This handler is called when playback is paused. +*/ + +/*! + \qmlsignal Video::onStopped() + + This handler is called when playback is stopped. +*/ + +/*! + \qmlproperty enumeration Video::status + + This property holds the status of media loading. It can be one of: + + \list + \o NoMedia - no media has been set. + \o Loading - the media is currently being loaded. + \o Loaded - the media has been loaded. + \o Buffering - the media is buffering data. + \o Stalled - playback has been interrupted while the media is buffering data. + \o Buffered - the media has buffered data. + \o EndOfMedia - the media has played to the end. + \o InvalidMedia - the media cannot be played. + \o UnknownStatus - the status of the media is cannot be determined. + \endlist +*/ + +QDeclarativeVideo::Status QDeclarativeVideo::status() const +{ + return Status(m_status); +} + +/*! + \qmlproperty int Video::duration + + This property holds the duration of the media in milliseconds. + + If the media doesn't have a fixed duration (a live stream for example) this will be 0. +*/ + +/*! + \qmlproperty int Video::position + + This property holds the current playback position in milliseconds. +*/ + +/*! + \qmlproperty real Video::volume + + This property holds the volume of the audio output, from 0.0 (silent) to 1.0 (maximum volume). +*/ + +/*! + \qmlproperty bool Video::muted + + This property holds whether the audio output is muted. +*/ + +/*! + \qmlproperty bool Video::hasAudio + + This property holds whether the media contains audio. +*/ + +bool QDeclarativeVideo::hasAudio() const +{ + return !m_complete ? false : m_playerControl->isAudioAvailable(); +} + +/*! + \qmlproperty bool Video::hasVideo + + This property holds whether the media contains video. +*/ + +bool QDeclarativeVideo::hasVideo() const +{ + return !m_complete ? false : m_playerControl->isVideoAvailable(); +} + +/*! + \qmlproperty real Video::bufferProgress + + This property holds how much of the data buffer is currently filled, from 0.0 (empty) to 1.0 + (full). +*/ + +/*! + \qmlproperty bool Video::seekable + + This property holds whether position of the video can be changed. +*/ + +/*! + \qmlproperty real Video::playbackRate + + This property holds the rate at which video is played at as a multiple of the normal rate. +*/ + +/*! + \qmlproperty enumeration Video::error + + This property holds the error state of the video. It can be one of: + + \list + \o NoError - there is no current error. + \o ResourceError - the video cannot be played due to a problem allocating resources. + \o FormatError - the video format is not supported. + \o NetworkError - the video cannot be played due to network issues. + \o AccessDenied - the video cannot be played due to insufficient permissions. + \o ServiceMissing - the video cannot be played because the media service could not be + instantiated. + \endlist +*/ + + +QDeclarativeVideo::Error QDeclarativeVideo::error() const +{ + return Error(m_error); +} + +/*! + \qmlproperty string Video::errorString + + This property holds a string describing the current error condition in more detail. +*/ + +/*! + \qmlsignal Video::onError(error, errorString) + + This handler is called when an \l {QMediaPlayer::Error}{error} has + occurred. The errorString parameter may contain more detailed + information about the error. +*/ + +/*! + \qmlproperty enumeration Video::fillMode + + Set this property to define how the video is scaled to fit the target area. + + \list + \o Stretch - the video is scaled to fit. + \o PreserveAspectFit - the video is scaled uniformly to fit without cropping + \o PreserveAspectCrop - the video is scaled uniformly to fill, cropping if necessary + \endlist + + The default fill mode is PreserveAspectFit. +*/ + +QDeclarativeVideo::FillMode QDeclarativeVideo::fillMode() const +{ + return FillMode(m_graphicsItem->aspectRatioMode()); +} + +void QDeclarativeVideo::setFillMode(FillMode mode) +{ + m_graphicsItem->setAspectRatioMode(Qt::AspectRatioMode(mode)); +} + +/*! + \qmlmethod Video::play() + + Starts playback of the media. + + Sets the \l playing property to true, and the \l paused property to false. +*/ + +void QDeclarativeVideo::play() +{ + if (!m_complete) + return; + + setPaused(false); + setPlaying(true); +} + +/*! + \qmlmethod Video::pause() + + Pauses playback of the media. + + Sets the \l playing and \l paused properties to true. +*/ + +void QDeclarativeVideo::pause() +{ + if (!m_complete) + return; + + setPaused(true); + setPlaying(true); +} + +/*! + \qmlmethod Video::stop() + + Stops playback of the media. + + Sets the \l playing and \l paused properties to false. +*/ + +void QDeclarativeVideo::stop() +{ + if (!m_complete) + return; + + setPlaying(false); + setPaused(false); +} + +void QDeclarativeVideo::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) +{ +} + +void QDeclarativeVideo::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + m_graphicsItem->setSize(newGeometry.size()); + + QDeclarativeItem::geometryChanged(newGeometry, oldGeometry); +} + +void QDeclarativeVideo::classBegin() +{ + m_graphicsItem = new QGraphicsVideoItem(this); + connect(m_graphicsItem, SIGNAL(nativeSizeChanged(QSizeF)), + this, SLOT(_q_nativeSizeChanged(QSizeF))); + + setObject(this); + + if (m_mediaService) { + connect(m_playerControl, SIGNAL(audioAvailableChanged(bool)), + this, SIGNAL(hasAudioChanged())); + connect(m_playerControl, SIGNAL(videoAvailableChanged(bool)), + this, SIGNAL(hasVideoChanged())); + + m_mediaObject->bind(m_graphicsItem); + } +} + +void QDeclarativeVideo::componentComplete() +{ + QDeclarativeMediaBase::componentComplete(); +} + +QT_END_NAMESPACE + +// *************************************** +// Documentation for meta-data properties. +// *************************************** + +/*! + \qmlproperty variant Video::metaData.title + + This property holds the tile of the media. + + \sa {QtMultimediaKit::Title} +*/ + +/*! + \qmlproperty variant Video::metaData.subTitle + + This property holds the sub-title of the media. + + \sa {QtMultimediaKit::SubTitle} +*/ + +/*! + \qmlproperty variant Video::metaData.author + + This property holds the author of the media. + + \sa {QtMultimediaKit::Author} +*/ + +/*! + \qmlproperty variant Video::metaData.comment + + This property holds a user comment about the media. + + \sa {QtMultimediaKit::Comment} +*/ + +/*! + \qmlproperty variant Video::metaData.description + + This property holds a description of the media. + + \sa {QtMultimediaKit::Description} +*/ + +/*! + \qmlproperty variant Video::metaData.category + + This property holds the category of the media + + \sa {QtMultimediaKit::Category} +*/ + +/*! + \qmlproperty variant Video::metaData.genre + + This property holds the genre of the media. + + \sa {QtMultimediaKit::Genre} +*/ + +/*! + \qmlproperty variant Video::metaData.year + + This property holds the year of release of the media. + + \sa {QtMultimediaKit::Year} +*/ + +/*! + \qmlproperty variant Video::metaData.date + + This property holds the date of the media. + + \sa {QtMultimediaKit::Date} +*/ + +/*! + \qmlproperty variant Video::metaData.userRating + + This property holds a user rating of the media in the range of 0 to 100. + + \sa {QtMultimediaKit::UserRating} +*/ + +/*! + \qmlproperty variant Video::metaData.keywords + + This property holds a list of keywords describing the media. + + \sa {QtMultimediaKit::Keywords} +*/ + +/*! + \qmlproperty variant Video::metaData.language + + This property holds the language of the media, as an ISO 639-2 code. + + \sa {QtMultimediaKit::Language} +*/ + +/*! + \qmlproperty variant Video::metaData.publisher + + This property holds the publisher of the media. + + \sa {QtMultimediaKit::Publisher} +*/ + +/*! + \qmlproperty variant Video::metaData.copyright + + This property holds the media's copyright notice. + + \sa {QtMultimediaKit::Copyright} +*/ + +/*! + \qmlproperty variant Video::metaData.parentalRating + + This property holds the parental rating of the media. + + \sa {QtMultimediaKit::ParentalRating} +*/ + +/*! + \qmlproperty variant Video::metaData.ratingOrganisation + + This property holds the name of the rating organisation responsible for the + parental rating of the media. + + \sa {QtMultimediaKit::RatingOrganisation} +*/ + +/*! + \qmlproperty variant Video::metaData.size + + This property property holds the size of the media in bytes. + + \sa {QtMultimediaKit::Size} +*/ + +/*! + \qmlproperty variant Video::metaData.mediaType + + This property holds the type of the media. + + \sa {QtMultimediaKit::MediaType} +*/ + +/*! + \qmlproperty variant Video::metaData.audioBitRate + + This property holds the bit rate of the media's audio stream ni bits per + second. + + \sa {QtMultimediaKit::AudioBitRate} +*/ + +/*! + \qmlproperty variant Video::metaData.audioCodec + + This property holds the encoding of the media audio stream. + + \sa {QtMultimediaKit::AudioCodec} +*/ + +/*! + \qmlproperty variant Video::metaData.averageLevel + + This property holds the average volume level of the media. + + \sa {QtMultimediaKit::AverageLevel} +*/ + +/*! + \qmlproperty variant Video::metaData.channelCount + + This property holds the number of channels in the media's audio stream. + + \sa {QtMultimediaKit::ChannelCount} +*/ + +/*! + \qmlproperty variant Video::metaData.peakValue + + This property holds the peak volume of media's audio stream. + + \sa {QtMultimediaKit::PeakValue} +*/ + +/*! + \qmlproperty variant Video::metaData.sampleRate + + This property holds the sample rate of the media's audio stream in hertz. + + \sa {QtMultimediaKit::SampleRate} +*/ + +/*! + \qmlproperty variant Video::metaData.albumTitle + + This property holds the title of the album the media belongs to. + + \sa {QtMultimediaKit::AlbumTitle} +*/ + +/*! + \qmlproperty variant Video::metaData.albumArtist + + This property holds the name of the principal artist of the album the media + belongs to. + + \sa {QtMultimediaKit::AlbumArtist} +*/ + +/*! + \qmlproperty variant Video::metaData.contributingArtist + + This property holds the names of artists contributing to the media. + + \sa {QtMultimediaKit::ContributingArtist} +*/ + +/*! + \qmlproperty variant Video::metaData.composer + + This property holds the composer of the media. + + \sa {QtMultimediaKit::Composer} +*/ + +/*! + \qmlproperty variant Video::metaData.conductor + + This property holds the conductor of the media. + + \sa {QtMultimediaKit::Conductor} +*/ + +/*! + \qmlproperty variant Video::metaData.lyrics + + This property holds the lyrics to the media. + + \sa {QtMultimediaKit::Lyrics} +*/ + +/*! + \qmlproperty variant Video::metaData.mood + + This property holds the mood of the media. + + \sa {QtMultimediaKit::Mood} +*/ + +/*! + \qmlproperty variant Video::metaData.trackNumber + + This property holds the track number of the media. + + \sa {QtMultimediaKit::TrackNumber} +*/ + +/*! + \qmlproperty variant Video::metaData.trackCount + + This property holds the number of track on the album containing the media. + + \sa {QtMultimediaKit::TrackNumber} +*/ + +/*! + \qmlproperty variant Video::metaData.coverArtUrlSmall + + This property holds the URL of a small cover art image. + + \sa {QtMultimediaKit::CoverArtUrlSmall} +*/ + +/*! + \qmlproperty variant Video::metaData.coverArtUrlLarge + + This property holds the URL of a large cover art image. + + \sa {QtMultimediaKit::CoverArtUrlLarge} +*/ + +/*! + \qmlproperty variant Video::metaData.resolution + + This property holds the dimension of an image or video. + + \sa {QtMultimediaKit::Resolution} +*/ + +/*! + \qmlproperty variant Video::metaData.pixelAspectRatio + + This property holds the pixel aspect ratio of an image or video. + + \sa {QtMultimediaKit::PixelAspectRatio} +*/ + +/*! + \qmlproperty variant Video::metaData.videoFrameRate + + This property holds the frame rate of the media's video stream. + + \sa {QtMultimediaKit::VideoFrameRate} +*/ + +/*! + \qmlproperty variant Video::metaData.videoBitRate + + This property holds the bit rate of the media's video stream in bits per + second. + + \sa {QtMultimediaKit::VideoBitRate} +*/ + +/*! + \qmlproperty variant Video::metaData.videoCodec + + This property holds the encoding of the media's video stream. + + \sa {QtMultimediaKit::VideoCodec} +*/ + +/*! + \qmlproperty variant Video::metaData.posterUrl + + This property holds the URL of a poster image. + + \sa {QtMultimediaKit::PosterUrl} +*/ + +/*! + \qmlproperty variant Video::metaData.chapterNumber + + This property holds the chapter number of the media. + + \sa {QtMultimediaKit::ChapterNumber} +*/ + +/*! + \qmlproperty variant Video::metaData.director + + This property holds the director of the media. + + \sa {QtMultimediaKit::Director} +*/ + +/*! + \qmlproperty variant Video::metaData.leadPerformer + + This property holds the lead performer in the media. + + \sa {QtMultimediaKit::LeadPerformer} +*/ + +/*! + \qmlproperty variant Video::metaData.writer + + This property holds the writer of the media. + + \sa {QtMultimediaKit::Writer} +*/ + +// The remaining properties are related to photos, and are technically +// available but will certainly never have values. +#ifndef Q_QDOC + +/*! + \qmlproperty variant Video::metaData.cameraManufacturer + + \sa {QtMultimediaKit::CameraManufacturer} +*/ + +/*! + \qmlproperty variant Video::metaData.cameraModel + + \sa {QtMultimediaKit::CameraModel} +*/ + +/*! + \qmlproperty variant Video::metaData.event + + \sa {QtMultimediaKit::Event} +*/ + +/*! + \qmlproperty variant Video::metaData.subject + + \sa {QtMultimediaKit::Subject} +*/ + +/*! + \qmlproperty variant Video::metaData.orientation + + \sa {QtMultimediaKit::Orientation} +*/ + +/*! + \qmlproperty variant Video::metaData.exposureTime + + \sa {QtMultimediaKit::ExposureTime} +*/ + +/*! + \qmlproperty variant Video::metaData.fNumber + + \sa {QtMultimediaKit::FNumber} +*/ + +/*! + \qmlproperty variant Video::metaData.exposureProgram + + \sa {QtMultimediaKit::ExposureProgram} +*/ + +/*! + \qmlproperty variant Video::metaData.isoSpeedRatings + + \sa {QtMultimediaKit::ISOSpeedRatings} +*/ + +/*! + \qmlproperty variant Video::metaData.exposureBiasValue + + \sa {QtMultimediaKit::ExposureBiasValue} +*/ + +/*! + \qmlproperty variant Video::metaData.dateTimeDigitized + + \sa {QtMultimediaKit::DateTimeDigitized} +*/ + +/*! + \qmlproperty variant Video::metaData.subjectDistance + + \sa {QtMultimediaKit::SubjectDistance} +*/ + +/*! + \qmlproperty variant Video::metaData.meteringMode + + \sa {QtMultimediaKit::MeteringMode} +*/ + +/*! + \qmlproperty variant Video::metaData.lightSource + + \sa {QtMultimediaKit::LightSource} +*/ + +/*! + \qmlproperty variant Video::metaData.flash + + \sa {QtMultimediaKit::Flash} +*/ + +/*! + \qmlproperty variant Video::metaData.focalLength + + \sa {QtMultimediaKit::FocalLength} +*/ + +/*! + \qmlproperty variant Video::metaData.exposureMode + + \sa {QtMultimediaKit::ExposureMode} +*/ + +/*! + \qmlproperty variant Video::metaData.whiteBalance + + \sa {QtMultimediaKit::WhiteBalance} +*/ + +/*! + \qmlproperty variant Video::metaData.DigitalZoomRatio + + \sa {QtMultimediaKit::DigitalZoomRatio} +*/ + +/*! + \qmlproperty variant Video::metaData.focalLengthIn35mmFilm + + \sa {QtMultimediaKit::FocalLengthIn35mmFile} +*/ + +/*! + \qmlproperty variant Video::metaData.sceneCaptureType + + \sa {QtMultimediaKit::SceneCaptureType} +*/ + +/*! + \qmlproperty variant Video::metaData.gainControl + + \sa {QtMultimediaKit::GainControl} +*/ + +/*! + \qmlproperty variant Video::metaData.contrast + + \sa {QtMultimediaKit::contrast} +*/ + +/*! + \qmlproperty variant Video::metaData.saturation + + \sa {QtMultimediaKit::Saturation} +*/ + +/*! + \qmlproperty variant Video::metaData.sharpness + + \sa {QtMultimediaKit::Sharpness} +*/ + +/*! + \qmlproperty variant Video::metaData.deviceSettingDescription + + \sa {QtMultimediaKit::DeviceSettingDescription} +*/ + +#endif + +#include "moc_qdeclarativevideo_p.cpp" diff --git a/src/imports/multimedia/qdeclarativevideo_p.h b/src/imports/multimedia/qdeclarativevideo_p.h new file mode 100644 index 000000000..115ef9d10 --- /dev/null +++ b/src/imports/multimedia/qdeclarativevideo_p.h @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEVIDEO_H +#define QDECLARATIVEVIDEO_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 "qdeclarativemediabase_p.h" + +#include + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QTimerEvent; +class QVideoSurfaceFormat; + + +class QDeclarativeVideo : public QDeclarativeItem, public QDeclarativeMediaBase +{ + Q_OBJECT + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(bool autoLoad READ isAutoLoad WRITE setAutoLoad NOTIFY autoLoadChanged) + Q_PROPERTY(bool playing READ isPlaying WRITE setPlaying NOTIFY playingChanged) + Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) + Q_PROPERTY(int duration READ duration NOTIFY durationChanged) + Q_PROPERTY(int position READ position WRITE setPosition NOTIFY positionChanged) + Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) + Q_PROPERTY(bool hasAudio READ hasAudio NOTIFY hasAudioChanged) + Q_PROPERTY(bool hasVideo READ hasVideo NOTIFY hasVideoChanged) + Q_PROPERTY(int bufferProgress READ bufferProgress NOTIFY bufferProgressChanged) + Q_PROPERTY(bool seekable READ isSeekable NOTIFY seekableChanged) + Q_PROPERTY(qreal playbackRate READ playbackRate WRITE setPlaybackRate NOTIFY playbackRateChanged) + Q_PROPERTY(Error error READ error NOTIFY errorChanged) + Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged) + Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode) + Q_PROPERTY(QDeclarativeMediaMetaData *metaData READ metaData CONSTANT) + Q_ENUMS(FillMode) + Q_ENUMS(Status) + Q_ENUMS(Error) +public: + enum FillMode + { + Stretch = Qt::IgnoreAspectRatio, + PreserveAspectFit = Qt::KeepAspectRatio, + PreserveAspectCrop = Qt::KeepAspectRatioByExpanding + }; + + enum Status + { + UnknownStatus = QMediaPlayer::UnknownMediaStatus, + NoMedia = QMediaPlayer::NoMedia, + Loading = QMediaPlayer::LoadingMedia, + Loaded = QMediaPlayer::LoadedMedia, + Stalled = QMediaPlayer::StalledMedia, + Buffering = QMediaPlayer::BufferingMedia, + Buffered = QMediaPlayer::BufferedMedia, + EndOfMedia = QMediaPlayer::EndOfMedia, + InvalidMedia = QMediaPlayer::InvalidMedia + }; + + enum Error + { + NoError = QMediaPlayer::NoError, + ResourceError = QMediaPlayer::ResourceError, + FormatError = QMediaPlayer::FormatError, + NetworkError = QMediaPlayer::NetworkError, + AccessDenied = QMediaPlayer::AccessDeniedError, + ServiceMissing = QMediaPlayer::ServiceMissingError + }; + + QDeclarativeVideo(QDeclarativeItem *parent = 0); + ~QDeclarativeVideo(); + + bool hasAudio() const; + bool hasVideo() const; + + FillMode fillMode() const; + void setFillMode(FillMode mode); + + Status status() const; + Error error() const; + + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); + + void classBegin(); + void componentComplete(); + +public Q_SLOTS: + void play(); + void pause(); + void stop(); + +Q_SIGNALS: + void sourceChanged(); + void autoLoadChanged(); + void playingChanged(); + void pausedChanged(); + void loopCountChanged(); + + void started(); + void resumed(); + void paused(); + void stopped(); + + void statusChanged(); + + void durationChanged(); + void positionChanged(); + + void volumeChanged(); + void mutedChanged(); + void hasAudioChanged(); + void hasVideoChanged(); + + void bufferProgressChanged(); + + void seekableChanged(); + void playbackRateChanged(); + + void errorChanged(); + void error(QDeclarativeVideo::Error error, const QString &errorString); + +protected: + void geometryChanged(const QRectF &geometry, const QRectF &); + +private Q_SLOTS: + void _q_nativeSizeChanged(const QSizeF &size); + void _q_error(int, const QString &); + +private: + Q_DISABLE_COPY(QDeclarativeVideo) + + QGraphicsVideoItem *m_graphicsItem; + + Q_PRIVATE_SLOT(mediaBase(), void _q_statusChanged()) + + inline QDeclarativeMediaBase *mediaBase() { return this; } +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QT_PREPEND_NAMESPACE(QDeclarativeVideo)) + +QT_END_HEADER + +#endif diff --git a/src/imports/multimedia/qmldir b/src/imports/multimedia/qmldir new file mode 100644 index 000000000..91caabad1 --- /dev/null +++ b/src/imports/multimedia/qmldir @@ -0,0 +1 @@ +plugin declarative_multimedia diff --git a/src/imports/qimportbase.pri b/src/imports/qimportbase.pri new file mode 100644 index 000000000..405af24ec --- /dev/null +++ b/src/imports/qimportbase.pri @@ -0,0 +1,38 @@ +load(qt_module) + +symbian:load(qt_plugin) +TEMPLATE = lib +CONFIG += qt plugin + +win32|mac:!wince*:!win32-msvc:!macx-xcode:CONFIG += debug_and_release + +isEmpty(TARGETPATH) { + error("qimportbase.pri: You must provide a TARGETPATH!") +} +isEmpty(TARGET) { + error("qimportbase.pri: You must provide a TARGET!") +} + +QMLDIRFILE = $${_PRO_FILE_PWD_}/qmldir +copy2build.input = QMLDIRFILE +copy2build.output = $$QT.declarative.imports/$$TARGETPATH/qmldir +!contains(TEMPLATE_PREFIX, vc):copy2build.variable_out = PRE_TARGETDEPS +copy2build.commands = $$QMAKE_COPY ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT} +copy2build.name = COPY ${QMAKE_FILE_IN} +copy2build.CONFIG += no_link +# `clean' should leave the build in a runnable state, which means it shouldn't delete qmldir +copy2build.CONFIG += no_clean +QMAKE_EXTRA_COMPILERS += copy2build + +TARGET = $$qtLibraryTarget($$TARGET) +contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols + +load(qt_targets) + +wince*:LIBS += $$QMAKE_LIBS_GUI + +symbian: { + TARGET.EPOCALLOWDLLDATA=1 + TARGET.CAPABILITY = All -Tcb + load(armcc_warnings) +} diff --git a/src/meegoinstalls/Makefile b/src/meegoinstalls/Makefile new file mode 100644 index 000000000..de0b65142 --- /dev/null +++ b/src/meegoinstalls/Makefile @@ -0,0 +1,40 @@ +PKG_NAME := qt-mobility +SPECFILE = $(addsuffix .spec, $(PKG_NAME)) +YAMLFILE = $(addsuffix .yaml, $(PKG_NAME)) + +first: custom-help + +include /usr/share/meego-packaging-tools/Makefile.common + +custom-help: help + @echo "The above are common MeeGo packaging targets." + @echo "$(PKG_NAME) also has these additional targets:" + @echo " spec-git Create spec file, with options appropriate for git" + @echo " build-trunk-i686 Do a local i686 build against Trunk, without using OBS" + @echo " build-trunk-testing-i686 Do a local i686 build against Trunk:Testing, without using OBS" + +spec-git: + specify --skip-scm --not-download --non-interactive + +git-archive: spec-git + @VER=$$(sed -n -r -e 's|^Version: +||p' $(SPECFILE)); \ + TARGZ=$$(sed -n -r \ + -e 's|^Source0:.*/([^/]+)$$|\1|' \ + -e 's|%\{name\}|$(PKG_NAME)|' \ + -e "s|%\{version\}|$$VER|" \ + -e 's|.tar.gz||p' \ + $(SPECFILE) ); \ + DIR="$$PWD"; \ + cd $$(git rev-parse --git-dir) && \ + echo "Creating $$DIR/$$TARGZ.tar.gz ..." && \ + git archive HEAD --prefix=$$TARGZ/ --format=tar | gzip > "$$DIR/$$TARGZ.tar.gz" + +build-no-obs = sudo build $(SPECFILE) --repository $1 --arch $2 + +build-no-obs-deps: /usr/bin/build git-archive + +build-trunk-i686: build-no-obs-deps + $(call build-no-obs,http://download.meego.com/live/Trunk/standard/,i686) + +build-trunk-testing-i686: build-no-obs-deps + $(call build-no-obs,http://download.meego.com/live/Trunk:/Testing/standard/,i686) diff --git a/src/meegoinstalls/README b/src/meegoinstalls/README new file mode 100644 index 000000000..fa3fc3049 --- /dev/null +++ b/src/meegoinstalls/README @@ -0,0 +1,95 @@ +This directory contains the MeeGo.com packaging metadata for Qt Mobility, +for use with the MeeGo.com OpenSuSE Build Service (OBS). + +Please see http://build.meego.com/ for more information about OBS. + +Quick Start: run `make' in this directory to see some useful things you +can do. + + + +PATCHES +======= + +At the time of writing, there are some MeeGo-specific patches hosted +on the MeeGo OBS. These patches are unable to be hosted in the Mobility +git repository at this time. + +In order to successfully build Mobility for MeeGo, you must also obtain +these patches, or you must modify qt-mobility.yaml and qt-mobility.spec +to remove the usage of the patches. + +Please do not add any more patches. + + + +HOW TO MAKE CHANGES +=================== + +Within this directory, there is a yaml file and a spec file. The yaml +file is maintained by hand; the spec file is partially generated from the +yaml file, but partially maintained by hand also, in specially marked +sections. + +The command used to generate the spec file from the yaml file is `specify'. +This is part of a tool named Spectacle. This can be installed from the +MeeGo tools repositories. It does not require a full MeeGo SDK install. +For example, on Ubuntu: + + $ sudo /bin/sh -c 'echo deb http://repo.meego.com/MeeGo/tools/repos/ubuntu/10.04/ / > /etc/apt/sources.list.d/meego-tools.list' + $ gpg --keyserver pgpkeys.mit.edu --recv 0BC7BEC479FC1F8A && gpg --export --armor 0BC7BEC479FC1F8A | sudo apt-key add - + $ sudo apt-get update + $ sudo apt-get install meego-packaging-tools + +Once you have installed meego-packaging-tools, you can run `make spec-git' +in this directory to regenerate the spec file from the yaml file. +The spec file and yaml file should be maintained together, so if you +modify the yaml file, you should do `make spec-git' and put the +modifications to the spec file in the same commit. + +Please see http://wiki.meego.com/Spectacle for more information about +spectacle. + + + +HOW TO BUILD +============ + +Note: these instructions are not canonical or supported in any way. +They are here as a quick start for people who want to contribute to +Qt Mobility and do not know how to compile for MeeGo. + +The most accurate way to build is to use the OpenSuSE build service +on build.meego.com. Unfortunately, at time of writing, anonymous +access to this service is not available. Therefore, using build.meego.com +is not an option for most people. + +However, a fairly accurate build can still be done using the `build' command +and referring to the live MeeGo repos. + + +Abbreviated example of how to install `build' for Ubuntu: + + $ sudo /bin/sh -c 'echo deb http://repo.meego.com/MeeGo/tools/repos/ubuntu/10.04/ / > /etc/apt/sources.list.d/meego-tools.list' + $ gpg --keyserver pgpkeys.mit.edu --recv 0BC7BEC479FC1F8A && gpg --export --armor 0BC7BEC479FC1F8A | sudo apt-key add - + $ sudo apt-get update + $ sudo apt-get install build + $ gpg --keyserver pgpkeys.mit.edu --recv 79FC1F8A && gpg --export --armor 79FC1F8A | sudo rpm --import - + + +Then, to do the build (for i686): + + $ make build-trunk-i686 + + +Or, to use the Trunk:Testing repository (which may contain newer versions of some packages): + + $ make build-trunk-testing-i686 + + +These builds will take place in a chroot, and hence will require root access. +They will attempt to use `sudo' for this. + +If you hit an error, `rpm: error while loading shared libraries: liblua-5.1.so', +edit /usr/lib/build/configs/default.conf and add liblua to one of the `Preinstall:' lines +(see http://comments.gmane.org/gmane.comp.handhelds.meego.devel/7139 ) diff --git a/src/meegoinstalls/qt-mobility.spec b/src/meegoinstalls/qt-mobility.spec new file mode 100644 index 000000000..fab3effff --- /dev/null +++ b/src/meegoinstalls/qt-mobility.spec @@ -0,0 +1,1360 @@ +# +# Do NOT Edit the Auto-generated Part! +# Generated by: spectacle version 0.21 +# +# >> macros +# << macros + +Name: qt-mobility +Summary: APIs for mobile device functionality +Version: 1.1.0+git2438 +Release: 1 +Group: System/Libraries +License: LGPLv2.1 with exception or GPLv3 +URL: http://qt.gitorious.org/qt-mobility +Source0: http://get.qt.nokia.com/qt/add-ons/%{name}-opensource-src-%{version}.tar.gz +Source100: qt-mobility.yaml +Requires: libqtconnectivity1 = %{version} +Requires: libqtcontacts1 = %{version} +Requires: libqtfeedback1 = %{version} +Requires: libqtgallery1 = %{version} +Requires: libqtlocation1 = %{version} +Requires: libqtmessaging1 = %{version} +Requires: libqtmultimediakit1 = %{version} +Requires: libqtorganizer1 = %{version} +Requires: libqtpublishsubscribe1 = %{version} +Requires: libqtsensors1 = %{version} +Requires: libqtserviceframework1 = %{version} +Requires: libqtsysteminfo1 = %{version} +Requires: libqtversit1 = %{version} +Requires: libqtversitorganizer1 = %{version} +BuildRequires: pkgconfig(QtGui) +BuildRequires: pkgconfig(QtOpenGL) +BuildRequires: pkgconfig(alsa) +BuildRequires: pkgconfig(blkid) +BuildRequires: pkgconfig(bluez) +BuildRequires: pkgconfig(connman) +BuildRequires: pkgconfig(contextsubscriber-1.0) +BuildRequires: pkgconfig(gconf-2.0) +BuildRequires: pkgconfig(geoclue) +BuildRequires: pkgconfig(gstreamer-plugins-bad-free-0.10) +BuildRequires: pkgconfig(gstreamer-plugins-base-0.10) +BuildRequires: pkgconfig(gypsy) +BuildRequires: pkgconfig(libiphb) +BuildRequires: pkgconfig(libpulse) +BuildRequires: pkgconfig(libmkcal) +BuildRequires: pkgconfig(meegotouch) +BuildRequires: pkgconfig(qttracker) +BuildRequires: pkgconfig(qmfclient) +BuildRequires: pkgconfig(sensord) +BuildRequires: pkgconfig(udev) +BuildRequires: pkgconfig(x11) +BuildRequires: pkgconfig(xext) +BuildRequires: pkgconfig(xrandr) +BuildRequires: pkgconfig(xrender) +BuildRequires: pkgconfig(xv) +BuildRequires: pkgconfig(QtSparql) +BuildRequires: pkgconfig(QtSparqlTrackerExtensions) +BuildRequires: qt-devel-tools +BuildRequires: fdupes + + +%description +Qt Mobility delivers a set of new APIs for mobile device functionality. These +APIs allow the developer to use these features with ease from one framework and +apply them to phones, netbooks and non-mobile personal computers. + + + +%package devel +Summary: APIs for mobile device functionality - development files +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} +Requires: servicefw + +%description devel +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the development files needed to build Qt applications +using Qt Mobility libraries. + + +%package -n libqtconnectivity1 +Summary: Qt Mobility Connectivity module +Group: System/Libraries +Requires: %{name} = %{version}-%{release} +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description -n libqtconnectivity1 +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the Connectivity API. It provides APIs for working with +local devices. + + +%package -n libqtcontacts1 +Summary: Qt Mobility Contacts module +Group: System/Libraries +Requires: %{name} = %{version}-%{release} +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description -n libqtcontacts1 +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains an API enabling clients to request contact data from +local or remote backends. + + +%package -n libqtfeedback1 +Summary: Qt Mobility Feedback module +Group: System/Libraries +Requires: %{name} = %{version}-%{release} +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description -n libqtfeedback1 +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the Feedback API. It enables a client to control +the vibration of the device or the piezo feedback from the screen. + + +%package -n libqtgallery1 +Summary: Qt Mobility Document Gallery module +Group: System/Libraries +Requires: %{name} = %{version}-%{release} +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description -n libqtgallery1 +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains an API for accessing collections of documents and media +and their meta-data. + + +%package -n libqtlocation1 +Summary: Qt Mobility Location module +Group: System/Libraries +Requires: %{name} = %{version}-%{release} +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description -n libqtlocation1 +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the Location API. It provides a library for distributing +and receiving location data using arbitrary data sources. + + +%package -n libqtmessaging1 +Summary: Qt Mobility Messaging module +Group: System/Libraries +Requires: %{name} = %{version}-%{release} +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description -n libqtmessaging1 +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the Messaging API. It is a common interface for handling +SMS, MMS, MIME Email and TNEF Email messages. + + +%package -n libqtmultimediakit1 +Summary: Qt Mobility MultimediaKit module +Group: System/Libraries +Requires: %{name} = %{version}-%{release} +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description -n libqtmultimediakit1 +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains a set of APIs to play and record media, and manage a +collection of media content. + + +%package -n libqtorganizer1 +Summary: Qt Mobility Organizer module +Group: System/Libraries +Requires: %{name} = %{version}-%{release} +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description -n libqtorganizer1 +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains an API for management of calendar, scheduling and +personal data from local or remote backends. It includes the ability to create, +edit, list, delete and lookup organizer information whether it is stored +locally or remotely. + + +%package -n libqtpublishsubscribe1 +Summary: Qt Mobility Publish and Subscribe module +Group: System/Libraries +Requires: %{name} = %{version}-%{release} +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description -n libqtpublishsubscribe1 +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the Publish and Subscribe API (containing Value Space). +It enables applications to read item values, navigate through and subscribe to +change notifications. + + +%package -n libqtsensors1 +Summary: Qt Mobility Sensors module +Group: System/Libraries +Requires: %{name} = %{version}-%{release} +Requires: libqtsql4-sqlite +Requires: sensorfw +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description -n libqtsensors1 +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the Sensors API. It provides access to sensors. + + +%package -n libqtserviceframework1 +Summary: Qt Mobility Service Framework module +Group: System/Libraries +Requires: %{name} = %{version}-%{release} +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description -n libqtserviceframework1 +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains a set of APIs to that allows clients to discover and +instantiate arbitrary services. + + +%package -n libqtsysteminfo1 +Summary: Qt Mobility System Information module +Group: System/Libraries +Requires: %{name} = %{version}-%{release} +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description -n libqtsysteminfo1 +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains a set of APIs to discover system related information and +capabilities. + + +%package -n libqtversit1 +Summary: Qt Mobility Versit (vCard) module +Group: System/Libraries +Requires: %{name} = %{version}-%{release} +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description -n libqtversit1 +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains an API to manage Versit documents, such as vCards. + + +%package -n libqtversitorganizer1 +Summary: Qt Mobility Versit (Organizer) module +Group: System/Libraries +Requires: %{name} = %{version}-%{release} +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description -n libqtversitorganizer1 +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains an API to manage Versit documents, such as iCalendar +documents. It interfaces the Organizer API and uses the same framework as for +vCards. + + +%package -n libdeclarative-contacts +Summary: Qt Mobility Contacts QML plugin +Group: System/Libraries +Requires: %{name} = %{version}-%{release} + +%description -n libdeclarative-contacts +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the Contacts QML plugin for QtDeclarative. + + +%package -n libdeclarative-feedback +Summary: Qt Mobility Feedback QML plugin +Group: System/Libraries +Requires: %{name} = %{version}-%{release} + +%description -n libdeclarative-feedback +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the Feedback QML plugin for QtDeclarative. + + +%package -n libdeclarative-gallery +Summary: Qt Mobility Document Gallery QML plugin +Group: System/Libraries +Requires: %{name} = %{version}-%{release} + +%description -n libdeclarative-gallery +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the Document Gallery QML plugin for QtDeclarative. + + +%package -n libdeclarative-location +Summary: Qt Mobility Location QML plugin +Group: System/Libraries +Requires: %{name} = %{version}-%{release} + +%description -n libdeclarative-location +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the Location QML plugin for QtDeclarative. + + +%package -n libdeclarative-messaging +Summary: Qt Mobility Messaging QML plugin +Group: System/Libraries +Requires: %{name} = %{version}-%{release} + +%description -n libdeclarative-messaging +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the Messaging QML plugin for QtDeclarative. + + +%package -n libdeclarative-multimedia +Summary: Qt Mobility Multimedia QML plugin +Group: System/Libraries +Requires: %{name} = %{version}-%{release} + +%description -n libdeclarative-multimedia +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the Multimedia QML plugin for QtDeclarative. + + +%package -n libdeclarative-organizer +Summary: Qt Mobility Organizer QML plugin +Group: System/Libraries +Requires: %{name} = %{version}-%{release} + +%description -n libdeclarative-organizer +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the Organizer QML plugin for QtDeclarative. + + +%package -n libdeclarative-publishsubscribe +Summary: Qt Mobility Publish and Subscribe QML plugin +Group: System/Libraries +Requires: %{name} = %{version}-%{release} + +%description -n libdeclarative-publishsubscribe +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the Publish and Subscribe QML plugin for QtDeclarative. + + +%package -n libdeclarative-sensors +Summary: Qt Mobility Sensors Framework QML plugin +Group: System/Libraries +Requires: %{name} = %{version}-%{release} + +%description -n libdeclarative-sensors +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the Sensors QML plugin for QtDeclarative. + + +%package -n libdeclarative-serviceframework +Summary: Qt Mobility Service Framework QML plugin +Group: System/Libraries +Requires: %{name} = %{version}-%{release} + +%description -n libdeclarative-serviceframework +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the Service Framework QML plugin for QtDeclarative. + + +%package -n libdeclarative-systeminfo +Summary: Qt Mobility System Information QML plugin +Group: System/Libraries +Requires: %{name} = %{version}-%{release} + +%description -n libdeclarative-systeminfo +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the System Information QML plugin for QtDeclarative. + + +%package -n libdeclarative-connectivity +Summary: Qt Mobility Connectivity QML plugin +Group: System/Libraries +Requires: %{name} = %{version}-%{release} + +%description -n libdeclarative-connectivity +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the Connectivity QML plugin for QtDeclarative. + + +%package -n servicefw +Summary: Qt Mobility Service Framework tool +Group: Development/Tools +Requires: %{name} = %{version}-%{release} + +%description -n servicefw +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains the Service Framework tool (servicefw). It allows +to register services and make them available over the Service Framework. + + +%package examples +Summary: Qt Mobility examples +Group: System/X11 +Requires: %{name} = %{version}-%{release} + +%description examples +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains Qt Mobility examples. + + +%package l10n +Summary: APIs for mobile device functionality - localization files +Group: System/I18n +Requires: %{name} = %{version}-%{release} + +%description l10n +Qt Mobility delivers a set of new APIs for mobile device functionality. + +This package contains Qt Mobility translations. + + + +%prep +%setup -q -n %{name}-opensource-src-%{version} + +# >> setup +# << setup + +%build +# >> build pre +# QMF environment variables should be set +export QMF_INCLUDEDIR=%{_includedir}/qmfclient +export QMF_LIBDIR=%{_libdir} +./configure \ +-prefix "%{_prefix}" \ +-headerdir "%{_includedir}" \ +-libdir "%{_libdir}" \ +-bindir "%{_bindir}" \ +-plugindir "%{_libdir}/qt4/plugins" \ +-demosdir "%{_libdir}/qtmobility/demos" \ +-examplesdir "%{_libdir}/qtmobility/examples" \ +-languages "ar cs da de es fr he hu ja pl pt ru sk sl sv zh_CN zh_TW" \ +-examples \ +-demos \ +-modules "location contacts multimedia publishsubscribe versit messaging systeminfo serviceframework sensors gallery organizer feedback connectivity" \ +-meego +make %{?_smp_mflags} +# << build pre + + + +# >> build post +# << build post +%install +rm -rf %{buildroot} +# >> install pre +# << install pre + +# >> install post +%qmake_install +# Fix wrong path in pkgconfig files +find %{buildroot}%{_libdir}/pkgconfig -type f -name '*.pc' \ +-exec perl -pi -e "s, -L%{_builddir}/%{name}-opensource-src-\Q%{version}\E/?\S+,,g" {} \; +# Fix executable permissions +find %{buildroot}%{_libdir}/qtmobility -type f -perm /u+x,g+x,o+x \( -false \ +-o -name \*.qml \ +-o -name \*.sci \ +-o -name qmldir \ +-o -name \*.txt \ +\) -exec chmod -x \{\} + +# Fix duplicate files +%fdupes %{buildroot}%{_includedir} +%fdupes %{buildroot}%{_libdir}/qtmobility +# << install post +%fdupes %{buildroot}/%{_datadir}/qtmobility/translations + + + + + + + + + + +%post -n libqtconnectivity1 -p /sbin/ldconfig + +%postun -n libqtconnectivity1 -p /sbin/ldconfig + + +%post -n libqtcontacts1 -p /sbin/ldconfig + +%postun -n libqtcontacts1 -p /sbin/ldconfig + + +%post -n libqtfeedback1 -p /sbin/ldconfig + +%postun -n libqtfeedback1 -p /sbin/ldconfig + + +%post -n libqtgallery1 -p /sbin/ldconfig + +%postun -n libqtgallery1 -p /sbin/ldconfig + + +%post -n libqtlocation1 -p /sbin/ldconfig + +%postun -n libqtlocation1 -p /sbin/ldconfig + + +%post -n libqtmessaging1 -p /sbin/ldconfig + +%postun -n libqtmessaging1 -p /sbin/ldconfig + + +%post -n libqtmultimediakit1 -p /sbin/ldconfig + +%postun -n libqtmultimediakit1 -p /sbin/ldconfig + + +%post -n libqtorganizer1 -p /sbin/ldconfig + +%postun -n libqtorganizer1 -p /sbin/ldconfig + + +%post -n libqtpublishsubscribe1 -p /sbin/ldconfig + +%postun -n libqtpublishsubscribe1 -p /sbin/ldconfig + + +%post -n libqtsensors1 -p /sbin/ldconfig + +%postun -n libqtsensors1 -p /sbin/ldconfig + + +%post -n libqtserviceframework1 -p /sbin/ldconfig + +%postun -n libqtserviceframework1 -p /sbin/ldconfig + + +%post -n libqtsysteminfo1 -p /sbin/ldconfig + +%postun -n libqtsysteminfo1 -p /sbin/ldconfig + + +%post -n libqtversit1 -p /sbin/ldconfig + +%postun -n libqtversit1 -p /sbin/ldconfig + + +%post -n libqtversitorganizer1 -p /sbin/ldconfig + +%postun -n libqtversitorganizer1 -p /sbin/ldconfig + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +%files +%defattr(-,root,root,-) +# >> files +# << files + + +%files devel +%defattr(-,root,root,-) +# >> files devel +%{_bindir}/icheck +%{_bindir}/ndefhandlergen +%{_bindir}/qcrmlgen +%{_bindir}/servicedbgen +%{_bindir}/servicexmlgen +%{_bindir}/vsexplorer +%{_includedir}/QtConnectivity/*.h +%{_includedir}/QtConnectivity/QBluetoothAddress +%{_includedir}/QtConnectivity/QBluetoothDeviceDiscoveryAgent +%{_includedir}/QtConnectivity/QBluetoothDeviceInfo +%{_includedir}/QtConnectivity/QBluetoothHostInfo +%{_includedir}/QtConnectivity/QBluetoothLocalDevice +%{_includedir}/QtConnectivity/QBluetoothServiceDiscoveryAgent +%{_includedir}/QtConnectivity/QBluetoothServiceInfo +%{_includedir}/QtConnectivity/QBluetoothSocket +%{_includedir}/QtConnectivity/QBluetoothTransferManager +%{_includedir}/QtConnectivity/QBluetoothTransferReply +%{_includedir}/QtConnectivity/QBluetoothTransferRequest +%{_includedir}/QtConnectivity/QBluetoothUuid +%{_includedir}/QtConnectivity/QDeclarativeNdefRecord +%{_includedir}/QtConnectivity/QL2capServer +%{_includedir}/QtConnectivity/QL2capSocket +%{_includedir}/QtConnectivity/QLlcpServer +%{_includedir}/QtConnectivity/QLlcpSocket +%{_includedir}/QtConnectivity/QNdefFilter +%{_includedir}/QtConnectivity/QNdefMessage +%{_includedir}/QtConnectivity/QNdefNfcTextRecord +%{_includedir}/QtConnectivity/QNdefNfcUriRecord +%{_includedir}/QtConnectivity/QNdefRecord +%{_includedir}/QtConnectivity/QNearFieldManager +%{_includedir}/QtConnectivity/QNearFieldTagType1 +%{_includedir}/QtConnectivity/QNearFieldTagType2 +%{_includedir}/QtConnectivity/QNearFieldTagType3 +%{_includedir}/QtConnectivity/QNearFieldTagType4 +%{_includedir}/QtConnectivity/QNearFieldTarget +%{_includedir}/QtConnectivity/QRfcommServer +%{_includedir}/QtConnectivity/QRfcommSocket +%{_includedir}/QtContacts/*.h +%{_includedir}/QtContacts/QContact +%{_includedir}/QtContacts/QContactAbstractRequest +%{_includedir}/QtContacts/QContactAction +%{_includedir}/QtContacts/QContactActionDescriptor +%{_includedir}/QtContacts/QContactActionFactory +%{_includedir}/QtContacts/QContactActionFilter +%{_includedir}/QtContacts/QContactActionTarget +%{_includedir}/QtContacts/QContactAddress +%{_includedir}/QtContacts/QContactAnniversary +%{_includedir}/QtContacts/QContactAvatar +%{_includedir}/QtContacts/QContactBirthday +%{_includedir}/QtContacts/QContactChangeLogFilter +%{_includedir}/QtContacts/QContactChangeSet +%{_includedir}/QtContacts/QContactDetail +%{_includedir}/QtContacts/QContactDetailDefinition +%{_includedir}/QtContacts/QContactDetailDefinitionFetchRequest +%{_includedir}/QtContacts/QContactDetailDefinitionRemoveRequest +%{_includedir}/QtContacts/QContactDetailDefinitionSaveRequest +%{_includedir}/QtContacts/QContactDetailFieldDefinition +%{_includedir}/QtContacts/QContactDetailFilter +%{_includedir}/QtContacts/QContactDetailRangeFilter +%{_includedir}/QtContacts/QContactDisplayLabel +%{_includedir}/QtContacts/QContactEmailAddress +%{_includedir}/QtContacts/QContactFamily +%{_includedir}/QtContacts/QContactFavorite +%{_includedir}/QtContacts/QContactFetchByIdRequest +%{_includedir}/QtContacts/QContactFetchHint +%{_includedir}/QtContacts/QContactFetchRequest +%{_includedir}/QtContacts/QContactFilter +%{_includedir}/QtContacts/QContactGender +%{_includedir}/QtContacts/QContactGeoLocation +%{_includedir}/QtContacts/QContactGlobalPresence +%{_includedir}/QtContacts/QContactGuid +%{_includedir}/QtContacts/QContactHobby +%{_includedir}/QtContacts/QContactId +%{_includedir}/QtContacts/QContactIntersectionFilter +%{_includedir}/QtContacts/QContactInvalidFilter +%{_includedir}/QtContacts/QContactLocalIdFetchRequest +%{_includedir}/QtContacts/QContactLocalIdFilter +%{_includedir}/QtContacts/QContactManager +%{_includedir}/QtContacts/QContactManagerEngine +%{_includedir}/QtContacts/QContactManagerEngineFactory +%{_includedir}/QtContacts/QContactManagerEngineV2 +%{_includedir}/QtContacts/QContactName +%{_includedir}/QtContacts/QContactNickname +%{_includedir}/QtContacts/QContactNote +%{_includedir}/QtContacts/QContactObserver +%{_includedir}/QtContacts/QContactOnlineAccount +%{_includedir}/QtContacts/QContactOrganization +%{_includedir}/QtContacts/QContactPhoneNumber +%{_includedir}/QtContacts/QContactPresence +%{_includedir}/QtContacts/QContactRelationship +%{_includedir}/QtContacts/QContactRelationshipFetchRequest +%{_includedir}/QtContacts/QContactRelationshipFilter +%{_includedir}/QtContacts/QContactRelationshipRemoveRequest +%{_includedir}/QtContacts/QContactRelationshipSaveRequest +%{_includedir}/QtContacts/QContactRemoveRequest +%{_includedir}/QtContacts/QContactRingtone +%{_includedir}/QtContacts/QContactSaveRequest +%{_includedir}/QtContacts/QContactSortOrder +%{_includedir}/QtContacts/QContactSyncTarget +%{_includedir}/QtContacts/QContactTag +%{_includedir}/QtContacts/QContactThumbnail +%{_includedir}/QtContacts/QContactTimestamp +%{_includedir}/QtContacts/QContactType +%{_includedir}/QtContacts/QContactUnionFilter +%{_includedir}/QtContacts/QContactUrl +%{_includedir}/QtFeedback/*.h +%{_includedir}/QtFeedback/QFeedbackActuator +%{_includedir}/QtFeedback/QFeedbackEffect +%{_includedir}/QtFeedback/QFeedbackFileEffect +%{_includedir}/QtFeedback/QFeedbackFileInterface +%{_includedir}/QtFeedback/QFeedbackHapticsEffect +%{_includedir}/QtFeedback/QFeedbackHapticsInterface +%{_includedir}/QtFeedback/QFeedbackInterface +%{_includedir}/QtFeedback/QFeedbackThemeInterface +%{_includedir}/QtGallery/*.h +%{_includedir}/QtGallery/QAbstractGallery +%{_includedir}/QtGallery/QDocumentGallery +%{_includedir}/QtGallery/QGalleryAbstractRequest +%{_includedir}/QtGallery/QGalleryAbstractResponse +%{_includedir}/QtGallery/QGalleryFilter +%{_includedir}/QtGallery/QGalleryIntersectionFilter +%{_includedir}/QtGallery/QGalleryItemRequest +%{_includedir}/QtGallery/QGalleryMetaDataFilter +%{_includedir}/QtGallery/QGalleryQueryModel +%{_includedir}/QtGallery/QGalleryQueryRequest +%{_includedir}/QtGallery/QGalleryResource +%{_includedir}/QtGallery/QGalleryResultSet +%{_includedir}/QtGallery/QGalleryTypeRequest +%{_includedir}/QtGallery/QGalleryUnionFilter +%{_includedir}/QtLocation/*.h +%{_includedir}/QtLocation/QGeoAddress +%{_includedir}/QtLocation/QGeoAreaMonitor +%{_includedir}/QtLocation/QGeoBoundingArea +%{_includedir}/QtLocation/QGeoBoundingBox +%{_includedir}/QtLocation/QGeoBoundingCircle +%{_includedir}/QtLocation/QGeoCoordinate +%{_includedir}/QtLocation/QGeoManeuver +%{_includedir}/QtLocation/QGeoMapCircleObject +%{_includedir}/QtLocation/QGeoMapCustomObject +%{_includedir}/QtLocation/QGeoMapData +%{_includedir}/QtLocation/QGeoMapGroupObject +%{_includedir}/QtLocation/QGeoMapObject +%{_includedir}/QtLocation/QGeoMapObjectInfo +%{_includedir}/QtLocation/QGeoMapOverlay +%{_includedir}/QtLocation/QGeoMapPixmapObject +%{_includedir}/QtLocation/QGeoMapPolygonObject +%{_includedir}/QtLocation/QGeoMapPolylineObject +%{_includedir}/QtLocation/QGeoMapRectangleObject +%{_includedir}/QtLocation/QGeoMapRouteObject +%{_includedir}/QtLocation/QGeoMapTextObject +%{_includedir}/QtLocation/QGeoMappingManager +%{_includedir}/QtLocation/QGeoMappingManagerEngine +%{_includedir}/QtLocation/QGeoPlace +%{_includedir}/QtLocation/QGeoPositionInfo +%{_includedir}/QtLocation/QGeoPositionInfoSource +%{_includedir}/QtLocation/QGeoPositionInfoSourceFactory +%{_includedir}/QtLocation/QGeoRoute +%{_includedir}/QtLocation/QGeoRouteReply +%{_includedir}/QtLocation/QGeoRouteRequest +%{_includedir}/QtLocation/QGeoRouteSegment +%{_includedir}/QtLocation/QGeoRoutingManager +%{_includedir}/QtLocation/QGeoRoutingManagerEngine +%{_includedir}/QtLocation/QGeoSatelliteInfo +%{_includedir}/QtLocation/QGeoSatelliteInfoSource +%{_includedir}/QtLocation/QGeoSearchManager +%{_includedir}/QtLocation/QGeoSearchManagerEngine +%{_includedir}/QtLocation/QGeoSearchReply +%{_includedir}/QtLocation/QGeoServiceProvider +%{_includedir}/QtLocation/QGeoServiceProviderFactory +%{_includedir}/QtLocation/QGeoTiledMapData +%{_includedir}/QtLocation/QGeoTiledMapReply +%{_includedir}/QtLocation/QGeoTiledMapRequest +%{_includedir}/QtLocation/QGeoTiledMappingManagerEngine +%{_includedir}/QtLocation/QGraphicsGeoMap +%{_includedir}/QtLocation/QLandmark +%{_includedir}/QtLocation/QLandmarkAbstractRequest +%{_includedir}/QtLocation/QLandmarkAttributeFilter +%{_includedir}/QtLocation/QLandmarkBoxFilter +%{_includedir}/QtLocation/QLandmarkCategory +%{_includedir}/QtLocation/QLandmarkCategoryFetchByIdRequest +%{_includedir}/QtLocation/QLandmarkCategoryFetchRequest +%{_includedir}/QtLocation/QLandmarkCategoryFilter +%{_includedir}/QtLocation/QLandmarkCategoryId +%{_includedir}/QtLocation/QLandmarkCategoryIdFetchRequest +%{_includedir}/QtLocation/QLandmarkCategoryRemoveRequest +%{_includedir}/QtLocation/QLandmarkCategorySaveRequest +%{_includedir}/QtLocation/QLandmarkExportRequest +%{_includedir}/QtLocation/QLandmarkFetchByIdRequest +%{_includedir}/QtLocation/QLandmarkFetchRequest +%{_includedir}/QtLocation/QLandmarkFilter +%{_includedir}/QtLocation/QLandmarkId +%{_includedir}/QtLocation/QLandmarkIdFetchRequest +%{_includedir}/QtLocation/QLandmarkIdFilter +%{_includedir}/QtLocation/QLandmarkImportRequest +%{_includedir}/QtLocation/QLandmarkIntersectionFilter +%{_includedir}/QtLocation/QLandmarkManager +%{_includedir}/QtLocation/QLandmarkManagerEngine +%{_includedir}/QtLocation/QLandmarkManagerEngineFactory +%{_includedir}/QtLocation/QLandmarkNameFilter +%{_includedir}/QtLocation/QLandmarkNameSort +%{_includedir}/QtLocation/QLandmarkProximityFilter +%{_includedir}/QtLocation/QLandmarkRemoveRequest +%{_includedir}/QtLocation/QLandmarkSaveRequest +%{_includedir}/QtLocation/QLandmarkSortOrder +%{_includedir}/QtLocation/QLandmarkUnionFilter +%{_includedir}/QtLocation/QNmeaPositionInfoSource +%{_includedir}/QtMessaging/*.h +%{_includedir}/QtMessaging/QMessage +%{_includedir}/QtMessaging/QMessageAccount +%{_includedir}/QtMessaging/QMessageAccountFilter +%{_includedir}/QtMessaging/QMessageAccountId +%{_includedir}/QtMessaging/QMessageAccountSortOrder +%{_includedir}/QtMessaging/QMessageAddress +%{_includedir}/QtMessaging/QMessageContentContainer +%{_includedir}/QtMessaging/QMessageContentContainerId +%{_includedir}/QtMessaging/QMessageDataComparator +%{_includedir}/QtMessaging/QMessageFilter +%{_includedir}/QtMessaging/QMessageFolder +%{_includedir}/QtMessaging/QMessageFolderFilter +%{_includedir}/QtMessaging/QMessageFolderId +%{_includedir}/QtMessaging/QMessageFolderSortOrder +%{_includedir}/QtMessaging/QMessageId +%{_includedir}/QtMessaging/QMessageManager +%{_includedir}/QtMessaging/QMessageService +%{_includedir}/QtMessaging/QMessageSortOrder +%{_includedir}/QtMobility/*.h +%{_includedir}/QtMobility/QLatin1Constant +%{_includedir}/QtMultimediaKit/*.h +%{_includedir}/QtMultimediaKit/QAbstractAudioDeviceInfo +%{_includedir}/QtMultimediaKit/QAbstractAudioInput +%{_includedir}/QtMultimediaKit/QAbstractAudioOutput +%{_includedir}/QtMultimediaKit/QAbstractVideoBuffer +%{_includedir}/QtMultimediaKit/QAbstractVideoSurface +%{_includedir}/QtMultimediaKit/QAudio +%{_includedir}/QtMultimediaKit/QAudioCaptureSource +%{_includedir}/QtMultimediaKit/QAudioDeviceInfo +%{_includedir}/QtMultimediaKit/QAudioEncoderControl +%{_includedir}/QtMultimediaKit/QAudioEncoderSettings +%{_includedir}/QtMultimediaKit/QAudioEndpointSelector +%{_includedir}/QtMultimediaKit/QAudioFormat +%{_includedir}/QtMultimediaKit/QAudioInput +%{_includedir}/QtMultimediaKit/QAudioOutput +%{_includedir}/QtMultimediaKit/QAudioSystemPlugin +%{_includedir}/QtMultimediaKit/QCamera +%{_includedir}/QtMultimediaKit/QCameraControl +%{_includedir}/QtMultimediaKit/QCameraExposure +%{_includedir}/QtMultimediaKit/QCameraExposureControl +%{_includedir}/QtMultimediaKit/QCameraFlashControl +%{_includedir}/QtMultimediaKit/QCameraFocus +%{_includedir}/QtMultimediaKit/QCameraFocusControl +%{_includedir}/QtMultimediaKit/QCameraFocusZone +%{_includedir}/QtMultimediaKit/QCameraImageCapture +%{_includedir}/QtMultimediaKit/QCameraImageCaptureControl +%{_includedir}/QtMultimediaKit/QCameraImageProcessing +%{_includedir}/QtMultimediaKit/QCameraImageProcessingControl +%{_includedir}/QtMultimediaKit/QCameraCaptureBufferFormatControl +%{_includedir}/QtMultimediaKit/QCameraCaptureDestinationControl +%{_includedir}/QtMultimediaKit/QCameraLocksControl +%{_includedir}/QtMultimediaKit/QCameraViewfinder +%{_includedir}/QtMultimediaKit/QGraphicsVideoItem +%{_includedir}/QtMultimediaKit/QImageEncoderControl +%{_includedir}/QtMultimediaKit/QImageEncoderSettings +%{_includedir}/QtMultimediaKit/QLocalMediaPlaylistProvider +%{_includedir}/QtMultimediaKit/QMediaBindableInterface +%{_includedir}/QtMultimediaKit/QMediaContainerControl +%{_includedir}/QtMultimediaKit/QMediaContent +%{_includedir}/QtMultimediaKit/QMediaControl +%{_includedir}/QtMultimediaKit/QMediaImageViewer +%{_includedir}/QtMultimediaKit/QMediaObject +%{_includedir}/QtMultimediaKit/QMediaPlayer +%{_includedir}/QtMultimediaKit/QMediaPlayerControl +%{_includedir}/QtMultimediaKit/QMediaPlaylist +%{_includedir}/QtMultimediaKit/QMediaPlaylistControl +%{_includedir}/QtMultimediaKit/QMediaPlaylistIOPlugin +%{_includedir}/QtMultimediaKit/QMediaPlaylistNavigator +%{_includedir}/QtMultimediaKit/QMediaPlaylistProvider +%{_includedir}/QtMultimediaKit/QMediaPlaylistReader +%{_includedir}/QtMultimediaKit/QMediaPlaylistSourceControl +%{_includedir}/QtMultimediaKit/QMediaPlaylistWriter +%{_includedir}/QtMultimediaKit/QMediaRecorder +%{_includedir}/QtMultimediaKit/QMediaRecorderControl +%{_includedir}/QtMultimediaKit/QMediaResource +%{_includedir}/QtMultimediaKit/QMediaService +%{_includedir}/QtMultimediaKit/QMediaServiceProvider +%{_includedir}/QtMultimediaKit/QMediaServiceProviderHint +%{_includedir}/QtMultimediaKit/QMediaServiceProviderPlugin +%{_includedir}/QtMultimediaKit/QMediaStreamsControl +%{_includedir}/QtMultimediaKit/QMediaTimeInterval +%{_includedir}/QtMultimediaKit/QMediaTimeRange +%{_includedir}/QtMultimediaKit/QMetaDataReaderControl +%{_includedir}/QtMultimediaKit/QMetaDataWriterControl +%{_includedir}/QtMultimediaKit/QRadioTuner +%{_includedir}/QtMultimediaKit/QRadioTunerControl +%{_includedir}/QtMultimediaKit/QVideoDeviceControl +%{_includedir}/QtMultimediaKit/QVideoEncoderControl +%{_includedir}/QtMultimediaKit/QVideoEncoderSettings +%{_includedir}/QtMultimediaKit/QVideoFrame +%{_includedir}/QtMultimediaKit/QVideoRendererControl +%{_includedir}/QtMultimediaKit/QVideoSurfaceFormat +%{_includedir}/QtMultimediaKit/QVideoWidget +%{_includedir}/QtMultimediaKit/QVideoWidgetControl +%{_includedir}/QtMultimediaKit/QVideoWindowControl +%{_includedir}/QtMultimediaKit/QMediaNetworkAccessControl +%{_includedir}/QtOrganizer/*.h +%{_includedir}/QtOrganizer/QOrganizerAbstractRequest +%{_includedir}/QtOrganizer/QOrganizerCollection +%{_includedir}/QtOrganizer/QOrganizerCollectionChangeSet +%{_includedir}/QtOrganizer/QOrganizerCollectionEngineId +%{_includedir}/QtOrganizer/QOrganizerCollectionFetchRequest +%{_includedir}/QtOrganizer/QOrganizerCollectionId +%{_includedir}/QtOrganizer/QOrganizerCollectionRemoveRequest +%{_includedir}/QtOrganizer/QOrganizerCollectionSaveRequest +%{_includedir}/QtOrganizer/QOrganizerEvent +%{_includedir}/QtOrganizer/QOrganizerEventOccurrence +%{_includedir}/QtOrganizer/QOrganizerEventTime +%{_includedir}/QtOrganizer/QOrganizerItem +%{_includedir}/QtOrganizer/QOrganizerItemAudibleReminder +%{_includedir}/QtOrganizer/QOrganizerItemChangeLogFilter +%{_includedir}/QtOrganizer/QOrganizerItemChangeSet +%{_includedir}/QtOrganizer/QOrganizerItemCollectionFilter +%{_includedir}/QtOrganizer/QOrganizerItemComment +%{_includedir}/QtOrganizer/QOrganizerItemDescription +%{_includedir}/QtOrganizer/QOrganizerItemDetail +%{_includedir}/QtOrganizer/QOrganizerItemDetailDefinition +%{_includedir}/QtOrganizer/QOrganizerItemDetailDefinitionFetchRequest +%{_includedir}/QtOrganizer/QOrganizerItemDetailDefinitionRemoveRequest +%{_includedir}/QtOrganizer/QOrganizerItemDetailDefinitionSaveRequest +%{_includedir}/QtOrganizer/QOrganizerItemDetailFieldDefinition +%{_includedir}/QtOrganizer/QOrganizerItemDetailFilter +%{_includedir}/QtOrganizer/QOrganizerItemDetailRangeFilter +%{_includedir}/QtOrganizer/QOrganizerItemDisplayLabel +%{_includedir}/QtOrganizer/QOrganizerItemEmailReminder +%{_includedir}/QtOrganizer/QOrganizerItemEngineId +%{_includedir}/QtOrganizer/QOrganizerItemFetchByIdRequest +%{_includedir}/QtOrganizer/QOrganizerItemFetchForExportRequest +%{_includedir}/QtOrganizer/QOrganizerItemFetchHint +%{_includedir}/QtOrganizer/QOrganizerItemFetchRequest +%{_includedir}/QtOrganizer/QOrganizerItemFilter +%{_includedir}/QtOrganizer/QOrganizerItemGuid +%{_includedir}/QtOrganizer/QOrganizerItemId +%{_includedir}/QtOrganizer/QOrganizerItemIdFetchRequest +%{_includedir}/QtOrganizer/QOrganizerItemIdFilter +%{_includedir}/QtOrganizer/QOrganizerItemIntersectionFilter +%{_includedir}/QtOrganizer/QOrganizerItemInvalidFilter +%{_includedir}/QtOrganizer/QOrganizerItemLocation +%{_includedir}/QtOrganizer/QOrganizerItemObserver +%{_includedir}/QtOrganizer/QOrganizerItemOccurrenceFetchRequest +%{_includedir}/QtOrganizer/QOrganizerItemParent +%{_includedir}/QtOrganizer/QOrganizerItemPriority +%{_includedir}/QtOrganizer/QOrganizerItemRecurrence +%{_includedir}/QtOrganizer/QOrganizerItemReminder +%{_includedir}/QtOrganizer/QOrganizerItemRemoveRequest +%{_includedir}/QtOrganizer/QOrganizerItemSaveRequest +%{_includedir}/QtOrganizer/QOrganizerItemSortOrder +%{_includedir}/QtOrganizer/QOrganizerItemTag +%{_includedir}/QtOrganizer/QOrganizerItemTimestamp +%{_includedir}/QtOrganizer/QOrganizerItemType +%{_includedir}/QtOrganizer/QOrganizerItemUnionFilter +%{_includedir}/QtOrganizer/QOrganizerItemVisualReminder +%{_includedir}/QtOrganizer/QOrganizerJournal +%{_includedir}/QtOrganizer/QOrganizerJournalTime +%{_includedir}/QtOrganizer/QOrganizerManager +%{_includedir}/QtOrganizer/QOrganizerManagerEngine +%{_includedir}/QtOrganizer/QOrganizerManagerEngineFactory +%{_includedir}/QtOrganizer/QOrganizerManagerEngineV2 +%{_includedir}/QtOrganizer/QOrganizerNote +%{_includedir}/QtOrganizer/QOrganizerRecurrenceRule +%{_includedir}/QtOrganizer/QOrganizerTodo +%{_includedir}/QtOrganizer/QOrganizerTodoOccurrence +%{_includedir}/QtOrganizer/QOrganizerTodoProgress +%{_includedir}/QtOrganizer/QOrganizerTodoTime +%{_includedir}/QtPublishSubscribe/*.h +%{_includedir}/QtPublishSubscribe/QValueSpace +%{_includedir}/QtPublishSubscribe/QValueSpacePublisher +%{_includedir}/QtPublishSubscribe/QValueSpaceSubscriber +%{_includedir}/QtSensors/*.h +%{_includedir}/QtSensors/QAccelerometer +%{_includedir}/QtSensors/QAccelerometerFilter +%{_includedir}/QtSensors/QAccelerometerReading +%{_includedir}/QtSensors/QAmbientLightFilter +%{_includedir}/QtSensors/QAmbientLightReading +%{_includedir}/QtSensors/QAmbientLightSensor +%{_includedir}/QtSensors/QCompass +%{_includedir}/QtSensors/QCompassFilter +%{_includedir}/QtSensors/QCompassReading +%{_includedir}/QtSensors/QGyroscope +%{_includedir}/QtSensors/QGyroscopeFilter +%{_includedir}/QtSensors/QGyroscopeReading +%{_includedir}/QtSensors/QLightFilter +%{_includedir}/QtSensors/QLightReading +%{_includedir}/QtSensors/QLightSensor +%{_includedir}/QtSensors/QMagnetometer +%{_includedir}/QtSensors/QMagnetometerFilter +%{_includedir}/QtSensors/QMagnetometerReading +%{_includedir}/QtSensors/QOrientationFilter +%{_includedir}/QtSensors/QOrientationReading +%{_includedir}/QtSensors/QOrientationSensor +%{_includedir}/QtSensors/QProximityFilter +%{_includedir}/QtSensors/QProximityReading +%{_includedir}/QtSensors/QProximitySensor +%{_includedir}/QtSensors/QRotationFilter +%{_includedir}/QtSensors/QRotationReading +%{_includedir}/QtSensors/QRotationSensor +%{_includedir}/QtSensors/QSensor +%{_includedir}/QtSensors/QSensorBackend +%{_includedir}/QtSensors/QSensorBackendFactory +%{_includedir}/QtSensors/QSensorChangesInterface +%{_includedir}/QtSensors/QSensorFilter +%{_includedir}/QtSensors/QSensorManager +%{_includedir}/QtSensors/QSensorPluginInterface +%{_includedir}/QtSensors/QSensorReading +%{_includedir}/QtSensors/QTapFilter +%{_includedir}/QtSensors/QTapReading +%{_includedir}/QtSensors/QTapSensor +%{_includedir}/QtServiceFramework/*.h +%{_includedir}/QtServiceFramework/QAbstractSecuritySession +%{_includedir}/QtServiceFramework/QRemoteServiceRegister +%{_includedir}/QtServiceFramework/QService +%{_includedir}/QtServiceFramework/QServiceContext +%{_includedir}/QtServiceFramework/QServiceFilter +%{_includedir}/QtServiceFramework/QServiceInterfaceDescriptor +%{_includedir}/QtServiceFramework/QServiceManager +%{_includedir}/QtServiceFramework/QServicePluginInterface +%{_includedir}/QtSystemInfo/*.h +%{_includedir}/QtSystemInfo/QSystemAlignedTimer +%{_includedir}/QtSystemInfo/QSystemBatteryInfo +%{_includedir}/QtSystemInfo/QSystemDeviceInfo +%{_includedir}/QtSystemInfo/QSystemDisplayInfo +%{_includedir}/QtSystemInfo/QSystemInfo +%{_includedir}/QtSystemInfo/QSystemNetworkInfo +%{_includedir}/QtSystemInfo/QSystemScreenSaver +%{_includedir}/QtSystemInfo/QSystemStorageInfo +%{_includedir}/QtVersit/*.h +%{_includedir}/QtVersit/QVersitContactExporter +%{_includedir}/QtVersit/QVersitContactExporterDetailHandler +%{_includedir}/QtVersit/QVersitContactExporterDetailHandlerV2 +%{_includedir}/QtVersit/QVersitContactHandler +%{_includedir}/QtVersit/QVersitContactHandlerFactory +%{_includedir}/QtVersit/QVersitContactImporter +%{_includedir}/QtVersit/QVersitContactImporterPropertyHandler +%{_includedir}/QtVersit/QVersitContactImporterPropertyHandlerV2 +%{_includedir}/QtVersit/QVersitDefaultResourceHandler +%{_includedir}/QtVersit/QVersitDocument +%{_includedir}/QtVersit/QVersitProperty +%{_includedir}/QtVersit/QVersitReader +%{_includedir}/QtVersit/QVersitResourceHandler +%{_includedir}/QtVersit/QVersitWriter +%{_includedir}/QtVersitOrganizer/*.h +%{_includedir}/QtVersitOrganizer/QVersitOrganizerExporter +%{_includedir}/QtVersitOrganizer/QVersitOrganizerExporterDetailHandler +%{_includedir}/QtVersitOrganizer/QVersitOrganizerHandler +%{_includedir}/QtVersitOrganizer/QVersitOrganizerHandlerFactory +%{_includedir}/QtVersitOrganizer/QVersitOrganizerImporter +%{_includedir}/QtVersitOrganizer/QVersitOrganizerImporterPropertyHandler +%{_includedir}/QtVersitOrganizer/QVersitTimeZoneHandler +%{_libdir}/libQtConnectivity.prl +%{_libdir}/libQtConnectivity.so +%{_libdir}/libQtContacts.prl +%{_libdir}/libQtContacts.so +%{_libdir}/libQtFeedback.prl +%{_libdir}/libQtFeedback.so +%{_libdir}/libQtGallery.prl +%{_libdir}/libQtGallery.so +%{_libdir}/libQtLocation.prl +%{_libdir}/libQtLocation.so +%{_libdir}/libQtMessaging.prl +%{_libdir}/libQtMessaging.so +%{_libdir}/libQtMultimediaKit.prl +%{_libdir}/libQtMultimediaKit.so +%{_libdir}/libQtOrganizer.prl +%{_libdir}/libQtOrganizer.so +%{_libdir}/libQtPublishSubscribe.prl +%{_libdir}/libQtPublishSubscribe.so +%{_libdir}/libQtSensors.prl +%{_libdir}/libQtSensors.so +%{_libdir}/libQtServiceFramework.prl +%{_libdir}/libQtServiceFramework.so +%{_libdir}/libQtSystemInfo.prl +%{_libdir}/libQtSystemInfo.so +%{_libdir}/libQtVersit.prl +%{_libdir}/libQtVersit.so +%{_libdir}/libQtVersitOrganizer.prl +%{_libdir}/libQtVersitOrganizer.so +%{_libdir}/pkgconfig/QtConnectivity.pc +%{_libdir}/pkgconfig/QtContacts.pc +%{_libdir}/pkgconfig/QtFeedback.pc +%{_libdir}/pkgconfig/QtGallery.pc +%{_libdir}/pkgconfig/QtLocation.pc +%{_libdir}/pkgconfig/QtMessaging.pc +%{_libdir}/pkgconfig/QtMultimediaKit.pc +%{_libdir}/pkgconfig/QtOrganizer.pc +%{_libdir}/pkgconfig/QtPublishSubscribe.pc +%{_libdir}/pkgconfig/QtSensors.pc +%{_libdir}/pkgconfig/QtServiceFramework.pc +%{_libdir}/pkgconfig/QtSystemInfo.pc +%{_libdir}/pkgconfig/QtVersit.pc +%{_libdir}/pkgconfig/QtVersitOrganizer.pc +%{_datadir}/qt4/mkspecs/features/mobility.prf +%{_datadir}/qt4/mkspecs/features/mobilityconfig.prf +# << files devel + +%files -n libqtconnectivity1 +%defattr(-,root,root,-) +# >> files libqtconnectivity1 +%{_libdir}/libQtConnectivity.so.* +# << files libqtconnectivity1 + +%files -n libqtcontacts1 +%defattr(-,root,root,-) +# >> files libqtcontacts1 +%{_libdir}/libQtContacts.so.* +%{_libdir}/qt4/plugins/contacts/libqtcontacts_serviceactionmanager.so +# << files libqtcontacts1 + +%files -n libqtfeedback1 +%defattr(-,root,root,-) +# >> files libqtfeedback1 +%{_libdir}/libQtFeedback.so.* +%{_libdir}/qt4/plugins/feedback/libqtfeedback_meegotouch.so +%{_libdir}/qt4/plugins/feedback/libqtfeedback_mmk.so +# << files libqtfeedback1 + +%files -n libqtgallery1 +%defattr(-,root,root,-) +# >> files libqtgallery1 +%{_libdir}/libQtGallery.so.* +# << files libqtgallery1 + +%files -n libqtlocation1 +%defattr(-,root,root,-) +# >> files libqtlocation1 +%{_libdir}/libQtLocation.so.* +%{_libdir}/qt4/plugins/geoservices/libqtgeoservices_nokia.so +%{_libdir}/qt4/plugins/landmarks/libqtlandmarks_qsparql.so +# << files libqtlocation1 + +%files -n libqtmessaging1 +%defattr(-,root,root,-) +# >> files libqtmessaging1 +%{_libdir}/libQtMessaging.so.* +# << files libqtmessaging1 + +%files -n libqtmultimediakit1 +%defattr(-,root,root,-) +# >> files libqtmultimediakit1 +%{_libdir}/libQtMultimediaKit.so.* +%{_libdir}/qt4/plugins/mediaservice/libqgstengine.so +%{_libdir}/qt4/plugins/mediaservice/libqtmedia_v4lengine.so +%{_libdir}/qt4/plugins/playlistformats/libqtmultimediakit_m3u.so +%{_libdir}/qt4/plugins/audio/libqtmedia_pulse.so +# << files libqtmultimediakit1 + +%files -n libqtorganizer1 +%defattr(-,root,root,-) +# >> files libqtorganizer1 +%{_libdir}/libQtOrganizer.so.* +%{_libdir}/qt4/plugins/organizer/libqtorganizer_mkcal.so +# << files libqtorganizer1 + +%files -n libqtpublishsubscribe1 +%defattr(-,root,root,-) +# >> files libqtpublishsubscribe1 +%{_libdir}/libQtPublishSubscribe.so.* +# << files libqtpublishsubscribe1 + +%files -n libqtsensors1 +%defattr(-,root,root,-) +# >> files libqtsensors1 +%config %{_sysconfdir}/xdg/Nokia/Sensors.conf +%{_libdir}/libQtSensors.so.* +%{_libdir}/qt4/plugins/sensors/libqtsensors_generic.so +%{_libdir}/qt4/plugins/sensors/libqtsensors_meego.so +# << files libqtsensors1 + +%files -n libqtserviceframework1 +%defattr(-,root,root,-) +# >> files libqtserviceframework1 +%{_libdir}/libQtServiceFramework.so.* +# << files libqtserviceframework1 + +%files -n libqtsysteminfo1 +%defattr(-,root,root,-) +# >> files libqtsysteminfo1 +%{_libdir}/libQtSystemInfo.so.* +# << files libqtsysteminfo1 + +%files -n libqtversit1 +%defattr(-,root,root,-) +# >> files libqtversit1 +%{_libdir}/libQtVersit.so.* +%{_libdir}/qt4/plugins/versit/libqtversit_backuphandler.so +%{_libdir}/qt4/plugins/versit/libqtversit_vcardpreserver.so +# << files libqtversit1 + +%files -n libqtversitorganizer1 +%defattr(-,root,root,-) +# >> files libqtversitorganizer1 +%{_libdir}/libQtVersitOrganizer.so.* +# << files libqtversitorganizer1 + +%files -n libdeclarative-contacts +%defattr(-,root,root,-) +# >> files libdeclarative-contacts +%{_libdir}/qt4/imports/QtMobility/contacts/libdeclarative_contacts.so +%{_libdir}/qt4/imports/QtMobility/contacts/qmldir +# << files libdeclarative-contacts + +%files -n libdeclarative-feedback +%defattr(-,root,root,-) +# >> files libdeclarative-feedback +%{_libdir}/qt4/imports/QtMobility/feedback/libdeclarative_feedback.so +%{_libdir}/qt4/imports/QtMobility/feedback/qmldir +# << files libdeclarative-feedback + +%files -n libdeclarative-gallery +%defattr(-,root,root,-) +# >> files libdeclarative-gallery +%{_libdir}/qt4/imports/QtMobility/gallery/libdeclarative_gallery.so +%{_libdir}/qt4/imports/QtMobility/gallery/qmldir +# << files libdeclarative-gallery + +%files -n libdeclarative-location +%defattr(-,root,root,-) +# >> files libdeclarative-location +%{_libdir}/qt4/imports/QtMobility/location/libdeclarative_location.so +%{_libdir}/qt4/imports/QtMobility/location/qmldir +# << files libdeclarative-location + +%files -n libdeclarative-messaging +%defattr(-,root,root,-) +# >> files libdeclarative-messaging +%{_libdir}/qt4/imports/QtMobility/messaging/libdeclarative_messaging.so +%{_libdir}/qt4/imports/QtMobility/messaging/qmldir +# << files libdeclarative-messaging + +%files -n libdeclarative-multimedia +%defattr(-,root,root,-) +# >> files libdeclarative-multimedia +%{_libdir}/qt4/imports/QtMultimediaKit/libdeclarative_multimedia.so +%{_libdir}/qt4/imports/QtMultimediaKit/qmldir +# << files libdeclarative-multimedia + +%files -n libdeclarative-organizer +%defattr(-,root,root,-) +# >> files libdeclarative-organizer +%{_libdir}/qt4/imports/QtMobility/organizer/libdeclarative_organizer.so +%{_libdir}/qt4/imports/QtMobility/organizer/qmldir +# << files libdeclarative-organizer + +%files -n libdeclarative-publishsubscribe +%defattr(-,root,root,-) +# >> files libdeclarative-publishsubscribe +%{_libdir}/qt4/imports/QtMobility/publishsubscribe/libdeclarative_publishsubscribe.so +%{_libdir}/qt4/imports/QtMobility/publishsubscribe/qmldir +# << files libdeclarative-publishsubscribe + +%files -n libdeclarative-sensors +%defattr(-,root,root,-) +# >> files libdeclarative-sensors +%{_libdir}/qt4/imports/QtMobility/sensors/libdeclarative_sensors.so +%{_libdir}/qt4/imports/QtMobility/sensors/qmldir +# << files libdeclarative-sensors + +%files -n libdeclarative-serviceframework +%defattr(-,root,root,-) +# >> files libdeclarative-serviceframework +%{_libdir}/qt4/imports/QtMobility/serviceframework/libdeclarative_serviceframework.so +%{_libdir}/qt4/imports/QtMobility/serviceframework/qmldir +# << files libdeclarative-serviceframework + +%files -n libdeclarative-systeminfo +%defattr(-,root,root,-) +# >> files libdeclarative-systeminfo +%{_libdir}/qt4/imports/QtMobility/systeminfo/libdeclarative_systeminfo.so +%{_libdir}/qt4/imports/QtMobility/systeminfo/qmldir +# << files libdeclarative-systeminfo + +%files -n libdeclarative-connectivity +%defattr(-,root,root,-) +# >> files libdeclarative-connectivity +%{_libdir}/qt4/imports/QtMobility/connectivity/libdeclarative_connectivity.so +%{_libdir}/qt4/imports/QtMobility/connectivity/qmldir +# << files libdeclarative-connectivity + +%files -n servicefw +%defattr(-,root,root,-) +# >> files servicefw +%{_bindir}/servicefw +# << files servicefw + +%files examples +%defattr(-,root,root,-) +# >> files examples +%{_libdir}/qt4/plugins/sensors/libqtsensors_grueplugin.so +%{_libdir}/qt4/plugins/serviceframework/libserviceframework_bluetoothtransferplugin.so +%{_libdir}/qt4/plugins/serviceframework/libserviceframework_filemanagerplugin.so +%{_libdir}/qt4/plugins/serviceframework/libserviceframework_landlinedialerservice.so +%{_libdir}/qt4/plugins/serviceframework/libserviceframework_notesmanagerplugin.so +%{_libdir}/qt4/plugins/serviceframework/libserviceframework_voipdialerservice.so +%{_libdir}/qtmobility/demos/ +%{_libdir}/qtmobility/examples/ +# << files examples + +%files l10n +%defattr(-,root,root,-) +# >> files l10n +%{_datadir}/qtmobility/translations/qtmobility_ar.qm +%{_datadir}/qtmobility/translations/qtmobility_cs.qm +%{_datadir}/qtmobility/translations/qtmobility_da.qm +%{_datadir}/qtmobility/translations/qtmobility_de.qm +%{_datadir}/qtmobility/translations/qtmobility_es.qm +%{_datadir}/qtmobility/translations/qtmobility_fr.qm +%{_datadir}/qtmobility/translations/qtmobility_he.qm +%{_datadir}/qtmobility/translations/qtmobility_hu.qm +%{_datadir}/qtmobility/translations/qtmobility_ja.qm +%{_datadir}/qtmobility/translations/qtmobility_pl.qm +%{_datadir}/qtmobility/translations/qtmobility_pt.qm +%{_datadir}/qtmobility/translations/qtmobility_ru.qm +%{_datadir}/qtmobility/translations/qtmobility_sk.qm +%{_datadir}/qtmobility/translations/qtmobility_sl.qm +%{_datadir}/qtmobility/translations/qtmobility_sv.qm +#%{_datadir}/qtmobility/translations/qtmobility_uk.qm +%{_datadir}/qtmobility/translations/qtmobility_zh_CN.qm +%{_datadir}/qtmobility/translations/qtmobility_zh_TW.qm +# << files l10n + diff --git a/src/meegoinstalls/qt-mobility.yaml b/src/meegoinstalls/qt-mobility.yaml new file mode 100644 index 000000000..99c84c16c --- /dev/null +++ b/src/meegoinstalls/qt-mobility.yaml @@ -0,0 +1,353 @@ +Name: qt-mobility +Summary: APIs for mobile device functionality +Version: 1.1.0+git2438 +Release: 1 +Group: System/Libraries +License: LGPLv2.1 with exception or GPLv3 +URL: http://qt.gitorious.org/qt-mobility +Sources: + - http://get.qt.nokia.com/qt/add-ons/%{name}-opensource-src-%{version}.tar.gz +SourcePrefix: "%{name}-opensource-src-%{version}" +Patches: +Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. These + APIs allow the developer to use these features with ease from one framework and + apply them to phones, netbooks and non-mobile personal computers. +Requires: + - libqtconnectivity1 = %{version} + - libqtcontacts1 = %{version} + - libqtfeedback1 = %{version} + - libqtgallery1 = %{version} + - libqtlocation1 = %{version} + - libqtmessaging1 = %{version} + - libqtmultimediakit1 = %{version} + - libqtorganizer1 = %{version} + - libqtpublishsubscribe1 = %{version} + - libqtsensors1 = %{version} + - libqtserviceframework1 = %{version} + - libqtsysteminfo1 = %{version} + - libqtversit1 = %{version} + - libqtversitorganizer1 = %{version} +PkgConfigBR: + - QtGui + - QtOpenGL + - alsa + - blkid + - bluez + - connman + - contextsubscriber-1.0 + - gconf-2.0 + - geoclue + - gstreamer-plugins-bad-free-0.10 + - gstreamer-plugins-base-0.10 + - gypsy + - libiphb + - libpulse + - libmkcal + - meegotouch + - qttracker + - qmfclient + - sensord + - udev + - x11 + - xext + - xrandr + - xrender + - xv + - QtSparql + - QtSparqlTrackerExtensions +PkgBR: + - qt-devel-tools +Configure: none +Builder: none +RunFdupes: "%{_datadir}/qtmobility/translations" +SubPackages: + - Name: devel + Summary: APIs for mobile device functionality - development files + Group: Development/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the development files needed to build Qt applications + using Qt Mobility libraries. + Requires: + - servicefw + + - Name: libqtconnectivity1 + AsWholeName: yes + Summary: Qt Mobility Connectivity module + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the Connectivity API. It provides APIs for working with + local devices. + + - Name: libqtcontacts1 + AsWholeName: yes + Summary: Qt Mobility Contacts module + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains an API enabling clients to request contact data from + local or remote backends. + + - Name: libqtfeedback1 + AsWholeName: yes + Summary: Qt Mobility Feedback module + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the Feedback API. It enables a client to control + the vibration of the device or the piezo feedback from the screen. + + - Name: libqtgallery1 + AsWholeName: yes + Summary: Qt Mobility Document Gallery module + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains an API for accessing collections of documents and media + and their meta-data. + + - Name: libqtlocation1 + AsWholeName: yes + Summary: Qt Mobility Location module + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the Location API. It provides a library for distributing + and receiving location data using arbitrary data sources. + + - Name: libqtmessaging1 + AsWholeName: yes + Summary: Qt Mobility Messaging module + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the Messaging API. It is a common interface for handling + SMS, MMS, MIME Email and TNEF Email messages. + + - Name: libqtmultimediakit1 + AsWholeName: yes + Summary: Qt Mobility MultimediaKit module + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains a set of APIs to play and record media, and manage a + collection of media content. + + - Name: libqtorganizer1 + AsWholeName: yes + Summary: Qt Mobility Organizer module + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains an API for management of calendar, scheduling and + personal data from local or remote backends. It includes the ability to create, + edit, list, delete and lookup organizer information whether it is stored + locally or remotely. + + - Name: libqtpublishsubscribe1 + AsWholeName: yes + Summary: Qt Mobility Publish and Subscribe module + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the Publish and Subscribe API (containing Value Space). + It enables applications to read item values, navigate through and subscribe to + change notifications. + + - Name: libqtsensors1 + AsWholeName: yes + Summary: Qt Mobility Sensors module + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the Sensors API. It provides access to sensors. + Requires: + - libqtsql4-sqlite + - sensorfw + + - Name: libqtserviceframework1 + AsWholeName: yes + Summary: Qt Mobility Service Framework module + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains a set of APIs to that allows clients to discover and + instantiate arbitrary services. + + - Name: libqtsysteminfo1 + AsWholeName: yes + Summary: Qt Mobility System Information module + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains a set of APIs to discover system related information and + capabilities. + + - Name: libqtversit1 + AsWholeName: yes + Summary: Qt Mobility Versit (vCard) module + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains an API to manage Versit documents, such as vCards. + + - Name: libqtversitorganizer1 + AsWholeName: yes + Summary: Qt Mobility Versit (Organizer) module + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains an API to manage Versit documents, such as iCalendar + documents. It interfaces the Organizer API and uses the same framework as for + vCards. + + - Name: libdeclarative-contacts + AsWholeName: yes + Summary: Qt Mobility Contacts QML plugin + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the Contacts QML plugin for QtDeclarative. + + - Name: libdeclarative-feedback + AsWholeName: yes + Summary: Qt Mobility Feedback QML plugin + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the Feedback QML plugin for QtDeclarative. + + - Name: libdeclarative-gallery + AsWholeName: yes + Summary: Qt Mobility Document Gallery QML plugin + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the Document Gallery QML plugin for QtDeclarative. + + - Name: libdeclarative-location + AsWholeName: yes + Summary: Qt Mobility Location QML plugin + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the Location QML plugin for QtDeclarative. + + - Name: libdeclarative-messaging + AsWholeName: yes + Summary: Qt Mobility Messaging QML plugin + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the Messaging QML plugin for QtDeclarative. + + - Name: libdeclarative-multimedia + AsWholeName: yes + Summary: Qt Mobility Multimedia QML plugin + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the Multimedia QML plugin for QtDeclarative. + + - Name: libdeclarative-organizer + AsWholeName: yes + Summary: Qt Mobility Organizer QML plugin + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the Organizer QML plugin for QtDeclarative. + + - Name: libdeclarative-publishsubscribe + AsWholeName: yes + Summary: Qt Mobility Publish and Subscribe QML plugin + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the Publish and Subscribe QML plugin for QtDeclarative. + + - Name: libdeclarative-sensors + AsWholeName: yes + Summary: Qt Mobility Sensors Framework QML plugin + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the Sensors QML plugin for QtDeclarative. + + - Name: libdeclarative-serviceframework + AsWholeName: yes + Summary: Qt Mobility Service Framework QML plugin + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the Service Framework QML plugin for QtDeclarative. + + - Name: libdeclarative-systeminfo + AsWholeName: yes + Summary: Qt Mobility System Information QML plugin + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the System Information QML plugin for QtDeclarative. + + - Name: libdeclarative-connectivity + AsWholeName: yes + Summary: Qt Mobility Connectivity QML plugin + Group: System/Libraries + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the Connectivity QML plugin for QtDeclarative. + + - Name: servicefw + AsWholeName: yes + Summary: Qt Mobility Service Framework tool + Group: Development/Tools + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains the Service Framework tool (servicefw). It allows + to register services and make them available over the Service Framework. + + - Name: examples + Summary: Qt Mobility examples + Group: System/X11 + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains Qt Mobility examples. + + - Name: l10n + Summary: APIs for mobile device functionality - localization files + Group: System/I18n + Description: | + Qt Mobility delivers a set of new APIs for mobile device functionality. + + This package contains Qt Mobility translations. diff --git a/src/multimediakit/audio/audio.pri b/src/multimediakit/audio/audio.pri new file mode 100644 index 000000000..19163d4fc --- /dev/null +++ b/src/multimediakit/audio/audio.pri @@ -0,0 +1,79 @@ +INCLUDEPATH += audio + +PUBLIC_HEADERS += audio/qaudio.h \ + audio/qaudioformat.h \ + audio/qaudioinput.h \ + audio/qaudiooutput.h \ + audio/qaudiodeviceinfo.h \ + audio/qaudiosystemplugin.h \ + audio/qaudiosystem.h + +PRIVATE_HEADERS += audio/qaudiodevicefactory_p.h audio/qaudiopluginloader_p.h + + +SOURCES += audio/qaudio.cpp \ + audio/qaudioformat.cpp \ + audio/qaudiodeviceinfo.cpp \ + audio/qaudiooutput.cpp \ + audio/qaudioinput.cpp \ + audio/qaudiosystemplugin.cpp \ + audio/qaudiosystem.cpp \ + audio/qaudiodevicefactory.cpp \ + audio/qaudiopluginloader.cpp + +mac { + PRIVATE_HEADERS += audio/qaudioinput_mac_p.h \ + audio/qaudiooutput_mac_p.h \ + audio/qaudiodeviceinfo_mac_p.h \ + audio/qaudio_mac_p.h + + SOURCES += audio/qaudiodeviceinfo_mac_p.cpp \ + audio/qaudiooutput_mac_p.cpp \ + audio/qaudioinput_mac_p.cpp \ + audio/qaudio_mac.cpp + + LIBS += -framework ApplicationServices -framework CoreAudio -framework AudioUnit -framework AudioToolbox +} + +win32 { + PRIVATE_HEADERS += audio/qaudioinput_win32_p.h audio/qaudiooutput_win32_p.h audio/qaudiodeviceinfo_win32_p.h + SOURCES += audio/qaudiodeviceinfo_win32_p.cpp \ + audio/qaudiooutput_win32_p.cpp \ + audio/qaudioinput_win32_p.cpp + !wince*:LIBS += -lwinmm + wince*:LIBS += -lcoredll + LIBS += -lstrmiids -lole32 -loleaut32 +} + +symbian { + INCLUDEPATH += $${EPOCROOT}epoc32/include/mmf/common + INCLUDEPATH += $${EPOCROOT}epoc32/include/mmf/server + + PRIVATE_HEADERS += audio/qaudio_symbian_p.h \ + audio/qaudiodeviceinfo_symbian_p.h \ + audio/qaudioinput_symbian_p.h \ + audio/qaudiooutput_symbian_p.h + + SOURCES += audio/qaudio_symbian_p.cpp \ + audio/qaudiodeviceinfo_symbian_p.cpp \ + audio/qaudioinput_symbian_p.cpp \ + audio/qaudiooutput_symbian_p.cpp + + LIBS += -lmmfdevsound +} + +unix:!mac:!symbian { + contains(pulseaudio_enabled, yes) { + DEFINES += QT_NO_AUDIO_BACKEND + } + else:contains(QT_CONFIG, alsa) { + linux-*|freebsd-*|openbsd-* { + DEFINES += HAS_ALSA + PRIVATE_HEADERS += audio/qaudiooutput_alsa_p.h audio/qaudioinput_alsa_p.h audio/qaudiodeviceinfo_alsa_p.h + SOURCES += audio/qaudiodeviceinfo_alsa_p.cpp \ + audio/qaudiooutput_alsa_p.cpp \ + audio/qaudioinput_alsa_p.cpp + LIBS_PRIVATE += -lasound + } + } +} diff --git a/src/multimediakit/audio/qaudio.cpp b/src/multimediakit/audio/qaudio.cpp new file mode 100644 index 000000000..e823283f3 --- /dev/null +++ b/src/multimediakit/audio/qaudio.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include + + +QT_BEGIN_NAMESPACE + +namespace QAudio +{ + +class RegisterMetaTypes +{ +public: + RegisterMetaTypes() + { + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + } + +} _register; + +} + +/* + \namespace QAudio + \brief The QAudio namespace contains enums used by the audio classes. + \inmodule QtMultimediaKit + \ingroup multimedia +*/ + +/* + \enum QAudio::Error + + \value NoError No errors have occurred + \value OpenError An error occurred opening the audio device + \value IOError An error occurred during read/write of audio device + \value UnderrunError Audio data is not being fed to the audio device at a fast enough rate + \value FatalError A non-recoverable error has occurred, the audio device is not usable at this time. +*/ + +/* + \enum QAudio::State + + \value ActiveState Audio data is being processed, this state is set after start() is called + and while audio data is available to be processed. + \value SuspendedState The audio device is in a suspended state, this state will only be entered + after suspend() is called. + \value StoppedState The audio device is closed, and is not processing any audio data + \value IdleState The QIODevice passed in has no data and audio system's buffer is empty, this state + is set after start() is called and while no audio data is available to be processed. +*/ + +/* + \enum QAudio::Mode + + \value AudioOutput audio output device + \value AudioInput audio input device +*/ + + +QT_END_NAMESPACE + diff --git a/src/multimediakit/audio/qaudio.h b/src/multimediakit/audio/qaudio.h new file mode 100644 index 000000000..b8b585b69 --- /dev/null +++ b/src/multimediakit/audio/qaudio.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QAUDIO_H +#define QAUDIO_H + +#include +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE +//QTM_SYNC_HEADER_EXPORT QAudio + +namespace QAudio +{ + enum Error { NoError, OpenError, IOError, UnderrunError, FatalError }; + enum State { ActiveState, SuspendedState, StoppedState, IdleState }; + enum Mode { AudioInput, AudioOutput }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +Q_DECLARE_METATYPE(QAudio::Error) +Q_DECLARE_METATYPE(QAudio::State) +Q_DECLARE_METATYPE(QAudio::Mode) + +#endif // QAUDIO_H diff --git a/src/multimediakit/audio/qaudio_mac.cpp b/src/multimediakit/audio/qaudio_mac.cpp new file mode 100644 index 000000000..a13b54c39 --- /dev/null +++ b/src/multimediakit/audio/qaudio_mac.cpp @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qaudio_mac_p.h" + +QT_BEGIN_NAMESPACE + +// Debugging +QDebug operator<<(QDebug dbg, const QAudioFormat& audioFormat) +{ + dbg.nospace() << "QAudioFormat(" << + audioFormat.frequency() << "," << + audioFormat.channels() << "," << + audioFormat.sampleSize()<< "," << + audioFormat.codec() << "," << + audioFormat.byteOrder() << "," << + audioFormat.sampleType() << ")"; + + return dbg.space(); +} + + +// Conversion +QAudioFormat toQAudioFormat(AudioStreamBasicDescription const& sf) +{ + QAudioFormat audioFormat; + + audioFormat.setFrequency(sf.mSampleRate); + audioFormat.setChannels(sf.mChannelsPerFrame); + audioFormat.setSampleSize(sf.mBitsPerChannel); + audioFormat.setCodec(QString::fromLatin1("audio/pcm")); + audioFormat.setByteOrder((sf.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0 ? QAudioFormat::BigEndian : QAudioFormat::LittleEndian); + QAudioFormat::SampleType type = QAudioFormat::UnSignedInt; + if ((sf.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0) + type = QAudioFormat::SignedInt; + else if ((sf.mFormatFlags & kAudioFormatFlagIsFloat) != 0) + type = QAudioFormat::Float; + audioFormat.setSampleType(type); + + return audioFormat; +} + +AudioStreamBasicDescription toAudioStreamBasicDescription(QAudioFormat const& audioFormat) +{ + AudioStreamBasicDescription sf; + + sf.mFormatFlags = kAudioFormatFlagIsPacked; + sf.mSampleRate = audioFormat.frequency(); + sf.mFramesPerPacket = 1; + sf.mChannelsPerFrame = audioFormat.channels(); + sf.mBitsPerChannel = audioFormat.sampleSize(); + sf.mBytesPerFrame = sf.mChannelsPerFrame * (sf.mBitsPerChannel / 8); + sf.mBytesPerPacket = sf.mFramesPerPacket * sf.mBytesPerFrame; + sf.mFormatID = kAudioFormatLinearPCM; + + switch (audioFormat.sampleType()) { + case QAudioFormat::SignedInt: sf.mFormatFlags |= kAudioFormatFlagIsSignedInteger; break; + case QAudioFormat::UnSignedInt: /* default */ break; + case QAudioFormat::Float: sf.mFormatFlags |= kAudioFormatFlagIsFloat; break; + case QAudioFormat::Unknown: default: break; + } + + if (audioFormat.byteOrder() == QAudioFormat::BigEndian) + sf.mFormatFlags |= kAudioFormatFlagIsBigEndian; + + return sf; +} + +// QAudioRingBuffer +QAudioRingBuffer::QAudioRingBuffer(int bufferSize): + m_bufferSize(bufferSize) +{ + m_buffer = new char[m_bufferSize]; + reset(); +} + +QAudioRingBuffer::~QAudioRingBuffer() +{ + delete m_buffer; +} + +int QAudioRingBuffer::used() const +{ + return m_bufferUsed; +} + +int QAudioRingBuffer::free() const +{ + return m_bufferSize - m_bufferUsed; +} + +int QAudioRingBuffer::size() const +{ + return m_bufferSize; +} + +void QAudioRingBuffer::reset() +{ + m_readPos = 0; + m_writePos = 0; + m_bufferUsed = 0; +} + +QT_END_NAMESPACE + + diff --git a/src/multimediakit/audio/qaudio_mac_p.h b/src/multimediakit/audio/qaudio_mac_p.h new file mode 100644 index 000000000..bbd63e485 --- /dev/null +++ b/src/multimediakit/audio/qaudio_mac_p.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QAUDIO_MAC_P_H +#define QAUDIO_MAC_P_H + +#include + +#include +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +extern QDebug operator<<(QDebug dbg, const QAudioFormat& audioFormat); + +extern QAudioFormat toQAudioFormat(const AudioStreamBasicDescription& streamFormat); +extern AudioStreamBasicDescription toAudioStreamBasicDescription(QAudioFormat const& audioFormat); + +class QAudioRingBuffer +{ +public: + typedef QPair Region; + + QAudioRingBuffer(int bufferSize); + ~QAudioRingBuffer(); + + Region acquireReadRegion(int size) + { + const int used = m_bufferUsed.fetchAndAddAcquire(0); + + if (used > 0) { + const int readSize = qMin(size, qMin(m_bufferSize - m_readPos, used)); + + return readSize > 0 ? Region(m_buffer + m_readPos, readSize) : Region(0, 0); + } + + return Region(0, 0); + } + + void releaseReadRegion(Region const& region) + { + m_readPos = (m_readPos + region.second) % m_bufferSize; + + m_bufferUsed.fetchAndAddRelease(-region.second); + } + + Region acquireWriteRegion(int size) + { + const int free = m_bufferSize - m_bufferUsed.fetchAndAddAcquire(0); + + if (free > 0) { + const int writeSize = qMin(size, qMin(m_bufferSize - m_writePos, free)); + + return writeSize > 0 ? Region(m_buffer + m_writePos, writeSize) : Region(0, 0); + } + + return Region(0, 0); + } + + void releaseWriteRegion(Region const& region) + { + m_writePos = (m_writePos + region.second) % m_bufferSize; + + m_bufferUsed.fetchAndAddRelease(region.second); + } + + int used() const; + int free() const; + int size() const; + + void reset(); + +private: + int m_bufferSize; + int m_readPos; + int m_writePos; + char* m_buffer; + QAtomicInt m_bufferUsed; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIO_MAC_P_H + + diff --git a/src/multimediakit/audio/qaudio_symbian_p.cpp b/src/multimediakit/audio/qaudio_symbian_p.cpp new file mode 100644 index 000000000..08f329790 --- /dev/null +++ b/src/multimediakit/audio/qaudio_symbian_p.cpp @@ -0,0 +1,663 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaudio_symbian_p.h" +#include + +QT_BEGIN_NAMESPACE + +namespace SymbianAudio { +namespace Utils { + +//----------------------------------------------------------------------------- +// Static data +//----------------------------------------------------------------------------- + +// Sample rate / frequency + +typedef TMMFSampleRate SampleRateNative; +typedef int SampleRateQt; + +const int SampleRateCount = 12; + +const SampleRateNative SampleRateListNative[SampleRateCount] = { + EMMFSampleRate8000Hz + , EMMFSampleRate11025Hz + , EMMFSampleRate12000Hz + , EMMFSampleRate16000Hz + , EMMFSampleRate22050Hz + , EMMFSampleRate24000Hz + , EMMFSampleRate32000Hz + , EMMFSampleRate44100Hz + , EMMFSampleRate48000Hz + , EMMFSampleRate64000Hz + , EMMFSampleRate88200Hz + , EMMFSampleRate96000Hz +}; + +const SampleRateQt SampleRateListQt[SampleRateCount] = { + 8000 + , 11025 + , 12000 + , 16000 + , 22050 + , 24000 + , 32000 + , 44100 + , 48000 + , 64000 + , 88200 + , 96000 +}; + +// Channels + +typedef TMMFMonoStereo ChannelsNative; +typedef int ChannelsQt; + +const int ChannelsCount = 2; + +const ChannelsNative ChannelsListNative[ChannelsCount] = { + EMMFMono + , EMMFStereo +}; + +const ChannelsQt ChannelsListQt[ChannelsCount] = { + 1 + , 2 +}; + +// Encoding + +const int EncodingCount = 6; + +const TUint32 EncodingFourCC[EncodingCount] = { + KMMFFourCCCodePCM8 // 0 + , KMMFFourCCCodePCMU8 // 1 + , KMMFFourCCCodePCM16 // 2 + , KMMFFourCCCodePCMU16 // 3 + , KMMFFourCCCodePCM16B // 4 + , KMMFFourCCCodePCMU16B // 5 +}; + +// The characterised DevSound API specification states that the iEncoding +// field in TMMFCapabilities is ignored, and that the FourCC should be used +// to specify the PCM encoding. +// See "SGL.GT0287.102 Multimedia DevSound Baseline Compatibility.doc" in the +// mm_info/mm_docs repository. +const TMMFSoundEncoding EncodingNative[EncodingCount] = { + EMMFSoundEncoding16BitPCM // 0 + , EMMFSoundEncoding16BitPCM // 1 + , EMMFSoundEncoding16BitPCM // 2 + , EMMFSoundEncoding16BitPCM // 3 + , EMMFSoundEncoding16BitPCM // 4 + , EMMFSoundEncoding16BitPCM // 5 +}; + + +const int EncodingSampleSize[EncodingCount] = { + 8 // 0 + , 8 // 1 + , 16 // 2 + , 16 // 3 + , 16 // 4 + , 16 // 5 +}; + +const QAudioFormat::Endian EncodingByteOrder[EncodingCount] = { + QAudioFormat::LittleEndian // 0 + , QAudioFormat::LittleEndian // 1 + , QAudioFormat::LittleEndian // 2 + , QAudioFormat::LittleEndian // 3 + , QAudioFormat::BigEndian // 4 + , QAudioFormat::BigEndian // 5 +}; + +const QAudioFormat::SampleType EncodingSampleType[EncodingCount] = { + QAudioFormat::SignedInt // 0 + , QAudioFormat::UnSignedInt // 1 + , QAudioFormat::SignedInt // 2 + , QAudioFormat::UnSignedInt // 3 + , QAudioFormat::SignedInt // 4 + , QAudioFormat::UnSignedInt // 5 +}; + + +//----------------------------------------------------------------------------- +// Private functions +//----------------------------------------------------------------------------- + +// Helper functions for implementing parameter conversions + +template +bool findValue(const Input *inputArray, int length, Input input, int &index) { + bool result = false; + for (int i=0; !result && i +bool convertValue(const Input *inputArray, const Output *outputArray, + int length, Input input, Output &output) { + int index; + const bool result = findValue(inputArray, length, input, index); + if (result) + output = outputArray[index]; + return result; +} + +/** + * Macro which is used to generate the implementation of the conversion + * functions. The implementation is just a wrapper around the templated + * convertValue function, e.g. + * + * CONVERSION_FUNCTION_IMPL(SampleRate, Qt, Native) + * + * expands to + * + * bool SampleRateQtToNative(int input, TMMFSampleRate &output) { + * return convertValue + * (SampleRateListQt, SampleRateListNative, SampleRateCount, + * input, output); + * } + */ +#define CONVERSION_FUNCTION_IMPL(FieldLc, Field, Input, Output) \ +bool FieldLc##Input##To##Output(Field##Input input, Field##Output &output) { \ + return convertValue(Field##List##Input, \ + Field##List##Output, Field##Count, input, output); \ +} + +//----------------------------------------------------------------------------- +// Local helper functions +//----------------------------------------------------------------------------- + +CONVERSION_FUNCTION_IMPL(sampleRate, SampleRate, Qt, Native) +CONVERSION_FUNCTION_IMPL(sampleRate, SampleRate, Native, Qt) +CONVERSION_FUNCTION_IMPL(channels, Channels, Qt, Native) +CONVERSION_FUNCTION_IMPL(channels, Channels, Native, Qt) + +bool sampleInfoQtToNative(int inputSampleSize, + QAudioFormat::Endian inputByteOrder, + QAudioFormat::SampleType inputSampleType, + TUint32 &outputFourCC, + TMMFSoundEncoding &outputEncoding) { + + bool found = false; + + for (int i=0; i &frequencies, + QList &channels, + QList &sampleSizes, + QList &byteOrders, + QList &sampleTypes) { + + frequencies.clear(); + sampleSizes.clear(); + byteOrders.clear(); + sampleTypes.clear(); + channels.clear(); + + for (int i=0; i& DevSoundWrapper::supportedCodecs() const +{ + return m_supportedCodecs; +} + +void DevSoundWrapper::initialize(const QString& codec) +{ + Q_ASSERT(StateInitializing != m_state); + m_state = StateInitializing; + if (QLatin1String("audio/pcm") == codec) { + m_fourcc = KMMFFourCCCodePCM16; + TRAPD(err, m_devsound->InitializeL(*this, m_fourcc, m_nativeMode)); + if (KErrNone != err) { + m_state = StateIdle; + emit initializeComplete(err); + } + } else { + emit initializeComplete(KErrNotSupported); + } +} + +const QList& DevSoundWrapper::supportedFrequencies() const +{ + Q_ASSERT(StateInitialized == m_state); + return m_supportedFrequencies; +} + +const QList& DevSoundWrapper::supportedChannels() const +{ + Q_ASSERT(StateInitialized == m_state); + return m_supportedChannels; +} + +const QList& DevSoundWrapper::supportedSampleSizes() const +{ + Q_ASSERT(StateInitialized == m_state); + return m_supportedSampleSizes; +} + +const QList& DevSoundWrapper::supportedByteOrders() const +{ + Q_ASSERT(StateInitialized == m_state); + return m_supportedByteOrders; +} + +const QList& DevSoundWrapper::supportedSampleTypes() const +{ + Q_ASSERT(StateInitialized == m_state); + return m_supportedSampleTypes; +} + +bool DevSoundWrapper::isFormatSupported(const QAudioFormat &format) const +{ + Q_ASSERT(StateInitialized == m_state); + return m_supportedCodecs.contains(format.codec()) + && m_supportedFrequencies.contains(format.frequency()) + && m_supportedChannels.contains(format.channels()) + && m_supportedSampleSizes.contains(format.sampleSize()) + && m_supportedSampleTypes.contains(format.sampleType()) + && m_supportedByteOrders.contains(format.byteOrder()); +} + +int DevSoundWrapper::samplesProcessed() const +{ + int result = 0; + if (StateInitialized == m_state) { + switch (m_mode) { + case QAudio::AudioInput: + result = m_devsound->SamplesRecorded(); + break; + case QAudio::AudioOutput: + result = m_devsound->SamplesPlayed(); + break; + } + } + return result; +} + +bool DevSoundWrapper::setFormat(const QAudioFormat &format) +{ + Q_ASSERT(StateInitialized == m_state); + bool result = false; + TUint32 fourcc; + TMMFCapabilities nativeFormat; + if (Utils::formatQtToNative(format, fourcc, nativeFormat)) { + TMMFCapabilities currentNativeFormat = m_devsound->Config(); + nativeFormat.iBufferSize = currentNativeFormat.iBufferSize; + TRAPD(err, m_devsound->SetConfigL(nativeFormat)); + result = (KErrNone == err); + } + return result; +} + +bool DevSoundWrapper::start() +{ + Q_ASSERT(StateInitialized == m_state); + int err = KErrArgument; + switch (m_mode) { + case QAudio::AudioInput: + TRAP(err, m_devsound->RecordInitL()); + break; + case QAudio::AudioOutput: + TRAP(err, m_devsound->PlayInitL()); + break; + } + return (KErrNone == err); +} + +bool DevSoundWrapper::pause() +{ + Q_ASSERT(StateInitialized == m_state); +#ifndef PRE_S60_52_PLATFORM + if (m_mode == QAudio::AudioOutput ) { + m_devsound->Pause(); + return true; + } else { + const bool canPause = isResumeSupported(); + if (canPause) + m_devsound->Pause(); + else + stop(); + return canPause; + } +#else + const bool canPause = isResumeSupported(); + if (canPause) + m_devsound->Pause(); + else + stop(); + return canPause; +#endif +} + +void DevSoundWrapper::resume() +{ + Q_ASSERT(StateInitialized == m_state); + Q_ASSERT(isResumeSupported()); + // TODO: QTBUG-13625 +} + +void DevSoundWrapper::stop() +{ + m_devsound->Stop(); +} + +void DevSoundWrapper::bufferProcessed() +{ + Q_ASSERT(StateInitialized == m_state); + switch (m_mode) { + case QAudio::AudioInput: + m_devsound->RecordData(); + break; + case QAudio::AudioOutput: + m_devsound->PlayData(); + break; + } +} + +void DevSoundWrapper::getSupportedCodecs() +{ +/* + * TODO: once we support formats other than PCM, this function should + * convert the array of FourCC codes into MIME types for each codec. + * + RArray fourcc; + QT_TRAP_THROWING(CleanupClosePushL(&fourcc)); + + TMMFPrioritySettings settings; + switch (mode) { + case QAudio::AudioOutput: + settings.iState = EMMFStatePlaying; + m_devsound->GetSupportedInputDataTypesL(fourcc, settings); + break; + + case QAudio::AudioInput: + settings.iState = EMMFStateRecording; + m_devsound->GetSupportedInputDataTypesL(fourcc, settings); + break; + + default: + Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid mode"); + } + + CleanupStack::PopAndDestroy(); // fourcc +*/ + + m_supportedCodecs.append(QLatin1String("audio/pcm")); +} + +void DevSoundWrapper::populateCapabilities() +{ + m_supportedFrequencies.clear(); + m_supportedChannels.clear(); + m_supportedSampleSizes.clear(); + m_supportedByteOrders.clear(); + m_supportedSampleTypes.clear(); + + const TMMFCapabilities caps = m_devsound->Capabilities(); + + for (int i=0; iEmptyBuffers(); +} +#endif +} // namespace SymbianAudio + +QT_END_NAMESPACE + + diff --git a/src/multimediakit/audio/qaudio_symbian_p.h b/src/multimediakit/audio/qaudio_symbian_p.h new file mode 100644 index 000000000..26f1a3f44 --- /dev/null +++ b/src/multimediakit/audio/qaudio_symbian_p.h @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QAUDIO_SYMBIAN_P_H +#define QAUDIO_SYMBIAN_P_H + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace SymbianAudio { + +/** + * Default values used by audio input and output classes, when underlying + * DevSound instance has not yet been created. + */ + +const int DefaultBufferSize = 4096; // bytes +const int DefaultNotifyInterval = 1000; // ms + +/** + * Enumeration used to track state of internal DevSound instances. + * Values are translated to the corresponding QAudio::State values by + * SymbianAudio::Utils::stateNativeToQt. + */ +enum State { + ClosedState + , InitializingState + , ActiveState + , IdleState + // QAudio is suspended; DevSound is paused + , SuspendedPausedState + // QAudio is suspended; DevSound is stopped + , SuspendedStoppedState +}; + +/** + * Wrapper around DevSound instance + */ +class DevSoundWrapper + : public QObject + , public MDevSoundObserver +{ + Q_OBJECT + +public: + DevSoundWrapper(QAudio::Mode mode, QObject *parent = 0); + ~DevSoundWrapper(); + +public: + // List of supported codecs; can be called once object is constructed + const QList& supportedCodecs() const; + + // Asynchronous initialization function; emits devsoundInitializeComplete + void initialize(const QString& codec); + + // Capabilities, for selected codec. Can be called once initialize has returned + // successfully. + const QList& supportedFrequencies() const; + const QList& supportedChannels() const; + const QList& supportedSampleSizes() const; + const QList& supportedByteOrders() const; + const QList& supportedSampleTypes() const; + + bool isFormatSupported(const QAudioFormat &format) const; + + int samplesProcessed() const; + bool setFormat(const QAudioFormat &format); + bool start(); + + // If DevSound implementation supports pause, calls pause and returns true. + // Otherwise calls stop and returns false. In this case, all DevSound buffers + // currently held by the backend must be discarded. + bool pause(); + + void resume(); + + void stop(); + void bufferProcessed(); +#ifndef PRE_S60_52_PLATFORM + int flush(); +#endif + +public: + // MDevSoundObserver + void InitializeComplete(TInt aError); + void ToneFinished(TInt aError); + void BufferToBeFilled(CMMFBuffer *aBuffer); + void PlayError(TInt aError); + void BufferToBeEmptied(CMMFBuffer *aBuffer); + void RecordError(TInt aError); + void ConvertError(TInt aError); + void DeviceMessage(TUid aMessageType, const TDesC8 &aMsg); + +signals: + void initializeComplete(int error); + void bufferToBeProcessed(CMMFBuffer *buffer); + void processingError(int error); + +private: + void getSupportedCodecs(); + void populateCapabilities(); + bool isResumeSupported() const; + +private: + const QAudio::Mode m_mode; + TMMFState m_nativeMode; + + enum State { + StateIdle, + StateInitializing, + StateInitialized + } m_state; + + CMMFDevSound* m_devsound; + TFourCC m_fourcc; + + QList m_supportedCodecs; + QList m_supportedFrequencies; + QList m_supportedChannels; + QList m_supportedSampleSizes; + QList m_supportedByteOrders; + QList m_supportedSampleTypes; + +}; + + +namespace Utils { + +/** + * Convert internal states to QAudio states. + */ +QAudio::State stateNativeToQt(State nativeState); + +/** + * Convert data length to number of samples. + */ +qint64 bytesToSamples(const QAudioFormat &format, qint64 length); + +/** + * Convert number of samples to data length. + */ +qint64 samplesToBytes(const QAudioFormat &format, qint64 samples); + +} // namespace Utils +} // namespace SymbianAudio + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/audio/qaudiodevicefactory.cpp b/src/multimediakit/audio/qaudiodevicefactory.cpp new file mode 100644 index 000000000..221b327dc --- /dev/null +++ b/src/multimediakit/audio/qaudiodevicefactory.cpp @@ -0,0 +1,292 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "qaudiosystem.h" +#include "qaudiosystemplugin.h" + +#include "qaudiopluginloader_p.h" +#include "qaudiodevicefactory_p.h" + +#ifndef QT_NO_AUDIO_BACKEND +#if defined(Q_OS_WIN) +#include "qaudiodeviceinfo_win32_p.h" +#include "qaudiooutput_win32_p.h" +#include "qaudioinput_win32_p.h" +#elif defined(Q_OS_MAC) +#include "qaudiodeviceinfo_mac_p.h" +#include "qaudiooutput_mac_p.h" +#include "qaudioinput_mac_p.h" +#elif defined(HAS_ALSA) +#include "qaudiodeviceinfo_alsa_p.h" +#include "qaudiooutput_alsa_p.h" +#include "qaudioinput_alsa_p.h" +#elif defined(Q_OS_SYMBIAN) +#include "qaudiodeviceinfo_symbian_p.h" +#include "qaudiooutput_symbian_p.h" +#include "qaudioinput_symbian_p.h" +#endif +#endif + +QT_BEGIN_NAMESPACE + +#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +Q_GLOBAL_STATIC_WITH_ARGS(QAudioPluginLoader, audioLoader, + (QAudioSystemFactoryInterface_iid, QLatin1String("/audio"), Qt::CaseInsensitive)) +#endif + +class QNullDeviceInfo : public QAbstractAudioDeviceInfo +{ +public: + QAudioFormat preferredFormat() const { qWarning()<<"using null deviceinfo, none available"; return QAudioFormat(); } + bool isFormatSupported(const QAudioFormat& ) const { return false; } + QAudioFormat nearestFormat(const QAudioFormat& ) const { return QAudioFormat(); } + QString deviceName() const { return QString(); } + QStringList supportedCodecs() { return QStringList(); } + QList supportedSampleRates() { return QList(); } + QList supportedChannelCounts() { return QList(); } + QList supportedSampleSizes() { return QList(); } + QList supportedByteOrders() { return QList(); } + QList supportedSampleTypes() { return QList(); } +}; + +class QNullInputDevice : public QAbstractAudioInput +{ +public: + void start(QIODevice*) { qWarning()<<"using null input device, none available";} + QIODevice* start() { qWarning()<<"using null input device, none available"; return 0; } + void stop() {} + void reset() {} + void suspend() {} + void resume() {} + int bytesReady() const { return 0; } + int periodSize() const { return 0; } + void setBufferSize(int ) {} + int bufferSize() const { return 0; } + void setNotifyInterval(int ) {} + int notifyInterval() const { return 0; } + qint64 processedUSecs() const { return 0; } + qint64 elapsedUSecs() const { return 0; } + QAudio::Error error() const { return QAudio::OpenError; } + QAudio::State state() const { return QAudio::StoppedState; } + void setFormat(const QAudioFormat&) {} + QAudioFormat format() const { return QAudioFormat(); } +}; + +class QNullOutputDevice : public QAbstractAudioOutput +{ +public: + void start(QIODevice*) {qWarning()<<"using null output device, none available";} + QIODevice* start() { qWarning()<<"using null output device, none available"; return 0; } + void stop() {} + void reset() {} + void suspend() {} + void resume() {} + int bytesFree() const { return 0; } + int periodSize() const { return 0; } + void setBufferSize(int ) {} + int bufferSize() const { return 0; } + void setNotifyInterval(int ) {} + int notifyInterval() const { return 0; } + qint64 processedUSecs() const { return 0; } + qint64 elapsedUSecs() const { return 0; } + QAudio::Error error() const { return QAudio::OpenError; } + QAudio::State state() const { return QAudio::StoppedState; } + void setFormat(const QAudioFormat&) {} + QAudioFormat format() const { return QAudioFormat(); } +}; + +QList QAudioDeviceFactory::availableDevices(QAudio::Mode mode) +{ + QList devices; +#ifndef QT_NO_AUDIO_BACKEND +#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA) || defined(Q_OS_SYMBIAN)) + foreach (const QByteArray &handle, QAudioDeviceInfoInternal::availableDevices(mode)) + devices << QAudioDeviceInfo(QLatin1String("builtin"), handle, mode); +#endif +#endif + +#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + QAudioPluginLoader* l = audioLoader(); + foreach (const QString& key, l->keys()) { + QAudioSystemFactoryInterface* plugin = qobject_cast(l->instance(key)); + if (plugin) { + foreach (QByteArray const& handle, plugin->availableDevices(mode)) + devices << QAudioDeviceInfo(key, handle, mode); + } + + delete plugin; + } +#endif + + return devices; +} + +QAudioDeviceInfo QAudioDeviceFactory::defaultInputDevice() +{ +#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + QAudioSystemFactoryInterface* plugin = qobject_cast(audioLoader()->instance(QLatin1String("default"))); + + if (plugin) { + QList list = plugin->availableDevices(QAudio::AudioInput); + if (list.size() > 0) + return QAudioDeviceInfo(QLatin1String("default"), list.at(0), QAudio::AudioInput); + } +#endif + +#ifndef QT_NO_AUDIO_BACKEND +#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA) || defined(Q_OS_SYMBIAN)) + return QAudioDeviceInfo(QLatin1String("builtin"), QAudioDeviceInfoInternal::defaultInputDevice(), QAudio::AudioInput); +#endif +#endif + return QAudioDeviceInfo(); +} + +QAudioDeviceInfo QAudioDeviceFactory::defaultOutputDevice() +{ +#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + QAudioSystemFactoryInterface* plugin = qobject_cast(audioLoader()->instance(QLatin1String("default"))); + + if (plugin) { + QList list = plugin->availableDevices(QAudio::AudioOutput); + if (list.size() > 0) + return QAudioDeviceInfo(QLatin1String("default"), list.at(0), QAudio::AudioOutput); + } +#endif + +#ifndef QT_NO_AUDIO_BACKEND +#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA) || defined(Q_OS_SYMBIAN)) + return QAudioDeviceInfo(QLatin1String("builtin"), QAudioDeviceInfoInternal::defaultOutputDevice(), QAudio::AudioOutput); +#endif +#endif + return QAudioDeviceInfo(); +} + +QAbstractAudioDeviceInfo* QAudioDeviceFactory::audioDeviceInfo(const QString &realm, const QByteArray &handle, QAudio::Mode mode) +{ + QAbstractAudioDeviceInfo *rc = 0; + +#ifndef QT_NO_AUDIO_BACKEND +#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA) || defined(Q_OS_SYMBIAN)) + if (realm == QLatin1String("builtin")) + return new QAudioDeviceInfoInternal(handle, mode); +#endif +#endif + +#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + QAudioSystemFactoryInterface* plugin = + qobject_cast(audioLoader()->instance(realm)); + + if (plugin) + rc = plugin->createDeviceInfo(handle, mode); +#endif + + return rc == 0 ? new QNullDeviceInfo() : rc; +} + +QAbstractAudioInput* QAudioDeviceFactory::createDefaultInputDevice(QAudioFormat const &format) +{ + return createInputDevice(defaultInputDevice(), format); +} + +QAbstractAudioOutput* QAudioDeviceFactory::createDefaultOutputDevice(QAudioFormat const &format) +{ + return createOutputDevice(defaultOutputDevice(), format); +} + +QAbstractAudioInput* QAudioDeviceFactory::createInputDevice(QAudioDeviceInfo const& deviceInfo, QAudioFormat const &format) +{ + if (deviceInfo.isNull()) + return new QNullInputDevice(); +#ifndef QT_NO_AUDIO_BACKEND +#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA) || defined(Q_OS_SYMBIAN)) + if (deviceInfo.realm() == QLatin1String("builtin")) { + QAbstractAudioInput* p = new QAudioInputPrivate(deviceInfo.handle()); + if (p) p->setFormat(format); + return p; + } +#endif +#endif +#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + QAudioSystemFactoryInterface* plugin = + qobject_cast(audioLoader()->instance(deviceInfo.realm())); + + if (plugin) { + QAbstractAudioInput* p = plugin->createInput(deviceInfo.handle()); + if (p) p->setFormat(format); + return p; + } +#endif + + return new QNullInputDevice(); +} + +QAbstractAudioOutput* QAudioDeviceFactory::createOutputDevice(QAudioDeviceInfo const& deviceInfo, QAudioFormat const &format) +{ + if (deviceInfo.isNull()) + return new QNullOutputDevice(); +#ifndef QT_NO_AUDIO_BACKEND +#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA) || defined(Q_OS_SYMBIAN)) + if (deviceInfo.realm() == QLatin1String("builtin")) { + QAbstractAudioOutput* p = new QAudioOutputPrivate(deviceInfo.handle()); + if (p) p->setFormat(format); + return p; + } +#endif +#endif + +#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + QAudioSystemFactoryInterface* plugin = + qobject_cast(audioLoader()->instance(deviceInfo.realm())); + + if (plugin) { + QAbstractAudioOutput* p = plugin->createOutput(deviceInfo.handle()); + if (p) p->setFormat(format); + return p; + } +#endif + + return new QNullOutputDevice(); +} + +QT_END_NAMESPACE + diff --git a/src/multimediakit/audio/qaudiodevicefactory_p.h b/src/multimediakit/audio/qaudiodevicefactory_p.h new file mode 100644 index 000000000..e162e04d6 --- /dev/null +++ b/src/multimediakit/audio/qaudiodevicefactory_p.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QAUDIODEVICEFACTORY_P_H +#define QAUDIODEVICEFACTORY_P_H + +#include +#include + +#include +#include + +#include "qaudiodeviceinfo.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QAbstractAudioInput; +class QAbstractAudioOutput; +class QAbstractAudioDeviceInfo; + +class QAudioDeviceFactory +{ +public: + static QList availableDevices(QAudio::Mode mode); + + static QAudioDeviceInfo defaultInputDevice(); + static QAudioDeviceInfo defaultOutputDevice(); + + static QAbstractAudioDeviceInfo* audioDeviceInfo(const QString &realm, const QByteArray &handle, QAudio::Mode mode); + + static QAbstractAudioInput* createDefaultInputDevice(QAudioFormat const &format); + static QAbstractAudioOutput* createDefaultOutputDevice(QAudioFormat const &format); + + static QAbstractAudioInput* createInputDevice(QAudioDeviceInfo const &device, QAudioFormat const &format); + static QAbstractAudioOutput* createOutputDevice(QAudioDeviceInfo const &device, QAudioFormat const &format); + + static QAbstractAudioInput* createNullInput(); + static QAbstractAudioOutput* createNullOutput(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIODEVICEFACTORY_P_H + diff --git a/src/multimediakit/audio/qaudiodeviceinfo.cpp b/src/multimediakit/audio/qaudiodeviceinfo.cpp new file mode 100644 index 000000000..44cc8fe79 --- /dev/null +++ b/src/multimediakit/audio/qaudiodeviceinfo.cpp @@ -0,0 +1,487 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaudiodevicefactory_p.h" +#include "qaudiosystem.h" +#include "qaudiodeviceinfo.h" + +#include + +QT_BEGIN_NAMESPACE + +class QAudioDeviceInfoPrivate : public QSharedData +{ +public: + QAudioDeviceInfoPrivate():info(0) {} + QAudioDeviceInfoPrivate(const QString &r, const QByteArray &h, QAudio::Mode m): + realm(r), handle(h), mode(m) + { + if (!handle.isEmpty()) + info = QAudioDeviceFactory::audioDeviceInfo(realm, handle, mode); + else + info = NULL; + } + + QAudioDeviceInfoPrivate(const QAudioDeviceInfoPrivate &other): + QSharedData(other), + realm(other.realm), handle(other.handle), mode(other.mode) + { + info = QAudioDeviceFactory::audioDeviceInfo(realm, handle, mode); + } + + QAudioDeviceInfoPrivate& operator=(const QAudioDeviceInfoPrivate &other) + { + delete info; + + realm = other.realm; + handle = other.handle; + mode = other.mode; + info = QAudioDeviceFactory::audioDeviceInfo(realm, handle, mode); + return *this; + } + + ~QAudioDeviceInfoPrivate() + { + delete info; + } + + QString realm; + QByteArray handle; + QAudio::Mode mode; + QAbstractAudioDeviceInfo* info; +}; + + +/*! + \class QAudioDeviceInfo + \brief The QAudioDeviceInfo class provides an interface to query audio devices and their functionality. + \inmodule QtMultimediaKit + \ingroup multimedia + + \since QtMobility 1.0 + + QAudioDeviceInfo lets you query for audio devices--such as sound + cards and USB headsets--that are currently available on the system. + The audio devices available are dependent on the platform or audio plugins installed. + + A QAudioDeviceInfo is used by Qt to construct + classes that communicate with the device--such as + QAudioInput, and QAudioOutput. + + You can also query each device for the formats it supports. A + format in this context is a set consisting of a specific byte + order, channel, codec, frequency, sample rate, and sample type. A + format is represented by the QAudioFormat class. + + The values supported by the the device for each of these + parameters can be fetched with + supportedByteOrders(), supportedChannelCounts(), supportedCodecs(), + supportedSampleRates(), supportedSampleSizes(), and + supportedSampleTypes(). The combinations supported are dependent on the platform, + audio plugins installed and the audio device capabilities. If you need a + specific format, you can check if + the device supports it with isFormatSupported(), or fetch a + supported format that is as close as possible to the format with + nearestFormat(). For instance: + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Setting audio format + + The static + functions defaultInputDevice(), defaultOutputDevice(), and + availableDevices() let you get a list of all available + devices. Devices are fetched according to the value of mode + this is specified by the \l {QAudio}::Mode enum. + The QAudioDeviceInfo returned are only valid for the \l {QAudio}::Mode. + + For instance: + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Dumping audio formats + + In this code sample, we loop through all devices that are able to output + sound, i.e., play an audio stream in a supported format. For each device we + find, we simply print the deviceName(). + + \sa QAudioOutput, QAudioInput +*/ + +/*! + Constructs an empty QAudioDeviceInfo object. +*/ +QAudioDeviceInfo::QAudioDeviceInfo(): + d(new QAudioDeviceInfoPrivate) +{ +} + +/*! + Constructs a copy of \a other. + \since 1.0 +*/ +QAudioDeviceInfo::QAudioDeviceInfo(const QAudioDeviceInfo& other): + d(other.d) +{ +} + +/*! + Destroy this audio device info. +*/ +QAudioDeviceInfo::~QAudioDeviceInfo() +{ +} + +/*! + Sets the QAudioDeviceInfo object to be equal to \a other. + \since 1.0 +*/ +QAudioDeviceInfo& QAudioDeviceInfo::operator=(const QAudioDeviceInfo &other) +{ + d = other.d; + return *this; +} + +/*! + Returns whether this QAudioDeviceInfo object holds a device definition. + \since 1.0 +*/ +bool QAudioDeviceInfo::isNull() const +{ + return d->info == 0; +} + +/*! + Returns the human readable name of the audio device. + + Device names vary depending on the platform/audio plugin being used. + + XXX + + They are a unique string identifier for the audio device. + + eg. default, Intel, U0x46d0x9a4 + \since 1.0 +*/ +QString QAudioDeviceInfo::deviceName() const +{ + return isNull() ? QString() : d->info->deviceName(); +} + +/*! + Returns true if the supplied \a settings are supported by the audio + device described by this QAudioDeviceInfo. + \since 1.0 +*/ +bool QAudioDeviceInfo::isFormatSupported(const QAudioFormat &settings) const +{ + return isNull() ? false : d->info->isFormatSupported(settings); +} + +/*! + Returns the default audio format settings for this device. + + These settings are provided by the platform/audio plugin being used. + + They are also dependent on the \l {QAudio}::Mode being used. + + A typical audio system would provide something like: + \list + \o Input settings: 8000Hz mono 8 bit. + \o Output settings: 44100Hz stereo 16 bit little endian. + \endlist + \since 1.0 +*/ +QAudioFormat QAudioDeviceInfo::preferredFormat() const +{ + return isNull() ? QAudioFormat() : d->info->preferredFormat(); +} + +/*! + Returns the closest QAudioFormat to the supplied \a settings that the system supports. + + These settings are provided by the platform/audio plugin being used. + + They are also dependent on the \l {QAudio}::Mode being used. + \since 1.0 +*/ +QAudioFormat QAudioDeviceInfo::nearestFormat(const QAudioFormat &settings) const +{ + if (isFormatSupported(settings)) + return settings; + + QAudioFormat nearest = settings; + + QList testCodecs = supportedCodecs(); + QList testChannels = supportedChannels(); + QList testByteOrders = supportedByteOrders(); + QList testSampleTypes; + QList sampleTypesAvailable = supportedSampleTypes(); + QMap testFrequencies; + QList frequenciesAvailable = supportedFrequencies(); + QMap testSampleSizes; + QList sampleSizesAvailable = supportedSampleSizes(); + + // Get sorted lists for checking + if (testCodecs.contains(settings.codec())) { + testCodecs.removeAll(settings.codec()); + testCodecs.insert(0, settings.codec()); + } + testChannels.removeAll(settings.channels()); + testChannels.insert(0, settings.channels()); + testByteOrders.removeAll(settings.byteOrder()); + testByteOrders.insert(0, settings.byteOrder()); + + if (sampleTypesAvailable.contains(settings.sampleType())) + testSampleTypes.append(settings.sampleType()); + if (sampleTypesAvailable.contains(QAudioFormat::SignedInt)) + testSampleTypes.append(QAudioFormat::SignedInt); + if (sampleTypesAvailable.contains(QAudioFormat::UnSignedInt)) + testSampleTypes.append(QAudioFormat::UnSignedInt); + if (sampleTypesAvailable.contains(QAudioFormat::Float)) + testSampleTypes.append(QAudioFormat::Float); + + if (sampleSizesAvailable.contains(settings.sampleSize())) + testSampleSizes.insert(0,settings.sampleSize()); + sampleSizesAvailable.removeAll(settings.sampleSize()); + foreach (int size, sampleSizesAvailable) { + int larger = (size > settings.sampleSize()) ? size : settings.sampleSize(); + int smaller = (size > settings.sampleSize()) ? settings.sampleSize() : size; + bool isMultiple = ( 0 == (larger % smaller)); + int diff = larger - smaller; + testSampleSizes.insert((isMultiple ? diff : diff+100000), size); + } + if (frequenciesAvailable.contains(settings.frequency())) + testFrequencies.insert(0,settings.frequency()); + frequenciesAvailable.removeAll(settings.frequency()); + foreach (int frequency, frequenciesAvailable) { + int larger = (frequency > settings.frequency()) ? frequency : settings.frequency(); + int smaller = (frequency > settings.frequency()) ? settings.frequency() : frequency; + bool isMultiple = ( 0 == (larger % smaller)); + int diff = larger - smaller; + testFrequencies.insert((isMultiple ? diff : diff+100000), frequency); + } + + // Try to find nearest + foreach (QString codec, testCodecs) { + nearest.setCodec(codec); + foreach (QAudioFormat::Endian order, testByteOrders) { + nearest.setByteOrder(order); + foreach (QAudioFormat::SampleType sample, testSampleTypes) { + nearest.setSampleType(sample); + QMapIterator sz(testSampleSizes); + while (sz.hasNext()) { + sz.next(); + nearest.setSampleSize(sz.value()); + foreach (int channel, testChannels) { + nearest.setChannels(channel); + QMapIterator i(testFrequencies); + while (i.hasNext()) { + i.next(); + nearest.setFrequency(i.value()); + if (isFormatSupported(nearest)) + return nearest; + } + } + } + } + } + } + //Fallback + return preferredFormat(); +} + +/*! + Returns a list of supported codecs. + + All platform and plugin implementations should provide support for: + + "audio/pcm" - Linear PCM + + For writing plugins to support additional codecs refer to: + + http://www.iana.org/assignments/media-types/audio/ + \since 1.0 +*/ +QStringList QAudioDeviceInfo::supportedCodecs() const +{ + return isNull() ? QStringList() : d->info->supportedCodecs(); +} + +/*! + Returns a list of supported sample rates (in Hertz). + + \since 1.0 +*/ +QList QAudioDeviceInfo::supportedSampleRates() const +{ + return supportedFrequencies(); +} + +/*! + \obsolete + + Use supportedSampleRates() instead. + \since 1.0 +*/ +QList QAudioDeviceInfo::supportedFrequencies() const +{ + return isNull() ? QList() : d->info->supportedSampleRates(); +} + +/*! + Returns a list of supported channel counts. + + This is typically 1 for mono sound, or 2 for stereo sound. + + \since 1.0 +*/ +QList QAudioDeviceInfo::supportedChannelCounts() const +{ + return supportedChannels(); +} + +/*! + \obsolete + + Use supportedChannelCount() instead. + \since 1.0 +*/ +QList QAudioDeviceInfo::supportedChannels() const +{ + return isNull() ? QList() : d->info->supportedChannelCounts(); +} + +/*! + Returns a list of supported sample sizes (in bits). + + Typically this will include 8 and 16 bit sample sizes. + + \since 1.0 +*/ +QList QAudioDeviceInfo::supportedSampleSizes() const +{ + return isNull() ? QList() : d->info->supportedSampleSizes(); +} + +/*! + Returns a list of supported byte orders. + \since 1.0 +*/ +QList QAudioDeviceInfo::supportedByteOrders() const +{ + return isNull() ? QList() : d->info->supportedByteOrders(); +} + +/*! + Returns a list of supported sample types. + \since 1.0 +*/ +QList QAudioDeviceInfo::supportedSampleTypes() const +{ + return isNull() ? QList() : d->info->supportedSampleTypes(); +} + +/*! + Returns the information for the default input audio device. + All platform and audio plugin implementations provide a default audio device to use. + \since 1.0 +*/ +QAudioDeviceInfo QAudioDeviceInfo::defaultInputDevice() +{ + return QAudioDeviceFactory::defaultInputDevice(); +} + +/*! + Returns the information for the default output audio device. + All platform and audio plugin implementations provide a default audio device to use. + \since 1.0 +*/ +QAudioDeviceInfo QAudioDeviceInfo::defaultOutputDevice() +{ + return QAudioDeviceFactory::defaultOutputDevice(); +} + +/*! + Returns a list of audio devices that support \a mode. + \since 1.0 +*/ +QList QAudioDeviceInfo::availableDevices(QAudio::Mode mode) +{ + return QAudioDeviceFactory::availableDevices(mode); +} + + +/*! + \internal + \since 1.0 +*/ +QAudioDeviceInfo::QAudioDeviceInfo(const QString &realm, const QByteArray &handle, QAudio::Mode mode): + d(new QAudioDeviceInfoPrivate(realm, handle, mode)) +{ +} + +/*! + \internal + \since 1.0 +*/ +QString QAudioDeviceInfo::realm() const +{ + return d->realm; +} + +/*! + \internal + \since 1.0 +*/ +QByteArray QAudioDeviceInfo::handle() const +{ + return d->handle; +} + + +/*! + \internal + \since 1.0 +*/ +QAudio::Mode QAudioDeviceInfo::mode() const +{ + return d->mode; +} + +QT_END_NAMESPACE + diff --git a/src/multimediakit/audio/qaudiodeviceinfo.h b/src/multimediakit/audio/qaudiodeviceinfo.h new file mode 100644 index 000000000..547093238 --- /dev/null +++ b/src/multimediakit/audio/qaudiodeviceinfo.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QAUDIODEVICEINFO_H +#define QAUDIODEVICEINFO_H + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QAudioDeviceFactory; + +class QAudioDeviceInfoPrivate; +class Q_MULTIMEDIA_EXPORT QAudioDeviceInfo +{ + friend class QAudioDeviceFactory; + +public: + QAudioDeviceInfo(); + QAudioDeviceInfo(const QAudioDeviceInfo& other); + ~QAudioDeviceInfo(); + + QAudioDeviceInfo& operator=(const QAudioDeviceInfo& other); + + bool isNull() const; + + QString deviceName() const; + + bool isFormatSupported(const QAudioFormat &format) const; + QAudioFormat preferredFormat() const; + QAudioFormat nearestFormat(const QAudioFormat &format) const; + + QStringList supportedCodecs() const; + QList supportedFrequencies() const; + QList supportedSampleRates() const; + QList supportedChannels() const; + QList supportedChannelCounts() const; + QList supportedSampleSizes() const; + QList supportedByteOrders() const; + QList supportedSampleTypes() const; + + static QAudioDeviceInfo defaultInputDevice(); + static QAudioDeviceInfo defaultOutputDevice(); + + static QList availableDevices(QAudio::Mode mode); + +private: + QAudioDeviceInfo(const QString &realm, const QByteArray &handle, QAudio::Mode mode); + QString realm() const; + QByteArray handle() const; + QAudio::Mode mode() const; + + QSharedDataPointer d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +Q_DECLARE_METATYPE(QAudioDeviceInfo) + +#endif // QAUDIODEVICEINFO_H diff --git a/src/multimediakit/audio/qaudiodeviceinfo_alsa_p.cpp b/src/multimediakit/audio/qaudiodeviceinfo_alsa_p.cpp new file mode 100644 index 000000000..bce7039ab --- /dev/null +++ b/src/multimediakit/audio/qaudiodeviceinfo_alsa_p.cpp @@ -0,0 +1,535 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include "qaudiodeviceinfo_alsa_p.h" + +#include + +QT_BEGIN_NAMESPACE + +QAudioDeviceInfoInternal::QAudioDeviceInfoInternal(QByteArray dev, QAudio::Mode mode) +{ + handle = 0; + + device = QLatin1String(dev); + this->mode = mode; + + checkSurround(); +} + +QAudioDeviceInfoInternal::~QAudioDeviceInfoInternal() +{ + close(); +} + +bool QAudioDeviceInfoInternal::isFormatSupported(const QAudioFormat& format) const +{ + return testSettings(format); +} + +QAudioFormat QAudioDeviceInfoInternal::preferredFormat() const +{ + QAudioFormat nearest; + if(mode == QAudio::AudioOutput) { + nearest.setFrequency(44100); + nearest.setChannels(2); + nearest.setByteOrder(QAudioFormat::LittleEndian); + nearest.setSampleType(QAudioFormat::SignedInt); + nearest.setSampleSize(16); + nearest.setCodec(QLatin1String("audio/pcm")); + } else { + nearest.setFrequency(8000); + nearest.setChannels(1); + nearest.setSampleType(QAudioFormat::UnSignedInt); + nearest.setSampleSize(8); + nearest.setCodec(QLatin1String("audio/pcm")); + if(!testSettings(nearest)) { + nearest.setChannels(2); + nearest.setSampleSize(16); + nearest.setSampleType(QAudioFormat::SignedInt); + } + } + return nearest; +} + +QString QAudioDeviceInfoInternal::deviceName() const +{ + return device; +} + +QStringList QAudioDeviceInfoInternal::supportedCodecs() +{ + updateLists(); + return codecz; +} + +QList QAudioDeviceInfoInternal::supportedSampleRates() +{ + updateLists(); + return freqz; +} + +QList QAudioDeviceInfoInternal::supportedChannelCounts() +{ + updateLists(); + return channelz; +} + +QList QAudioDeviceInfoInternal::supportedSampleSizes() +{ + updateLists(); + return sizez; +} + +QList QAudioDeviceInfoInternal::supportedByteOrders() +{ + updateLists(); + return byteOrderz; +} + +QList QAudioDeviceInfoInternal::supportedSampleTypes() +{ + updateLists(); + return typez; +} + +bool QAudioDeviceInfoInternal::open() +{ + int err = 0; + QString dev = device; + QList devices = availableDevices(mode); + + if(dev.compare(QLatin1String("default")) == 0) { +#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) + if (devices.size() > 0) + dev = QLatin1String(devices.first().constData()); + else + return false; +#else + dev = QLatin1String("hw:0,0"); +#endif + } else { +#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) + dev = device; +#else + int idx = 0; + char *name; + + QString shortName = device.mid(device.indexOf(QLatin1String("="),0)+1); + + while(snd_card_get_name(idx,&name) == 0) { + if(dev.contains(QLatin1String(name))) + break; + idx++; + } + dev = QString(QLatin1String("hw:%1,0")).arg(idx); +#endif + } + if(mode == QAudio::AudioOutput) { + err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0); + } else { + err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0); + } + if(err < 0) { + handle = 0; + return false; + } + return true; +} + +void QAudioDeviceInfoInternal::close() +{ + if(handle) + snd_pcm_close(handle); + handle = 0; +} + +bool QAudioDeviceInfoInternal::testSettings(const QAudioFormat& format) const +{ + // Set nearest to closest settings that do work. + // See if what is in settings will work (return value). + int err = 0; + snd_pcm_t* handle; + snd_pcm_hw_params_t *params; + QString dev = device; + + QList devices = QAudioDeviceInfoInternal::availableDevices(QAudio::AudioOutput); + + if(dev.compare(QLatin1String("default")) == 0) { +#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) + dev = QLatin1String(devices.first().constData()); +#else + dev = QLatin1String("hw:0,0"); +#endif + } else { +#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) + dev = device; +#else + int idx = 0; + char *name; + + QString shortName = device.mid(device.indexOf(QLatin1String("="),0)+1); + + while(snd_card_get_name(idx,&name) == 0) { + if(shortName.compare(QLatin1String(name)) == 0) + break; + idx++; + } + dev = QString(QLatin1String("hw:%1,0")).arg(idx); +#endif + } + if(mode == QAudio::AudioOutput) { + err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0); + } else { + err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0); + } + if(err < 0) { + handle = 0; + return false; + } + + bool testChannel = false; + bool testCodec = false; + bool testFreq = false; + bool testType = false; + bool testSize = false; + + int dir = 0; + + snd_pcm_nonblock( handle, 0 ); + snd_pcm_hw_params_alloca( ¶ms ); + snd_pcm_hw_params_any( handle, params ); + + // set the values! + snd_pcm_hw_params_set_channels(handle,params,format.channels()); + snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir); + + err = -1; + + switch(format.sampleSize()) { + case 8: + if(format.sampleType() == QAudioFormat::SignedInt) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8); + else if(format.sampleType() == QAudioFormat::UnSignedInt) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8); + break; + case 16: + if(format.sampleType() == QAudioFormat::SignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE); + } else if(format.sampleType() == QAudioFormat::UnSignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE); + } + break; + case 32: + if(format.sampleType() == QAudioFormat::SignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE); + } else if(format.sampleType() == QAudioFormat::UnSignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE); + } + } + + // For now, just accept only audio/pcm codec + if(!format.codec().startsWith(QLatin1String("audio/pcm"))) { + err=-1; + } else + testCodec = true; + + if(err>=0 && format.channels() != -1) { + err = snd_pcm_hw_params_test_channels(handle,params,format.channels()); + if(err>=0) + err = snd_pcm_hw_params_set_channels(handle,params,format.channels()); + if(err>=0) + testChannel = true; + } + + if(err>=0 && format.frequency() != -1) { + err = snd_pcm_hw_params_test_rate(handle,params,format.frequency(),0); + if(err>=0) + err = snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir); + if(err>=0) + testFreq = true; + } + + if((err>=0 && format.sampleSize() != -1) && + (format.sampleType() != QAudioFormat::Unknown)) { + switch(format.sampleSize()) { + case 8: + if(format.sampleType() == QAudioFormat::SignedInt) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8); + else if(format.sampleType() == QAudioFormat::UnSignedInt) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8); + break; + case 16: + if(format.sampleType() == QAudioFormat::SignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE); + } else if(format.sampleType() == QAudioFormat::UnSignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE); + } + break; + case 32: + if(format.sampleType() == QAudioFormat::SignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE); + } else if(format.sampleType() == QAudioFormat::UnSignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE); + } + } + if(err>=0) { + testSize = true; + testType = true; + } + } + if(err>=0) + err = snd_pcm_hw_params(handle, params); + + if(err == 0) { + // settings work + // close() + if(handle) + snd_pcm_close(handle); + return true; + } + if(handle) + snd_pcm_close(handle); + + return false; +} + +void QAudioDeviceInfoInternal::updateLists() +{ + // redo all lists based on current settings + freqz.clear(); + channelz.clear(); + sizez.clear(); + byteOrderz.clear(); + typez.clear(); + codecz.clear(); + + if(!handle) + open(); + + if(!handle) + return; + + for(int i=0; i<(int)MAX_SAMPLE_RATES; i++) { + //if(snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0) + freqz.append(SAMPLE_RATES[i]); + } + channelz.append(1); + channelz.append(2); + if (surround40) channelz.append(4); + if (surround51) channelz.append(6); + if (surround71) channelz.append(8); + sizez.append(8); + sizez.append(16); + sizez.append(32); + byteOrderz.append(QAudioFormat::LittleEndian); + byteOrderz.append(QAudioFormat::BigEndian); + typez.append(QAudioFormat::SignedInt); + typez.append(QAudioFormat::UnSignedInt); + typez.append(QAudioFormat::Float); + codecz.append(QLatin1String("audio/pcm")); + close(); +} + +QList QAudioDeviceInfoInternal::availableDevices(QAudio::Mode mode) +{ + QList allDevices; + QList devices; + QByteArray filter; + +#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) + // Create a list of all current audio devices that support mode + void **hints, **n; + char *name, *descr, *io; + + if(snd_device_name_hint(-1, "pcm", &hints) < 0) { + qWarning() << "no alsa devices available"; + return devices; + } + n = hints; + + if(mode == QAudio::AudioInput) { + filter = "Input"; + } else { + filter = "Output"; + } + + while (*n != NULL) { + name = snd_device_name_get_hint(*n, "NAME"); + if (name != 0 && qstrcmp(name, "null") != 0) { + descr = snd_device_name_get_hint(*n, "DESC"); + io = snd_device_name_get_hint(*n, "IOID"); + + if ((descr != NULL) && ((io == NULL) || (io == filter))) { + QString deviceName = QLatin1String(name); + QString deviceDescription = QLatin1String(descr); + allDevices.append(deviceName.toLocal8Bit().constData()); + if (deviceDescription.contains(QLatin1String("Default Audio Device"))) + devices.append(deviceName.toLocal8Bit().constData()); + } + + free(name); + if (descr != NULL) + free(descr); + if (io != NULL) + free(io); + } + ++n; + } + snd_device_name_free_hint(hints); + + if(devices.size() > 0) { + devices.append("default"); + } +#else + int idx = 0; + char* name; + + while(snd_card_get_name(idx,&name) == 0) { + devices.append(name); + idx++; + } + if (idx > 0) + devices.append("default"); +#endif +#if (!defined(Q_WS_MAEMO_5) && !defined(Q_WS_MAEMO_6)) + if (devices.size() == 0 && allDevices.size() > 0) + return allDevices; +#endif + + return devices; +} + +QByteArray QAudioDeviceInfoInternal::defaultInputDevice() +{ + QList devices = availableDevices(QAudio::AudioInput); + if(devices.size() == 0) + return QByteArray(); + + return devices.first(); +} + +QByteArray QAudioDeviceInfoInternal::defaultOutputDevice() +{ + QList devices = availableDevices(QAudio::AudioOutput); + if(devices.size() == 0) + return QByteArray(); + + return devices.first(); +} + +void QAudioDeviceInfoInternal::checkSurround() +{ + QList devices; + surround40 = false; + surround51 = false; + surround71 = false; + + void **hints, **n; + char *name, *descr, *io; + + if(snd_device_name_hint(-1, "pcm", &hints) < 0) + return; + + n = hints; + + while (*n != NULL) { + name = snd_device_name_get_hint(*n, "NAME"); + descr = snd_device_name_get_hint(*n, "DESC"); + io = snd_device_name_get_hint(*n, "IOID"); + if((name != NULL) && (descr != NULL)) { + QString deviceName = QLatin1String(name); + if (mode == QAudio::AudioOutput) { + if(deviceName.contains(QLatin1String("surround40"))) + surround40 = true; + if(deviceName.contains(QLatin1String("surround51"))) + surround51 = true; + if(deviceName.contains(QLatin1String("surround71"))) + surround71 = true; + } + } + if(name != NULL) + free(name); + if(descr != NULL) + free(descr); + if(io != NULL) + free(io); + ++n; + } + snd_device_name_free_hint(hints); +} + +QT_END_NAMESPACE diff --git a/src/multimediakit/audio/qaudiodeviceinfo_alsa_p.h b/src/multimediakit/audio/qaudiodeviceinfo_alsa_p.h new file mode 100644 index 000000000..02a633bea --- /dev/null +++ b/src/multimediakit/audio/qaudiodeviceinfo_alsa_p.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QAUDIODEVICEINFOALSA_H +#define QAUDIODEVICEINFOALSA_H + +#include + +#include +#include +#include +#include + +#include "qaudio.h" +#include "qaudiodeviceinfo.h" +#include "qaudiosystem.h" + +QT_BEGIN_NAMESPACE + +const unsigned int MAX_SAMPLE_RATES = 5; +const unsigned int SAMPLE_RATES[] = + { 8000, 11025, 22050, 44100, 48000 }; + +class QAudioDeviceInfoInternal : public QAbstractAudioDeviceInfo +{ + Q_OBJECT +public: + QAudioDeviceInfoInternal(QByteArray dev,QAudio::Mode mode); + ~QAudioDeviceInfoInternal(); + + bool testSettings(const QAudioFormat& format) const; + void updateLists(); + QAudioFormat preferredFormat() const; + bool isFormatSupported(const QAudioFormat& format) const; + QString deviceName() const; + QStringList supportedCodecs(); + QList supportedSampleRates(); + QList supportedChannelCounts(); + QList supportedSampleSizes(); + QList supportedByteOrders(); + QList supportedSampleTypes(); + static QByteArray defaultInputDevice(); + static QByteArray defaultOutputDevice(); + static QList availableDevices(QAudio::Mode); + +private: + bool open(); + void close(); + + void checkSurround(); + bool surround40; + bool surround51; + bool surround71; + + QString device; + QAudio::Mode mode; + QAudioFormat nearest; + QList freqz; + QList channelz; + QList sizez; + QList byteOrderz; + QStringList codecz; + QList typez; + snd_pcm_t* handle; + snd_pcm_hw_params_t *params; +}; + +QT_END_NAMESPACE + +#endif + diff --git a/src/multimediakit/audio/qaudiodeviceinfo_mac_p.cpp b/src/multimediakit/audio/qaudiodeviceinfo_mac_p.cpp new file mode 100644 index 000000000..ee6660c6e --- /dev/null +++ b/src/multimediakit/audio/qaudiodeviceinfo_mac_p.cpp @@ -0,0 +1,351 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include +#include +#include +#include +#include + +#include +#include "qaudio_mac_p.h" +#include "qaudiodeviceinfo_mac_p.h" + + + +QT_BEGIN_NAMESPACE + +// XXX: remove at some future date +static inline QString cfStringToQString(CFStringRef str) +{ + CFIndex length = CFStringGetLength(str); + const UniChar *chars = CFStringGetCharactersPtr(str); + if (chars) + return QString(reinterpret_cast(chars), length); + + UniChar buffer[length]; + CFStringGetCharacters(str, CFRangeMake(0, length), buffer); + return QString(reinterpret_cast(buffer), length); +} + +QAudioDeviceInfoInternal::QAudioDeviceInfoInternal(QByteArray const& handle, QAudio::Mode) +{ + QDataStream ds(handle); + quint32 did, tm; + + ds >> did >> tm >> name; + deviceId = AudioDeviceID(did); + mode = QAudio::Mode(tm); +} + +bool QAudioDeviceInfoInternal::isFormatSupported(const QAudioFormat& format) const +{ + QAudioDeviceInfoInternal *self = const_cast(this); + + return format.isValid() + && format.codec() == QString::fromLatin1("audio/pcm") + && self->supportedSampleRates().contains(format.sampleRate()) + && self->supportedChannelCounts().contains(format.channelCount()) + && self->supportedSampleSizes().contains(format.sampleSize()); +} + +QAudioFormat QAudioDeviceInfoInternal::preferredFormat() const +{ + QAudioFormat rc; + + UInt32 propSize = 0; + + if (AudioDeviceGetPropertyInfo(deviceId, + 0, + mode == QAudio::AudioInput, + kAudioDevicePropertyStreams, + &propSize, + 0) == noErr) { + + const int sc = propSize / sizeof(AudioStreamID); + + if (sc > 0) { + AudioStreamID* streams = new AudioStreamID[sc]; + + if (AudioDeviceGetProperty(deviceId, + 0, + mode == QAudio::AudioInput, + kAudioDevicePropertyStreams, + &propSize, + streams) == noErr) { + + for (int i = 0; i < sc; ++i) { + if (AudioStreamGetPropertyInfo(streams[i], + 0, + kAudioStreamPropertyPhysicalFormat, + &propSize, + 0) == noErr) { + + AudioStreamBasicDescription sf; + + if (AudioStreamGetProperty(streams[i], + 0, + kAudioStreamPropertyPhysicalFormat, + &propSize, + &sf) == noErr) { + rc = toQAudioFormat(sf); + break; + } + } + } + } + + delete streams; + } + } + + return rc; +} + +QString QAudioDeviceInfoInternal::deviceName() const +{ + return name; +} + +QStringList QAudioDeviceInfoInternal::supportedCodecs() +{ + return QStringList() << QString::fromLatin1("audio/pcm"); +} + +QList QAudioDeviceInfoInternal::supportedSampleRates() +{ + QSet rc; + + // Add some common frequencies + rc << 8000 << 11025 << 22050 << 44100; + + // + UInt32 propSize = 0; + + if (AudioDeviceGetPropertyInfo(deviceId, + 0, + mode == QAudio::AudioInput, + kAudioDevicePropertyAvailableNominalSampleRates, + &propSize, + 0) == noErr) { + + const int pc = propSize / sizeof(AudioValueRange); + + if (pc > 0) { + AudioValueRange* vr = new AudioValueRange[pc]; + + if (AudioDeviceGetProperty(deviceId, + 0, + mode == QAudio::AudioInput, + kAudioDevicePropertyAvailableNominalSampleRates, + &propSize, + vr) == noErr) { + + for (int i = 0; i < pc; ++i) + rc << vr[i].mMaximum; + } + + delete vr; + } + } + + return rc.toList(); +} + +QList QAudioDeviceInfoInternal::supportedChannelCounts() +{ + QList rc; + + // Can mix down to 1 channel + rc << 1; + + UInt32 propSize = 0; + int channels = 0; + + if (AudioDeviceGetPropertyInfo(deviceId, + 0, + mode == QAudio::AudioInput, + kAudioDevicePropertyStreamConfiguration, + &propSize, + 0) == noErr) { + + AudioBufferList* audioBufferList = static_cast(qMalloc(propSize)); + + if (audioBufferList != 0) { + if (AudioDeviceGetProperty(deviceId, + 0, + mode == QAudio::AudioInput, + kAudioDevicePropertyStreamConfiguration, + &propSize, + audioBufferList) == noErr) { + + for (int i = 0; i < int(audioBufferList->mNumberBuffers); ++i) { + channels += audioBufferList->mBuffers[i].mNumberChannels; + rc << channels; + } + } + + qFree(audioBufferList); + } + } + + return rc; +} + +QList QAudioDeviceInfoInternal::supportedSampleSizes() +{ + return QList() << 8 << 16 << 24 << 32 << 64; +} + +QList QAudioDeviceInfoInternal::supportedByteOrders() +{ + return QList() << QAudioFormat::LittleEndian << QAudioFormat::BigEndian; +} + +QList QAudioDeviceInfoInternal::supportedSampleTypes() +{ + return QList() << QAudioFormat::SignedInt << QAudioFormat::UnSignedInt << QAudioFormat::Float; +} + +static QByteArray get_device_info(AudioDeviceID audioDevice, QAudio::Mode mode) +{ + UInt32 size; + QByteArray device; + QDataStream ds(&device, QIODevice::WriteOnly); + AudioStreamBasicDescription sf; + CFStringRef name; + Boolean isInput = mode == QAudio::AudioInput; + + // Id + ds << quint32(audioDevice); + + // Mode + size = sizeof(AudioStreamBasicDescription); + if (AudioDeviceGetProperty(audioDevice, 0, isInput, kAudioDevicePropertyStreamFormat, + &size, &sf) != noErr) { + return QByteArray(); + } + ds << quint32(mode); + + // Name + size = sizeof(CFStringRef); + if (AudioDeviceGetProperty(audioDevice, 0, isInput, kAudioObjectPropertyName, + &size, &name) != noErr) { + qWarning() << "QAudioDeviceInfo: Unable to find device name"; + return QByteArray(); + } + ds << cfStringToQString(name); + + CFRelease(name); + + return device; +} + +QByteArray QAudioDeviceInfoInternal::defaultInputDevice() +{ + AudioDeviceID audioDevice; + UInt32 size = sizeof(audioDevice); + + if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &size, + &audioDevice) != noErr) { + qWarning() << "QAudioDeviceInfo: Unable to find default input device"; + return QByteArray(); + } + + return get_device_info(audioDevice, QAudio::AudioInput); +} + +QByteArray QAudioDeviceInfoInternal::defaultOutputDevice() +{ + AudioDeviceID audioDevice; + UInt32 size = sizeof(audioDevice); + + if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, + &audioDevice) != noErr) { + qWarning() << "QAudioDeviceInfo: Unable to find default output device"; + return QByteArray(); + } + + return get_device_info(audioDevice, QAudio::AudioOutput); +} + +QList QAudioDeviceInfoInternal::availableDevices(QAudio::Mode mode) +{ + QList devices; + + UInt32 propSize = 0; + + if (AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propSize, 0) == noErr) { + + const int dc = propSize / sizeof(AudioDeviceID); + + if (dc > 0) { + AudioDeviceID* audioDevices = new AudioDeviceID[dc]; + + if (AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propSize, audioDevices) == noErr) { + for (int i = 0; i < dc; ++i) { + QByteArray info = get_device_info(audioDevices[i], mode); + if (!info.isNull()) + devices << info; + } + } + + delete audioDevices; + } + } + + return devices; +} + + +QT_END_NAMESPACE + diff --git a/src/multimediakit/audio/qaudiodeviceinfo_mac_p.h b/src/multimediakit/audio/qaudiodeviceinfo_mac_p.h new file mode 100644 index 000000000..5cd5deae3 --- /dev/null +++ b/src/multimediakit/audio/qaudiodeviceinfo_mac_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QDEVICEINFO_MAC_P_H +#define QDEVICEINFO_MAC_P_H + +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QAudioDeviceInfoInternal : public QAbstractAudioDeviceInfo +{ +public: + AudioDeviceID deviceId; + QString name; + QAudio::Mode mode; + + QAudioDeviceInfoInternal(QByteArray const& handle, QAudio::Mode mode); + + bool isFormatSupported(const QAudioFormat& format) const; + QAudioFormat preferredFormat() const; + + QString deviceName() const; + + QStringList supportedCodecs(); + QList supportedSampleRates(); + QList supportedChannelCounts(); + QList supportedSampleSizes(); + QList supportedByteOrders(); + QList supportedSampleTypes(); + + static QByteArray defaultInputDevice(); + static QByteArray defaultOutputDevice(); + + static QList availableDevices(QAudio::Mode mode); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDEVICEINFO_MAC_P_H diff --git a/src/multimediakit/audio/qaudiodeviceinfo_symbian_p.cpp b/src/multimediakit/audio/qaudiodeviceinfo_symbian_p.cpp new file mode 100644 index 000000000..a4cec57ed --- /dev/null +++ b/src/multimediakit/audio/qaudiodeviceinfo_symbian_p.cpp @@ -0,0 +1,235 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "qaudiodeviceinfo_symbian_p.h" +#include "qaudio_symbian_p.h" + +QT_BEGIN_NAMESPACE + +QAudioDeviceInfoInternal::QAudioDeviceInfoInternal(QByteArray device, + QAudio::Mode mode) + : m_deviceName(QLatin1String(device)) + , m_mode(mode) + , m_updated(false) +{ + +} + +QAudioDeviceInfoInternal::~QAudioDeviceInfoInternal() +{ + +} + +QAudioFormat QAudioDeviceInfoInternal::preferredFormat() const +{ + QAudioFormat format; + switch (m_mode) { + case QAudio::AudioOutput: + format.setFrequency(44100); + format.setChannels(2); + format.setSampleSize(16); + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleType(QAudioFormat::SignedInt); + format.setCodec(QLatin1String("audio/pcm")); + break; + + case QAudio::AudioInput: + format.setFrequency(8000); + format.setChannels(1); + format.setSampleSize(16); + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleType(QAudioFormat::SignedInt); + format.setCodec(QLatin1String("audio/pcm")); + break; + + default: + Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid mode"); + } + + if (!isFormatSupported(format)) { + format = QAudioFormat(); + format.setCodec(QLatin1String("audio/pcm")); + if (m_capabilities.contains(format.codec())) { + const Capabilities &codecCaps = m_capabilities[format.codec()]; + if (codecCaps.m_frequencies.size()) + format.setFrequency(codecCaps.m_frequencies[0]); + if (codecCaps.m_channels.size()) + format.setChannels(codecCaps.m_channels[0]); + if (codecCaps.m_sampleSizes.size()) + format.setSampleSize(codecCaps.m_sampleSizes[0]); + if (codecCaps.m_byteOrders.size()) + format.setByteOrder(codecCaps.m_byteOrders[0]); + if (codecCaps.m_sampleTypes.size()) + format.setSampleType(codecCaps.m_sampleTypes[0]); + } + } + + return format; +} + +bool QAudioDeviceInfoInternal::isFormatSupported( + const QAudioFormat &format) const +{ + getSupportedFormats(); + bool supported = false; + if (m_capabilities.contains(format.codec())) { + const Capabilities &codecCaps = m_capabilities[format.codec()]; + supported = codecCaps.m_frequencies.contains(format.frequency()) + && codecCaps.m_channels.contains(format.channels()) + && codecCaps.m_sampleSizes.contains(format.sampleSize()) + && codecCaps.m_byteOrders.contains(format.byteOrder()) + && codecCaps.m_sampleTypes.contains(format.sampleType()); + } + return supported; +} + +QString QAudioDeviceInfoInternal::deviceName() const +{ + return m_deviceName; +} + +QStringList QAudioDeviceInfoInternal::supportedCodecs() +{ + getSupportedFormats(); + return m_capabilities.keys(); +} + +QList QAudioDeviceInfoInternal::supportedSampleRates() +{ + getSupportedFormats(); + return m_unionCapabilities.m_frequencies; +} + +QList QAudioDeviceInfoInternal::supportedChannelCounts() +{ + getSupportedFormats(); + return m_unionCapabilities.m_channels; +} + +QList QAudioDeviceInfoInternal::supportedSampleSizes() +{ + getSupportedFormats(); + return m_unionCapabilities.m_sampleSizes; +} + +QList QAudioDeviceInfoInternal::supportedByteOrders() +{ + getSupportedFormats(); + return m_unionCapabilities.m_byteOrders; +} + +QList QAudioDeviceInfoInternal::supportedSampleTypes() +{ + getSupportedFormats(); + return m_unionCapabilities. m_sampleTypes; +} + +QByteArray QAudioDeviceInfoInternal::defaultInputDevice() +{ + return QByteArray("default"); +} + +QByteArray QAudioDeviceInfoInternal::defaultOutputDevice() +{ + return QByteArray("default"); +} + +QList QAudioDeviceInfoInternal::availableDevices(QAudio::Mode) +{ + QList result; + result += QByteArray("default"); + return result; +} + +void QAudioDeviceInfoInternal::devsoundInitializeComplete(int err) +{ + m_intializationResult = err; + m_initializing = false; +} + +// Helper function +template +void appendUnique(QList &left, const QList &right) +{ + foreach (const T &value, right) + if (!left.contains(value)) + left += value; +} + +void QAudioDeviceInfoInternal::getSupportedFormats() const +{ + if (!m_updated) { + QScopedPointer devsound(new SymbianAudio::DevSoundWrapper(m_mode)); + connect(devsound.data(), SIGNAL(initializeComplete(int)), + this, SLOT(devsoundInitializeComplete(int))); + + foreach (const QString& codec, devsound->supportedCodecs()) { + m_initializing = true; + devsound->initialize(codec); + while (m_initializing) + QCoreApplication::instance()->processEvents(QEventLoop::WaitForMoreEvents); + if (KErrNone == m_intializationResult) { + m_capabilities[codec].m_frequencies = devsound->supportedFrequencies(); + appendUnique(m_unionCapabilities.m_frequencies, devsound->supportedFrequencies()); + + m_capabilities[codec].m_channels = devsound->supportedChannels(); + appendUnique(m_unionCapabilities.m_channels, devsound->supportedChannels()); + + m_capabilities[codec].m_sampleSizes = devsound->supportedSampleSizes(); + appendUnique(m_unionCapabilities.m_sampleSizes, devsound->supportedSampleSizes()); + + m_capabilities[codec].m_byteOrders = devsound->supportedByteOrders(); + appendUnique(m_unionCapabilities.m_byteOrders, devsound->supportedByteOrders()); + + m_capabilities[codec].m_sampleTypes = devsound->supportedSampleTypes(); + appendUnique(m_unionCapabilities.m_sampleTypes, devsound->supportedSampleTypes()); + } + } + + m_updated = true; + } +} + +QT_END_NAMESPACE + +#include "moc_qaudiodeviceinfo_symbian_p.cpp" + diff --git a/src/multimediakit/audio/qaudiodeviceinfo_symbian_p.h b/src/multimediakit/audio/qaudiodeviceinfo_symbian_p.h new file mode 100644 index 000000000..487afd50e --- /dev/null +++ b/src/multimediakit/audio/qaudiodeviceinfo_symbian_p.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QAUDIODEVICEINFO_SYMBIAN_P_H +#define QAUDIODEVICEINFO_SYMBIAN_P_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QAudioDeviceInfoInternal + : public QAbstractAudioDeviceInfo +{ + Q_OBJECT + +public: + QAudioDeviceInfoInternal(QByteArray device, QAudio::Mode mode); + ~QAudioDeviceInfoInternal(); + + // QAbstractAudioDeviceInfo + QAudioFormat preferredFormat() const; + bool isFormatSupported(const QAudioFormat &format) const; + QString deviceName() const; + QStringList supportedCodecs(); + QList supportedSampleRates(); + QList supportedChannelCounts(); + QList supportedSampleSizes(); + QList supportedByteOrders(); + QList supportedSampleTypes(); + static QByteArray defaultInputDevice(); + static QByteArray defaultOutputDevice(); + static QList availableDevices(QAudio::Mode); + +private slots: + void devsoundInitializeComplete(int err); + +private: + void getSupportedFormats() const; + +private: + mutable bool m_initializing; + int m_intializationResult; + + QString m_deviceName; + QAudio::Mode m_mode; + + struct Capabilities + { + QList m_frequencies; + QList m_channels; + QList m_sampleSizes; + QList m_byteOrders; + QList m_sampleTypes; + }; + + // Mutable to allow lazy initialization when called from const-qualified + // public functions (isFormatSupported, nearestFormat) + mutable bool m_updated; + mutable QMap m_capabilities; + mutable Capabilities m_unionCapabilities; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/audio/qaudiodeviceinfo_win32_p.cpp b/src/multimediakit/audio/qaudiodeviceinfo_win32_p.cpp new file mode 100644 index 000000000..0f29bf5bc --- /dev/null +++ b/src/multimediakit/audio/qaudiodeviceinfo_win32_p.cpp @@ -0,0 +1,471 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + + +#include +#include +#include "qaudiodeviceinfo_win32_p.h" +#include + +#if defined(Q_CC_MINGW) + +extern GUID CLSID_AudioInputDeviceCategory; + +#ifndef __IErrorLog_INTERFACE_DEFINED__ +#define __IErrorLog_INTERFACE_DEFINED__ + +DECLARE_INTERFACE_(IErrorLog, IUnknown) +{ + STDMETHOD(AddError)(THIS_ LPCOLESTR, EXCEPINFO *) PURE; +}; + +#endif /* __IErrorLog_INTERFACE_DEFINED__ */ + +#ifndef __IPropertyBag_INTERFACE_DEFINED__ +#define __IPropertyBag_INTERFACE_DEFINED__ + +const GUID IID_IPropertyBag = {0x55272A00, 0x42CB, 0x11CE, {0x81, 0x35, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51}}; + +DECLARE_INTERFACE_(IPropertyBag, IUnknown) +{ + STDMETHOD(Read)(THIS_ LPCOLESTR, VARIANT *, IErrorLog *) PURE; + STDMETHOD(Write)(THIS_ LPCOLESTR, VARIANT *) PURE; +}; + +#endif /* __IPropertyBag_INTERFACE_DEFINED__ */ + +#endif//Q_CC_MINGW + +QT_BEGIN_NAMESPACE + +// For mingw toolchain mmsystem.h only defines half the defines, so add if needed. +#ifndef WAVE_FORMAT_44M08 +#define WAVE_FORMAT_44M08 0x00000100 +#define WAVE_FORMAT_44S08 0x00000200 +#define WAVE_FORMAT_44M16 0x00000400 +#define WAVE_FORMAT_44S16 0x00000800 +#define WAVE_FORMAT_48M08 0x00001000 +#define WAVE_FORMAT_48S08 0x00002000 +#define WAVE_FORMAT_48M16 0x00004000 +#define WAVE_FORMAT_48S16 0x00008000 +#define WAVE_FORMAT_96M08 0x00010000 +#define WAVE_FORMAT_96S08 0x00020000 +#define WAVE_FORMAT_96M16 0x00040000 +#define WAVE_FORMAT_96S16 0x00080000 +#endif + + +QAudioDeviceInfoInternal::QAudioDeviceInfoInternal(QByteArray dev, QAudio::Mode mode) +{ + QDataStream ds(&dev, QIODevice::ReadOnly); + ds >> devId >> device; + this->mode = mode; + + updateLists(); +} + +QAudioDeviceInfoInternal::~QAudioDeviceInfoInternal() +{ + close(); +} + +bool QAudioDeviceInfoInternal::isFormatSupported(const QAudioFormat& format) const +{ + return testSettings(format); +} + +QAudioFormat QAudioDeviceInfoInternal::preferredFormat() const +{ + QAudioFormat nearest; + if(mode == QAudio::AudioOutput) { + nearest.setFrequency(44100); + nearest.setChannelCount(2); + nearest.setByteOrder(QAudioFormat::LittleEndian); + nearest.setSampleType(QAudioFormat::SignedInt); + nearest.setSampleSize(16); + nearest.setCodec(QLatin1String("audio/pcm")); + } else { + nearest.setFrequency(11025); + nearest.setChannelCount(1); + nearest.setByteOrder(QAudioFormat::LittleEndian); + nearest.setSampleType(QAudioFormat::SignedInt); + nearest.setSampleSize(8); + nearest.setCodec(QLatin1String("audio/pcm")); + } + return nearest; +} + +QString QAudioDeviceInfoInternal::deviceName() const +{ + return device; +} + +QStringList QAudioDeviceInfoInternal::supportedCodecs() +{ + updateLists(); + return codecz; +} + +QList QAudioDeviceInfoInternal::supportedSampleRates() +{ + updateLists(); + return freqz; +} + +QList QAudioDeviceInfoInternal::supportedChannelCounts() +{ + updateLists(); + return channelz; +} + +QList QAudioDeviceInfoInternal::supportedSampleSizes() +{ + updateLists(); + return sizez; +} + +QList QAudioDeviceInfoInternal::supportedByteOrders() +{ + updateLists(); + return byteOrderz; +} + +QList QAudioDeviceInfoInternal::supportedSampleTypes() +{ + updateLists(); + return typez; +} + + +bool QAudioDeviceInfoInternal::open() +{ + return true; +} + +void QAudioDeviceInfoInternal::close() +{ +} + +bool QAudioDeviceInfoInternal::testSettings(const QAudioFormat& format) const +{ + // Set nearest to closest settings that do work. + // See if what is in settings will work (return value). + + bool failed = false; + bool match = false; + + // check codec + for( int i = 0; i < codecz.count(); i++) { + if (format.codec() == codecz.at(i)) + match = true; + } + if (!match) failed = true; + + // check channel + match = false; + if (!failed) { + for( int i = 0; i < channelz.count(); i++) { + if (format.channels() == channelz.at(i)) { + match = true; + break; + } + } + if (!match) + failed = true; + } + + // check frequency + match = false; + if (!failed) { + for( int i = 0; i < freqz.count(); i++) { + if (format.frequency() == freqz.at(i)) { + match = true; + break; + } + } + if (!match) + failed = true; + } + + // check sample size + match = false; + if (!failed) { + for( int i = 0; i < sizez.count(); i++) { + if (format.sampleSize() == sizez.at(i)) { + match = true; + break; + } + } + if (!match) + failed = true; + } + + // check byte order + match = false; + if (!failed) { + for( int i = 0; i < byteOrderz.count(); i++) { + if (format.byteOrder() == byteOrderz.at(i)) { + match = true; + break; + } + } + if (!match) + failed = true; + } + + // check sample type + match = false; + if (!failed) { + for( int i = 0; i < typez.count(); i++) { + if (format.sampleType() == typez.at(i)) { + match = true; + break; + } + } + if (!match) + failed = true; + } + + if(!failed) { + // settings work + return true; + } + return false; +} + +void QAudioDeviceInfoInternal::updateLists() +{ + // redo all lists based on current settings + bool match = false; + DWORD fmt = NULL; + + if(mode == QAudio::AudioOutput) { + WAVEOUTCAPS woc; + if (waveOutGetDevCaps(devId, &woc, sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR) { + match = true; + fmt = woc.dwFormats; + } + } else { + WAVEINCAPS woc; + if (waveInGetDevCaps(devId, &woc, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR) { + match = true; + fmt = woc.dwFormats; + } + } + sizez.clear(); + freqz.clear(); + channelz.clear(); + byteOrderz.clear(); + typez.clear(); + codecz.clear(); + + if(match) { + if((fmt && WAVE_FORMAT_1M08) + || (fmt && WAVE_FORMAT_1S08) + || (fmt && WAVE_FORMAT_2M08) + || (fmt && WAVE_FORMAT_2S08) + || (fmt && WAVE_FORMAT_4M08) + || (fmt && WAVE_FORMAT_4S08) +#ifndef Q_OS_WINCE + || (fmt && WAVE_FORMAT_48M08) + || (fmt && WAVE_FORMAT_48S08) + || (fmt && WAVE_FORMAT_96M08) + || (fmt && WAVE_FORMAT_96S08) +#endif + ) { + sizez.append(8); + } + if((fmt && WAVE_FORMAT_1M16) + || (fmt && WAVE_FORMAT_1S16) + || (fmt && WAVE_FORMAT_2M16) + || (fmt && WAVE_FORMAT_2S16) + || (fmt && WAVE_FORMAT_4M16) + || (fmt && WAVE_FORMAT_4S16) +#ifndef Q_OS_WINCE + || (fmt && WAVE_FORMAT_48M16) + || (fmt && WAVE_FORMAT_48S16) + || (fmt && WAVE_FORMAT_96M16) + || (fmt && WAVE_FORMAT_96S16) +#endif + ) { + sizez.append(16); + } + if((fmt && WAVE_FORMAT_1M08) + || (fmt && WAVE_FORMAT_1S08) + || (fmt && WAVE_FORMAT_1M16) + || (fmt && WAVE_FORMAT_1S16)) { + freqz.append(11025); + } + if((fmt && WAVE_FORMAT_2M08) + || (fmt && WAVE_FORMAT_2S08) + || (fmt && WAVE_FORMAT_2M16) + || (fmt && WAVE_FORMAT_2S16)) { + freqz.append(22050); + } + if((fmt && WAVE_FORMAT_4M08) + || (fmt && WAVE_FORMAT_4S08) + || (fmt && WAVE_FORMAT_4M16) + || (fmt && WAVE_FORMAT_4S16)) { + freqz.append(44100); + } +#ifndef Q_OS_WINCE + if((fmt && WAVE_FORMAT_48M08) + || (fmt && WAVE_FORMAT_48S08) + || (fmt && WAVE_FORMAT_48M16) + || (fmt && WAVE_FORMAT_48S16)) { + freqz.append(48000); + } + if((fmt && WAVE_FORMAT_96M08) + || (fmt && WAVE_FORMAT_96S08) + || (fmt && WAVE_FORMAT_96M16) + || (fmt && WAVE_FORMAT_96S16)) { + freqz.append(96000); + } +#endif + channelz.append(1); + channelz.append(2); + if (mode == QAudio::AudioOutput) { + channelz.append(4); + channelz.append(6); + channelz.append(8); + } + + byteOrderz.append(QAudioFormat::LittleEndian); + + typez.append(QAudioFormat::SignedInt); + typez.append(QAudioFormat::UnSignedInt); + + codecz.append(QLatin1String("audio/pcm")); + } + if (freqz.count() > 0) + freqz.prepend(8000); +} + +QList QAudioDeviceInfoInternal::availableDevices(QAudio::Mode mode) +{ + Q_UNUSED(mode) + + QList devices; + //enumerate device fullnames through directshow api + CoInitialize(NULL); + ICreateDevEnum *pDevEnum = NULL; + IEnumMoniker *pEnum = NULL; + // Create the System device enumerator + HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, + CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, + reinterpret_cast(&pDevEnum)); + + unsigned long iNumDevs = mode == QAudio::AudioOutput ? waveOutGetNumDevs() : waveInGetNumDevs(); + if (SUCCEEDED(hr)) { + // Create the enumerator for the audio input/output category + if (pDevEnum->CreateClassEnumerator( + mode == QAudio::AudioOutput ? CLSID_AudioRendererCategory : CLSID_AudioInputDeviceCategory, + &pEnum, 0) == S_OK) { + pEnum->Reset(); + // go through and find all audio devices + IMoniker *pMoniker = NULL; + while (pEnum->Next(1, &pMoniker, NULL) == S_OK) { + IPropertyBag *pPropBag; + hr = pMoniker->BindToStorage(0,0,IID_IPropertyBag, + reinterpret_cast(&pPropBag)); + if (FAILED(hr)) { + pMoniker->Release(); + continue; // skip this one + } + // Find if it is a wave device + VARIANT var; + VariantInit(&var); + hr = pPropBag->Read(mode == QAudio::AudioOutput ? L"WaveOutID" : L"WaveInID", &var, 0); + if (SUCCEEDED(hr)) { + LONG waveID = var.lVal; + if (waveID >= 0 && waveID < LONG(iNumDevs)) { + VariantClear(&var); + // Find the description + hr = pPropBag->Read(L"FriendlyName", &var, 0); + if (SUCCEEDED(hr)) { + QByteArray device; + QDataStream ds(&device, QIODevice::WriteOnly); + ds << quint32(waveID) << QString::fromWCharArray(var.bstrVal); + devices.append(device); + } + } + } + + pPropBag->Release(); + pMoniker->Release(); + } + } + } + CoUninitialize(); + + return devices; +} + +QByteArray QAudioDeviceInfoInternal::defaultOutputDevice() +{ + QList list = availableDevices(QAudio::AudioOutput); + if (list.size() > 0) + return list.at(0); + else + return QByteArray(); +} + +QByteArray QAudioDeviceInfoInternal::defaultInputDevice() +{ + QList list = availableDevices(QAudio::AudioInput); + if (list.size() > 0) + return list.at(0); + else + return QByteArray(); +} + +QT_END_NAMESPACE diff --git a/src/multimediakit/audio/qaudiodeviceinfo_win32_p.h b/src/multimediakit/audio/qaudiodeviceinfo_win32_p.h new file mode 100644 index 000000000..78f3d7fad --- /dev/null +++ b/src/multimediakit/audio/qaudiodeviceinfo_win32_p.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QAUDIODEVICEINFOWIN_H +#define QAUDIODEVICEINFOWIN_H + +#include +#include +#include +#include + +#include +#include + + +QT_BEGIN_NAMESPACE + +const unsigned int MAX_SAMPLE_RATES = 5; +const unsigned int SAMPLE_RATES[] = { 8000, 11025, 22050, 44100, 48000 }; + +class QAudioDeviceInfoInternal : public QAbstractAudioDeviceInfo +{ + Q_OBJECT + +public: + QAudioDeviceInfoInternal(QByteArray dev,QAudio::Mode mode); + ~QAudioDeviceInfoInternal(); + + bool open(); + void close(); + + bool testSettings(const QAudioFormat& format) const; + void updateLists(); + QAudioFormat preferredFormat() const; + bool isFormatSupported(const QAudioFormat& format) const; + QString deviceName() const; + QStringList supportedCodecs(); + QList supportedSampleRates(); + QList supportedChannelCounts(); + QList supportedSampleSizes(); + QList supportedByteOrders(); + QList supportedSampleTypes(); + static QByteArray defaultInputDevice(); + static QByteArray defaultOutputDevice(); + static QList availableDevices(QAudio::Mode); + +private: + QAudio::Mode mode; + QString device; + quint32 devId; + QAudioFormat nearest; + QList freqz; + QList channelz; + QList sizez; + QList byteOrderz; + QStringList codecz; + QList typez; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/audio/qaudioformat.cpp b/src/multimediakit/audio/qaudioformat.cpp new file mode 100644 index 000000000..3afba7ee4 --- /dev/null +++ b/src/multimediakit/audio/qaudioformat.cpp @@ -0,0 +1,407 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include + + +QT_BEGIN_NAMESPACE + + +class QAudioFormatPrivate : public QSharedData +{ +public: + QAudioFormatPrivate() + { + frequency = -1; + channels = -1; + sampleSize = -1; + byteOrder = QAudioFormat::Endian(QSysInfo::ByteOrder); + sampleType = QAudioFormat::Unknown; + } + + QAudioFormatPrivate(const QAudioFormatPrivate &other): + QSharedData(other), + codec(other.codec), + byteOrder(other.byteOrder), + sampleType(other.sampleType), + frequency(other.frequency), + channels(other.channels), + sampleSize(other.sampleSize) + { + } + + QAudioFormatPrivate& operator=(const QAudioFormatPrivate &other) + { + codec = other.codec; + byteOrder = other.byteOrder; + sampleType = other.sampleType; + frequency = other.frequency; + channels = other.channels; + sampleSize = other.sampleSize; + + return *this; + } + + QString codec; + QAudioFormat::Endian byteOrder; + QAudioFormat::SampleType sampleType; + int frequency; + int channels; + int sampleSize; +}; + +/*! + \class QAudioFormat + \brief The QAudioFormat class stores audio stream parameter information. + + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + An audio format specifies how data in an audio stream is arranged, + i.e, how the stream is to be interpreted. The encoding itself is + specified by the codec() used for the stream. + + In addition to the encoding, QAudioFormat contains other + parameters that further specify how the audio sample data is arranged. + These are the frequency, the number of channels, the sample size, + the sample type, and the byte order. The following table describes + these in more detail. + + \table + \header + \o Parameter + \o Description + \row + \o Sample Rate + \o Samples per second of audio data in Hertz. + \row + \o Number of channels + \o The number of audio channels (typically one for mono + or two for stereo) + \row + \o Sample size + \o How much data is stored in each sample (typically 8 + or 16 bits) + \row + \o Sample type + \o Numerical representation of sample (typically signed integer, + unsigned integer or float) + \row + \o Byte order + \o Byte ordering of sample (typically little endian, big endian) + \endtable + + This class is typically used in conjunction with QAudioInput or + QAudioOutput to allow you to specify the parameters of the audio + stream being read or written. + + You can obtain audio formats compatible with the audio device used + through functions in QAudioDeviceInfo. This class also lets you + query available parameter values for a device, so that you can set + the parameters yourself. See the \l QAudioDeviceInfo class + description for details. You need to know the format of the audio + streams you wish to play or record. +*/ + +/*! + Construct a new audio format. + + Values are initialized as follows: + \list + \o sampleRate() = -1 + \o channelCount() = -1 + \o sampleSize() = -1 + \o byteOrder() = QAudioFormat::Endian(QSysInfo::ByteOrder) + \o sampleType() = QAudioFormat::Unknown + \c codec() = "" + \endlist +*/ +QAudioFormat::QAudioFormat(): + d(new QAudioFormatPrivate) +{ +} + +/*! + Construct a new audio format using \a other. + \since 1.0 +*/ +QAudioFormat::QAudioFormat(const QAudioFormat &other): + d(other.d) +{ +} + +/*! + Destroy this audio format. +*/ +QAudioFormat::~QAudioFormat() +{ +} + +/*! + Assigns \a other to this QAudioFormat implementation. + \since 1.0 +*/ +QAudioFormat& QAudioFormat::operator=(const QAudioFormat &other) +{ + d = other.d; + return *this; +} + +/*! + Returns true if this QAudioFormat is equal to the \a other + QAudioFormat; otherwise returns false. + + All elements of QAudioFormat are used for the comparison. + \since 1.0 +*/ +bool QAudioFormat::operator==(const QAudioFormat &other) const +{ + return d->frequency == other.d->frequency && + d->channels == other.d->channels && + d->sampleSize == other.d->sampleSize && + d->byteOrder == other.d->byteOrder && + d->codec == other.d->codec && + d->sampleType == other.d->sampleType; +} + +/*! + Returns true if this QAudioFormat is not equal to the \a other + QAudioFormat; otherwise returns false. + + All elements of QAudioFormat are used for the comparison. + \since 1.0 +*/ +bool QAudioFormat::operator!=(const QAudioFormat& other) const +{ + return !(*this == other); +} + +/*! + Returns true if all of the parameters are valid. + \since 1.0 +*/ +bool QAudioFormat::isValid() const +{ + return d->frequency != -1 && d->channels != -1 && d->sampleSize != -1 && + d->sampleType != QAudioFormat::Unknown && !d->codec.isEmpty(); +} + +/*! + Sets the sample rate to \a samplerate Hertz. + + \since 1.0 +*/ +void QAudioFormat::setSampleRate(int samplerate) +{ + d->frequency = samplerate; +} + +/*! + \obsolete + + Use setSampleRate() instead. +*/ +void QAudioFormat::setFrequency(int frequency) +{ + d->frequency = frequency; +} + +/*! + Returns the current sample rate in Hertz. + + \since 1.0 +*/ +int QAudioFormat::sampleRate() const +{ + return d->frequency; +} + +/*! + \obsolete + + Use sampleRate() instead. +*/ +int QAudioFormat::frequency() const +{ + return d->frequency; +} + +/*! + Sets the channel count to \a channels. + + \since 1.0 +*/ +void QAudioFormat::setChannelCount(int channels) +{ + d->channels = channels; +} + +/*! + \obsolete + + Use setChannelCount() instead. +*/ +void QAudioFormat::setChannels(int channels) +{ + d->channels = channels; +} + +/*! + Returns the current channel count value. + + \since 1.0 +*/ +int QAudioFormat::channelCount() const +{ + return d->channels; +} + +/*! + \obsolete + + Use channelCount() instead. +*/ +int QAudioFormat::channels() const +{ + return d->channels; +} + +/*! + Sets the sample size to the \a sampleSize specified, in bits. + + This is typically 8 or 16, but some systems may support higher sample sizes. + \since 1.0 +*/ +void QAudioFormat::setSampleSize(int sampleSize) +{ + d->sampleSize = sampleSize; +} + +/*! + Returns the current sample size value, in bits. + \since 1.0 +*/ +int QAudioFormat::sampleSize() const +{ + return d->sampleSize; +} + +/*! + Sets the codec to \a codec. + + The parameter to this function should be one of the types + reported by the QAudioDeviceInfo::supportedCodecs() function + for the audio device you are working with. + + \since 1.0 + \sa QAudioDeviceInfo::supportedCodecs() +*/ +void QAudioFormat::setCodec(const QString &codec) +{ + d->codec = codec; +} + +/*! + Returns the current codec identifier. + + \since 1.0 + \sa QAudioDeviceInfo::supportedCodecs() +*/ +QString QAudioFormat::codec() const +{ + return d->codec; +} + +/*! + Sets the byteOrder to \a byteOrder. + \since 1.0 +*/ +void QAudioFormat::setByteOrder(QAudioFormat::Endian byteOrder) +{ + d->byteOrder = byteOrder; +} + +/*! + Returns the current byteOrder value. + \since 1.0 +*/ +QAudioFormat::Endian QAudioFormat::byteOrder() const +{ + return d->byteOrder; +} + +/*! + Sets the sampleType to \a sampleType. + \since 1.0 +*/ +void QAudioFormat::setSampleType(QAudioFormat::SampleType sampleType) +{ + d->sampleType = sampleType; +} + +/*! + Returns the current SampleType value. + \since 1.0 +*/ +QAudioFormat::SampleType QAudioFormat::sampleType() const +{ + return d->sampleType; +} + +/*! + \enum QAudioFormat::SampleType + + \value Unknown Not Set + \value SignedInt Samples are signed integers + \value UnSignedInt Samples are unsigned intergers + \value Float Samples are floats +*/ + +/*! + \enum QAudioFormat::Endian + + \value BigEndian Samples are big endian byte order + \value LittleEndian Samples are little endian byte order +*/ + +QT_END_NAMESPACE + diff --git a/src/multimediakit/audio/qaudioformat.h b/src/multimediakit/audio/qaudioformat.h new file mode 100644 index 000000000..b7d0a4027 --- /dev/null +++ b/src/multimediakit/audio/qaudioformat.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QAUDIOFORMAT_H +#define QAUDIOFORMAT_H + +#include +#include + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QAudioFormatPrivate; + +class Q_MULTIMEDIA_EXPORT QAudioFormat +{ +public: + enum SampleType { Unknown, SignedInt, UnSignedInt, Float }; + enum Endian { BigEndian = QSysInfo::BigEndian, LittleEndian = QSysInfo::LittleEndian }; + + QAudioFormat(); + QAudioFormat(const QAudioFormat &other); + ~QAudioFormat(); + + QAudioFormat& operator=(const QAudioFormat &other); + bool operator==(const QAudioFormat &other) const; + bool operator!=(const QAudioFormat &other) const; + + bool isValid() const; + + void setFrequency(int frequency); + int frequency() const; + void setSampleRate(int sampleRate); + int sampleRate() const; + + void setChannels(int channels); + int channels() const; + void setChannelCount(int channelCount); + int channelCount() const; + + void setSampleSize(int sampleSize); + int sampleSize() const; + + void setCodec(const QString &codec); + QString codec() const; + + void setByteOrder(QAudioFormat::Endian byteOrder); + QAudioFormat::Endian byteOrder() const; + + void setSampleType(QAudioFormat::SampleType sampleType); + QAudioFormat::SampleType sampleType() const; + +private: + QSharedDataPointer d; +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIOFORMAT_H diff --git a/src/multimediakit/audio/qaudioinput.cpp b/src/multimediakit/audio/qaudioinput.cpp new file mode 100644 index 000000000..c20ea41c2 --- /dev/null +++ b/src/multimediakit/audio/qaudioinput.cpp @@ -0,0 +1,426 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qaudio.h" +#include "qaudiodeviceinfo.h" +#include "qaudiosystem.h" +#include "qaudioinput.h" + +#include "qaudiodevicefactory_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QAudioInput + \brief The QAudioInput class provides an interface for receiving audio data from an audio input device. + + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + XXX Needs more blurb about use cases etc + Link to terminology etc + Push/Pull mode + State diagram + + + You can construct an audio input with the system's + \l{QAudioDeviceInfo::defaultInputDevice()}{default audio input + device}. It is also possible to create QAudioInput with a + specific QAudioDeviceInfo. When you create the audio input, you + should also send in the QAudioFormat to be used for the recording + (see the QAudioFormat class description for details). + + To record to a file: + + QAudioInput lets you record audio with an audio input device. The + default constructor of this class will use the systems default + audio device, but you can also specify a QAudioDeviceInfo for a + specific device. You also need to pass in the QAudioFormat in + which you wish to record. + + Starting up the QAudioInput is simply a matter of calling start() + with a QIODevice opened for writing. For instance, to record to a + file, you can: + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Audio input class members + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Audio input setup + + This will start recording if the format specified is supported by + the input device (you can check this with + QAudioDeviceInfo::isFormatSupported(). In case there are any + snags, use the error() function to check what went wrong. We stop + recording in the \c stopRecording() slot. + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Audio input stop recording + + At any point in time, QAudioInput will be in one of four states: + active, suspended, stopped, or idle. These states are specified by + the QAudio::State enum. You can request a state change directly through + suspend(), resume(), stop(), reset(), and start(). The current + state is reported by state(). QAudioOutput will also signal you + when the state changes (stateChanged()). + + QAudioInput provides several ways of measuring the time that has + passed since the start() of the recording. The \c processedUSecs() + function returns the length of the stream in microseconds written, + i.e., it leaves out the times the audio input was suspended or idle. + The elapsedUSecs() function returns the time elapsed since start() was called regardless of + which states the QAudioInput has been in. + + If an error should occur, you can fetch its reason with error(). + The possible error reasons are described by the QAudio::Error + enum. The QAudioInput will enter the \l{QAudio::}{StoppedState} when + an error is encountered. Connect to the stateChanged() signal to + handle the error: + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Audio input state changed + + \sa QAudioOutput, QAudioDeviceInfo + + \section1 Symbian Platform Security Requirements + + On Symbian, processes which use this class must have the + \c UserEnvironment platform security capability. If the client + process lacks this capability, calls to either overload of start() + will fail. + This failure is indicated by the QAudioInput object setting + its error() value to \l{QAudio::OpenError} and then emitting a + \l{stateChanged()}{stateChanged}(\l{QAudio::StoppedState}) signal. + + Platform security capabilities are added via the + \l{qmake-variable-reference.html#target-capability}{TARGET.CAPABILITY} + qmake variable. +*/ + +/*! + Construct a new audio input and attach it to \a parent. + The default audio input device is used with the output + \a format parameters. + \since 1.0 +*/ + +QAudioInput::QAudioInput(const QAudioFormat &format, QObject *parent): + QObject(parent) +{ + d = QAudioDeviceFactory::createDefaultInputDevice(format); + connect(d, SIGNAL(notify()), SIGNAL(notify())); + connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State))); +} + +/*! + Construct a new audio input and attach it to \a parent. + The device referenced by \a audioDevice is used with the input + \a format parameters. + \since 1.0 +*/ + +QAudioInput::QAudioInput(const QAudioDeviceInfo &audioDevice, const QAudioFormat &format, QObject *parent): + QObject(parent) +{ + d = QAudioDeviceFactory::createInputDevice(audioDevice, format); + connect(d, SIGNAL(notify()), SIGNAL(notify())); + connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State))); +} + +/*! + Destroy this audio input. +*/ + +QAudioInput::~QAudioInput() +{ + delete d; +} + +/*! + Uses the \a device as the QIODevice to transfer data. + Passing a QIODevice allows the data to be transferred without any extra code. + All that is required is to open the QIODevice. + + If able to successfully get audio data from the systems audio device the + state() is set to either QAudio::ActiveState or QAudio::IdleState, + error() is set to QAudio::NoError and the stateChanged() signal is emitted. + + If a problem occurs during this process the error() is set to QAudio::OpenError, + state() is set to QAudio::StoppedState and stateChanged() signal is emitted. + + \l{QAudioInput#Symbian Platform Security Requirements} + + \since 1.0 + \sa QIODevice +*/ + +void QAudioInput::start(QIODevice* device) +{ + d->start(device); +} + +/*! + Returns a pointer to the QIODevice being used to handle the data + transfer. This QIODevice can be used to read() audio data + directly. + + If able to access the systems audio device the state() is set to + QAudio::IdleState, error() is set to QAudio::NoError + and the stateChanged() signal is emitted. + + If a problem occurs during this process the error() is set to QAudio::OpenError, + state() is set to QAudio::StoppedState and stateChanged() signal is emitted. + + \l{QAudioInput#Symbian Platform Security Requirements} + + \since 1.0 + \sa QIODevice +*/ + +QIODevice* QAudioInput::start() +{ + return d->start(); +} + +/*! + Returns the QAudioFormat being used. + \since 1.0 +*/ + +QAudioFormat QAudioInput::format() const +{ + return d->format(); +} + +/*! + Stops the audio input, detaching from the system resource. + + Sets error() to QAudio::NoError, state() to QAudio::StoppedState and + emit stateChanged() signal. + \since 1.0 +*/ + +void QAudioInput::stop() +{ + d->stop(); +} + +/*! + Drops all audio data in the buffers, resets buffers to zero. + \since 1.0 +*/ + +void QAudioInput::reset() +{ + d->reset(); +} + +/*! + Stops processing audio data, preserving buffered audio data. + + Sets error() to QAudio::NoError, state() to QAudio::SuspendedState and + emit stateChanged() signal. + \since 1.0 +*/ + +void QAudioInput::suspend() +{ + d->suspend(); +} + +/*! + Resumes processing audio data after a suspend(). + + Sets error() to QAudio::NoError. + Sets state() to QAudio::ActiveState if you previously called start(QIODevice*). + Sets state() to QAudio::IdleState if you previously called start(). + emits stateChanged() signal. + \since 1.0 +*/ + +void QAudioInput::resume() +{ + d->resume(); +} + +/*! + Sets the audio buffer size to \a value milliseconds. + + Note: This function can be called anytime before start(), calls to this + are ignored after start(). It should not be assumed that the buffer size + set is the actual buffer size used, calling bufferSize() anytime after start() + will return the actual buffer size being used. + + \since 1.0 +*/ + +void QAudioInput::setBufferSize(int value) +{ + d->setBufferSize(value); +} + +/*! + Returns the audio buffer size in milliseconds. + + If called before start(), returns platform default value. + If called before start() but setBufferSize() was called prior, returns value set by setBufferSize(). + If called after start(), returns the actual buffer size being used. This may not be what was set previously + by setBufferSize(). + + \since 1.0 +*/ + +int QAudioInput::bufferSize() const +{ + return d->bufferSize(); +} + +/*! + Returns the amount of audio data available to read in bytes. + + NOTE: returned value is only valid while in QAudio::ActiveState or QAudio::IdleState + state, otherwise returns zero. + \since 1.0 +*/ + +int QAudioInput::bytesReady() const +{ + /* + -If not ActiveState|IdleState, return 0 + -return amount of audio data available to read + */ + return d->bytesReady(); +} + +/*! + Returns the period size in bytes. + + Note: This is the recommended read size in bytes. + \since 1.0 +*/ + +int QAudioInput::periodSize() const +{ + return d->periodSize(); +} + +/*! + Sets the interval for notify() signal to be emitted. + This is based on the \a ms of audio data processed + not on actual real-time. + The minimum resolution of the timer is platform specific and values + should be checked with notifyInterval() to confirm actual value + being used. + \since 1.0 +*/ + +void QAudioInput::setNotifyInterval(int ms) +{ + d->setNotifyInterval(ms); +} + +/*! + Returns the notify interval in milliseconds. + \since 1.0 +*/ + +int QAudioInput::notifyInterval() const +{ + return d->notifyInterval(); +} + +/*! + Returns the amount of audio data processed since start() + was called in microseconds. + \since 1.0 +*/ + +qint64 QAudioInput::processedUSecs() const +{ + return d->processedUSecs(); +} + +/*! + Returns the microseconds since start() was called, including time in Idle and + Suspend states. + \since 1.0 +*/ + +qint64 QAudioInput::elapsedUSecs() const +{ + return d->elapsedUSecs(); +} + +/*! + Returns the error state. + \since 1.0 +*/ + +QAudio::Error QAudioInput::error() const +{ + return d->error(); +} + +/*! + Returns the state of audio processing. + \since 1.0 +*/ + +QAudio::State QAudioInput::state() const +{ + return d->state(); +} + +/*! + \fn QAudioInput::stateChanged(QAudio::State state) + This signal is emitted when the device \a state has changed. + \since 1.0 +*/ + +/*! + \fn QAudioInput::notify() + This signal is emitted when x ms of audio data has been processed + the interval set by setNotifyInterval(x). + \since 1.0 +*/ + +QT_END_NAMESPACE + +#include "moc_qaudioinput.cpp" + diff --git a/src/multimediakit/audio/qaudioinput.h b/src/multimediakit/audio/qaudioinput.h new file mode 100644 index 000000000..c1b866eb6 --- /dev/null +++ b/src/multimediakit/audio/qaudioinput.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QAUDIOINPUT_H +#define QAUDIOINPUT_H + +#include + +#include +#include + +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QAbstractAudioInput; + +class Q_MULTIMEDIA_EXPORT QAudioInput : public QObject +{ + Q_OBJECT + +public: + explicit QAudioInput(const QAudioFormat &format = QAudioFormat(), QObject *parent = 0); + explicit QAudioInput(const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format = QAudioFormat(), QObject *parent = 0); + ~QAudioInput(); + + QAudioFormat format() const; + + void start(QIODevice *device); + QIODevice* start(); + + void stop(); + void reset(); + void suspend(); + void resume(); + + void setBufferSize(int bytes); + int bufferSize() const; + + int bytesReady() const; + int periodSize() const; + + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + + QAudio::Error error() const; + QAudio::State state() const; + +Q_SIGNALS: + void stateChanged(QAudio::State); + void notify(); + +private: + Q_DISABLE_COPY(QAudioInput) + + QAbstractAudioInput* d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIOINPUT_H diff --git a/src/multimediakit/audio/qaudioinput_alsa_p.cpp b/src/multimediakit/audio/qaudioinput_alsa_p.cpp new file mode 100644 index 000000000..e7a04599f --- /dev/null +++ b/src/multimediakit/audio/qaudioinput_alsa_p.cpp @@ -0,0 +1,867 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include +#include "qaudioinput_alsa_p.h" +#include "qaudiodeviceinfo_alsa_p.h" + +QT_BEGIN_NAMESPACE + +//#define DEBUG_AUDIO 1 + +QAudioInputPrivate::QAudioInputPrivate(const QByteArray &device) +{ + bytesAvailable = 0; + handle = 0; + ahandler = 0; + access = SND_PCM_ACCESS_RW_INTERLEAVED; + pcmformat = SND_PCM_FORMAT_S16; + buffer_size = 0; + period_size = 0; + buffer_time = 100000; + period_time = 20000; + totalTimeValue = 0; + intervalTime = 1000; + errorState = QAudio::NoError; + deviceState = QAudio::StoppedState; + audioSource = 0; + pullMode = true; + resuming = false; + + m_device = device; + + timer = new QTimer(this); + connect(timer,SIGNAL(timeout()),SLOT(userFeed())); +} + +QAudioInputPrivate::~QAudioInputPrivate() +{ + close(); + disconnect(timer, SIGNAL(timeout())); + QCoreApplication::processEvents(); + delete timer; +} + +QAudio::Error QAudioInputPrivate::error() const +{ + return errorState; +} + +QAudio::State QAudioInputPrivate::state() const +{ + return deviceState; +} + +void QAudioInputPrivate::setFormat(const QAudioFormat& fmt) +{ + if (deviceState == QAudio::StoppedState) + settings = fmt; +} + +QAudioFormat QAudioInputPrivate::format() const +{ + return settings; +} + +int QAudioInputPrivate::xrun_recovery(int err) +{ + int count = 0; + bool reset = false; + + if(err == -EPIPE) { + errorState = QAudio::UnderrunError; + err = snd_pcm_prepare(handle); + if(err < 0) + reset = true; + else { + bytesAvailable = checkBytesReady(); + if (bytesAvailable <= 0) + reset = true; + } + + } else if((err == -ESTRPIPE)||(err == -EIO)) { + errorState = QAudio::IOError; + while((err = snd_pcm_resume(handle)) == -EAGAIN){ + usleep(100); + count++; + if(count > 5) { + reset = true; + break; + } + } + if(err < 0) { + err = snd_pcm_prepare(handle); + if(err < 0) + reset = true; + } + } + if(reset) { + close(); + open(); + snd_pcm_prepare(handle); + return 0; + } + return err; +} + +int QAudioInputPrivate::setFormat() +{ + snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN; + + if(settings.sampleSize() == 8) { + format = SND_PCM_FORMAT_U8; + } else if(settings.sampleSize() == 16) { + if(settings.sampleType() == QAudioFormat::SignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_S16_LE; + else + format = SND_PCM_FORMAT_S16_BE; + } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_U16_LE; + else + format = SND_PCM_FORMAT_U16_BE; + } + } else if(settings.sampleSize() == 24) { + if(settings.sampleType() == QAudioFormat::SignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_S24_LE; + else + format = SND_PCM_FORMAT_S24_BE; + } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_U24_LE; + else + format = SND_PCM_FORMAT_U24_BE; + } + } else if(settings.sampleSize() == 32) { + if(settings.sampleType() == QAudioFormat::SignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_S32_LE; + else + format = SND_PCM_FORMAT_S32_BE; + } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_U32_LE; + else + format = SND_PCM_FORMAT_U32_BE; + } else if(settings.sampleType() == QAudioFormat::Float) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_FLOAT_LE; + else + format = SND_PCM_FORMAT_FLOAT_BE; + } + } else if(settings.sampleSize() == 64) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_FLOAT64_LE; + else + format = SND_PCM_FORMAT_FLOAT64_BE; + } + + return format != SND_PCM_FORMAT_UNKNOWN + ? snd_pcm_hw_params_set_format( handle, hwparams, format) + : -1; +} + +void QAudioInputPrivate::start(QIODevice* device) +{ + if(deviceState != QAudio::StoppedState) + close(); + + if(!pullMode && audioSource) + delete audioSource; + + pullMode = true; + audioSource = device; + + deviceState = QAudio::ActiveState; + + if( !open() ) + return; + + emit stateChanged(deviceState); +} + +QIODevice* QAudioInputPrivate::start() +{ + if(deviceState != QAudio::StoppedState) + close(); + + if(!pullMode && audioSource) + delete audioSource; + + pullMode = false; + audioSource = new InputPrivate(this); + audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered); + + deviceState = QAudio::IdleState; + + if( !open() ) + return 0; + + emit stateChanged(deviceState); + + return audioSource; +} + +void QAudioInputPrivate::stop() +{ + if(deviceState == QAudio::StoppedState) + return; + + deviceState = QAudio::StoppedState; + + close(); + emit stateChanged(deviceState); +} + +bool QAudioInputPrivate::open() +{ +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()< devices = QAudioDeviceInfoInternal::availableDevices(QAudio::AudioInput); + if(dev.compare(QLatin1String("default")) == 0) { +#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) + if (devices.size() > 0) + dev = QLatin1String(devices.first()); + else + return false; +#else + dev = QLatin1String("hw:0,0"); +#endif + } else { +#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) + dev = QLatin1String(m_device); +#else + int idx = 0; + char *name; + + QString shortName = QLatin1String(m_device.mid(m_device.indexOf('=',0)+1).constData()); + + while(snd_card_get_name(idx,&name) == 0) { + if(qstrncmp(shortName.toLocal8Bit().constData(),name,shortName.length()) == 0) + break; + idx++; + } + dev = QString(QLatin1String("hw:%1,0")).arg(idx); +#endif + } + + // Step 1: try and open the device + while((count < 5) && (err < 0)) { + err=snd_pcm_open(&handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0); + if(err < 0) + count++; + } + if (( err < 0)||(handle == 0)) { + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + return false; + } + snd_pcm_nonblock( handle, 0 ); + + // Step 2: Set the desired HW parameters. + snd_pcm_hw_params_alloca( &hwparams ); + + bool fatal = false; + QString errMessage; + unsigned int chunks = 8; + + err = snd_pcm_hw_params_any( handle, hwparams ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_any: err = %1").arg(err); + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_rate_resample( handle, hwparams, 1 ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_rate_resample: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_access( handle, hwparams, access ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_access: err = %1").arg(err); + } + } + if ( !fatal ) { + err = setFormat(); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_format: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_channels( handle, hwparams, (unsigned int)settings.channels() ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_channels: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_rate_near( handle, hwparams, &freakuency, 0 ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_rate_near: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_buffer_time_near: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_period_time_near: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &chunks, &dir); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_periods_near: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params(handle, hwparams); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params: err = %1").arg(err); + } + } + if( err < 0) { + qWarning()<start(period_time*chunks/2000); + + errorState = QAudio::NoError; + + totalTimeValue = 0; + + return true; +} + +void QAudioInputPrivate::close() +{ + timer->stop(); + + if ( handle ) { + snd_pcm_drop( handle ); + snd_pcm_close( handle ); + handle = 0; + } +} + +int QAudioInputPrivate::checkBytesReady() +{ + if(resuming) + bytesAvailable = period_size; + else if(deviceState != QAudio::ActiveState + && deviceState != QAudio::IdleState) + bytesAvailable = 0; + else { + int frames = snd_pcm_avail_update(handle); + if (frames < 0) { + bytesAvailable = frames; + } else { + if((int)frames > (int)buffer_frames) + frames = buffer_frames; + bytesAvailable = snd_pcm_frames_to_bytes(handle, frames); + } + } + return bytesAvailable; +} + +int QAudioInputPrivate::bytesReady() const +{ + return qMax(bytesAvailable, 0); +} + +qint64 QAudioInputPrivate::read(char* data, qint64 len) +{ + // Read in some audio data and write it to QIODevice, pull mode + if ( !handle ) + return 0; + + int bytesRead = 0; + int bytesInRingbufferBeforeRead = ringBuffer.bytesOfDataInBuffer(); + + if (ringBuffer.bytesOfDataInBuffer() < len) { + + // bytesAvaiable is saved as a side effect of checkBytesReady(). + int bytesToRead = checkBytesReady(); + + if (bytesToRead < 0) { + // bytesAvailable as negative is error code, try to recover from it. + xrun_recovery(bytesToRead); + bytesToRead = checkBytesReady(); + if (bytesToRead < 0) { + // recovery failed must stop and set error. + close(); + errorState = QAudio::IOError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + return 0; + } + } + + bytesToRead = qMin(len, bytesToRead); + bytesToRead = qMin(ringBuffer.freeBytes(), bytesToRead); + bytesToRead -= bytesToRead % period_size; + + int count=0; + int err = 0; + while(count < 5 && bytesToRead > 0) { + char buffer[bytesToRead]; + int chunks = bytesToRead / period_size; + int frames = chunks * period_frames; + if (frames > (int)buffer_frames) + frames = buffer_frames; + + int readFrames = snd_pcm_readi(handle, buffer, frames); + + if (readFrames >= 0) { + bytesRead = snd_pcm_frames_to_bytes(handle, readFrames); + ringBuffer.write(buffer, bytesRead); +#ifdef DEBUG_AUDIO + qDebug() << QString::fromLatin1("read in bytes = %1 (frames=%2)").arg(bytesRead).arg(readFrames).toLatin1().constData(); +#endif + break; + } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) { + errorState = QAudio::IOError; + err = 0; + break; + } else { + if(readFrames == -EPIPE) { + errorState = QAudio::UnderrunError; + err = snd_pcm_prepare(handle); + } else if(readFrames == -ESTRPIPE) { + err = snd_pcm_prepare(handle); + } + if(err != 0) break; + } + count++; + } + + } + + bytesRead += bytesInRingbufferBeforeRead; + + if (bytesRead > 0) { + // got some send it onward +#ifdef DEBUG_AUDIO + qDebug() << "frames to write to QIODevice = " << + snd_pcm_bytes_to_frames( handle, (int)bytesRead ) << " (" << bytesRead << ") bytes"; +#endif + if (deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) + return 0; + + if (pullMode) { + qint64 l = 0; + qint64 bytesWritten = 0; + while (ringBuffer.bytesOfDataInBuffer() > 0) { + l = audioSource->write(ringBuffer.availableData(), ringBuffer.availableDataBlockSize()); + if (l > 0) { + ringBuffer.readBytes(l); + bytesWritten += l; + } else { + break; + } + } + + if (l < 0) { + close(); + errorState = QAudio::IOError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + } else if (l == 0 && bytesWritten == 0) { + if (deviceState != QAudio::IdleState) { + errorState = QAudio::NoError; + deviceState = QAudio::IdleState; + emit stateChanged(deviceState); + } + } else { + bytesAvailable -= bytesWritten; + totalTimeValue += bytesWritten; + resuming = false; + if (deviceState != QAudio::ActiveState) { + errorState = QAudio::NoError; + deviceState = QAudio::ActiveState; + emit stateChanged(deviceState); + } + } + + return bytesWritten; + } else { + while (ringBuffer.bytesOfDataInBuffer() > 0) { + int size = ringBuffer.availableDataBlockSize(); + memcpy(data, ringBuffer.availableData(), size); + data += size; + ringBuffer.readBytes(size); + } + + bytesAvailable -= bytesRead; + totalTimeValue += bytesRead; + resuming = false; + if (deviceState != QAudio::ActiveState) { + errorState = QAudio::NoError; + deviceState = QAudio::ActiveState; + emit stateChanged(deviceState); + } + + return bytesRead; + } + } + + return 0; +} + +void QAudioInputPrivate::resume() +{ + if(deviceState == QAudio::SuspendedState) { + int err = 0; + + if(handle) { + err = snd_pcm_prepare( handle ); + if(err < 0) + xrun_recovery(err); + + err = snd_pcm_start(handle); + if(err < 0) + xrun_recovery(err); + + bytesAvailable = buffer_size; + } + resuming = true; + deviceState = QAudio::ActiveState; + int chunks = buffer_size/period_size; + timer->start(period_time*chunks/2000); + emit stateChanged(deviceState); + } +} + +void QAudioInputPrivate::setBufferSize(int value) +{ + buffer_size = value; +} + +int QAudioInputPrivate::bufferSize() const +{ + return buffer_size; +} + +int QAudioInputPrivate::periodSize() const +{ + return period_size; +} + +void QAudioInputPrivate::setNotifyInterval(int ms) +{ + intervalTime = qMax(0, ms); +} + +int QAudioInputPrivate::notifyInterval() const +{ + return intervalTime; +} + +qint64 QAudioInputPrivate::processedUSecs() const +{ + qint64 result = qint64(1000000) * totalTimeValue / + (settings.channels()*(settings.sampleSize()/8)) / + settings.frequency(); + + return result; +} + +void QAudioInputPrivate::suspend() +{ + if(deviceState == QAudio::ActiveState||resuming) { + timer->stop(); + deviceState = QAudio::SuspendedState; + emit stateChanged(deviceState); + } +} + +void QAudioInputPrivate::userFeed() +{ + if(deviceState == QAudio::StoppedState || deviceState == QAudio::SuspendedState) + return; +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()<(audioSource); + a->trigger(); + } + bytesAvailable = checkBytesReady(); + + if(deviceState != QAudio::ActiveState) + return true; + + if (bytesAvailable < 0) { + // bytesAvailable as negative is error code, try to recover from it. + xrun_recovery(bytesAvailable); + bytesAvailable = checkBytesReady(); + if (bytesAvailable < 0) { + // recovery failed must stop and set error. + close(); + errorState = QAudio::IOError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + return 0; + } + } + + if(intervalTime && (timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) { + emit notify(); + elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime; + timeStamp.restart(); + } + return true; +} + +qint64 QAudioInputPrivate::elapsedUSecs() const +{ + if (deviceState == QAudio::StoppedState) + return 0; + + return clockStamp.elapsed()*1000; +} + +void QAudioInputPrivate::reset() +{ + if(handle) + snd_pcm_reset(handle); + stop(); + bytesAvailable = 0; +} + +void QAudioInputPrivate::drain() +{ + if(handle) + snd_pcm_drain(handle); +} + +InputPrivate::InputPrivate(QAudioInputPrivate* audio) +{ + audioDevice = qobject_cast(audio); +} + +InputPrivate::~InputPrivate() +{ +} + +qint64 InputPrivate::readData( char* data, qint64 len) +{ + return audioDevice->read(data,len); +} + +qint64 InputPrivate::writeData(const char* data, qint64 len) +{ + Q_UNUSED(data) + Q_UNUSED(len) + return 0; +} + +void InputPrivate::trigger() +{ + emit readyRead(); +} + +RingBuffer::RingBuffer() : + m_head(0), + m_tail(0) +{ +} + +void RingBuffer::resize(int size) +{ + m_data.resize(size); +} + +int RingBuffer::bytesOfDataInBuffer() const +{ + if (m_head < m_tail) + return m_tail - m_head; + else if (m_tail < m_head) + return m_data.size() + m_tail - m_head; + else + return 0; +} + +int RingBuffer::freeBytes() const +{ + if (m_head > m_tail) + return m_head - m_tail - 1; + else if (m_tail > m_head) + return m_data.size() - m_tail + m_head - 1; + else + return m_data.size() - 1; +} + +const char *RingBuffer::availableData() const +{ + return (m_data.constData() + m_head); +} + +int RingBuffer::availableDataBlockSize() const +{ + if (m_head > m_tail) + return m_data.size() - m_head; + else if (m_tail > m_head) + return m_tail - m_head; + else + return 0; +} + +void RingBuffer::readBytes(int bytes) +{ + m_head = (m_head + bytes) % m_data.size(); +} + +void RingBuffer::write(char *data, int len) +{ + if (m_tail + len < m_data.size()) { + memcpy(m_data.data() + m_tail, data, len); + m_tail += len; + } else { + int bytesUntilEnd = m_data.size() - m_tail; + memcpy(m_data.data() + m_tail, data, bytesUntilEnd); + if (len - bytesUntilEnd > 0) + memcpy(m_data.data(), data + bytesUntilEnd, len - bytesUntilEnd); + m_tail = len - bytesUntilEnd; + } +} + +QT_END_NAMESPACE + +#include "moc_qaudioinput_alsa_p.cpp" diff --git a/src/multimediakit/audio/qaudioinput_alsa_p.h b/src/multimediakit/audio/qaudioinput_alsa_p.h new file mode 100644 index 000000000..a6f371642 --- /dev/null +++ b/src/multimediakit/audio/qaudioinput_alsa_p.h @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QAUDIOINPUTALSA_H +#define QAUDIOINPUTALSA_H + +#include + +#include +#include +#include +#include +#include +#include + +#include "qaudio.h" +#include "qaudiodeviceinfo.h" +#include "qaudiosystem.h" + +QT_BEGIN_NAMESPACE + +class InputPrivate; + +class RingBuffer +{ +public: + RingBuffer(); + + void resize(int size); + + int bytesOfDataInBuffer() const; + int freeBytes() const; + + const char *availableData() const; + int availableDataBlockSize() const; + void readBytes(int bytes); + + void write(char *data, int len); + +private: + int m_head; + int m_tail; + + QByteArray m_data; +}; + +class QAudioInputPrivate : public QAbstractAudioInput +{ + Q_OBJECT +public: + QAudioInputPrivate(const QByteArray &device); + ~QAudioInputPrivate(); + + qint64 read(char* data, qint64 len); + + void start(QIODevice* device); + QIODevice* start(); + void stop(); + void reset(); + void suspend(); + void resume(); + int bytesReady() const; + int periodSize() const; + void setBufferSize(int value); + int bufferSize() const; + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + QAudio::Error error() const; + QAudio::State state() const; + void setFormat(const QAudioFormat& fmt); + QAudioFormat format() const; + bool resuming; + snd_pcm_t* handle; + qint64 totalTimeValue; + QIODevice* audioSource; + QAudioFormat settings; + QAudio::Error errorState; + QAudio::State deviceState; + +private slots: + void userFeed(); + bool deviceReady(); + +private: + int checkBytesReady(); + int xrun_recovery(int err); + int setFormat(); + bool open(); + void close(); + void drain(); + + QTimer* timer; + QTime timeStamp; + QTime clockStamp; + qint64 elapsedTimeOffset; + int intervalTime; + RingBuffer ringBuffer; + int bytesAvailable; + QByteArray m_device; + bool pullMode; + int buffer_size; + int period_size; + unsigned int buffer_time; + unsigned int period_time; + snd_pcm_uframes_t buffer_frames; + snd_pcm_uframes_t period_frames; + snd_async_handler_t* ahandler; + snd_pcm_access_t access; + snd_pcm_format_t pcmformat; + snd_timestamp_t* timestamp; + snd_pcm_hw_params_t *hwparams; +}; + +class InputPrivate : public QIODevice +{ + Q_OBJECT +public: + InputPrivate(QAudioInputPrivate* audio); + ~InputPrivate(); + + qint64 readData( char* data, qint64 len); + qint64 writeData(const char* data, qint64 len); + + void trigger(); +private: + QAudioInputPrivate *audioDevice; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/audio/qaudioinput_mac_p.cpp b/src/multimediakit/audio/qaudioinput_mac_p.cpp new file mode 100644 index 000000000..8c3bbe600 --- /dev/null +++ b/src/multimediakit/audio/qaudioinput_mac_p.cpp @@ -0,0 +1,989 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include +#include +#include + +#include + +#include "qaudio_mac_p.h" +#include "qaudioinput_mac_p.h" +#include "qaudiodeviceinfo_mac_p.h" + +QT_BEGIN_NAMESPACE + + +namespace QtMultimediaKitInternal +{ + +static const int default_buffer_size = 4 * 1024; + +class QAudioBufferList +{ +public: + QAudioBufferList(AudioStreamBasicDescription const& streamFormat): + owner(false), + sf(streamFormat) + { + const bool isInterleaved = (sf.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0; + const int numberOfBuffers = isInterleaved ? 1 : sf.mChannelsPerFrame; + + dataSize = 0; + + bfs = reinterpret_cast(qMalloc(sizeof(AudioBufferList) + + (sizeof(AudioBuffer) * numberOfBuffers))); + + bfs->mNumberBuffers = numberOfBuffers; + for (int i = 0; i < numberOfBuffers; ++i) { + bfs->mBuffers[i].mNumberChannels = isInterleaved ? numberOfBuffers : 1; + bfs->mBuffers[i].mDataByteSize = 0; + bfs->mBuffers[i].mData = 0; + } + } + + QAudioBufferList(AudioStreamBasicDescription const& streamFormat, char* buffer, int bufferSize): + owner(false), + sf(streamFormat), + bfs(0) + { + dataSize = bufferSize; + + bfs = reinterpret_cast(qMalloc(sizeof(AudioBufferList) + sizeof(AudioBuffer))); + + bfs->mNumberBuffers = 1; + bfs->mBuffers[0].mNumberChannels = 1; + bfs->mBuffers[0].mDataByteSize = dataSize; + bfs->mBuffers[0].mData = buffer; + } + + QAudioBufferList(AudioStreamBasicDescription const& streamFormat, int framesToBuffer): + owner(true), + sf(streamFormat), + bfs(0) + { + const bool isInterleaved = (sf.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0; + const int numberOfBuffers = isInterleaved ? 1 : sf.mChannelsPerFrame; + + dataSize = framesToBuffer * sf.mBytesPerFrame; + + bfs = reinterpret_cast(qMalloc(sizeof(AudioBufferList) + + (sizeof(AudioBuffer) * numberOfBuffers))); + bfs->mNumberBuffers = numberOfBuffers; + for (int i = 0; i < numberOfBuffers; ++i) { + bfs->mBuffers[i].mNumberChannels = isInterleaved ? numberOfBuffers : 1; + bfs->mBuffers[i].mDataByteSize = dataSize; + bfs->mBuffers[i].mData = qMalloc(dataSize); + } + } + + ~QAudioBufferList() + { + if (owner) { + for (UInt32 i = 0; i < bfs->mNumberBuffers; ++i) + qFree(bfs->mBuffers[i].mData); + } + + qFree(bfs); + } + + AudioBufferList* audioBufferList() const + { + return bfs; + } + + char* data(int buffer = 0) const + { + return static_cast(bfs->mBuffers[buffer].mData); + } + + qint64 bufferSize(int buffer = 0) const + { + return bfs->mBuffers[buffer].mDataByteSize; + } + + int frameCount(int buffer = 0) const + { + return bfs->mBuffers[buffer].mDataByteSize / sf.mBytesPerFrame; + } + + int packetCount(int buffer = 0) const + { + return bfs->mBuffers[buffer].mDataByteSize / sf.mBytesPerPacket; + } + + int packetSize() const + { + return sf.mBytesPerPacket; + } + + void reset() + { + for (UInt32 i = 0; i < bfs->mNumberBuffers; ++i) { + bfs->mBuffers[i].mDataByteSize = dataSize; + bfs->mBuffers[i].mData = 0; + } + } + +private: + bool owner; + int dataSize; + AudioStreamBasicDescription sf; + AudioBufferList* bfs; +}; + +class QAudioPacketFeeder +{ +public: + QAudioPacketFeeder(QAudioBufferList* abl): + audioBufferList(abl) + { + totalPackets = audioBufferList->packetCount(); + position = 0; + } + + bool feed(AudioBufferList& dst, UInt32& packetCount) + { + if (position == totalPackets) { + dst.mBuffers[0].mDataByteSize = 0; + packetCount = 0; + return false; + } + + if (totalPackets - position < packetCount) + packetCount = totalPackets - position; + + dst.mBuffers[0].mDataByteSize = packetCount * audioBufferList->packetSize(); + dst.mBuffers[0].mData = audioBufferList->data() + (position * audioBufferList->packetSize()); + + position += packetCount; + + return true; + } + + bool empty() const + { + return position == totalPackets; + } + +private: + UInt32 totalPackets; + UInt32 position; + QAudioBufferList* audioBufferList; +}; + +class QAudioInputBuffer : public QObject +{ + Q_OBJECT + +public: + QAudioInputBuffer(int bufferSize, + int maxPeriodSize, + AudioStreamBasicDescription const& inputFormat, + AudioStreamBasicDescription const& outputFormat, + QObject* parent): + QObject(parent), + m_deviceError(false), + m_audioConverter(0), + m_inputFormat(inputFormat), + m_outputFormat(outputFormat) + { + m_maxPeriodSize = maxPeriodSize; + m_periodTime = m_maxPeriodSize / m_outputFormat.mBytesPerFrame * 1000 / m_outputFormat.mSampleRate; + m_buffer = new QAudioRingBuffer(bufferSize + (bufferSize % maxPeriodSize == 0 ? 0 : maxPeriodSize - (bufferSize % maxPeriodSize))); + m_inputBufferList = new QAudioBufferList(m_inputFormat); + + m_flushTimer = new QTimer(this); + connect(m_flushTimer, SIGNAL(timeout()), SLOT(flushBuffer())); + + if (toQAudioFormat(inputFormat) != toQAudioFormat(outputFormat)) { + if (AudioConverterNew(&m_inputFormat, &m_outputFormat, &m_audioConverter) != noErr) { + qWarning() << "QAudioInput: Unable to create an Audio Converter"; + m_audioConverter = 0; + } + } + } + + ~QAudioInputBuffer() + { + delete m_buffer; + } + + qint64 renderFromDevice(AudioUnit audioUnit, + AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames) + { + const bool pullMode = m_device == 0; + + OSStatus err; + qint64 framesRendered = 0; + + m_inputBufferList->reset(); + err = AudioUnitRender(audioUnit, + ioActionFlags, + inTimeStamp, + inBusNumber, + inNumberFrames, + m_inputBufferList->audioBufferList()); + + if (m_audioConverter != 0) { + QAudioPacketFeeder feeder(m_inputBufferList); + + int copied = 0; + const int available = m_buffer->free(); + + while (err == noErr && !feeder.empty()) { + QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(available); + + if (region.second == 0) + break; + + AudioBufferList output; + output.mNumberBuffers = 1; + output.mBuffers[0].mNumberChannels = 1; + output.mBuffers[0].mDataByteSize = region.second; + output.mBuffers[0].mData = region.first; + + UInt32 packetSize = region.second / m_outputFormat.mBytesPerPacket; + err = AudioConverterFillComplexBuffer(m_audioConverter, + converterCallback, + &feeder, + &packetSize, + &output, + 0); + region.second = output.mBuffers[0].mDataByteSize; + copied += region.second; + + m_buffer->releaseWriteRegion(region); + } + + framesRendered += copied / m_outputFormat.mBytesPerFrame; + } + else { + const int available = m_inputBufferList->bufferSize(); + bool wecan = true; + int copied = 0; + + while (wecan && copied < available) { + QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(available - copied); + + if (region.second > 0) { + memcpy(region.first, m_inputBufferList->data() + copied, region.second); + copied += region.second; + } + else + wecan = false; + + m_buffer->releaseWriteRegion(region); + } + + framesRendered = copied / m_outputFormat.mBytesPerFrame; + } + + if (pullMode && framesRendered > 0) + emit readyRead(); + + return framesRendered; + } + + qint64 readBytes(char* data, qint64 len) + { + bool wecan = true; + qint64 bytesCopied = 0; + + len -= len % m_maxPeriodSize; + while (wecan && bytesCopied < len) { + QAudioRingBuffer::Region region = m_buffer->acquireReadRegion(len - bytesCopied); + + if (region.second > 0) { + memcpy(data + bytesCopied, region.first, region.second); + bytesCopied += region.second; + } + else + wecan = false; + + m_buffer->releaseReadRegion(region); + } + + return bytesCopied; + } + + void setFlushDevice(QIODevice* device) + { + if (m_device != device) + m_device = device; + } + + void startFlushTimer() + { + if (m_device != 0) { + m_flushTimer->start((m_buffer->size() - (m_maxPeriodSize * 2)) / m_maxPeriodSize * m_periodTime); + } + } + + void stopFlushTimer() + { + m_flushTimer->stop(); + } + + void flush(bool all = false) + { + if (m_device == 0) + return; + + const int used = m_buffer->used(); + const int readSize = all ? used : used - (used % m_maxPeriodSize); + + if (readSize > 0) { + bool wecan = true; + int flushed = 0; + + while (!m_deviceError && wecan && flushed < readSize) { + QAudioRingBuffer::Region region = m_buffer->acquireReadRegion(readSize - flushed); + + if (region.second > 0) { + int bytesWritten = m_device->write(region.first, region.second); + if (bytesWritten < 0) { + stopFlushTimer(); + m_deviceError = true; + } + else { + region.second = bytesWritten; + flushed += bytesWritten; + wecan = bytesWritten != 0; + } + } + else + wecan = false; + + m_buffer->releaseReadRegion(region); + } + } + } + + void reset() + { + m_buffer->reset(); + m_deviceError = false; + } + + int available() const + { + return m_buffer->free(); + } + + int used() const + { + return m_buffer->used(); + } + +signals: + void readyRead(); + +private slots: + void flushBuffer() + { + flush(); + } + +private: + bool m_deviceError; + int m_maxPeriodSize; + int m_periodTime; + QIODevice* m_device; + QTimer* m_flushTimer; + QAudioRingBuffer* m_buffer; + QAudioBufferList* m_inputBufferList; + AudioConverterRef m_audioConverter; + AudioStreamBasicDescription m_inputFormat; + AudioStreamBasicDescription m_outputFormat; + + const static OSStatus as_empty = 'qtem'; + + // Converter callback + static OSStatus converterCallback(AudioConverterRef inAudioConverter, + UInt32* ioNumberDataPackets, + AudioBufferList* ioData, + AudioStreamPacketDescription** outDataPacketDescription, + void* inUserData) + { + Q_UNUSED(inAudioConverter); + Q_UNUSED(outDataPacketDescription); + + QAudioPacketFeeder* feeder = static_cast(inUserData); + + if (!feeder->feed(*ioData, *ioNumberDataPackets)) + return as_empty; + + return noErr; + } +}; + + +class MacInputDevice : public QIODevice +{ + Q_OBJECT + +public: + MacInputDevice(QAudioInputBuffer* audioBuffer, QObject* parent): + QIODevice(parent), + m_audioBuffer(audioBuffer) + { + open(QIODevice::ReadOnly | QIODevice::Unbuffered); + connect(m_audioBuffer, SIGNAL(readyRead()), SIGNAL(readyRead())); + } + + qint64 readData(char* data, qint64 len) + { + return m_audioBuffer->readBytes(data, len); + } + + qint64 writeData(const char* data, qint64 len) + { + Q_UNUSED(data); + Q_UNUSED(len); + + return 0; + } + + bool isSequential() const + { + return true; + } + +private: + QAudioInputBuffer* m_audioBuffer; +}; + +} + + +QAudioInputPrivate::QAudioInputPrivate(const QByteArray& device) +{ + QDataStream ds(device); + quint32 did, mode; + + ds >> did >> mode; + + if (QAudio::Mode(mode) == QAudio::AudioOutput) + errorCode = QAudio::OpenError; + else { + audioDeviceInfo = new QAudioDeviceInfoInternal(device, QAudio::AudioInput); + isOpen = false; + audioDeviceId = AudioDeviceID(did); + audioUnit = 0; + startTime = 0; + totalFrames = 0; + audioBuffer = 0; + internalBufferSize = QtMultimediaKitInternal::default_buffer_size; + clockFrequency = AudioGetHostClockFrequency() / 1000; + errorCode = QAudio::NoError; + stateCode = QAudio::StoppedState; + + intervalTimer = new QTimer(this); + intervalTimer->setInterval(1000); + connect(intervalTimer, SIGNAL(timeout()), SIGNAL(notify())); + } +} + +QAudioInputPrivate::~QAudioInputPrivate() +{ + close(); + delete audioDeviceInfo; +} + +bool QAudioInputPrivate::open() +{ + UInt32 size = 0; + + if (isOpen) + return true; + + ComponentDescription cd; + cd.componentType = kAudioUnitType_Output; + cd.componentSubType = kAudioUnitSubType_HALOutput; + cd.componentManufacturer = kAudioUnitManufacturer_Apple; + cd.componentFlags = 0; + cd.componentFlagsMask = 0; + + // Open + Component cp = FindNextComponent(NULL, &cd); + if (cp == 0) { + qWarning() << "QAudioInput: Failed to find HAL Output component"; + return false; + } + + if (OpenAComponent(cp, &audioUnit) != noErr) { + qWarning() << "QAudioInput: Unable to Open Output Component"; + return false; + } + + // Set mode + // switch to input mode + UInt32 enable = 1; + if (AudioUnitSetProperty(audioUnit, + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Input, + 1, + &enable, + sizeof(enable)) != noErr) { + qWarning() << "QAudioInput: Unable to switch to input mode (Enable Input)"; + return false; + } + + enable = 0; + if (AudioUnitSetProperty(audioUnit, + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Output, + 0, + &enable, + sizeof(enable)) != noErr) { + qWarning() << "QAudioInput: Unable to switch to input mode (Disable output)"; + return false; + } + + // register callback + AURenderCallbackStruct cb; + cb.inputProc = inputCallback; + cb.inputProcRefCon = this; + + if (AudioUnitSetProperty(audioUnit, + kAudioOutputUnitProperty_SetInputCallback, + kAudioUnitScope_Global, + 0, + &cb, + sizeof(cb)) != noErr) { + qWarning() << "QAudioInput: Failed to set AudioUnit callback"; + return false; + } + + // Set Audio Device + if (AudioUnitSetProperty(audioUnit, + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + 0, + &audioDeviceId, + sizeof(audioDeviceId)) != noErr) { + qWarning() << "QAudioInput: Unable to use configured device"; + return false; + } + + // Set format + // Wanted + streamFormat = toAudioStreamBasicDescription(audioFormat); + + // Required on unit + if (audioFormat == audioDeviceInfo->preferredFormat()) { + deviceFormat = streamFormat; + AudioUnitSetProperty(audioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + 1, + &deviceFormat, + sizeof(deviceFormat)); + } + else { + size = sizeof(deviceFormat); + if (AudioUnitGetProperty(audioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 1, + &deviceFormat, + &size) != noErr) { + qWarning() << "QAudioInput: Unable to retrieve device format"; + return false; + } + + if (AudioUnitSetProperty(audioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + 1, + &deviceFormat, + sizeof(deviceFormat)) != noErr) { + qWarning() << "QAudioInput: Unable to set device format"; + return false; + } + } + + // Setup buffers + UInt32 numberOfFrames; + size = sizeof(UInt32); + if (AudioUnitGetProperty(audioUnit, + kAudioDevicePropertyBufferFrameSize, + kAudioUnitScope_Global, + 0, + &numberOfFrames, + &size) != noErr) { + qWarning() << "QAudioInput: Failed to get audio period size"; + return false; + } + + // Allocate buffer + periodSizeBytes = numberOfFrames * streamFormat.mBytesPerFrame; + + if (internalBufferSize < periodSizeBytes * 2) + internalBufferSize = periodSizeBytes * 2; + else + internalBufferSize -= internalBufferSize % streamFormat.mBytesPerFrame; + + audioBuffer = new QtMultimediaKitInternal::QAudioInputBuffer(internalBufferSize, + periodSizeBytes, + deviceFormat, + streamFormat, + this); + + audioIO = new QtMultimediaKitInternal::MacInputDevice(audioBuffer, this); + + // Init + if (AudioUnitInitialize(audioUnit) != noErr) { + qWarning() << "QAudioInput: Failed to initialize AudioUnit"; + return false; + } + + isOpen = true; + + return isOpen; +} + +void QAudioInputPrivate::close() +{ + if (audioUnit != 0) { + AudioOutputUnitStop(audioUnit); + AudioUnitUninitialize(audioUnit); + CloseComponent(audioUnit); + } + + delete audioBuffer; +} + +QAudioFormat QAudioInputPrivate::format() const +{ + return audioFormat; +} + +void QAudioInputPrivate::setFormat(const QAudioFormat& fmt) +{ + if (stateCode == QAudio::StoppedState) + audioFormat = fmt; +} + +void QAudioInputPrivate::start(QIODevice* device) +{ + QIODevice* op = device; + + if (!audioDeviceInfo->isFormatSupported(audioFormat) || !open()) { + stateCode = QAudio::StoppedState; + errorCode = QAudio::OpenError; + return; + } + + reset(); + audioBuffer->reset(); + audioBuffer->setFlushDevice(op); + + if (op == 0) + op = audioIO; + + // Start + startTime = AudioGetCurrentHostTime(); + totalFrames = 0; + + audioThreadStart(); + + stateCode = QAudio::ActiveState; + errorCode = QAudio::NoError; + emit stateChanged(stateCode); +} + +QIODevice* QAudioInputPrivate::start() +{ + QIODevice* op = 0; + + if (!audioDeviceInfo->isFormatSupported(audioFormat) || !open()) { + stateCode = QAudio::StoppedState; + errorCode = QAudio::OpenError; + return audioIO; + } + + reset(); + audioBuffer->reset(); + audioBuffer->setFlushDevice(op); + + if (op == 0) + op = audioIO; + + // Start + startTime = AudioGetCurrentHostTime(); + totalFrames = 0; + + audioThreadStart(); + + stateCode = QAudio::ActiveState; + errorCode = QAudio::NoError; + emit stateChanged(stateCode); + + return op; +} + +void QAudioInputPrivate::stop() +{ + QMutexLocker lock(&mutex); + if (stateCode != QAudio::StoppedState) { + audioThreadStop(); + audioBuffer->flush(true); + + errorCode = QAudio::NoError; + stateCode = QAudio::StoppedState; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +void QAudioInputPrivate::reset() +{ + QMutexLocker lock(&mutex); + if (stateCode != QAudio::StoppedState) { + audioThreadStop(); + + errorCode = QAudio::NoError; + stateCode = QAudio::StoppedState; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +void QAudioInputPrivate::suspend() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::ActiveState || stateCode == QAudio::IdleState) { + audioThreadStop(); + + errorCode = QAudio::NoError; + stateCode = QAudio::SuspendedState; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +void QAudioInputPrivate::resume() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::SuspendedState) { + audioThreadStart(); + + errorCode = QAudio::NoError; + stateCode = QAudio::ActiveState; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +int QAudioInputPrivate::bytesReady() const +{ + return audioBuffer->used(); +} + +int QAudioInputPrivate::periodSize() const +{ + return periodSizeBytes; +} + +void QAudioInputPrivate::setBufferSize(int bs) +{ + internalBufferSize = bs; +} + +int QAudioInputPrivate::bufferSize() const +{ + return internalBufferSize; +} + +void QAudioInputPrivate::setNotifyInterval(int milliSeconds) +{ + if (intervalTimer->interval() == milliSeconds) + return; + + if (milliSeconds <= 0) + milliSeconds = 0; + + intervalTimer->setInterval(milliSeconds); +} + +int QAudioInputPrivate::notifyInterval() const +{ + return intervalTimer->interval(); +} + +qint64 QAudioInputPrivate::processedUSecs() const +{ + return totalFrames * 1000000 / audioFormat.frequency(); +} + +qint64 QAudioInputPrivate::elapsedUSecs() const +{ + if (stateCode == QAudio::StoppedState) + return 0; + + return (AudioGetCurrentHostTime() - startTime) / (clockFrequency / 1000); +} + +QAudio::Error QAudioInputPrivate::error() const +{ + return errorCode; +} + +QAudio::State QAudioInputPrivate::state() const +{ + return stateCode; +} + +void QAudioInputPrivate::audioThreadStop() +{ + stopTimers(); + if (audioThreadState.testAndSetAcquire(Running, Stopped)) + threadFinished.wait(&mutex); +} + +void QAudioInputPrivate::audioThreadStart() +{ + startTimers(); + audioThreadState = Running; + AudioOutputUnitStart(audioUnit); +} + +void QAudioInputPrivate::audioDeviceStop() +{ + AudioOutputUnitStop(audioUnit); + audioThreadState = Stopped; + threadFinished.wakeOne(); +} + +void QAudioInputPrivate::audioDeviceFull() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::ActiveState) { + audioDeviceStop(); + + errorCode = QAudio::UnderrunError; + stateCode = QAudio::IdleState; + QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection); + } +} + +void QAudioInputPrivate::audioDeviceError() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::ActiveState) { + audioDeviceStop(); + + errorCode = QAudio::IOError; + stateCode = QAudio::StoppedState; + QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection); + } +} + +void QAudioInputPrivate::startTimers() +{ + audioBuffer->startFlushTimer(); + if (intervalTimer->interval() > 0) + intervalTimer->start(); +} + +void QAudioInputPrivate::stopTimers() +{ + audioBuffer->stopFlushTimer(); + intervalTimer->stop(); +} + +void QAudioInputPrivate::deviceStopped() +{ + stopTimers(); + emit stateChanged(stateCode); +} + +// Input callback +OSStatus QAudioInputPrivate::inputCallback(void* inRefCon, + AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList* ioData) +{ + Q_UNUSED(ioData); + + QAudioInputPrivate* d = static_cast(inRefCon); + + const int threadState = d->audioThreadState.fetchAndAddAcquire(0); + if (threadState == Stopped) + d->audioDeviceStop(); + else { + qint64 framesWritten; + + framesWritten = d->audioBuffer->renderFromDevice(d->audioUnit, + ioActionFlags, + inTimeStamp, + inBusNumber, + inNumberFrames); + + if (framesWritten > 0) + d->totalFrames += framesWritten; + else if (framesWritten == 0) + d->audioDeviceFull(); + else if (framesWritten < 0) + d->audioDeviceError(); + } + + return noErr; +} + + +QT_END_NAMESPACE + +#include "qaudioinput_mac_p.moc" diff --git a/src/multimediakit/audio/qaudioinput_mac_p.h b/src/multimediakit/audio/qaudioinput_mac_p.h new file mode 100644 index 000000000..61b6edf75 --- /dev/null +++ b/src/multimediakit/audio/qaudioinput_mac_p.h @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QAUDIOINPUT_MAC_P_H +#define QAUDIOINPUT_MAC_P_H + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QTimer; +class QIODevice; +class QAbstractAudioDeviceInfo; + +namespace QtMultimediaKitInternal +{ +class QAudioInputBuffer; +} + +class QAudioInputPrivate : public QAbstractAudioInput +{ + Q_OBJECT + +public: + bool isOpen; + int periodSizeBytes; + int internalBufferSize; + qint64 totalFrames; + QAudioFormat audioFormat; + QIODevice* audioIO; + AudioUnit audioUnit; + AudioDeviceID audioDeviceId; + Float64 clockFrequency; + UInt64 startTime; + QAudio::Error errorCode; + QAudio::State stateCode; + QtMultimediaKitInternal::QAudioInputBuffer* audioBuffer; + QMutex mutex; + QWaitCondition threadFinished; + QAtomicInt audioThreadState; + QTimer* intervalTimer; + AudioStreamBasicDescription streamFormat; + AudioStreamBasicDescription deviceFormat; + QAbstractAudioDeviceInfo *audioDeviceInfo; + + QAudioInputPrivate(const QByteArray& device); + ~QAudioInputPrivate(); + + bool open(); + void close(); + + QAudioFormat format() const; + void setFormat(const QAudioFormat& fmt); + + QIODevice* start(); + void start(QIODevice* device); + void stop(); + void reset(); + void suspend(); + void resume(); + void idle(); + + int bytesReady() const; + int periodSize() const; + + void setBufferSize(int value); + int bufferSize() const; + + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + + QAudio::Error error() const; + QAudio::State state() const; + + void audioThreadStart(); + void audioThreadStop(); + + void audioDeviceStop(); + void audioDeviceFull(); + void audioDeviceError(); + + void startTimers(); + void stopTimers(); + +private slots: + void deviceStopped(); + +private: + enum { Running, Stopped }; + + // Input callback + static OSStatus inputCallback(void* inRefCon, + AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList* ioData); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIOINPUT_MAC_P_H diff --git a/src/multimediakit/audio/qaudioinput_symbian_p.cpp b/src/multimediakit/audio/qaudioinput_symbian_p.cpp new file mode 100644 index 000000000..fe250cf32 --- /dev/null +++ b/src/multimediakit/audio/qaudioinput_symbian_p.cpp @@ -0,0 +1,594 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaudioinput_symbian_p.h" + +QT_BEGIN_NAMESPACE + +//----------------------------------------------------------------------------- +// Constants +//----------------------------------------------------------------------------- + +const int PushInterval = 50; // ms + + +//----------------------------------------------------------------------------- +// Private class +//----------------------------------------------------------------------------- + +SymbianAudioInputPrivate::SymbianAudioInputPrivate( + QAudioInputPrivate *audioDevice) + : m_audioDevice(audioDevice) +{ + +} + +SymbianAudioInputPrivate::~SymbianAudioInputPrivate() +{ + +} + +qint64 SymbianAudioInputPrivate::readData(char *data, qint64 len) +{ + qint64 totalRead = 0; + + if (m_audioDevice->state() == QAudio::ActiveState || + m_audioDevice->state() == QAudio::IdleState) { + + while (totalRead < len) { + const qint64 read = m_audioDevice->read(data + totalRead, + len - totalRead); + if (read > 0) + totalRead += read; + else + break; + } + } + + return totalRead; +} + +qint64 SymbianAudioInputPrivate::writeData(const char *data, qint64 len) +{ + Q_UNUSED(data) + Q_UNUSED(len) + return 0; +} + +void SymbianAudioInputPrivate::dataReady() +{ + emit readyRead(); +} + + +//----------------------------------------------------------------------------- +// Public functions +//----------------------------------------------------------------------------- + +QAudioInputPrivate::QAudioInputPrivate(const QByteArray &device) + : m_device(device) + , m_clientBufferSize(SymbianAudio::DefaultBufferSize) + , m_notifyInterval(SymbianAudio::DefaultNotifyInterval) + , m_notifyTimer(new QTimer(this)) + , m_lastNotifyPosition(0) + , m_error(QAudio::NoError) + , m_internalState(SymbianAudio::ClosedState) + , m_externalState(QAudio::StoppedState) + , m_pullMode(false) + , m_sink(0) + , m_pullTimer(new QTimer(this)) + , m_devSound(0) + , m_devSoundBuffer(0) + , m_devSoundBufferSize(0) + , m_totalBytesReady(0) + , m_devSoundBufferPos(0) + , m_totalSamplesRecorded(0) +{ + qRegisterMetaType("CMMFBuffer *"); + + connect(m_notifyTimer.data(), SIGNAL(timeout()), + this, SIGNAL(notifyTimerExpired())); + + m_pullTimer->setInterval(PushInterval); + connect(m_pullTimer.data(), SIGNAL(timeout()), this, SLOT(pullData())); +} + +void QAudioInputPrivate::setFormat(const QAudioFormat& fmt) +{ + m_format = fmt; +} + +QAudioInputPrivate::~QAudioInputPrivate() +{ + close(); +} + +void QAudioInputPrivate::start(QIODevice *device) +{ + stop(); + + open(); + if (SymbianAudio::ClosedState != m_internalState) { + m_pullMode = true; + m_sink = device; + m_elapsed.restart(); + } +} + +QIODevice* QAudioInputPrivate::start() +{ + stop(); + + open(); + if (SymbianAudio::ClosedState != m_internalState) { + m_sink = new SymbianAudioInputPrivate(this); + m_sink->open(QIODevice::ReadOnly | QIODevice::Unbuffered); + m_elapsed.restart(); + } + + return m_sink; +} + +void QAudioInputPrivate::stop() +{ + close(); +} + +void QAudioInputPrivate::reset() +{ + m_totalSamplesRecorded += getSamplesRecorded(); + m_devSound->stop(); + startRecording(); +} + +void QAudioInputPrivate::suspend() +{ + if (SymbianAudio::ActiveState == m_internalState + || SymbianAudio::IdleState == m_internalState) { + m_pullTimer->stop(); + const qint64 samplesRecorded = getSamplesRecorded(); + m_totalSamplesRecorded += samplesRecorded; + + const bool paused = m_devSound->pause(); + if (paused) { + if (m_devSoundBuffer) + m_devSoundBufferQ.append(m_devSoundBuffer); + m_devSoundBuffer = 0; + setState(SymbianAudio::SuspendedPausedState); + } else { + m_devSoundBuffer = 0; + m_devSoundBufferQ.clear(); + m_devSoundBufferPos = 0; + setState(SymbianAudio::SuspendedStoppedState); + } + } +} + +void QAudioInputPrivate::resume() +{ + if (QAudio::SuspendedState == m_externalState) { + if (SymbianAudio::SuspendedPausedState == m_internalState) + m_devSound->resume(); + else + m_devSound->start(); + startDataTransfer(); + } +} + +int QAudioInputPrivate::bytesReady() const +{ + Q_ASSERT(m_devSoundBufferPos <= m_totalBytesReady); + return m_totalBytesReady - m_devSoundBufferPos; +} + +int QAudioInputPrivate::periodSize() const +{ + return bufferSize(); +} + +void QAudioInputPrivate::setBufferSize(int value) +{ + // Note that DevSound does not allow its client to specify the buffer size. + // This functionality is available via custom interfaces, but since these + // cannot be guaranteed to work across all DevSound implementations, we + // do not use them here. + // In order to comply with the expected bevahiour of QAudioInput, we store + // the value and return it from bufferSize(), but the underlying DevSound + // buffer size remains unchanged. + if (value > 0) + m_clientBufferSize = value; +} + +int QAudioInputPrivate::bufferSize() const +{ + return m_devSoundBufferSize ? m_devSoundBufferSize : m_clientBufferSize; +} + +void QAudioInputPrivate::setNotifyInterval(int ms) +{ + if (ms >= 0) { + //const int oldNotifyInterval = m_notifyInterval; + m_notifyInterval = ms; + if (m_notifyInterval && (SymbianAudio::ActiveState == m_internalState || + SymbianAudio::IdleState == m_internalState)) + m_notifyTimer->start(m_notifyInterval); + else + m_notifyTimer->stop(); + } +} + +int QAudioInputPrivate::notifyInterval() const +{ + return m_notifyInterval; +} + +qint64 QAudioInputPrivate::processedUSecs() const +{ + int samplesPlayed = 0; + if (m_devSound && QAudio::SuspendedState != m_externalState) + samplesPlayed = getSamplesRecorded(); + + // Protect against division by zero + Q_ASSERT_X(m_format.frequency() > 0, Q_FUNC_INFO, "Invalid frequency"); + + const qint64 result = qint64(1000000) * + (samplesPlayed + m_totalSamplesRecorded) + / m_format.frequency(); + + return result; +} + +qint64 QAudioInputPrivate::elapsedUSecs() const +{ + const qint64 result = (QAudio::StoppedState == state()) ? + 0 : m_elapsed.elapsed() * 1000; + return result; +} + +QAudio::Error QAudioInputPrivate::error() const +{ + return m_error; +} + +QAudio::State QAudioInputPrivate::state() const +{ + return m_externalState; +} + +QAudioFormat QAudioInputPrivate::format() const +{ + return m_format; +} + + +//----------------------------------------------------------------------------- +// Private functions +//----------------------------------------------------------------------------- + +void QAudioInputPrivate::open() +{ + Q_ASSERT_X(SymbianAudio::ClosedState == m_internalState, + Q_FUNC_INFO, "DevSound already opened"); + + Q_ASSERT(!m_devSound); + m_devSound = new SymbianAudio::DevSoundWrapper(QAudio::AudioInput, this); + + connect(m_devSound, SIGNAL(initializeComplete(int)), + this, SLOT(devsoundInitializeComplete(int))); + connect(m_devSound, SIGNAL(bufferToBeProcessed(CMMFBuffer *)), + this, SLOT(devsoundBufferToBeEmptied(CMMFBuffer *))); + connect(m_devSound, SIGNAL(processingError(int)), + this, SLOT(devsoundRecordError(int))); + + setState(SymbianAudio::InitializingState); + m_devSound->initialize(m_format.codec()); +} + +void QAudioInputPrivate::startRecording() +{ + const int samplesRecorded = m_devSound->samplesProcessed(); + Q_ASSERT(samplesRecorded == 0); + + bool ok = m_devSound->setFormat(m_format); + if (ok) + ok = m_devSound->start(); + + if (ok) { + startDataTransfer(); + } else { + setError(QAudio::OpenError); + close(); + } +} + +void QAudioInputPrivate::startDataTransfer() +{ + if (m_notifyInterval) + m_notifyTimer->start(m_notifyInterval); + + if (m_pullMode) + m_pullTimer->start(); + + if (bytesReady()) { + setState(SymbianAudio::ActiveState); + if (!m_pullMode) + pushData(); + } else { + if (QAudio::SuspendedState == m_externalState) + setState(SymbianAudio::ActiveState); + else + setState(SymbianAudio::IdleState); + } +} + +CMMFDataBuffer* QAudioInputPrivate::currentBuffer() const +{ + CMMFDataBuffer *result = m_devSoundBuffer; + if (!result && !m_devSoundBufferQ.empty()) + result = m_devSoundBufferQ.front(); + return result; +} + +void QAudioInputPrivate::pushData() +{ + Q_ASSERT_X(bytesReady(), Q_FUNC_INFO, "No data available"); + Q_ASSERT_X(!m_pullMode, Q_FUNC_INFO, "pushData called when in pull mode"); + qobject_cast(m_sink)->dataReady(); +} + +qint64 QAudioInputPrivate::read(char *data, qint64 len) +{ + // SymbianAudioInputPrivate is ready to read data + + Q_ASSERT_X(!m_pullMode, Q_FUNC_INFO, + "read called when in pull mode"); + + qint64 bytesRead = 0; + + CMMFDataBuffer *buffer = 0; + buffer = currentBuffer(); + while (buffer && (bytesRead < len)) { + if (SymbianAudio::IdleState == m_internalState) + setState(SymbianAudio::ActiveState); + + TDesC8 &inputBuffer = buffer->Data(); + + Q_ASSERT(inputBuffer.Length() >= m_devSoundBufferPos); + const qint64 inputBytes = inputBuffer.Length() - m_devSoundBufferPos; + const qint64 outputBytes = len - bytesRead; + const qint64 copyBytes = outputBytes < inputBytes ? + outputBytes : inputBytes; + + memcpy(data, inputBuffer.Ptr() + m_devSoundBufferPos, copyBytes); + + m_devSoundBufferPos += copyBytes; + data += copyBytes; + bytesRead += copyBytes; + + if (inputBytes == copyBytes) + bufferEmptied(); + + buffer = currentBuffer(); + } + + return bytesRead; +} + +void QAudioInputPrivate::notifyTimerExpired() +{ + const qint64 pos = processedUSecs(); + if (pos > m_lastNotifyPosition) { + int count = (pos - m_lastNotifyPosition) / (m_notifyInterval * 1000); + while (count--) { + emit notify(); + m_lastNotifyPosition += m_notifyInterval * 1000; + } + } +} + +void QAudioInputPrivate::pullData() +{ + Q_ASSERT_X(m_pullMode, Q_FUNC_INFO, + "pullData called when in push mode"); + + CMMFDataBuffer *buffer = 0; + buffer = currentBuffer(); + while (buffer) { + if (SymbianAudio::IdleState == m_internalState) + setState(SymbianAudio::ActiveState); + + TDesC8 &inputBuffer = buffer->Data(); + + Q_ASSERT(inputBuffer.Length() >= m_devSoundBufferPos); + const qint64 inputBytes = inputBuffer.Length() - m_devSoundBufferPos; + const qint64 bytesPushed = m_sink->write( + (char*)inputBuffer.Ptr() + m_devSoundBufferPos, inputBytes); + + m_devSoundBufferPos += bytesPushed; + + if (inputBytes == bytesPushed) + bufferEmptied(); + + if (!bytesPushed) + break; + + buffer = currentBuffer(); + } +} + +void QAudioInputPrivate::devsoundInitializeComplete(int err) +{ + Q_ASSERT_X(SymbianAudio::InitializingState == m_internalState, + Q_FUNC_INFO, "Invalid state"); + + if (!err && m_devSound->isFormatSupported(m_format)) + startRecording(); + else + setError(QAudio::OpenError); +} + +void QAudioInputPrivate::devsoundBufferToBeEmptied(CMMFBuffer *baseBuffer) +{ + // Following receipt of this signal, DevSound should not provide another + // buffer until we have returned the current one. + Q_ASSERT_X(!m_devSoundBuffer, Q_FUNC_INFO, "Buffer already held"); + + CMMFDataBuffer *const buffer = static_cast(baseBuffer); + + if (!m_devSoundBufferSize) + m_devSoundBufferSize = buffer->Data().MaxLength(); + + m_totalBytesReady += buffer->Data().Length(); + + if (SymbianAudio::SuspendedPausedState == m_internalState) { + m_devSoundBufferQ.append(buffer); + } else { + // Will be returned to DevSoundWrapper by bufferProcessed(). + m_devSoundBuffer = buffer; + m_devSoundBufferPos = 0; + + if (bytesReady() && !m_pullMode) + pushData(); + } +} + +void QAudioInputPrivate::devsoundRecordError(int err) +{ + Q_UNUSED(err) + setError(QAudio::IOError); +} + +void QAudioInputPrivate::bufferEmptied() +{ + m_devSoundBufferPos = 0; + + if (m_devSoundBuffer) { + m_totalBytesReady -= m_devSoundBuffer->Data().Length(); + m_devSoundBuffer = 0; + m_devSound->bufferProcessed(); + } else { + Q_ASSERT(!m_devSoundBufferQ.empty()); + m_totalBytesReady -= m_devSoundBufferQ.front()->Data().Length(); + m_devSoundBufferQ.erase(m_devSoundBufferQ.begin()); + + // If the queue has been emptied, resume transfer from the hardware + if (m_devSoundBufferQ.empty()) + if (!m_devSound->start()) + setError(QAudio::IOError); + } + + Q_ASSERT(m_totalBytesReady >= 0); +} + +void QAudioInputPrivate::close() +{ + m_lastNotifyPosition = 0; + m_pullTimer->stop(); + + m_error = QAudio::NoError; + + if (m_devSound) + m_devSound->stop(); + delete m_devSound; + m_devSound = 0; + + m_devSoundBuffer = 0; + m_devSoundBufferSize = 0; + m_totalBytesReady = 0; + + if (!m_pullMode) // m_sink is owned + delete m_sink; + m_pullMode = false; + m_sink = 0; + + m_devSoundBufferQ.clear(); + m_devSoundBufferPos = 0; + m_totalSamplesRecorded = 0; + + setState(SymbianAudio::ClosedState); +} + +qint64 QAudioInputPrivate::getSamplesRecorded() const +{ + qint64 result = 0; + if (m_devSound) + result = qint64(m_devSound->samplesProcessed()); + return result; +} + +void QAudioInputPrivate::setError(QAudio::Error error) +{ + m_error = error; + + // Although no state transition actually occurs here, a stateChanged event + // must be emitted to inform the client that the call to start() was + // unsuccessful. + if (QAudio::OpenError == error) { + emit stateChanged(QAudio::StoppedState); + } else { + if (QAudio::UnderrunError == error) + setState(SymbianAudio::IdleState); + else + // Close the DevSound instance. This causes a transition to + // StoppedState. This must be done asynchronously in case the + // current function was called from a DevSound event handler, in which + // case deleting the DevSound instance may cause an exception. + QMetaObject::invokeMethod(this, "close", Qt::QueuedConnection); + } +} + +void QAudioInputPrivate::setState(SymbianAudio::State newInternalState) +{ + const QAudio::State oldExternalState = m_externalState; + m_internalState = newInternalState; + m_externalState = SymbianAudio::Utils::stateNativeToQt(m_internalState); + + if (m_externalState != QAudio::ActiveState && + m_externalState != QAudio::IdleState) + m_notifyTimer->stop(); + + if (m_externalState != oldExternalState) + emit stateChanged(m_externalState); +} + +QT_END_NAMESPACE + +#include "moc_qaudioinput_symbian_p.cpp" diff --git a/src/multimediakit/audio/qaudioinput_symbian_p.h b/src/multimediakit/audio/qaudioinput_symbian_p.h new file mode 100644 index 000000000..9f6128390 --- /dev/null +++ b/src/multimediakit/audio/qaudioinput_symbian_p.h @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QAUDIOINPUT_SYMBIAN_P_H +#define QAUDIOINPUT_SYMBIAN_P_H + +#include +#include +#include +#include "qaudio_symbian_p.h" + +QT_BEGIN_NAMESPACE + +class QAudioInputPrivate; + +class SymbianAudioInputPrivate : public QIODevice +{ + friend class QAudioInputPrivate; + Q_OBJECT +public: + SymbianAudioInputPrivate(QAudioInputPrivate *audio); + ~SymbianAudioInputPrivate(); + + qint64 readData(char *data, qint64 len); + qint64 writeData(const char *data, qint64 len); + + void dataReady(); + +private: + QAudioInputPrivate *const m_audioDevice; +}; + +class QAudioInputPrivate + : public QAbstractAudioInput +{ + friend class SymbianAudioInputPrivate; + Q_OBJECT +public: + QAudioInputPrivate(const QByteArray &device); + ~QAudioInputPrivate(); + + // QAbstractAudioInput + void start(QIODevice *device); + QIODevice* start(); + void stop(); + void reset(); + void suspend(); + void resume(); + int bytesReady() const; + int periodSize() const; + void setBufferSize(int value); + int bufferSize() const; + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + QAudio::Error error() const; + QAudio::State state() const; + QAudioFormat format() const; + void setFormat(const QAudioFormat& fmt); + +private slots: + void notifyTimerExpired(); + void pullData(); + void devsoundInitializeComplete(int err); + void devsoundBufferToBeEmptied(CMMFBuffer *); + void devsoundRecordError(int err); + + +private: + void open(); + void startRecording(); + void startDataTransfer(); + CMMFDataBuffer* currentBuffer() const; + void pushData(); + qint64 read(char *data, qint64 len); + void bufferEmptied(); + Q_INVOKABLE void close(); + + qint64 getSamplesRecorded() const; + + void setError(QAudio::Error error); + void setState(SymbianAudio::State state); + +private: + const QByteArray m_device; + QAudioFormat m_format; + + int m_clientBufferSize; + int m_notifyInterval; + QScopedPointer m_notifyTimer; + qint64 m_lastNotifyPosition; + QTime m_elapsed; + QAudio::Error m_error; + + SymbianAudio::State m_internalState; + QAudio::State m_externalState; + + bool m_pullMode; + QIODevice *m_sink; + + QScopedPointer m_pullTimer; + + SymbianAudio::DevSoundWrapper* m_devSound; + + // Latest buffer provided by DevSound, to be empied of data. + CMMFDataBuffer *m_devSoundBuffer; + + int m_devSoundBufferSize; + + // Total amount of data in buffers provided by DevSound + int m_totalBytesReady; + + // Queue of buffers returned after call to CMMFDevSound::Pause(). + QList m_devSoundBufferQ; + + // Current read position within m_devSoundBuffer + qint64 m_devSoundBufferPos; + + // Samples recorded up to the last call to suspend(). It is necessary + // to cache this because suspend() is implemented using + // CMMFDevSound::Stop(), which resets DevSound's SamplesRecorded() counter. + quint32 m_totalSamplesRecorded; + +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/audio/qaudioinput_win32_p.cpp b/src/multimediakit/audio/qaudioinput_win32_p.cpp new file mode 100644 index 000000000..c258a2cbf --- /dev/null +++ b/src/multimediakit/audio/qaudioinput_win32_p.cpp @@ -0,0 +1,649 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + + +#include "qaudioinput_win32_p.h" + +QT_BEGIN_NAMESPACE + +//#define DEBUG_AUDIO 1 + +QAudioInputPrivate::QAudioInputPrivate(const QByteArray &device) +{ + bytesAvailable = 0; + buffer_size = 0; + period_size = 0; + m_device = device; + totalTimeValue = 0; + intervalTime = 1000; + errorState = QAudio::NoError; + deviceState = QAudio::StoppedState; + audioSource = 0; + pullMode = true; + resuming = false; + finished = false; + waveBlockOffset = 0; +} + +QAudioInputPrivate::~QAudioInputPrivate() +{ + stop(); +} + +void QT_WIN_CALLBACK QAudioInputPrivate::waveInProc( HWAVEIN hWaveIn, UINT uMsg, + DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) +{ + Q_UNUSED(dwParam1) + Q_UNUSED(dwParam2) + Q_UNUSED(hWaveIn) + + QAudioInputPrivate* qAudio; + qAudio = (QAudioInputPrivate*)(dwInstance); + if(!qAudio) + return; + + QMutexLocker(&qAudio->mutex); + + switch(uMsg) { + case WIM_OPEN: + break; + case WIM_DATA: + if(qAudio->waveFreeBlockCount > 0) + qAudio->waveFreeBlockCount--; + qAudio->feedback(); + break; + case WIM_CLOSE: + qAudio->finished = true; + break; + default: + return; + } +} + +WAVEHDR* QAudioInputPrivate::allocateBlocks(int size, int count) +{ + int i; + unsigned char* buffer; + WAVEHDR* blocks; + DWORD totalBufferSize = (size + sizeof(WAVEHDR))*count; + + if((buffer=(unsigned char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, + totalBufferSize)) == 0) { + qWarning("QAudioInput: Memory allocation error"); + return 0; + } + blocks = (WAVEHDR*)buffer; + buffer += sizeof(WAVEHDR)*count; + for(i = 0; i < count; i++) { + blocks[i].dwBufferLength = size; + blocks[i].lpData = (LPSTR)buffer; + blocks[i].dwBytesRecorded=0; + blocks[i].dwUser = 0L; + blocks[i].dwFlags = 0L; + blocks[i].dwLoops = 0L; + result = waveInPrepareHeader(hWaveIn,&blocks[i], sizeof(WAVEHDR)); + if(result != MMSYSERR_NOERROR) { + qWarning("QAudioInput: Can't prepare block %d",i); + return 0; + } + buffer += size; + } + return blocks; +} + +void QAudioInputPrivate::freeBlocks(WAVEHDR* blockArray) +{ + WAVEHDR* blocks = blockArray; + + int count = buffer_size/period_size; + + for(int i = 0; i < count; i++) { + waveInUnprepareHeader(hWaveIn,blocks, sizeof(WAVEHDR)); + blocks++; + } + HeapFree(GetProcessHeap(), 0, blockArray); +} + +QAudio::Error QAudioInputPrivate::error() const +{ + return errorState; +} + +QAudio::State QAudioInputPrivate::state() const +{ + return deviceState; +} + +void QAudioInputPrivate::setFormat(const QAudioFormat& fmt) +{ + if (deviceState == QAudio::StoppedState) + settings = fmt; +} + +QAudioFormat QAudioInputPrivate::format() const +{ + return settings; +} + +void QAudioInputPrivate::start(QIODevice* device) +{ + if(deviceState != QAudio::StoppedState) + close(); + + if(!pullMode && audioSource) + delete audioSource; + + pullMode = true; + audioSource = device; + + deviceState = QAudio::ActiveState; + + if(!open()) + return; + + emit stateChanged(deviceState); +} + +QIODevice* QAudioInputPrivate::start() +{ + if(deviceState != QAudio::StoppedState) + close(); + + if(!pullMode && audioSource) + delete audioSource; + + pullMode = false; + audioSource = new InputPrivate(this); + audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered); + + deviceState = QAudio::IdleState; + + if(!open()) + return 0; + + emit stateChanged(deviceState); + + return audioSource; +} + +void QAudioInputPrivate::stop() +{ + if(deviceState == QAudio::StoppedState) + return; + + close(); + emit stateChanged(deviceState); +} + +bool QAudioInputPrivate::open() +{ +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()< 48000) { + qWarning("QAudioInput: open error, frequency out of range (%d).", settings.frequency()); + } else if (buffer_size == 0) { + + buffer_size + = (settings.frequency() + * settings.channelCount() + * settings.sampleSize() +#ifndef Q_OS_WINCE // Default buffer size, 200ms, default period size is 40ms + + 39) / 40; + period_size = buffer_size / 5; + } else { + period_size = buffer_size / 5; +#else // For wince reduce size to 40ms for buffer size and 20ms period + + 199) / 200; + period_size = buffer_size / 2; + } else { + period_size = buffer_size / 2; +#endif + } + + if (period_size == 0) { + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + return false; + } + + timeStamp.restart(); + elapsedTimeOffset = 0; + wfx.nSamplesPerSec = settings.frequency(); + wfx.wBitsPerSample = settings.sampleSize(); + wfx.nChannels = settings.channels(); + wfx.cbSize = 0; + + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels; + wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec; + + QDataStream ds(&m_device, QIODevice::ReadOnly); + quint32 deviceId; + ds >> deviceId; + + if (waveInOpen(&hWaveIn, UINT_PTR(deviceId), &wfx, + (DWORD_PTR)&waveInProc, + (DWORD_PTR) this, + CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + qWarning("QAudioInput: failed to open audio device"); + return false; + } + waveBlocks = allocateBlocks(period_size, buffer_size/period_size); + waveBlockOffset = 0; + + if(waveBlocks == 0) { + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + qWarning("QAudioInput: failed to allocate blocks. open failed"); + return false; + } + + mutex.lock(); + waveFreeBlockCount = buffer_size/period_size; + mutex.unlock(); + + for(int i=0; i 0 && waveBlocks[header].dwFlags & WHDR_DONE) { + if(pullMode) { + l = audioSource->write(waveBlocks[header].lpData + waveBlockOffset, + waveBlocks[header].dwBytesRecorded - waveBlockOffset); +#ifdef DEBUG_AUDIO + qDebug()<<"IN: "<(len, waveBlocks[header].dwBytesRecorded - waveBlockOffset); + // push mode + memcpy(p, waveBlocks[header].lpData + waveBlockOffset, l); + + len -= l; + +#ifdef DEBUG_AUDIO + qDebug()<<"IN: "<= buffer_size/period_size) + header = 0; + p+=l; + + mutex.lock(); + if(!pullMode) { + if(len < period_size || waveFreeBlockCount == buffer_size/period_size) + done = true; + } else { + if(waveFreeBlockCount == buffer_size/period_size) + done = true; + } + mutex.unlock(); + } + + written+=l; + } +#ifdef DEBUG_AUDIO + qDebug()<<"read in len="<(audioSource); + a->trigger(); + } + + if(intervalTime && (timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) { + emit notify(); + elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime; + timeStamp.restart(); + } + return true; +} + +qint64 QAudioInputPrivate::elapsedUSecs() const +{ + if (deviceState == QAudio::StoppedState) + return 0; + + return timeStampOpened.elapsed()*1000; +} + +void QAudioInputPrivate::reset() +{ + stop(); + if (period_size > 0) + waveFreeBlockCount = buffer_size / period_size; +} + +InputPrivate::InputPrivate(QAudioInputPrivate* audio) +{ + audioDevice = qobject_cast(audio); +} + +InputPrivate::~InputPrivate() {} + +qint64 InputPrivate::readData( char* data, qint64 len) +{ + // push mode, user read() called + if(audioDevice->deviceState != QAudio::ActiveState && + audioDevice->deviceState != QAudio::IdleState) + return 0; + // Read in some audio data + return audioDevice->read(data,len); +} + +qint64 InputPrivate::writeData(const char* data, qint64 len) +{ + Q_UNUSED(data) + Q_UNUSED(len) + + emit readyRead(); + return 0; +} + +void InputPrivate::trigger() +{ + emit readyRead(); +} + +QT_END_NAMESPACE + +#include "moc_qaudioinput_win32_p.cpp" + diff --git a/src/multimediakit/audio/qaudioinput_win32_p.h b/src/multimediakit/audio/qaudioinput_win32_p.h new file mode 100644 index 000000000..e1972cd66 --- /dev/null +++ b/src/multimediakit/audio/qaudioinput_win32_p.h @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QAUDIOINPUTWIN_H +#define QAUDIOINPUTWIN_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +QT_BEGIN_NAMESPACE + +// For compat with 4.6 +#if !defined(QT_WIN_CALLBACK) +# if defined(Q_CC_MINGW) +# define QT_WIN_CALLBACK CALLBACK __attribute__ ((force_align_arg_pointer)) +# else +# define QT_WIN_CALLBACK CALLBACK +# endif +#endif + +class QAudioInputPrivate : public QAbstractAudioInput +{ + Q_OBJECT +public: + QAudioInputPrivate(const QByteArray &device); + ~QAudioInputPrivate(); + + qint64 read(char* data, qint64 len); + + void setFormat(const QAudioFormat& fmt); + QAudioFormat format() const; + QIODevice* start(); + void start(QIODevice* device); + void stop(); + void reset(); + void suspend(); + void resume(); + int bytesReady() const; + int periodSize() const; + void setBufferSize(int value); + int bufferSize() const; + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + QAudio::Error error() const; + QAudio::State state() const; + + QIODevice* audioSource; + QAudioFormat settings; + QAudio::Error errorState; + QAudio::State deviceState; + +private: + qint32 buffer_size; + qint32 period_size; + qint32 header; + QByteArray m_device; + int bytesAvailable; + int intervalTime; + QTime timeStamp; + qint64 elapsedTimeOffset; + QTime timeStampOpened; + qint64 totalTimeValue; + bool pullMode; + bool resuming; + WAVEFORMATEX wfx; + HWAVEIN hWaveIn; + MMRESULT result; + WAVEHDR* waveBlocks; + volatile bool finished; + volatile int waveFreeBlockCount; + int waveBlockOffset; + + QMutex mutex; + static void QT_WIN_CALLBACK waveInProc( HWAVEIN hWaveIn, UINT uMsg, + DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ); + + WAVEHDR* allocateBlocks(int size, int count); + void freeBlocks(WAVEHDR* blockArray); + bool open(); + void close(); + +private slots: + void feedback(); + bool deviceReady(); + +signals: + void processMore(); +}; + +class InputPrivate : public QIODevice +{ + Q_OBJECT +public: + InputPrivate(QAudioInputPrivate* audio); + ~InputPrivate(); + + qint64 readData( char* data, qint64 len); + qint64 writeData(const char* data, qint64 len); + + void trigger(); +private: + QAudioInputPrivate *audioDevice; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/audio/qaudiooutput.cpp b/src/multimediakit/audio/qaudiooutput.cpp new file mode 100644 index 000000000..afde7ff14 --- /dev/null +++ b/src/multimediakit/audio/qaudiooutput.cpp @@ -0,0 +1,393 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qaudio.h" +#include "qaudiodeviceinfo.h" +#include "qaudiosystem.h" +#include "qaudiooutput.h" + +#include "qaudiodevicefactory_p.h" + + +QT_BEGIN_NAMESPACE + +/*! + \class QAudioOutput + \brief The QAudioOutput class provides an interface for sending audio data to an audio output device. + + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + XXX + + You can construct an audio output with the system's + \l{QAudioDeviceInfo::defaultOutputDevice()}{default audio output + device}. It is also possible to create QAudioOutput with a + specific QAudioDeviceInfo. When you create the audio output, you + should also send in the QAudioFormat to be used for the playback + (see the QAudioFormat class description for details). + + To play a file: + + Starting to play an audio stream is simply a matter of calling + start() with a QIODevice. QAudioOutput will then fetch the data it + needs from the io device. So playing back an audio file is as + simple as: + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Audio output class members + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Audio output setup + + The file will start playing assuming that the audio system and + output device support it. If you run out of luck, check what's + up with the error() function. + + After the file has finished playing, we need to stop the device: + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Audio output state changed + + At any given time, the QAudioOutput will be in one of four states: + active, suspended, stopped, or idle. These states are described + by the QAudio::State enum. + State changes are reported through the stateChanged() signal. You + can use this signal to, for instance, update the GUI of the + application; the mundane example here being changing the state of + a \c { play/pause } button. You request a state change directly + with suspend(), stop(), reset(), resume(), and start(). + + While the stream is playing, you can set a notify interval in + milliseconds with setNotifyInterval(). This interval specifies the + time between two emissions of the notify() signal. This is + relative to the position in the stream, i.e., if the QAudioOutput + is in the SuspendedState or the IdleState, the notify() signal is + not emitted. A typical use-case would be to update a + \l{QSlider}{slider} that allows seeking in the stream. + If you want the time since playback started regardless of which + states the audio output has been in, elapsedUSecs() is the function for you. + + If an error occurs, you can fetch the \l{QAudio::Error}{error + type} with the error() function. Please see the QAudio::Error enum + for a description of the possible errors that are reported. When + an error is encountered, the state changes to QAudio::StoppedState. + You can check for errors by connecting to the stateChanged() + signal: + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Audio output state changed + + \sa QAudioInput, QAudioDeviceInfo +*/ + +/*! + Construct a new audio output and attach it to \a parent. + The default audio output device is used with the output + \a format parameters. + \since 1.0 +*/ +QAudioOutput::QAudioOutput(const QAudioFormat &format, QObject *parent): + QObject(parent) +{ + d = QAudioDeviceFactory::createDefaultOutputDevice(format); + connect(d, SIGNAL(notify()), SIGNAL(notify())); + connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State))); +} + +/*! + Construct a new audio output and attach it to \a parent. + The device referenced by \a audioDevice is used with the output + \a format parameters. + \since 1.0 +*/ +QAudioOutput::QAudioOutput(const QAudioDeviceInfo &audioDevice, const QAudioFormat &format, QObject *parent): + QObject(parent) +{ + d = QAudioDeviceFactory::createOutputDevice(audioDevice, format); + connect(d, SIGNAL(notify()), SIGNAL(notify())); + connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State))); +} + +/*! + Destroys this audio output. + + XXX This will release any system resources used and free any buffers. +*/ +QAudioOutput::~QAudioOutput() +{ + delete d; +} + +/*! + Returns the QAudioFormat being used. + + \since 1.0 +*/ +QAudioFormat QAudioOutput::format() const +{ + return d->format(); +} + +/*! + Uses the \a device as the QIODevice to transfer data. + Passing a QIODevice allows the data to be transferred without any extra code. + All that is required is to open the QIODevice. + + If able to successfully output audio data to the systems audio device the + state() is set to QAudio::ActiveState, error() is set to QAudio::NoError + and the stateChanged() signal is emitted. + + If a problem occurs during this process the error() is set to QAudio::OpenError, + state() is set to QAudio::StoppedState and stateChanged() signal is emitted. + + \since 1.0 + \sa QIODevice +*/ +void QAudioOutput::start(QIODevice* device) +{ + d->start(device); +} + +/*! + Returns a pointer to the QIODevice being used to handle the data + transfer. This QIODevice can be used to write() audio data directly. + + If able to access the systems audio device the state() is set to + QAudio::IdleState, error() is set to QAudio::NoError + and the stateChanged() signal is emitted. + + If a problem occurs during this process the error() is set to QAudio::OpenError, + state() is set to QAudio::StoppedState and stateChanged() signal is emitted. + + \since 1.0 + \sa QIODevice +*/ +QIODevice* QAudioOutput::start() +{ + return d->start(); +} + +/*! + Stops the audio output, detaching from the system resource. + + XXX + Sets error() to QAudio::NoError, state() to QAudio::StoppedState and + emit stateChanged() signal. + \since 1.0 +*/ +void QAudioOutput::stop() +{ + d->stop(); +} + +/*! + Drops all audio data in the buffers, resets buffers to zero. + + XXX what about state + \since 1.0 +*/ +void QAudioOutput::reset() +{ + d->reset(); +} + +/*! + Stops processing audio data, preserving buffered audio data. + + XXX + + Sets error() to QAudio::NoError, state() to QAudio::SuspendedState and + emits stateChanged() signal. + \since 1.0 +*/ +void QAudioOutput::suspend() +{ + d->suspend(); +} + +/*! + Resumes processing audio data after a suspend(). + +XXX + + Sets error() to QAudio::NoError. + Sets state() to QAudio::ActiveState if you previously called start(QIODevice*). + Sets state() to QAudio::IdleState if you previously called start(). + emits stateChanged() signal. + \since 1.0 +*/ +void QAudioOutput::resume() +{ + d->resume(); +} + +/*! + Returns the number of free bytes available in the audio buffer. + + \note The returned value is only valid while in QAudio::ActiveState or QAudio::IdleState + state, otherwise returns zero. + \since 1.0 +*/ +int QAudioOutput::bytesFree() const +{ + return d->bytesFree(); +} + +/*! + Returns the period size in bytes. This is the amount of data required each period + to prevent buffer underrun, and to ensure uninterrupted playback. + + \note It is recommended to provide at least enough data for a full period with each + write operation. + \since 1.0 +*/ +int QAudioOutput::periodSize() const +{ + return d->periodSize(); +} + +/*! + Sets the audio buffer size to \a value in bytes. + + \note This function can be called anytime before start(). Calls to this + are ignored after start(). It should not be assumed that the buffer size + set is the actual buffer size used - call bufferSize() anytime after start() + to return the actual buffer size being used. + \since 1.0 +*/ +void QAudioOutput::setBufferSize(int value) +{ + d->setBufferSize(value); +} + +/*! + Returns the audio buffer size in bytes. + + If called before start(), returns platform default value. + If called before start() but setBufferSize() was called prior, returns value set by setBufferSize(). + If called after start(), returns the actual buffer size being used. This may not be what was set previously + by setBufferSize(). + + \since 1.0 +*/ +int QAudioOutput::bufferSize() const +{ + return d->bufferSize(); +} + +/*! + Sets the interval for notify() signal to be emitted. + This is based on the \a ms of audio data processed, + not on wall clock time. + The minimum resolution of the timer is platform specific and values + should be checked with notifyInterval() to confirm the actual value + being used. + \since 1.0 +*/ +void QAudioOutput::setNotifyInterval(int ms) +{ + d->setNotifyInterval(ms); +} + +/*! + Returns the notify interval in milliseconds. + \since 1.0 +*/ +int QAudioOutput::notifyInterval() const +{ + return d->notifyInterval(); +} + +/*! + Returns the amount of audio data processed since start() + was called (in microseconds). + \since 1.0 +*/ +qint64 QAudioOutput::processedUSecs() const +{ + return d->processedUSecs(); +} + +/*! + Returns the microseconds since start() was called, including time in Idle and + Suspend states. + \since 1.0 +*/ +qint64 QAudioOutput::elapsedUSecs() const +{ + return d->elapsedUSecs(); +} + +/*! + Returns the error state. + \since 1.0 +*/ +QAudio::Error QAudioOutput::error() const +{ + return d->error(); +} + +/*! + Returns the state of audio processing. + \since 1.0 +*/ +QAudio::State QAudioOutput::state() const +{ + return d->state(); +} + +/*! + \fn QAudioOutput::stateChanged(QAudio::State state) + This signal is emitted when the device \a state has changed. + This is the current state of the audio output. + \since 1.0 +*/ + +/*! + \fn QAudioOutput::notify() + This signal is emitted when a certain interval of milliseconds + of audio data has been processed. The interval is set by + setNotifyInterval(). + \since 1.0 +*/ + +QT_END_NAMESPACE + +#include "moc_qaudiooutput.cpp" diff --git a/src/multimediakit/audio/qaudiooutput.h b/src/multimediakit/audio/qaudiooutput.h new file mode 100644 index 000000000..68b0eb2d6 --- /dev/null +++ b/src/multimediakit/audio/qaudiooutput.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QAUDIOOUTPUT_H +#define QAUDIOOUTPUT_H + +#include + +#include +#include + +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QAbstractAudioOutput; + +class Q_MULTIMEDIA_EXPORT QAudioOutput : public QObject +{ + Q_OBJECT + +public: + explicit QAudioOutput(const QAudioFormat &format = QAudioFormat(), QObject *parent = 0); + explicit QAudioOutput(const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format = QAudioFormat(), QObject *parent = 0); + ~QAudioOutput(); + + QAudioFormat format() const; + + void start(QIODevice *device); + QIODevice* start(); + + void stop(); + void reset(); + void suspend(); + void resume(); + + void setBufferSize(int bytes); + int bufferSize() const; + + int bytesFree() const; + int periodSize() const; + + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + + QAudio::Error error() const; + QAudio::State state() const; + +Q_SIGNALS: + void stateChanged(QAudio::State); + void notify(); + +private: + Q_DISABLE_COPY(QAudioOutput) + + QAbstractAudioOutput* d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIOOUTPUT_H diff --git a/src/multimediakit/audio/qaudiooutput_alsa_p.cpp b/src/multimediakit/audio/qaudiooutput_alsa_p.cpp new file mode 100644 index 000000000..3a0c7e344 --- /dev/null +++ b/src/multimediakit/audio/qaudiooutput_alsa_p.cpp @@ -0,0 +1,834 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include +#include "qaudiooutput_alsa_p.h" +#include "qaudiodeviceinfo_alsa_p.h" + +QT_BEGIN_NAMESPACE + +//#define DEBUG_AUDIO 1 + +QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray &device) +{ + bytesAvailable = 0; + handle = 0; + ahandler = 0; + access = SND_PCM_ACCESS_RW_INTERLEAVED; + pcmformat = SND_PCM_FORMAT_S16; + buffer_frames = 0; + period_frames = 0; + buffer_size = 0; + period_size = 0; + buffer_time = 100000; + period_time = 20000; + totalTimeValue = 0; + intervalTime = 1000; + audioBuffer = 0; + errorState = QAudio::NoError; + deviceState = QAudio::StoppedState; + audioSource = 0; + pullMode = true; + resuming = false; + opened = false; + + m_device = device; + + timer = new QTimer(this); + connect(timer,SIGNAL(timeout()),SLOT(userFeed())); +} + +QAudioOutputPrivate::~QAudioOutputPrivate() +{ + close(); + disconnect(timer, SIGNAL(timeout())); + QCoreApplication::processEvents(); + delete timer; +} + +QAudio::Error QAudioOutputPrivate::error() const +{ + return errorState; +} + +QAudio::State QAudioOutputPrivate::state() const +{ + return deviceState; +} + +void QAudioOutputPrivate::async_callback(snd_async_handler_t *ahandler) +{ + QAudioOutputPrivate* audioOut; + + audioOut = static_cast + (snd_async_handler_get_callback_private(ahandler)); + + if((audioOut->deviceState==QAudio::ActiveState)||(audioOut->resuming)) + audioOut->feedback(); +} + +int QAudioOutputPrivate::xrun_recovery(int err) +{ + int count = 0; + bool reset = false; + + if(err == -EPIPE) { + errorState = QAudio::UnderrunError; + emit errorChanged(errorState); + err = snd_pcm_prepare(handle); + if(err < 0) + reset = true; + + } else if((err == -ESTRPIPE)||(err == -EIO)) { + errorState = QAudio::IOError; + emit errorChanged(errorState); + while((err = snd_pcm_resume(handle)) == -EAGAIN){ + usleep(100); + count++; + if(count > 5) { + reset = true; + break; + } + } + if(err < 0) { + err = snd_pcm_prepare(handle); + if(err < 0) + reset = true; + } + } + if(reset) { + close(); + open(); + snd_pcm_prepare(handle); + return 0; + } + return err; +} + +int QAudioOutputPrivate::setFormat() +{ + snd_pcm_format_t pcmformat = SND_PCM_FORMAT_UNKNOWN; + + if(settings.sampleSize() == 8) { + pcmformat = SND_PCM_FORMAT_U8; + + } else if(settings.sampleSize() == 16) { + if(settings.sampleType() == QAudioFormat::SignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_S16_LE; + else + pcmformat = SND_PCM_FORMAT_S16_BE; + } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_U16_LE; + else + pcmformat = SND_PCM_FORMAT_U16_BE; + } + } else if(settings.sampleSize() == 24) { + if(settings.sampleType() == QAudioFormat::SignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_S24_LE; + else + pcmformat = SND_PCM_FORMAT_S24_BE; + } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_U24_LE; + else + pcmformat = SND_PCM_FORMAT_U24_BE; + } + } else if(settings.sampleSize() == 32) { + if(settings.sampleType() == QAudioFormat::SignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_S32_LE; + else + pcmformat = SND_PCM_FORMAT_S32_BE; + } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_U32_LE; + else + pcmformat = SND_PCM_FORMAT_U32_BE; + } else if(settings.sampleType() == QAudioFormat::Float) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_FLOAT_LE; + else + pcmformat = SND_PCM_FORMAT_FLOAT_BE; + } + } else if(settings.sampleSize() == 64) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_FLOAT64_LE; + else + pcmformat = SND_PCM_FORMAT_FLOAT64_BE; + } + + return pcmformat != SND_PCM_FORMAT_UNKNOWN + ? snd_pcm_hw_params_set_format( handle, hwparams, pcmformat) + : -1; +} + +void QAudioOutputPrivate::start(QIODevice* device) +{ + if(deviceState != QAudio::StoppedState) + deviceState = QAudio::StoppedState; + + errorState = QAudio::NoError; + + // Handle change of mode + if(audioSource && !pullMode) { + delete audioSource; + audioSource = 0; + } + + close(); + + pullMode = true; + audioSource = device; + + deviceState = QAudio::ActiveState; + + open(); + + emit stateChanged(deviceState); +} + +QIODevice* QAudioOutputPrivate::start() +{ + if(deviceState != QAudio::StoppedState) + deviceState = QAudio::StoppedState; + + errorState = QAudio::NoError; + + // Handle change of mode + if(audioSource && !pullMode) { + delete audioSource; + audioSource = 0; + } + + close(); + + audioSource = new OutputPrivate(this); + audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered); + pullMode = false; + + deviceState = QAudio::IdleState; + + open(); + + emit stateChanged(deviceState); + + return audioSource; +} + +void QAudioOutputPrivate::stop() +{ + if(deviceState == QAudio::StoppedState) + return; + errorState = QAudio::NoError; + deviceState = QAudio::StoppedState; + close(); + emit stateChanged(deviceState); +} + +bool QAudioOutputPrivate::open() +{ + if(opened) + return true; + +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()< devices = QAudioDeviceInfoInternal::availableDevices(QAudio::AudioOutput); + if(dev.compare(QLatin1String("default")) == 0) { +#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) + if (devices.size() > 0) + dev = QLatin1String(devices.first()); + else + return false; +#else + dev = QLatin1String("hw:0,0"); +#endif + } else { +#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) + dev = QLatin1String(m_device); +#else + int idx = 0; + char *name; + + QString shortName = QLatin1String(m_device.mid(m_device.indexOf('=',0)+1).constData()); + + while(snd_card_get_name(idx,&name) == 0) { + if(qstrncmp(shortName.toLocal8Bit().constData(),name,shortName.length()) == 0) + break; + idx++; + } + dev = QString(QLatin1String("hw:%1,0")).arg(idx); +#endif + } + + // Step 1: try and open the device + while((count < 5) && (err < 0)) { + err=snd_pcm_open(&handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0); + if(err < 0) + count++; + } + if (( err < 0)||(handle == 0)) { + errorState = QAudio::OpenError; + emit errorChanged(errorState); + deviceState = QAudio::StoppedState; + return false; + } + snd_pcm_nonblock( handle, 0 ); + + // Step 2: Set the desired HW parameters. + snd_pcm_hw_params_alloca( &hwparams ); + + bool fatal = false; + QString errMessage; + unsigned int chunks = 8; + + err = snd_pcm_hw_params_any( handle, hwparams ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_any: err = %1").arg(err); + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_rate_resample( handle, hwparams, 1 ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_rate_resample: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_access( handle, hwparams, access ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_access: err = %1").arg(err); + } + } + if ( !fatal ) { + err = setFormat(); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_format: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_channels( handle, hwparams, (unsigned int)settings.channels() ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_channels: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_rate_near( handle, hwparams, &freakuency, 0 ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_rate_near: err = %1").arg(err); + } + } + if ( !fatal ) { + unsigned int maxBufferTime = 0; + unsigned int minBufferTime = 0; + unsigned int maxPeriodTime = 0; + unsigned int minPeriodTime = 0; + + err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &maxBufferTime, &dir); + if ( err >= 0) + err = snd_pcm_hw_params_get_buffer_time_min(hwparams, &minBufferTime, &dir); + if ( err >= 0) + err = snd_pcm_hw_params_get_period_time_max(hwparams, &maxPeriodTime, &dir); + if ( err >= 0) + err = snd_pcm_hw_params_get_period_time_min(hwparams, &minPeriodTime, &dir); + + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioOutput: buffer/period min and max: err = %1").arg(err); + } else { + if (maxBufferTime < buffer_time || buffer_time < minBufferTime || maxPeriodTime < period_time || minPeriodTime > period_time) { +#ifdef DEBUG_AUDIO + qDebug()<<"defaults out of range"; + qDebug()<<"pmin="<start(period_time/1000); + + clockStamp.restart(); + timeStamp.restart(); + elapsedTimeOffset = 0; + errorState = QAudio::NoError; + totalTimeValue = 0; + opened = true; + + return true; +} + +void QAudioOutputPrivate::close() +{ + timer->stop(); + + if ( handle ) { + snd_pcm_drain( handle ); + snd_pcm_close( handle ); + handle = 0; + delete [] audioBuffer; + audioBuffer=0; + } + if(!pullMode && audioSource) { + delete audioSource; + audioSource = 0; + } + opened = false; +} + +int QAudioOutputPrivate::bytesFree() const +{ + if(resuming) + return period_size; + + if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) + return 0; + + int frames = snd_pcm_avail_update(handle); + if (frames == -EPIPE) { + // Try and handle buffer underrun + int err = snd_pcm_recover(handle, frames, 0); + if (err < 0) + return 0; + else + frames = snd_pcm_avail_update(handle); + } else if (frames < 0) { + return 0; + } + + if ((int)frames > (int)buffer_frames) + frames = buffer_frames; + + return snd_pcm_frames_to_bytes(handle, frames); +} + +qint64 QAudioOutputPrivate::write( const char *data, qint64 len ) +{ + // Write out some audio data + if ( !handle ) + return 0; +#ifdef DEBUG_AUDIO + qDebug()<<"frames to write out = "<< + snd_pcm_bytes_to_frames( handle, (int)len )<<" ("< 0) { + totalTimeValue += err; + resuming = false; + errorState = QAudio::NoError; + if (deviceState != QAudio::ActiveState) { + deviceState = QAudio::ActiveState; + emit stateChanged(deviceState); + } + return snd_pcm_frames_to_bytes( handle, err ); + } else + err = xrun_recovery(err); + + if(err < 0) { + close(); + errorState = QAudio::FatalError; + emit errorChanged(errorState); + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + } + return 0; +} + +int QAudioOutputPrivate::periodSize() const +{ + return period_size; +} + +void QAudioOutputPrivate::setBufferSize(int value) +{ + if(deviceState == QAudio::StoppedState) + buffer_size = value; +} + +int QAudioOutputPrivate::bufferSize() const +{ + return buffer_size; +} + +void QAudioOutputPrivate::setNotifyInterval(int ms) +{ + intervalTime = qMax(0, ms); +} + +int QAudioOutputPrivate::notifyInterval() const +{ + return intervalTime; +} + +qint64 QAudioOutputPrivate::processedUSecs() const +{ + return qint64(1000000) * totalTimeValue / settings.frequency(); +} + +void QAudioOutputPrivate::resume() +{ + if(deviceState == QAudio::SuspendedState) { + int err = 0; + + if(handle) { + err = snd_pcm_prepare( handle ); + if(err < 0) + xrun_recovery(err); + + err = snd_pcm_start(handle); + if(err < 0) + xrun_recovery(err); + + bytesAvailable = (int)snd_pcm_frames_to_bytes(handle, buffer_frames); + } + resuming = true; + + deviceState = QAudio::ActiveState; + + errorState = QAudio::NoError; + timer->start(period_time/1000); + emit stateChanged(deviceState); + } +} + +void QAudioOutputPrivate::setFormat(const QAudioFormat& fmt) +{ + if (deviceState == QAudio::StoppedState) + settings = fmt; +} + +QAudioFormat QAudioOutputPrivate::format() const +{ + return settings; +} + +void QAudioOutputPrivate::suspend() +{ + if(deviceState == QAudio::ActiveState || deviceState == QAudio::IdleState || resuming) { + timer->stop(); + deviceState = QAudio::SuspendedState; + errorState = QAudio::NoError; + emit stateChanged(deviceState); + } +} + +void QAudioOutputPrivate::userFeed() +{ + if(deviceState == QAudio::StoppedState || deviceState == QAudio::SuspendedState) + return; +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()< + +#include +#include +#include +#include +#include +#include + +#include "qaudio.h" +#include "qaudiodeviceinfo.h" +#include "qaudiosystem.h" + +QT_BEGIN_NAMESPACE + +class OutputPrivate; + +class QAudioOutputPrivate : public QAbstractAudioOutput +{ + friend class OutputPrivate; + Q_OBJECT +public: + QAudioOutputPrivate(const QByteArray &device); + ~QAudioOutputPrivate(); + + qint64 write( const char *data, qint64 len ); + + void start(QIODevice* device); + QIODevice* start(); + void stop(); + void reset(); + void suspend(); + void resume(); + int bytesFree() const; + int periodSize() const; + void setBufferSize(int value); + int bufferSize() const; + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + QAudio::Error error() const; + QAudio::State state() const; + void setFormat(const QAudioFormat& fmt); + QAudioFormat format() const; + + QIODevice* audioSource; + QAudioFormat settings; + QAudio::Error errorState; + QAudio::State deviceState; + +private slots: + void userFeed(); + void feedback(); + void updateAvailable(); + bool deviceReady(); + +signals: + void processMore(); + +private: + bool opened; + bool pullMode; + bool resuming; + int buffer_size; + int period_size; + int intervalTime; + qint64 totalTimeValue; + unsigned int buffer_time; + unsigned int period_time; + snd_pcm_uframes_t buffer_frames; + snd_pcm_uframes_t period_frames; + static void async_callback(snd_async_handler_t *ahandler); + int xrun_recovery(int err); + + int setFormat(); + bool open(); + void close(); + + QTimer* timer; + QByteArray m_device; + int bytesAvailable; + QTime timeStamp; + QTime clockStamp; + qint64 elapsedTimeOffset; + char* audioBuffer; + snd_pcm_t* handle; + snd_async_handler_t* ahandler; + snd_pcm_access_t access; + snd_pcm_format_t pcmformat; + snd_timestamp_t* timestamp; + snd_pcm_hw_params_t *hwparams; +}; + +class OutputPrivate : public QIODevice +{ + friend class QAudioOutputPrivate; + Q_OBJECT +public: + OutputPrivate(QAudioOutputPrivate* audio); + ~OutputPrivate(); + + qint64 readData( char* data, qint64 len); + qint64 writeData(const char* data, qint64 len); + +private: + QAudioOutputPrivate *audioDevice; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/audio/qaudiooutput_mac_p.cpp b/src/multimediakit/audio/qaudiooutput_mac_p.cpp new file mode 100644 index 000000000..fcaa3cbd2 --- /dev/null +++ b/src/multimediakit/audio/qaudiooutput_mac_p.cpp @@ -0,0 +1,729 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "qaudio_mac_p.h" +#include "qaudiooutput_mac_p.h" +#include "qaudiodeviceinfo_mac_p.h" + + +QT_BEGIN_NAMESPACE + + +namespace QtMultimediaKitInternal +{ + +static const int default_buffer_size = 8 * 1024; + + +class QAudioOutputBuffer : public QObject +{ + Q_OBJECT + +public: + QAudioOutputBuffer(int bufferSize, int maxPeriodSize, QAudioFormat const& audioFormat): + m_deviceError(false), + m_maxPeriodSize(maxPeriodSize), + m_device(0) + { + m_buffer = new QAudioRingBuffer(bufferSize + (bufferSize % maxPeriodSize == 0 ? 0 : maxPeriodSize - (bufferSize % maxPeriodSize))); + m_bytesPerFrame = (audioFormat.sampleSize() / 8) * audioFormat.channels(); + m_periodTime = m_maxPeriodSize / m_bytesPerFrame * 1000 / audioFormat.frequency(); + + m_fillTimer = new QTimer(this); + connect(m_fillTimer, SIGNAL(timeout()), SLOT(fillBuffer())); + } + + ~QAudioOutputBuffer() + { + delete m_buffer; + } + + qint64 readFrames(char* data, qint64 maxFrames) + { + bool wecan = true; + qint64 framesRead = 0; + + while (wecan && framesRead < maxFrames) { + QAudioRingBuffer::Region region = m_buffer->acquireReadRegion((maxFrames - framesRead) * m_bytesPerFrame); + + if (region.second > 0) { + region.second -= region.second % m_bytesPerFrame; + memcpy(data + (framesRead * m_bytesPerFrame), region.first, region.second); + framesRead += region.second / m_bytesPerFrame; + } + else + wecan = false; + + m_buffer->releaseReadRegion(region); + } + + if (framesRead == 0 && m_deviceError) + framesRead = -1; + + return framesRead; + } + + qint64 writeBytes(const char* data, qint64 maxSize) + { + bool wecan = true; + qint64 bytesWritten = 0; + + maxSize -= maxSize % m_bytesPerFrame; + while (wecan && bytesWritten < maxSize) { + QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(maxSize - bytesWritten); + + if (region.second > 0) { + memcpy(region.first, data + bytesWritten, region.second); + bytesWritten += region.second; + } + else + wecan = false; + + m_buffer->releaseWriteRegion(region); + } + + if (bytesWritten > 0) + emit readyRead(); + + return bytesWritten; + } + + int available() const + { + return m_buffer->free(); + } + + void reset() + { + m_buffer->reset(); + m_device = 0; + m_deviceError = false; + } + + void setPrefetchDevice(QIODevice* device) + { + if (m_device != device) { + m_device = device; + if (m_device != 0) + fillBuffer(); + } + } + + void startFillTimer() + { + if (m_device != 0) + m_fillTimer->start(m_buffer->size() / 2 / m_maxPeriodSize * m_periodTime); + } + + void stopFillTimer() + { + m_fillTimer->stop(); + } + +signals: + void readyRead(); + +private slots: + void fillBuffer() + { + const int free = m_buffer->free(); + const int writeSize = free - (free % m_maxPeriodSize); + + if (writeSize > 0) { + bool wecan = true; + int filled = 0; + + while (!m_deviceError && wecan && filled < writeSize) { + QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(writeSize - filled); + + if (region.second > 0) { + region.second = m_device->read(region.first, region.second); + if (region.second > 0) + filled += region.second; + else if (region.second == 0) + wecan = false; + else if (region.second < 0) { + m_fillTimer->stop(); + region.second = 0; + m_deviceError = true; + } + } + else + wecan = false; + + m_buffer->releaseWriteRegion(region); + } + + if (filled > 0) + emit readyRead(); + } + } + +private: + bool m_deviceError; + int m_maxPeriodSize; + int m_bytesPerFrame; + int m_periodTime; + QIODevice* m_device; + QTimer* m_fillTimer; + QAudioRingBuffer* m_buffer; +}; + + +} + +class MacOutputDevice : public QIODevice +{ + Q_OBJECT + +public: + MacOutputDevice(QtMultimediaKitInternal::QAudioOutputBuffer* audioBuffer, QObject* parent): + QIODevice(parent), + m_audioBuffer(audioBuffer) + { + open(QIODevice::WriteOnly | QIODevice::Unbuffered); + } + + qint64 readData(char* data, qint64 len) + { + Q_UNUSED(data); + Q_UNUSED(len); + + return 0; + } + + qint64 writeData(const char* data, qint64 len) + { + return m_audioBuffer->writeBytes(data, len); + } + + bool isSequential() const + { + return true; + } + +private: + QtMultimediaKitInternal::QAudioOutputBuffer* m_audioBuffer; +}; + + +QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray& device) +{ + QDataStream ds(device); + quint32 did, mode; + + ds >> did >> mode; + + if (QAudio::Mode(mode) == QAudio::AudioInput) + errorCode = QAudio::OpenError; + else { + audioDeviceInfo = new QAudioDeviceInfoInternal(device, QAudio::AudioOutput); + isOpen = false; + audioDeviceId = AudioDeviceID(did); + audioUnit = 0; + audioIO = 0; + startTime = 0; + totalFrames = 0; + audioBuffer = 0; + internalBufferSize = QtMultimediaKitInternal::default_buffer_size; + clockFrequency = AudioGetHostClockFrequency() / 1000; + errorCode = QAudio::NoError; + stateCode = QAudio::StoppedState; + audioThreadState = Stopped; + + intervalTimer = new QTimer(this); + intervalTimer->setInterval(1000); + connect(intervalTimer, SIGNAL(timeout()), SIGNAL(notify())); + } +} + +QAudioOutputPrivate::~QAudioOutputPrivate() +{ + delete audioDeviceInfo; + close(); +} + +bool QAudioOutputPrivate::open() +{ + if (errorCode != QAudio::NoError) + return false; + + if (isOpen) + return true; + + ComponentDescription cd; + cd.componentType = kAudioUnitType_Output; + cd.componentSubType = kAudioUnitSubType_HALOutput; + cd.componentManufacturer = kAudioUnitManufacturer_Apple; + cd.componentFlags = 0; + cd.componentFlagsMask = 0; + + // Open + Component cp = FindNextComponent(NULL, &cd); + if (cp == 0) { + qWarning() << "QAudioOutput: Failed to find HAL Output component"; + return false; + } + + if (OpenAComponent(cp, &audioUnit) != noErr) { + qWarning() << "QAudioOutput: Unable to Open Output Component"; + return false; + } + + // register callback + AURenderCallbackStruct cb; + cb.inputProc = renderCallback; + cb.inputProcRefCon = this; + + if (AudioUnitSetProperty(audioUnit, + kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Global, + 0, + &cb, + sizeof(cb)) != noErr) { + qWarning() << "QAudioOutput: Failed to set AudioUnit callback"; + return false; + } + + // Set Audio Device + if (AudioUnitSetProperty(audioUnit, + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + 0, + &audioDeviceId, + sizeof(audioDeviceId)) != noErr) { + qWarning() << "QAudioOutput: Unable to use configured device"; + return false; + } + + // Set stream format + streamFormat = toAudioStreamBasicDescription(audioFormat); + + UInt32 size = sizeof(streamFormat); + if (AudioUnitSetProperty(audioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 0, + &streamFormat, + sizeof(streamFormat)) != noErr) { + qWarning() << "QAudioOutput: Unable to Set Stream information"; + return false; + } + + // Allocate buffer + UInt32 numberOfFrames = 0; + size = sizeof(UInt32); + if (AudioUnitGetProperty(audioUnit, + kAudioDevicePropertyBufferFrameSize, + kAudioUnitScope_Global, + 0, + &numberOfFrames, + &size) != noErr) { + qWarning() << "QAudioInput: Failed to get audio period size"; + return false; + } + + periodSizeBytes = numberOfFrames * streamFormat.mBytesPerFrame; + if (internalBufferSize < periodSizeBytes * 2) + internalBufferSize = periodSizeBytes * 2; + else + internalBufferSize -= internalBufferSize % streamFormat.mBytesPerFrame; + + audioBuffer = new QtMultimediaKitInternal::QAudioOutputBuffer(internalBufferSize, periodSizeBytes, audioFormat); + connect(audioBuffer, SIGNAL(readyRead()), SLOT(inputReady())); // Pull + + audioIO = new MacOutputDevice(audioBuffer, this); + + // Init + if (AudioUnitInitialize(audioUnit)) { + qWarning() << "QAudioOutput: Failed to initialize AudioUnit"; + return false; + } + + isOpen = true; + + return true; +} + +void QAudioOutputPrivate::close() +{ + if (audioUnit != 0) { + AudioOutputUnitStop(audioUnit); + AudioUnitUninitialize(audioUnit); + CloseComponent(audioUnit); + } + + delete audioBuffer; +} + +QAudioFormat QAudioOutputPrivate::format() const +{ + return audioFormat; +} + +void QAudioOutputPrivate::setFormat(const QAudioFormat& fmt) +{ + if (stateCode == QAudio::StoppedState) + audioFormat = fmt; +} + +void QAudioOutputPrivate::start(QIODevice* device) +{ + QIODevice* op = device; + + if (!audioDeviceInfo->isFormatSupported(audioFormat) || !open()) { + stateCode = QAudio::StoppedState; + errorCode = QAudio::OpenError; + } + + reset(); + audioBuffer->reset(); + audioBuffer->setPrefetchDevice(op); + + if (op == 0) { + op = audioIO; + stateCode = QAudio::IdleState; + } + else + stateCode = QAudio::ActiveState; + + // Start + errorCode = QAudio::NoError; + totalFrames = 0; + startTime = AudioGetCurrentHostTime(); + + if (stateCode == QAudio::ActiveState) + audioThreadStart(); + + emit stateChanged(stateCode); +} + +QIODevice* QAudioOutputPrivate::start() +{ + if (!audioDeviceInfo->isFormatSupported(audioFormat) || !open()) { + stateCode = QAudio::StoppedState; + errorCode = QAudio::OpenError; + return audioIO; + } + + reset(); + audioBuffer->reset(); + audioBuffer->setPrefetchDevice(0); + + stateCode = QAudio::IdleState; + + // Start + errorCode = QAudio::NoError; + totalFrames = 0; + startTime = AudioGetCurrentHostTime(); + + emit stateChanged(stateCode); + + return audioIO; +} + +void QAudioOutputPrivate::stop() +{ + QMutexLocker lock(&mutex); + if (stateCode != QAudio::StoppedState) { + audioThreadDrain(); + + stateCode = QAudio::StoppedState; + errorCode = QAudio::NoError; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +void QAudioOutputPrivate::reset() +{ + QMutexLocker lock(&mutex); + if (stateCode != QAudio::StoppedState) { + audioThreadStop(); + + stateCode = QAudio::StoppedState; + errorCode = QAudio::NoError; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +void QAudioOutputPrivate::suspend() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::ActiveState || stateCode == QAudio::IdleState) { + audioThreadStop(); + + stateCode = QAudio::SuspendedState; + errorCode = QAudio::NoError; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +void QAudioOutputPrivate::resume() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::SuspendedState) { + audioThreadStart(); + + stateCode = QAudio::ActiveState; + errorCode = QAudio::NoError; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +int QAudioOutputPrivate::bytesFree() const +{ + return audioBuffer->available(); +} + +int QAudioOutputPrivate::periodSize() const +{ + return periodSizeBytes; +} + +void QAudioOutputPrivate::setBufferSize(int bs) +{ + if (stateCode == QAudio::StoppedState) + internalBufferSize = bs; +} + +int QAudioOutputPrivate::bufferSize() const +{ + return internalBufferSize; +} + +void QAudioOutputPrivate::setNotifyInterval(int milliSeconds) +{ + if (intervalTimer->interval() == milliSeconds) + return; + + if (milliSeconds <= 0) + milliSeconds = 0; + + intervalTimer->setInterval(milliSeconds); +} + +int QAudioOutputPrivate::notifyInterval() const +{ + return intervalTimer->interval(); +} + +qint64 QAudioOutputPrivate::processedUSecs() const +{ + return totalFrames * 1000000 / audioFormat.frequency(); +} + +qint64 QAudioOutputPrivate::elapsedUSecs() const +{ + if (stateCode == QAudio::StoppedState) + return 0; + + return (AudioGetCurrentHostTime() - startTime) / (clockFrequency / 1000); +} + +QAudio::Error QAudioOutputPrivate::error() const +{ + return errorCode; +} + +QAudio::State QAudioOutputPrivate::state() const +{ + return stateCode; +} + +void QAudioOutputPrivate::audioThreadStart() +{ + startTimers(); + audioThreadState = Running; + AudioOutputUnitStart(audioUnit); +} + +void QAudioOutputPrivate::audioThreadStop() +{ + stopTimers(); + if (audioThreadState.testAndSetAcquire(Running, Stopped)) + threadFinished.wait(&mutex); +} + +void QAudioOutputPrivate::audioThreadDrain() +{ + stopTimers(); + if (audioThreadState.testAndSetAcquire(Running, Draining)) + threadFinished.wait(&mutex); +} + +void QAudioOutputPrivate::audioDeviceStop() +{ + AudioOutputUnitStop(audioUnit); + audioThreadState = Stopped; + threadFinished.wakeOne(); +} + +void QAudioOutputPrivate::audioDeviceIdle() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::ActiveState) { + audioDeviceStop(); + + errorCode = QAudio::UnderrunError; + stateCode = QAudio::IdleState; + QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection); + } +} + +void QAudioOutputPrivate::audioDeviceError() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::ActiveState) { + audioDeviceStop(); + + errorCode = QAudio::IOError; + stateCode = QAudio::StoppedState; + QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection); + } +} + +void QAudioOutputPrivate::startTimers() +{ + audioBuffer->startFillTimer(); + if (intervalTimer->interval() > 0) + intervalTimer->start(); +} + +void QAudioOutputPrivate::stopTimers() +{ + audioBuffer->stopFillTimer(); + intervalTimer->stop(); +} + + +void QAudioOutputPrivate::deviceStopped() +{ + intervalTimer->stop(); + emit stateChanged(stateCode); +} + +void QAudioOutputPrivate::inputReady() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::IdleState) { + audioThreadStart(); + + stateCode = QAudio::ActiveState; + errorCode = QAudio::NoError; + + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + + +OSStatus QAudioOutputPrivate::renderCallback(void* inRefCon, + AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList* ioData) +{ + Q_UNUSED(ioActionFlags) + Q_UNUSED(inTimeStamp) + Q_UNUSED(inBusNumber) + Q_UNUSED(inNumberFrames) + + QAudioOutputPrivate* d = static_cast(inRefCon); + + const int threadState = d->audioThreadState.fetchAndAddAcquire(0); + if (threadState == Stopped) { + ioData->mBuffers[0].mDataByteSize = 0; + d->audioDeviceStop(); + } + else { + const UInt32 bytesPerFrame = d->streamFormat.mBytesPerFrame; + qint64 framesRead; + + framesRead = d->audioBuffer->readFrames((char*)ioData->mBuffers[0].mData, + ioData->mBuffers[0].mDataByteSize / bytesPerFrame); + + if (framesRead > 0) { + ioData->mBuffers[0].mDataByteSize = framesRead * bytesPerFrame; + d->totalFrames += framesRead; + } + else { + ioData->mBuffers[0].mDataByteSize = 0; + if (framesRead == 0) { + if (threadState == Draining) + d->audioDeviceStop(); + else + d->audioDeviceIdle(); + } + else + d->audioDeviceError(); + } + } + + return noErr; +} + + +QT_END_NAMESPACE + +#include "qaudiooutput_mac_p.moc" diff --git a/src/multimediakit/audio/qaudiooutput_mac_p.h b/src/multimediakit/audio/qaudiooutput_mac_p.h new file mode 100644 index 000000000..5524621f9 --- /dev/null +++ b/src/multimediakit/audio/qaudiooutput_mac_p.h @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QAUDIOOUTPUT_MAC_P_H +#define QAUDIOOUTPUT_MAC_P_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QIODevice; +class QAbstractAudioDeviceInfo; + +namespace QtMultimediaKitInternal +{ +class QAudioOutputBuffer; +} + +class QAudioOutputPrivate : public QAbstractAudioOutput +{ + Q_OBJECT + +public: + bool isOpen; + int internalBufferSize; + int periodSizeBytes; + qint64 totalFrames; + QAudioFormat audioFormat; + QIODevice* audioIO; + AudioDeviceID audioDeviceId; + AudioUnit audioUnit; + Float64 clockFrequency; + UInt64 startTime; + AudioStreamBasicDescription deviceFormat; + AudioStreamBasicDescription streamFormat; + QtMultimediaKitInternal::QAudioOutputBuffer* audioBuffer; + QAtomicInt audioThreadState; + QWaitCondition threadFinished; + QMutex mutex; + QTimer* intervalTimer; + QAbstractAudioDeviceInfo *audioDeviceInfo; + + QAudio::Error errorCode; + QAudio::State stateCode; + + QAudioOutputPrivate(const QByteArray& device); + ~QAudioOutputPrivate(); + + bool open(); + void close(); + + QAudioFormat format() const; + void setFormat(const QAudioFormat& fmt); + + QIODevice* start(); + void start(QIODevice* device); + void stop(); + void reset(); + void suspend(); + void resume(); + + int bytesFree() const; + int periodSize() const; + + void setBufferSize(int value); + int bufferSize() const; + + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + + QAudio::Error error() const; + QAudio::State state() const; + + void audioThreadStart(); + void audioThreadStop(); + void audioThreadDrain(); + + void audioDeviceStop(); + void audioDeviceIdle(); + void audioDeviceError(); + + void startTimers(); + void stopTimers(); + +private slots: + void deviceStopped(); + void inputReady(); + +private: + enum { Running, Draining, Stopped }; + + static OSStatus renderCallback(void* inRefCon, + AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList* ioData); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimediakit/audio/qaudiooutput_symbian_p.cpp b/src/multimediakit/audio/qaudiooutput_symbian_p.cpp new file mode 100644 index 000000000..3a1bc2424 --- /dev/null +++ b/src/multimediakit/audio/qaudiooutput_symbian_p.cpp @@ -0,0 +1,713 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaudiooutput_symbian_p.h" + +QT_BEGIN_NAMESPACE + +//----------------------------------------------------------------------------- +// Constants +//----------------------------------------------------------------------------- + +const int UnderflowTimerInterval = 50; // ms + + +//----------------------------------------------------------------------------- +// Private class +//----------------------------------------------------------------------------- + +SymbianAudioOutputPrivate::SymbianAudioOutputPrivate( + QAudioOutputPrivate *audioDevice) + : m_audioDevice(audioDevice) +{ + +} + +SymbianAudioOutputPrivate::~SymbianAudioOutputPrivate() +{ + +} + +qint64 SymbianAudioOutputPrivate::readData(char *data, qint64 len) +{ + Q_UNUSED(data) + Q_UNUSED(len) + return 0; +} + +qint64 SymbianAudioOutputPrivate::writeData(const char *data, qint64 len) +{ + qint64 totalWritten = 0; + + if (m_audioDevice->state() == QAudio::ActiveState || + m_audioDevice->state() == QAudio::IdleState) { + + while (totalWritten < len) { + const qint64 written = m_audioDevice->pushData(data + totalWritten, + len - totalWritten); + if (written > 0) + totalWritten += written; + else + break; + } + } + + return totalWritten; +} + + +//----------------------------------------------------------------------------- +// Public functions +//----------------------------------------------------------------------------- + +QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray &device) + : m_device(device) + , m_clientBufferSize(SymbianAudio::DefaultBufferSize) + , m_notifyInterval(SymbianAudio::DefaultNotifyInterval) + , m_notifyTimer(new QTimer(this)) + , m_lastNotifyPosition(0) + , m_error(QAudio::NoError) + , m_internalState(SymbianAudio::ClosedState) + , m_externalState(QAudio::StoppedState) + , m_pullMode(false) + , m_source(0) + , m_devSound(0) + , m_devSoundBuffer(0) + , m_devSoundBufferSize(0) + , m_bytesWritten(0) + , m_pushDataReady(false) + , m_bytesPadding(0) + , m_underflow(false) + , m_lastBuffer(false) + , m_underflowTimer(new QTimer(this)) + , m_samplesPlayed(0) + , m_totalSamplesPlayed(0) +{ + connect(m_notifyTimer.data(), SIGNAL(timeout()), + this, SLOT(notifyTimerExpired())); + + m_underflowTimer->setInterval(UnderflowTimerInterval); + + connect(m_underflowTimer.data(), SIGNAL(timeout()), this, + SLOT(underflowTimerExpired())); +} + +QAudioOutputPrivate::~QAudioOutputPrivate() +{ + close(); +} + +void QAudioOutputPrivate::setFormat(const QAudioFormat& fmt) +{ + m_format = fmt; +} + +void QAudioOutputPrivate::start(QIODevice *device) +{ + stop(); + + // We have to set these before the call to open() because of the + // logic in initializingState() + m_pullMode = true; + m_source = device; + + open(); + + if (SymbianAudio::ClosedState != m_internalState) { + connect(m_source, SIGNAL(readyRead()), this, SLOT(dataReady())); + m_elapsed.restart(); + } +} + +QIODevice* QAudioOutputPrivate::start() +{ + stop(); + + open(); + + if (SymbianAudio::ClosedState != m_internalState) { + m_source = new SymbianAudioOutputPrivate(this); + m_source->open(QIODevice::WriteOnly | QIODevice::Unbuffered); + m_elapsed.restart(); + } + + return m_source; +} + +void QAudioOutputPrivate::stop() +{ + close(); +} + +void QAudioOutputPrivate::reset() +{ +#ifndef PRE_S60_52_PLATFORM + int err = m_devSound->flush(); + if (err != 0) + setError(QAudio::FatalError); +#else + m_totalSamplesPlayed += getSamplesPlayed(); + m_devSound->stop(); + m_bytesPadding = 0; + startPlayback(); +#endif +} + +void QAudioOutputPrivate::suspend() +{ + if (SymbianAudio::ActiveState == m_internalState + || SymbianAudio::IdleState == m_internalState) { + m_underflowTimer->stop(); + const qint64 samplesWritten = SymbianAudio::Utils::bytesToSamples( + m_format, m_bytesWritten); + const qint64 samplesPlayed = getSamplesPlayed(); +#ifdef PRE_S60_52_PLATFORM + m_totalSamplesPlayed += samplesPlayed; + m_bytesWritten = 0; +#endif + const bool paused = m_devSound->pause(); + if (paused) { + setState(SymbianAudio::SuspendedPausedState); + } else { + m_devSoundBuffer = 0; + // Calculate the amount of data dropped + const qint64 paddingSamples = samplesWritten - samplesPlayed; + Q_ASSERT(paddingSamples >= 0); + m_bytesPadding = SymbianAudio::Utils::samplesToBytes(m_format, + paddingSamples); + setState(SymbianAudio::SuspendedStoppedState); + } + } +} + +void QAudioOutputPrivate::resume() +{ + if (QAudio::SuspendedState == m_externalState) { + if (SymbianAudio::SuspendedPausedState == m_internalState) { +#ifndef PRE_S60_52_PLATFORM + setState(SymbianAudio::ActiveState); + if (m_devSoundBuffer != 0) + devsoundBufferToBeFilled(m_devSoundBuffer); + m_devSound->start(); +#else +//defined in else part of macro to enable compatibility of previous code + m_devSound->resume(); +#endif + } else { + startPlayback(); + } + } +} + +int QAudioOutputPrivate::bytesFree() const +{ + int result = 0; + if (m_devSoundBuffer) { + const TDes8 &outputBuffer = m_devSoundBuffer->Data(); + result = outputBuffer.MaxLength() - outputBuffer.Length(); + } + return result; +} + +int QAudioOutputPrivate::periodSize() const +{ + return bufferSize(); +} + +void QAudioOutputPrivate::setBufferSize(int value) +{ + // Note that DevSound does not allow its client to specify the buffer size. + // This functionality is available via custom interfaces, but since these + // cannot be guaranteed to work across all DevSound implementations, we + // do not use them here. + // In order to comply with the expected bevahiour of QAudioOutput, we store + // the value and return it from bufferSize(), but the underlying DevSound + // buffer size remains unchanged. + if (value > 0) + m_clientBufferSize = value; +} + +int QAudioOutputPrivate::bufferSize() const +{ + return m_devSoundBufferSize ? m_devSoundBufferSize : m_clientBufferSize; +} + +void QAudioOutputPrivate::setNotifyInterval(int ms) +{ + if (ms >= 0) { + //const int oldNotifyInterval = m_notifyInterval; + m_notifyInterval = ms; + if (m_notifyInterval && (SymbianAudio::ActiveState == m_internalState || + SymbianAudio::IdleState == m_internalState)) + m_notifyTimer->start(m_notifyInterval); + else + m_notifyTimer->stop(); + } +} + +int QAudioOutputPrivate::notifyInterval() const +{ + return m_notifyInterval; +} + +qint64 QAudioOutputPrivate::processedUSecs() const +{ + int samplesPlayed = 0; + + if (!m_devSound) + return samplesPlayed; + + if (QAudio::SuspendedState != m_externalState) + samplesPlayed = getSamplesPlayed(); + + // Protect against division by zero + Q_ASSERT_X(m_format.frequency() > 0, Q_FUNC_INFO, "Invalid frequency"); + +#ifndef PRE_S60_52_PLATFORM + const qint64 devSoundSamplesPlayed(m_devSound->samplesProcessed()); + const qint64 result = qint64(1000000) * + (devSoundSamplesPlayed) + / m_format.frequency(); +#else + const qint64 result = qint64(1000000) * + (samplesPlayed + m_totalSamplesPlayed) + / m_format.frequency(); +#endif + return result; +} + +qint64 QAudioOutputPrivate::elapsedUSecs() const +{ + const qint64 result = (QAudio::StoppedState == state()) ? + 0 : m_elapsed.elapsed() * 1000; + return result; +} + +QAudio::Error QAudioOutputPrivate::error() const +{ + return m_error; +} + +QAudio::State QAudioOutputPrivate::state() const +{ + return m_externalState; +} + +QAudioFormat QAudioOutputPrivate::format() const +{ + return m_format; +} + + +//----------------------------------------------------------------------------- +// Private functions +//----------------------------------------------------------------------------- + +void QAudioOutputPrivate::notifyTimerExpired() +{ + const qint64 pos = processedUSecs(); + if (pos > m_lastNotifyPosition) { + int count = (pos - m_lastNotifyPosition) / (m_notifyInterval * 1000); + while (count--) { + emit notify(); + m_lastNotifyPosition += m_notifyInterval * 1000; + } + } +} + +void QAudioOutputPrivate::dataReady() +{ + // Client-provided QIODevice has data ready to read. + + Q_ASSERT_X(m_source->bytesAvailable(), Q_FUNC_INFO, + "readyRead signal received, but no data available"); + + if (!m_bytesPadding) + pullData(); +} + +void QAudioOutputPrivate::underflowTimerExpired() +{ + const TInt samplesPlayed = getSamplesPlayed(); + if (m_samplesPlayed && (samplesPlayed == m_samplesPlayed)) { + setError(QAudio::UnderrunError); +#ifndef PRE_S60_52_PLATFORM + m_underflowTimer->stop(); +#endif + } else { + m_samplesPlayed = samplesPlayed; + m_underflowTimer->start(); + } +} + +void QAudioOutputPrivate::devsoundInitializeComplete(int err) +{ + Q_ASSERT_X(SymbianAudio::InitializingState == m_internalState, + Q_FUNC_INFO, "Invalid state"); + + if (!err && m_devSound->isFormatSupported(m_format)) + startPlayback(); + else + setError(QAudio::OpenError); +} + +void QAudioOutputPrivate::devsoundBufferToBeFilled(CMMFBuffer *bufferBase) +{ + // Following receipt of this signal, DevSound should not provide another + // buffer until we have returned the current one. + Q_ASSERT_X(!m_devSoundBuffer, Q_FUNC_INFO, "Buffer already held"); + + // Will be returned to DevSoundWrapper by bufferProcessed(). + m_devSoundBuffer = static_cast(bufferBase); +#ifndef PRE_S60_52_PLATFORM + if (m_externalState == QAudio::SuspendedState) { + // This condition occurs when buffertobefilled callback is received after + // pause command is processed. + return; + } +#endif + + if (!m_devSoundBufferSize) + m_devSoundBufferSize = m_devSoundBuffer->Data().MaxLength(); + + writePaddingData(); + + if (m_pullMode && isDataReady() && !m_bytesPadding) + pullData(); +} + +void QAudioOutputPrivate::devsoundPlayError(int err) +{ + switch (err) { + case KErrUnderflow: + m_underflow = true; + if (m_pullMode && !m_lastBuffer) + setError(QAudio::UnderrunError); + else + setState(SymbianAudio::IdleState); + break; + case KErrOverflow: + // Silently consume this error when in playback mode + break; + default: + setError(QAudio::IOError); + break; + } +} + +void QAudioOutputPrivate::open() +{ + Q_ASSERT_X(SymbianAudio::ClosedState == m_internalState, + Q_FUNC_INFO, "DevSound already opened"); + + Q_ASSERT(!m_devSound); + m_devSound = new SymbianAudio::DevSoundWrapper(QAudio::AudioOutput, this); + + connect(m_devSound, SIGNAL(initializeComplete(int)), + this, SLOT(devsoundInitializeComplete(int))); + connect(m_devSound, SIGNAL(bufferToBeProcessed(CMMFBuffer *)), + this, SLOT(devsoundBufferToBeFilled(CMMFBuffer *))); + connect(m_devSound, SIGNAL(processingError(int)), + this, SLOT(devsoundPlayError(int))); + + setState(SymbianAudio::InitializingState); + m_devSound->initialize(m_format.codec()); +} + +void QAudioOutputPrivate::startPlayback() +{ + bool ok = m_devSound->setFormat(m_format); + if (ok) + ok = m_devSound->start(); + + if (ok) { + if (isDataReady()) + setState(SymbianAudio::ActiveState); + else + setState(SymbianAudio::IdleState); + + if (m_notifyInterval) + m_notifyTimer->start(m_notifyInterval); + m_underflow = false; + + Q_ASSERT(m_devSound->samplesProcessed() == 0); + + writePaddingData(); + + if (m_pullMode && m_source->bytesAvailable() && !m_bytesPadding) + dataReady(); + } else { + setError(QAudio::OpenError); + close(); + } +} + +void QAudioOutputPrivate::writePaddingData() +{ + // See comments in suspend() + + while (m_devSoundBuffer && m_bytesPadding) { + if (SymbianAudio::IdleState == m_internalState) + setState(SymbianAudio::ActiveState); + + TDes8 &outputBuffer = m_devSoundBuffer->Data(); + const qint64 outputBytes = bytesFree(); + const qint64 paddingBytes = outputBytes < m_bytesPadding ? + outputBytes : m_bytesPadding; + unsigned char *ptr = const_cast(outputBuffer.Ptr()); + Mem::FillZ(ptr, paddingBytes); + outputBuffer.SetLength(outputBuffer.Length() + paddingBytes); + m_bytesPadding -= paddingBytes; + Q_ASSERT(m_bytesPadding >= 0); + + if (m_pullMode && m_source->atEnd()) + lastBufferFilled(); + if ((paddingBytes == outputBytes) || !m_bytesPadding) + bufferFilled(); + } +} + +qint64 QAudioOutputPrivate::pushData(const char *data, qint64 len) +{ + // Data has been written to SymbianAudioOutputPrivate + + Q_ASSERT_X(!m_pullMode, Q_FUNC_INFO, + "pushData called when in pull mode"); + + const unsigned char *const inputPtr = + reinterpret_cast(data); + qint64 bytesWritten = 0; + + if (SymbianAudio::IdleState == m_internalState) + setState(SymbianAudio::ActiveState); + + while (m_devSoundBuffer && (bytesWritten < len)) { + // writePaddingData() is called from BufferToBeFilled(), so we should + // never have any padding data left at this point. + Q_ASSERT_X(0 == m_bytesPadding, Q_FUNC_INFO, + "Padding bytes remaining in pushData"); + + TDes8 &outputBuffer = m_devSoundBuffer->Data(); + + const qint64 outputBytes = bytesFree(); + const qint64 inputBytes = len - bytesWritten; + const qint64 copyBytes = outputBytes < inputBytes ? + outputBytes : inputBytes; + + outputBuffer.Append(inputPtr + bytesWritten, copyBytes); + bytesWritten += copyBytes; + + bufferFilled(); + } + + m_pushDataReady = (bytesWritten < len); + + // If DevSound is still initializing (m_internalState == InitializingState), + // we cannot transition m_internalState to ActiveState, but we must emit + // an (external) state change from IdleState to ActiveState. The following + // call triggers this signal. + setState(m_internalState); + + return bytesWritten; +} + +void QAudioOutputPrivate::pullData() +{ + Q_ASSERT_X(m_pullMode, Q_FUNC_INFO, + "pullData called when in push mode"); + + // writePaddingData() is called by BufferToBeFilled() before pullData(), + // so we should never have any padding data left at this point. + Q_ASSERT_X(0 == m_bytesPadding, Q_FUNC_INFO, + "Padding bytes remaining in pullData"); + + qint64 inputBytes = m_source->bytesAvailable(); + while (m_devSoundBuffer && inputBytes) { + if (SymbianAudio::IdleState == m_internalState) + setState(SymbianAudio::ActiveState); + + TDes8 &outputBuffer = m_devSoundBuffer->Data(); + + const qint64 outputBytes = bytesFree(); + const qint64 copyBytes = outputBytes < inputBytes ? + outputBytes : inputBytes; + + char *outputPtr = (char*)(outputBuffer.Ptr() + outputBuffer.Length()); + const qint64 bytesCopied = m_source->read(outputPtr, copyBytes); + + //Partial buffers can be sent to DevSound. This assert not required. + //Q_ASSERT(bytesCopied == copyBytes); + outputBuffer.SetLength(outputBuffer.Length() + bytesCopied); + inputBytes -= bytesCopied; + + if(bytesCopied == 0) + return; + + if (m_source->atEnd()) + lastBufferFilled(); + else + bufferFilled(); + } +} + +void QAudioOutputPrivate::bufferFilled() +{ + Q_ASSERT_X(m_devSoundBuffer, Q_FUNC_INFO, "No buffer to return"); + + const TDes8 &outputBuffer = m_devSoundBuffer->Data(); + m_bytesWritten += outputBuffer.Length(); + + m_devSoundBuffer = 0; + + m_samplesPlayed = getSamplesPlayed(); + m_underflowTimer->start(); + + if (QAudio::UnderrunError == m_error) + m_error = QAudio::NoError; + + m_devSound->bufferProcessed(); +} + +void QAudioOutputPrivate::lastBufferFilled() +{ + Q_ASSERT_X(m_devSoundBuffer, Q_FUNC_INFO, "No buffer to fill"); + Q_ASSERT_X(!m_lastBuffer, Q_FUNC_INFO, "Last buffer already sent"); + m_lastBuffer = true; + m_devSoundBuffer->SetLastBuffer(ETrue); + bufferFilled(); +} + +void QAudioOutputPrivate::close() +{ + m_lastNotifyPosition = 0; + m_underflowTimer->stop(); + + m_error = QAudio::NoError; + + if (m_devSound) + m_devSound->stop(); + delete m_devSound; + m_devSound = 0; + + m_devSoundBuffer = 0; + m_devSoundBufferSize = 0; + + if (!m_pullMode) // m_source is owned + delete m_source; + m_pullMode = false; + m_source = 0; + + m_bytesWritten = 0; + m_pushDataReady = false; + m_bytesPadding = 0; + m_underflow = false; + m_lastBuffer = false; + m_samplesPlayed = 0; + m_totalSamplesPlayed = 0; + + setState(SymbianAudio::ClosedState); +} + +qint64 QAudioOutputPrivate::getSamplesPlayed() const +{ + qint64 result = 0; + if (m_devSound) { + const qint64 samplesWritten = SymbianAudio::Utils::bytesToSamples( + m_format, m_bytesWritten); + + if (m_underflow) { + result = samplesWritten; + } else { + // This is necessary because some DevSound implementations report + // that they have played more data than has actually been provided to them + // by the client. + const qint64 devSoundSamplesPlayed(m_devSound->samplesProcessed()); + result = qMin(devSoundSamplesPlayed, samplesWritten); + } + } + return result; +} + +void QAudioOutputPrivate::setError(QAudio::Error error) +{ + m_error = error; + + // Although no state transition actually occurs here, a stateChanged event + // must be emitted to inform the client that the call to start() was + // unsuccessful. + if (QAudio::OpenError == error) { + emit stateChanged(QAudio::StoppedState); + } else { + if (QAudio::UnderrunError == error) + setState(SymbianAudio::IdleState); + else + // Close the DevSound instance. This causes a transition to + // StoppedState. This must be done asynchronously in case the + // current function was called from a DevSound event handler, in which + // case deleting the DevSound instance may cause an exception. + QMetaObject::invokeMethod(this, "close", Qt::QueuedConnection); + } +} + +void QAudioOutputPrivate::setState(SymbianAudio::State newInternalState) +{ + const QAudio::State oldExternalState = m_externalState; + m_internalState = newInternalState; + m_externalState = SymbianAudio::Utils::stateNativeToQt(m_internalState); + + if (m_externalState != QAudio::ActiveState && + m_externalState != QAudio::IdleState) + m_notifyTimer->stop(); + + if (m_externalState != oldExternalState) + emit stateChanged(m_externalState); +} + +bool QAudioOutputPrivate::isDataReady() const +{ + return (m_source && m_source->bytesAvailable()) + || m_bytesPadding + || m_pushDataReady; +} + +QT_END_NAMESPACE + +#include "moc_qaudiooutput_symbian_p.cpp" diff --git a/src/multimediakit/audio/qaudiooutput_symbian_p.h b/src/multimediakit/audio/qaudiooutput_symbian_p.h new file mode 100644 index 000000000..2e2fd5db2 --- /dev/null +++ b/src/multimediakit/audio/qaudiooutput_symbian_p.h @@ -0,0 +1,201 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QAUDIOOUTPUT_SYMBIAN_P_H +#define QAUDIOOUTPUT_SYMBIAN_P_H + +#include +#include +#include +#include +#include "qaudio_symbian_p.h" + +QT_BEGIN_NAMESPACE + +class QAudioOutputPrivate; + +class SymbianAudioOutputPrivate : public QIODevice +{ + friend class QAudioOutputPrivate; + Q_OBJECT +public: + SymbianAudioOutputPrivate(QAudioOutputPrivate *audio); + ~SymbianAudioOutputPrivate(); + + qint64 readData(char *data, qint64 len); + qint64 writeData(const char *data, qint64 len); + +private: + QAudioOutputPrivate *const m_audioDevice; +}; + +class QAudioOutputPrivate + : public QAbstractAudioOutput +{ + friend class SymbianAudioOutputPrivate; + Q_OBJECT +public: + QAudioOutputPrivate(const QByteArray &device); + ~QAudioOutputPrivate(); + + // QAbstractAudioOutput + void start(QIODevice *device); + QIODevice* start(); + void stop(); + void reset(); + void suspend(); + void resume(); + int bytesFree() const; + int periodSize() const; + void setBufferSize(int value); + int bufferSize() const; + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + QAudio::Error error() const; + QAudio::State state() const; + QAudioFormat format() const; + void setFormat(const QAudioFormat& fmt); + +private slots: + void dataReady(); + void notifyTimerExpired(); + void underflowTimerExpired(); + void devsoundInitializeComplete(int err); + void devsoundBufferToBeFilled(CMMFBuffer *); + void devsoundPlayError(int err); + +private: + void open(); + void startPlayback(); + void writePaddingData(); + qint64 pushData(const char *data, qint64 len); + void pullData(); + void bufferFilled(); + void lastBufferFilled(); + Q_INVOKABLE void close(); + + qint64 getSamplesPlayed() const; + + void setError(QAudio::Error error); + void setState(SymbianAudio::State state); + + bool isDataReady() const; + +private: + const QByteArray m_device; + QAudioFormat m_format; + + int m_clientBufferSize; + int m_notifyInterval; + QScopedPointer m_notifyTimer; + qint64 m_lastNotifyPosition; + QTime m_elapsed; + QAudio::Error m_error; + + SymbianAudio::State m_internalState; + QAudio::State m_externalState; + + bool m_pullMode; + QIODevice *m_source; + + SymbianAudio::DevSoundWrapper* m_devSound; + + // Buffer provided by DevSound, to be filled with data. + CMMFDataBuffer *m_devSoundBuffer; + + int m_devSoundBufferSize; + + // Number of bytes transferred from QIODevice to QAudioOutput. It is + // necessary to count this because data is dropped when suspend() is + // called. The difference between the position reported by DevSound and + // this value allows us to calculate m_bytesPadding; + quint32 m_bytesWritten; + + // True if client has provided data while the audio subsystem was not + // ready to consume it. + bool m_pushDataReady; + + // Number of zero bytes which will be written when client calls resume(). + quint32 m_bytesPadding; + + // True if PlayError(KErrUnderflow) has been called. + bool m_underflow; + + // True if a buffer marked with the "last buffer" flag has been provided + // to DevSound. + bool m_lastBuffer; + + // Some DevSound implementations ignore all underflow errors raised by the + // audio driver, unless the last buffer flag has been set by the client. + // In push-mode playback, this flag will never be set, so the underflow + // error will never be reported. In order to work around this, a timer + // is used, which gets reset every time the client provides more data. If + // the timer expires, an underflow error is raised by this object. + QScopedPointer m_underflowTimer; + + // Result of previous call to CMMFDevSound::SamplesPlayed(). This value is + // used to determine whether, when m_underflowTimer expires, an + // underflow error has actually occurred. + quint32 m_samplesPlayed; + + // Samples played up to the last call to suspend(). It is necessary + // to cache this because suspend() is implemented using + // CMMFDevSound::Stop(), which resets DevSound's SamplesPlayed() counter. + quint32 m_totalSamplesPlayed; + +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/audio/qaudiooutput_win32_p.cpp b/src/multimediakit/audio/qaudiooutput_win32_p.cpp new file mode 100644 index 000000000..3f465de37 --- /dev/null +++ b/src/multimediakit/audio/qaudiooutput_win32_p.cpp @@ -0,0 +1,715 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include "qaudiooutput_win32_p.h" + +#ifndef SPEAKER_FRONT_LEFT + #define SPEAKER_FRONT_LEFT 0x00000001 + #define SPEAKER_FRONT_RIGHT 0x00000002 + #define SPEAKER_FRONT_CENTER 0x00000004 + #define SPEAKER_LOW_FREQUENCY 0x00000008 + #define SPEAKER_BACK_LEFT 0x00000010 + #define SPEAKER_BACK_RIGHT 0x00000020 + #define SPEAKER_FRONT_LEFT_OF_CENTER 0x00000040 + #define SPEAKER_FRONT_RIGHT_OF_CENTER 0x00000080 + #define SPEAKER_BACK_CENTER 0x00000100 + #define SPEAKER_SIDE_LEFT 0x00000200 + #define SPEAKER_SIDE_RIGHT 0x00000400 + #define SPEAKER_TOP_CENTER 0x00000800 + #define SPEAKER_TOP_FRONT_LEFT 0x00001000 + #define SPEAKER_TOP_FRONT_CENTER 0x00002000 + #define SPEAKER_TOP_FRONT_RIGHT 0x00004000 + #define SPEAKER_TOP_BACK_LEFT 0x00008000 + #define SPEAKER_TOP_BACK_CENTER 0x00010000 + #define SPEAKER_TOP_BACK_RIGHT 0x00020000 + #define SPEAKER_RESERVED 0x7FFC0000 + #define SPEAKER_ALL 0x80000000 +#endif + +#ifndef _WAVEFORMATEXTENSIBLE_ + + #define _WAVEFORMATEXTENSIBLE_ + typedef struct + { + WAVEFORMATEX Format; // Base WAVEFORMATEX data + union + { + WORD wValidBitsPerSample; // Valid bits in each sample container + WORD wSamplesPerBlock; // Samples per block of audio data; valid + // if wBitsPerSample=0 (but rarely used). + WORD wReserved; // Zero if neither case above applies. + } Samples; + DWORD dwChannelMask; // Positions of the audio channels + GUID SubFormat; // Format identifier GUID + } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE, *LPPWAVEFORMATEXTENSIBLE; + typedef const WAVEFORMATEXTENSIBLE* LPCWAVEFORMATEXTENSIBLE; + +#endif + +#if !defined(WAVE_FORMAT_EXTENSIBLE) +#define WAVE_FORMAT_EXTENSIBLE 0xFFFE +#endif + +//#define DEBUG_AUDIO 1 + +QT_BEGIN_NAMESPACE + +QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray &device) +{ + bytesAvailable = 0; + buffer_size = 0; + period_size = 0; + m_device = device; + totalTimeValue = 0; + intervalTime = 1000; + audioBuffer = 0; + errorState = QAudio::NoError; + deviceState = QAudio::StoppedState; + audioSource = 0; + pullMode = true; + finished = false; +} + +QAudioOutputPrivate::~QAudioOutputPrivate() +{ + mutex.lock(); + finished = true; + mutex.unlock(); + + close(); +} + +void CALLBACK QAudioOutputPrivate::waveOutProc( HWAVEOUT hWaveOut, UINT uMsg, + DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) +{ + Q_UNUSED(dwParam1) + Q_UNUSED(dwParam2) + Q_UNUSED(hWaveOut) + + QAudioOutputPrivate* qAudio; + qAudio = (QAudioOutputPrivate*)(dwInstance); + if(!qAudio) + return; + + QMutexLocker(&qAudio->mutex); + + switch(uMsg) { + case WOM_OPEN: + qAudio->feedback(); + break; + case WOM_CLOSE: + return; + case WOM_DONE: + if(qAudio->finished || qAudio->buffer_size == 0 || qAudio->period_size == 0) { + return; + } + qAudio->waveFreeBlockCount++; + if(qAudio->waveFreeBlockCount >= qAudio->buffer_size/qAudio->period_size) + qAudio->waveFreeBlockCount = qAudio->buffer_size/qAudio->period_size; + qAudio->feedback(); + break; + default: + return; + } +} + +WAVEHDR* QAudioOutputPrivate::allocateBlocks(int size, int count) +{ + int i; + unsigned char* buffer; + WAVEHDR* blocks; + DWORD totalBufferSize = (size + sizeof(WAVEHDR))*count; + + if((buffer=(unsigned char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, + totalBufferSize)) == 0) { + qWarning("QAudioOutput: Memory allocation error"); + return 0; + } + blocks = (WAVEHDR*)buffer; + buffer += sizeof(WAVEHDR)*count; + for(i = 0; i < count; i++) { + blocks[i].dwBufferLength = size; + blocks[i].lpData = (LPSTR)buffer; + buffer += size; + } + return blocks; +} + +void QAudioOutputPrivate::freeBlocks(WAVEHDR* blockArray) +{ + WAVEHDR* blocks = blockArray; + + int count = buffer_size/period_size; + + for(int i = 0; i < count; i++) { + waveOutUnprepareHeader(hWaveOut,blocks, sizeof(WAVEHDR)); + blocks++; + } + HeapFree(GetProcessHeap(), 0, blockArray); +} + +QAudioFormat QAudioOutputPrivate::format() const +{ + return settings; +} + +void QAudioOutputPrivate::setFormat(const QAudioFormat& fmt) +{ + if (deviceState == QAudio::StoppedState) + settings = fmt; +} + +void QAudioOutputPrivate::start(QIODevice* device) +{ + if(deviceState != QAudio::StoppedState) + close(); + + if(!pullMode && audioSource) + delete audioSource; + + pullMode = true; + audioSource = device; + + deviceState = QAudio::ActiveState; + + if(!open()) + return; + + emit stateChanged(deviceState); +} + +QIODevice* QAudioOutputPrivate::start() +{ + if(deviceState != QAudio::StoppedState) + close(); + + if(!pullMode && audioSource) + delete audioSource; + + pullMode = false; + audioSource = new OutputPrivate(this); + audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered); + + deviceState = QAudio::IdleState; + + if(!open()) + return 0; + + emit stateChanged(deviceState); + + return audioSource; +} + +void QAudioOutputPrivate::stop() +{ + if(deviceState == QAudio::StoppedState) + return; + close(); + if(!pullMode && audioSource) { + delete audioSource; + audioSource = 0; + } + emit stateChanged(deviceState); +} + +bool QAudioOutputPrivate::open() +{ +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()< 96000) { + qWarning("QAudioOutput: open error, frequency out of range (%d).", settings.frequency()); + } else if (buffer_size == 0) { + // Default buffer size, 200ms, default period size is 40ms + buffer_size + = (settings.frequency() + * settings.channelCount() + * settings.sampleSize() + + 39) / 40; + period_size = buffer_size / 5; + } else { + period_size = buffer_size / 5; + } + + if (period_size == 0) { + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + return false; + } + + waveBlocks = allocateBlocks(period_size, buffer_size/period_size); + + mutex.lock(); + waveFreeBlockCount = buffer_size/period_size; + mutex.unlock(); + + waveCurrentBlock = 0; + + if(audioBuffer == 0) + audioBuffer = new char[buffer_size]; + + timeStamp.restart(); + elapsedTimeOffset = 0; + + wfx.nSamplesPerSec = settings.frequency(); + wfx.wBitsPerSample = settings.sampleSize(); + wfx.nChannels = settings.channels(); + wfx.cbSize = 0; + + bool surround = false; + + if (settings.channels() > 2) + surround = true; + + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels; + wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec; + + QDataStream ds(&m_device, QIODevice::ReadOnly); + quint32 deviceId; + ds >> deviceId; + + if (!surround) { + if (waveOutOpen(&hWaveOut, UINT_PTR(deviceId), &wfx, + (DWORD_PTR)&waveOutProc, + (DWORD_PTR) this, + CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + qWarning("QAudioOutput: open error"); + return false; + } + } else { + WAVEFORMATEXTENSIBLE wfex; + wfex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wfex.Format.nChannels = settings.channels(); + wfex.Format.wBitsPerSample = settings.sampleSize(); + wfex.Format.nSamplesPerSec = settings.frequency(); + wfex.Format.nBlockAlign = wfex.Format.nChannels*wfex.Format.wBitsPerSample/8; + wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec*wfex.Format.nBlockAlign; + wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample; + static const GUID _KSDATAFORMAT_SUBTYPE_PCM = { + 0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; + wfex.SubFormat=_KSDATAFORMAT_SUBTYPE_PCM; + wfex.Format.cbSize=22; + + wfex.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; + if (settings.channels() >= 4) + wfex.dwChannelMask |= SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; + if (settings.channels() >= 6) + wfex.dwChannelMask |= SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY; + if (settings.channels() == 8) + wfex.dwChannelMask |= SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT; + + if (waveOutOpen(&hWaveOut, UINT_PTR(deviceId), &wfex.Format, + (DWORD_PTR)&waveOutProc, + (DWORD_PTR) this, + CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + qWarning("QAudioOutput: open error"); + return false; + } + } + + totalTimeValue = 0; + timeStampOpened.restart(); + elapsedTimeOffset = 0; + + errorState = QAudio::NoError; + if(pullMode) { + deviceState = QAudio::ActiveState; + QTimer::singleShot(10, this, SLOT(feedback())); + } else + deviceState = QAudio::IdleState; + + return true; +} + +void QAudioOutputPrivate::close() +{ + if(deviceState == QAudio::StoppedState) + return; + + deviceState = QAudio::StoppedState; + errorState = QAudio::NoError; + int delay = (buffer_size-bytesFree())*1000/(settings.frequency() + *settings.channels()*(settings.sampleSize()/8)); + waveOutReset(hWaveOut); + Sleep(delay+10); + + freeBlocks(waveBlocks); + waveOutClose(hWaveOut); + delete [] audioBuffer; + audioBuffer = 0; + buffer_size = 0; +} + +int QAudioOutputPrivate::bytesFree() const +{ + int buf; + buf = waveFreeBlockCount*period_size; + + return buf; +} + +int QAudioOutputPrivate::periodSize() const +{ + return period_size; +} + +void QAudioOutputPrivate::setBufferSize(int value) +{ + if(deviceState == QAudio::StoppedState) + buffer_size = value; +} + +int QAudioOutputPrivate::bufferSize() const +{ + return buffer_size; +} + +void QAudioOutputPrivate::setNotifyInterval(int ms) +{ + intervalTime = qMax(0, ms); +} + +int QAudioOutputPrivate::notifyInterval() const +{ + return intervalTime; +} + +qint64 QAudioOutputPrivate::processedUSecs() const +{ + if (deviceState == QAudio::StoppedState) + return 0; + qint64 result = qint64(1000000) * totalTimeValue / + (settings.channels()*(settings.sampleSize()/8)) / + settings.frequency(); + + return result; +} + +qint64 QAudioOutputPrivate::write( const char *data, qint64 len ) +{ + // Write out some audio data + if (deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) + return 0; + + char* p = (char*)data; + int l = (int)len; + + WAVEHDR* current; + int remain; + current = &waveBlocks[waveCurrentBlock]; + while(l > 0) { + mutex.lock(); + if(waveFreeBlockCount==0) { + mutex.unlock(); + break; + } + mutex.unlock(); + + if(current->dwFlags & WHDR_PREPARED) + waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR)); + + if(l < period_size) + remain = l; + else + remain = period_size; + memcpy(current->lpData, p, remain); + + l -= remain; + p += remain; + current->dwBufferLength = remain; + waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR)); + waveOutWrite(hWaveOut, current, sizeof(WAVEHDR)); + + mutex.lock(); + waveFreeBlockCount--; +#ifdef DEBUG_AUDIO + qDebug("write out l=%d, waveFreeBlockCount=%d", + current->dwBufferLength,waveFreeBlockCount); +#endif + mutex.unlock(); + + totalTimeValue += current->dwBufferLength; + waveCurrentBlock++; + waveCurrentBlock %= buffer_size/period_size; + current = &waveBlocks[waveCurrentBlock]; + current->dwUser = 0; + errorState = QAudio::NoError; + if (deviceState != QAudio::ActiveState) { + deviceState = QAudio::ActiveState; + emit stateChanged(deviceState); + } + } + return (len-l); +} + +void QAudioOutputPrivate::resume() +{ + if(deviceState == QAudio::SuspendedState) { + deviceState = QAudio::ActiveState; + errorState = QAudio::NoError; + waveOutRestart(hWaveOut); + QTimer::singleShot(10, this, SLOT(feedback())); + emit stateChanged(deviceState); + } +} + +void QAudioOutputPrivate::suspend() +{ + if(deviceState == QAudio::ActiveState || deviceState == QAudio::IdleState) { + int delay = (buffer_size-bytesFree())*1000/(settings.frequency() + *settings.channels()*(settings.sampleSize()/8)); + waveOutPause(hWaveOut); + Sleep(delay+10); + deviceState = QAudio::SuspendedState; + errorState = QAudio::NoError; + emit stateChanged(deviceState); + } +} + +void QAudioOutputPrivate::feedback() +{ +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()<= period_size) + QMetaObject::invokeMethod(this, "deviceReady", Qt::QueuedConnection); + } +} + +bool QAudioOutputPrivate::deviceReady() +{ + if(deviceState == QAudio::StoppedState || deviceState == QAudio::SuspendedState) + return false; + + if(pullMode) { + int chunks = bytesAvailable/period_size; +#ifdef DEBUG_AUDIO + qDebug()<<"deviceReady() avail="< intervalTime ) { + emit notify(); + elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime; + timeStamp.restart(); + } + return true; + } + + if(startup) + waveOutPause(hWaveOut); + int input = period_size*chunks; + int l = audioSource->read(audioBuffer,input); + if(l > 0) { + int out= write(audioBuffer,l); + if(out > 0) { + if (deviceState != QAudio::ActiveState) { + deviceState = QAudio::ActiveState; + emit stateChanged(deviceState); + } + } + if ( out < l) { + // Didn't write all data + audioSource->seek(audioSource->pos()-(l-out)); + } + if(startup) + waveOutRestart(hWaveOut); + } else if(l == 0) { + bytesAvailable = bytesFree(); + + int check = 0; + + mutex.lock(); + check = waveFreeBlockCount; + mutex.unlock(); + + if(check == buffer_size/period_size) { + if (deviceState != QAudio::IdleState) { + errorState = QAudio::UnderrunError; + deviceState = QAudio::IdleState; + emit stateChanged(deviceState); + } + } + + } else if(l < 0) { + bytesAvailable = bytesFree(); + if (errorState != QAudio::IOError) + errorState = QAudio::IOError; + } + } else { + int buffered; + + mutex.lock(); + buffered = waveFreeBlockCount; + mutex.unlock(); + + if (buffered >= buffer_size/period_size && deviceState == QAudio::ActiveState) { + if (deviceState != QAudio::IdleState) { + errorState = QAudio::UnderrunError; + deviceState = QAudio::IdleState; + emit stateChanged(deviceState); + } + } + } + if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) + return true; + + if(intervalTime && (timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) { + emit notify(); + elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime; + timeStamp.restart(); + } + + return true; +} + +qint64 QAudioOutputPrivate::elapsedUSecs() const +{ + if (deviceState == QAudio::StoppedState) + return 0; + + return timeStampOpened.elapsed()*1000; +} + +QAudio::Error QAudioOutputPrivate::error() const +{ + return errorState; +} + +QAudio::State QAudioOutputPrivate::state() const +{ + return deviceState; +} + +void QAudioOutputPrivate::reset() +{ + close(); +} + +OutputPrivate::OutputPrivate(QAudioOutputPrivate* audio) +{ + audioDevice = qobject_cast(audio); +} + +OutputPrivate::~OutputPrivate() {} + +qint64 OutputPrivate::readData( char* data, qint64 len) +{ + Q_UNUSED(data) + Q_UNUSED(len) + + return 0; +} + +qint64 OutputPrivate::writeData(const char* data, qint64 len) +{ + int retry = 0; + qint64 written = 0; + + if((audioDevice->deviceState == QAudio::ActiveState) + ||(audioDevice->deviceState == QAudio::IdleState)) { + qint64 l = len; + while(written < l) { + int chunk = audioDevice->write(data+written,(l-written)); + if(chunk <= 0) + retry++; + else + written+=chunk; + + if(retry > 10) + return written; + } + audioDevice->deviceState = QAudio::ActiveState; + } + return written; +} + +QT_END_NAMESPACE + +#include "moc_qaudiooutput_win32_p.cpp" diff --git a/src/multimediakit/audio/qaudiooutput_win32_p.h b/src/multimediakit/audio/qaudiooutput_win32_p.h new file mode 100644 index 000000000..53cfe71f7 --- /dev/null +++ b/src/multimediakit/audio/qaudiooutput_win32_p.h @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QAUDIOOUTPUTWIN_H +#define QAUDIOOUTPUTWIN_H + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// For compat with 4.6 +#if !defined(QT_WIN_CALLBACK) +# if defined(Q_CC_MINGW) +# define QT_WIN_CALLBACK CALLBACK __attribute__ ((force_align_arg_pointer)) +# else +# define QT_WIN_CALLBACK CALLBACK +# endif +#endif + +QT_BEGIN_NAMESPACE + +class QAudioOutputPrivate : public QAbstractAudioOutput +{ + Q_OBJECT +public: + QAudioOutputPrivate(const QByteArray &device); + ~QAudioOutputPrivate(); + + qint64 write( const char *data, qint64 len ); + + void setFormat(const QAudioFormat& fmt); + QAudioFormat format() const; + QIODevice* start(); + void start(QIODevice* device); + void stop(); + void reset(); + void suspend(); + void resume(); + int bytesFree() const; + int periodSize() const; + void setBufferSize(int value); + int bufferSize() const; + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + QAudio::Error error() const; + QAudio::State state() const; + + QIODevice* audioSource; + QAudioFormat settings; + QAudio::Error errorState; + QAudio::State deviceState; + +private slots: + void feedback(); + bool deviceReady(); + +private: + QByteArray m_device; + bool resuming; + int bytesAvailable; + QTime timeStamp; + qint64 elapsedTimeOffset; + QTime timeStampOpened; + qint32 buffer_size; + qint32 period_size; + qint64 totalTimeValue; + bool pullMode; + int intervalTime; + static void QT_WIN_CALLBACK waveOutProc( HWAVEOUT hWaveOut, UINT uMsg, + DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ); + + QMutex mutex; + + WAVEHDR* allocateBlocks(int size, int count); + void freeBlocks(WAVEHDR* blockArray); + bool open(); + void close(); + + WAVEFORMATEX wfx; + HWAVEOUT hWaveOut; + MMRESULT result; + WAVEHDR header; + WAVEHDR* waveBlocks; + volatile bool finished; + volatile int waveFreeBlockCount; + int waveCurrentBlock; + char* audioBuffer; +}; + +class OutputPrivate : public QIODevice +{ + Q_OBJECT +public: + OutputPrivate(QAudioOutputPrivate* audio); + ~OutputPrivate(); + + qint64 readData( char* data, qint64 len); + qint64 writeData(const char* data, qint64 len); + +private: + QAudioOutputPrivate *audioDevice; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/audio/qaudiopluginloader.cpp b/src/multimediakit/audio/qaudiopluginloader.cpp new file mode 100644 index 000000000..fc83f7a63 --- /dev/null +++ b/src/multimediakit/audio/qaudiopluginloader.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaudiosystemplugin.h" +#include "qaudiopluginloader_p.h" + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +QAudioPluginLoader::QAudioPluginLoader(const char *iid, const QString &location, Qt::CaseSensitivity): + m_iid(iid) +{ + m_location = location + "/"; + load(); +} + +QAudioPluginLoader::~QAudioPluginLoader() +{ + for (int i = 0; i < m_plugins.count(); i++ ) { + delete m_plugins.at(i); + } +} + +QStringList QAudioPluginLoader::pluginList() const +{ +#if !defined QT_NO_DEBUG + const bool showDebug = qgetenv("QT_DEBUG_PLUGINS").toInt() > 0; +#endif + + QStringList paths = QApplication::libraryPaths(); +#ifdef QTM_PLUGIN_PATH + paths << QLatin1String(QTM_PLUGIN_PATH); +#endif +#if !defined QT_NO_DEBUG + if (showDebug) + qDebug() << "Plugin paths:" << paths; +#endif + + //temp variable to avoid multiple identic path + QSet processed; + + /* Discover a bunch o plugins */ + QStringList plugins; + + /* Enumerate our plugin paths */ + for (int i=0; i < paths.count(); i++) { + if (processed.contains(paths.at(i))) + continue; + processed.insert(paths.at(i)); + QDir pluginsDir(paths.at(i)+m_location); + if (!pluginsDir.exists()) + continue; + + QStringList files = pluginsDir.entryList(QDir::Files); +#if !defined QT_NO_DEBUG + if (showDebug) + qDebug()<<"Looking for plugins in "<(&m_mutex)); + + QStringList list; + for (int i = 0; i < m_plugins.count(); i++) { + QAudioSystemPlugin* p = qobject_cast(m_plugins.at(i)->instance()); + if (p) list << p->keys(); + } + + return list; +} + +QObject* QAudioPluginLoader::instance(QString const &key) +{ + QMutexLocker locker(&m_mutex); + + for (int i = 0; i < m_plugins.count(); i++) { + QAudioSystemPlugin* p = qobject_cast(m_plugins.at(i)->instance()); + if (p && p->keys().contains(key)) + return m_plugins.at(i)->instance(); + } + return 0; +} + +QList QAudioPluginLoader::instances(QString const &key) +{ + QMutexLocker locker(&m_mutex); + + QList list; + for (int i = 0; i < m_plugins.count(); i++) { + QAudioSystemPlugin* p = qobject_cast(m_plugins.at(i)->instance()); + if (p && p->keys().contains(key)) + list << m_plugins.at(i)->instance(); + } + return list; +} + +void QAudioPluginLoader::load() +{ + if (!m_plugins.isEmpty()) + return; + +#if !defined QT_NO_DEBUG + const bool showDebug = qgetenv("QT_DEBUG_PLUGINS").toInt() > 0; +#endif + + QStringList plugins = pluginList(); + for (int i=0; i < plugins.count(); i++) { + QPluginLoader* loader = new QPluginLoader(plugins.at(i)); + QObject *o = loader->instance(); + if (o != 0 && o->qt_metacast(m_iid) != 0) { + m_plugins.append(loader); + } else { +#if !defined QT_NO_DEBUG + if (showDebug) + qWarning() << "QAudioPluginLoader: Failed to load plugin: " + << plugins.at(i) << loader->errorString(); +#endif + delete o; + //we are not calling loader->unload here for it may cause problem on some device + delete loader; + } + } +} +QT_END_NAMESPACE + diff --git a/src/multimediakit/audio/qaudiopluginloader_p.h b/src/multimediakit/audio/qaudiopluginloader_p.h new file mode 100644 index 000000000..6d5fef313 --- /dev/null +++ b/src/multimediakit/audio/qaudiopluginloader_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAUDIOPLUGINLOADER_H +#define QAUDIOPLUGINLOADER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include +#include + + +QT_BEGIN_NAMESPACE + +class QAudioPluginLoader +{ +public: + QAudioPluginLoader(const char *iid, + const QString &suffix = QString(), + Qt::CaseSensitivity = Qt::CaseSensitive); + + ~QAudioPluginLoader(); + + QStringList keys() const; + QObject* instance(QString const &key); + QList instances(QString const &key); + +private: + QStringList pluginList() const; + void load(); + + QMutex m_mutex; + + QByteArray m_iid; + QString m_location; + QList m_plugins; +}; + +QT_END_NAMESPACE + +#endif // QAUDIOPLUGINLOADER_H diff --git a/src/multimediakit/audio/qaudiosystem.cpp b/src/multimediakit/audio/qaudiosystem.cpp new file mode 100644 index 000000000..5b2b0c3be --- /dev/null +++ b/src/multimediakit/audio/qaudiosystem.cpp @@ -0,0 +1,423 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaudiosystem.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QAbstractAudioDeviceInfo + \brief The QAbstractAudioDeviceInfo class is a base class for audio backends. + + \ingroup multimedia + \inmodule QtMultimediaKit + \internal + \since 1.0 + + This class implements the audio functionality for + QAudioDeviceInfo, i.e., QAudioDeviceInfo keeps a + QAbstractAudioDeviceInfo and routes function calls to it. For a + description of the functionality that QAbstractAudioDeviceInfo + implements, you can read the class and functions documentation of + QAudioDeviceInfo. + + \sa QAudioDeviceInfo + \sa QAbstractAudioOutput, QAbstractAudioInput +*/ + +/*! + \fn virtual QAudioFormat QAbstractAudioDeviceInfo::preferredFormat() const + Returns the recommended settings to use. + \since 1.0 +*/ + +/*! + \fn virtual bool QAbstractAudioDeviceInfo::isFormatSupported(const QAudioFormat& format) const + Returns true if \a format is available from audio device. + \since 1.0 +*/ + +/*! + \fn virtual QString QAbstractAudioDeviceInfo::deviceName() const + Returns the audio device name. + \since 1.0 +*/ + +/*! + \fn virtual QStringList QAbstractAudioDeviceInfo::supportedCodecs() + Returns the list of currently available codecs. + \since 1.0 +*/ + +/*! + \fn virtual QList QAbstractAudioDeviceInfo::supportedSampleRates() + Returns the list of currently available sample rates. + \since 1.0 +*/ + +/*! + \fn virtual QList QAbstractAudioDeviceInfo::supportedChannelCounts() + Returns the list of currently available channels. + \since 1.0 +*/ + +/*! + \fn virtual QList QAbstractAudioDeviceInfo::supportedSampleSizes() + Returns the list of currently available sample sizes. + \since 1.0 +*/ + +/*! + \fn virtual QList QAbstractAudioDeviceInfo::supportedByteOrders() + Returns the list of currently available byte orders. + \since 1.0 +*/ + +/*! + \fn virtual QList QAbstractAudioDeviceInfo::supportedSampleTypes() + Returns the list of currently available sample types. + \since 1.0 +*/ + +/*! + \class QAbstractAudioOutput + \brief The QAbstractAudioOutput class is a base class for audio backends. + \since 1.0 + + \ingroup multimedia + \inmodule QtMultimediaKit + \internal + + QAbstractAudioOutput implements audio functionality for + QAudioOutput, i.e., QAudioOutput routes function calls to + QAbstractAudioOutput. For a description of the functionality that + is implemented, see the QAudioOutput class and function + descriptions. + + \sa QAudioOutput +*/ + +/*! + \fn virtual void QAbstractAudioOutput::start(QIODevice* device) + Uses the \a device as the QIODevice to transfer data. + \since 1.0 +*/ + +/*! + \fn virtual QIODevice* QAbstractAudioOutput::start() + Returns a pointer to the QIODevice being used to handle + the data transfer. This QIODevice can be used to write() audio data directly. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioOutput::stop() + Stops the audio output. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioOutput::reset() + Drops all audio data in the buffers, resets buffers to zero. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioOutput::suspend() + Stops processing audio data, preserving buffered audio data. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioOutput::resume() + Resumes processing audio data after a suspend() + \since 1.0 +*/ + +/*! + \fn virtual int QAbstractAudioOutput::bytesFree() const + Returns the free space available in bytes in the audio buffer. + \since 1.0 +*/ + +/*! + \fn virtual int QAbstractAudioOutput::periodSize() const + Returns the period size in bytes. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioOutput::setBufferSize(int value) + Sets the audio buffer size to \a value in bytes. + \since 1.0 +*/ + +/*! + \fn virtual int QAbstractAudioOutput::bufferSize() const + Returns the audio buffer size in bytes. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioOutput::setNotifyInterval(int ms) + Sets the interval for notify() signal to be emitted. This is based on the \a ms + of audio data processed not on actual real-time. The resolution of the timer + is platform specific. + \since 1.0 +*/ + +/*! + \fn virtual int QAbstractAudioOutput::notifyInterval() const + Returns the notify interval in milliseconds. + \since 1.0 +*/ + +/*! + \fn virtual qint64 QAbstractAudioOutput::processedUSecs() const + Returns the amount of audio data processed since start() was called in milliseconds. + \since 1.0 +*/ + +/*! + \fn virtual qint64 QAbstractAudioOutput::elapsedUSecs() const + Returns the milliseconds since start() was called, including time in Idle and suspend states. + \since 1.0 +*/ + +/*! + \fn virtual QAudio::Error QAbstractAudioOutput::error() const + Returns the error state. + \since 1.0 +*/ + +/*! + \fn virtual QAudio::State QAbstractAudioOutput::state() const + Returns the state of audio processing. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioOutput::setFormat(const QAudioFormat& fmt) + Set the QAudioFormat to use to \a fmt. + Setting the format is only allowable while in QAudio::StoppedState. + \since 1.0 +*/ + +/*! + \fn virtual QAudioFormat QAbstractAudioOutput::format() const + Returns the QAudioFormat being used. + \since 1.0 +*/ + +/*! + \fn QAbstractAudioOutput::errorChanged(QAudio::Error error) + This signal is emitted when the \a error state has changed. + \since 1.0 +*/ + +/*! + \fn QAbstractAudioOutput::stateChanged(QAudio::State state) + This signal is emitted when the device \a state has changed. + \since 1.0 +*/ + +/*! + \fn QAbstractAudioOutput::notify() + This signal is emitted when x ms of audio data has been processed + the interval set by setNotifyInterval(x). + \since 1.0 +*/ + + +/*! + \class QAbstractAudioInput + \brief The QAbstractAudioInput class provides access for QAudioInput to access the audio + device provided by the plugin. + \since 1.0 + + \ingroup multimedia + \inmodule QtMultimediaKit + \internal + + QAudioDeviceInput keeps an instance of QAbstractAudioInput and + routes calls to functions of the same name to QAbstractAudioInput. + This means that it is QAbstractAudioInput that implements the + audio functionality. For a description of the functionality, see + the QAudioInput class description. + + \sa QAudioInput +*/ + +/*! + \fn virtual void QAbstractAudioInput::start(QIODevice* device) + Uses the \a device as the QIODevice to transfer data. + \since 1.0 +*/ + +/*! + \fn virtual QIODevice* QAbstractAudioInput::start() + Returns a pointer to the QIODevice being used to handle + the data transfer. This QIODevice can be used to read() audio data directly. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioInput::stop() + Stops the audio input. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioInput::reset() + Drops all audio data in the buffers, resets buffers to zero. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioInput::suspend() + Stops processing audio data, preserving buffered audio data. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioInput::resume() + Resumes processing audio data after a suspend(). + \since 1.0 +*/ + +/*! + \fn virtual int QAbstractAudioInput::bytesReady() const + Returns the amount of audio data available to read in bytes. + \since 1.0 +*/ + +/*! + \fn virtual int QAbstractAudioInput::periodSize() const + Returns the period size in bytes. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioInput::setBufferSize(int value) + Sets the audio buffer size to \a value in milliseconds. + \since 1.0 +*/ + +/*! + \fn virtual int QAbstractAudioInput::bufferSize() const + Returns the audio buffer size in milliseconds. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioInput::setNotifyInterval(int ms) + Sets the interval for notify() signal to be emitted. This is based + on the \a ms of audio data processed not on actual real-time. + The resolution of the timer is platform specific. + \since 1.0 +*/ + +/*! + \fn virtual int QAbstractAudioInput::notifyInterval() const + Returns the notify interval in milliseconds. + \since 1.0 +*/ + +/*! + \fn virtual qint64 QAbstractAudioInput::processedUSecs() const + Returns the amount of audio data processed since start() was called in milliseconds. + \since 1.0 +*/ + +/*! + \fn virtual qint64 QAbstractAudioInput::elapsedUSecs() const + Returns the milliseconds since start() was called, including time in Idle and suspend states. + \since 1.0 +*/ + +/*! + \fn virtual QAudio::Error QAbstractAudioInput::error() const + Returns the error state. + \since 1.0 +*/ + +/*! + \fn virtual QAudio::State QAbstractAudioInput::state() const + Returns the state of audio processing. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioInput::setFormat(const QAudioFormat& fmt) + Set the QAudioFormat to use to \a fmt. + Setting the format is only allowable while in QAudio::StoppedState. + \since 1.0 +*/ + +/*! + \fn virtual QAudioFormat QAbstractAudioInput::format() const + Returns the QAudioFormat being used + \since 1.0 +*/ + +/*! + \fn QAbstractAudioInput::errorChanged(QAudio::Error error) + This signal is emitted when the \a error state has changed. + \since 1.0 +*/ + +/*! + \fn QAbstractAudioInput::stateChanged(QAudio::State state) + This signal is emitted when the device \a state has changed. + \since 1.0 +*/ + +/*! + \fn QAbstractAudioInput::notify() + This signal is emitted when x ms of audio data has been processed + the interval set by setNotifyInterval(x). + \since 1.0 +*/ + + +QT_END_NAMESPACE + +#include "moc_qaudiosystem.cpp" diff --git a/src/multimediakit/audio/qaudiosystem.h b/src/multimediakit/audio/qaudiosystem.h new file mode 100644 index 000000000..f2875a5cd --- /dev/null +++ b/src/multimediakit/audio/qaudiosystem.h @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAUDIOSYSTEM_H +#define QAUDIOSYSTEM_H + +#include +#include + +#include "qaudio.h" +#include "qaudioformat.h" +#include "qaudiodeviceinfo.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QAbstractAudioDeviceInfo : public QObject +{ + Q_OBJECT + +public: + virtual QAudioFormat preferredFormat() const = 0; + virtual bool isFormatSupported(const QAudioFormat &format) const = 0; + virtual QString deviceName() const = 0; + virtual QStringList supportedCodecs() = 0; + virtual QList supportedSampleRates() = 0; + virtual QList supportedChannelCounts() = 0; + virtual QList supportedSampleSizes() = 0; + virtual QList supportedByteOrders() = 0; + virtual QList supportedSampleTypes() = 0; +}; + +class Q_MULTIMEDIA_EXPORT QAbstractAudioOutput : public QObject +{ + Q_OBJECT + +public: + virtual void start(QIODevice *device) = 0; + virtual QIODevice* start() = 0; + virtual void stop() = 0; + virtual void reset() = 0; + virtual void suspend() = 0; + virtual void resume() = 0; + virtual int bytesFree() const = 0; + virtual int periodSize() const = 0; + virtual void setBufferSize(int value) = 0; + virtual int bufferSize() const = 0; + virtual void setNotifyInterval(int milliSeconds) = 0; + virtual int notifyInterval() const = 0; + virtual qint64 processedUSecs() const = 0; + virtual qint64 elapsedUSecs() const = 0; + virtual QAudio::Error error() const = 0; + virtual QAudio::State state() const = 0; + virtual void setFormat(const QAudioFormat& fmt) = 0; + virtual QAudioFormat format() const = 0; + +Q_SIGNALS: + void errorChanged(QAudio::Error); + void stateChanged(QAudio::State); + void notify(); +}; + +class Q_MULTIMEDIA_EXPORT QAbstractAudioInput : public QObject +{ + Q_OBJECT + +public: + virtual void start(QIODevice *device) = 0; + virtual QIODevice* start() = 0; + virtual void stop() = 0; + virtual void reset() = 0; + virtual void suspend() = 0; + virtual void resume() = 0; + virtual int bytesReady() const = 0; + virtual int periodSize() const = 0; + virtual void setBufferSize(int value) = 0; + virtual int bufferSize() const = 0; + virtual void setNotifyInterval(int milliSeconds) = 0; + virtual int notifyInterval() const = 0; + virtual qint64 processedUSecs() const = 0; + virtual qint64 elapsedUSecs() const = 0; + virtual QAudio::Error error() const = 0; + virtual QAudio::State state() const = 0; + virtual void setFormat(const QAudioFormat& fmt) = 0; + virtual QAudioFormat format() const = 0; + +Q_SIGNALS: + void errorChanged(QAudio::Error); + void stateChanged(QAudio::State); + void notify(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIOSYSTEM_H diff --git a/src/multimediakit/audio/qaudiosystemplugin.cpp b/src/multimediakit/audio/qaudiosystemplugin.cpp new file mode 100644 index 000000000..3744b6f88 --- /dev/null +++ b/src/multimediakit/audio/qaudiosystemplugin.cpp @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qaudiosystemplugin.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QAudioSystemPlugin + \brief The QAudioSystemPlugin class provides an abstract base for audio plugins. + \since 1.0 + + \ingroup multimedia + \inmodule QtMultimediaKit + \internal + + Writing a audio plugin is achieved by subclassing this base class, + reimplementing the pure virtual functions keys(), availableDevices(), + createInput(), createOutput() and createDeviceInfo() then exporting + the class with the Q_EXPORT_PLUGIN2() macro. + + Unit tests are available to help in debugging new plugins. + + \sa QAbstractAudioDeviceInfo, QAbstractAudioOutput, QAbstractAudioInput + + Qt supports win32, linux(alsa) and Mac OS X standard (builtin to the + QtMultimediaKit library at compile time). + + You can support other backends other than these predefined ones by + creating a plugin subclassing QAudioSystemPlugin, QAbstractAudioDeviceInfo, + QAbstractAudioOutput and QAbstractAudioInput. + + Add "default" to your list of keys() available to override the default + audio device to be provided by your plugin. + + -audio-backend configure option will force compiling in of the builtin backend + into the QtMultimediaKit library at compile time. This is automatic by default + and will only be compiled into the library if the dependencies are installed. + eg. alsa-devel package installed for linux. + + If the builtin backend is not compiled into the QtMultimediaKit library and + no audio plugins are available a fallback dummy backend will be used. + This should print out warnings if this is the case when you try and use QAudioInput or QAudioOutput. To fix this problem + reconfigure Qt using -audio-backend or create your own plugin with a default + key to always override the dummy fallback. The easiest way to determine + if you have only a dummy backend is to get a list of available audio devices. + + QAudioDeviceInfo::availableDevices(QAudio::AudioOutput).size() = 0 (dummy backend) +*/ + +/*! + Construct a new audio plugin with \a parent. + This is invoked automatically by the Q_EXPORT_PLUGIN2() macro. +*/ + +QAudioSystemPlugin::QAudioSystemPlugin(QObject* parent) : + QObject(parent) +{} + +/*! + Destroy the audio plugin + + You never have to call this explicitly. Qt destroys a plugin automatically when it is no longer used. +*/ + +QAudioSystemPlugin::~QAudioSystemPlugin() +{} + +/*! + \fn QStringList QAudioSystemPlugin::keys() const + Returns the list of device identifiers this plugin supports. + \since 1.0 +*/ + +/*! + \fn QList QAudioSystemPlugin::availableDevices(QAudio::Mode mode) const + Returns a list of available audio devices for \a mode + \since 1.0 +*/ + +/*! + \fn QAbstractAudioInput* QAudioSystemPlugin::createInput(const QByteArray& device) + Returns a pointer to a QAbstractAudioInput created using \a device identifier + \since 1.0 +*/ + +/*! + \fn QAbstractAudioOutput* QAudioSystemPlugin::createOutput(const QByteArray& device) + Returns a pointer to a QAbstractAudioOutput created using \a device identifier + + \since 1.0 +*/ + +/*! + \fn QAbstractAudioDeviceInfo* QAudioSystemPlugin::createDeviceInfo(const QByteArray& device, QAudio::Mode mode) + Returns a pointer to a QAbstractAudioDeviceInfo created using \a device and \a mode + + \since 1.0 +*/ + + +QT_END_NAMESPACE + +#include "moc_qaudiosystemplugin.cpp" diff --git a/src/multimediakit/audio/qaudiosystemplugin.h b/src/multimediakit/audio/qaudiosystemplugin.h new file mode 100644 index 000000000..740e1e427 --- /dev/null +++ b/src/multimediakit/audio/qaudiosystemplugin.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QAUDIOSYSTEMPLUGIN_H +#define QAUDIOSYSTEMPLUGIN_H + +#include +#include +#include + +#include +#include + +#include "qaudioformat.h" +#include "qaudiodeviceinfo.h" +#include "qaudiosystem.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +struct Q_MULTIMEDIA_EXPORT QAudioSystemFactoryInterface : public QFactoryInterface +{ + virtual QList availableDevices(QAudio::Mode) const = 0; + virtual QAbstractAudioInput* createInput(const QByteArray& device) = 0; + virtual QAbstractAudioOutput* createOutput(const QByteArray& device) = 0; + virtual QAbstractAudioDeviceInfo* createDeviceInfo(const QByteArray& device, QAudio::Mode mode) = 0; +}; + +#define QAudioSystemFactoryInterface_iid \ + "com.nokia.qt.QAudioSystemFactoryInterface" +Q_DECLARE_INTERFACE(QAudioSystemFactoryInterface, QAudioSystemFactoryInterface_iid) + +class Q_MULTIMEDIA_EXPORT QAudioSystemPlugin : public QObject, public QAudioSystemFactoryInterface +{ + Q_OBJECT + Q_INTERFACES(QAudioSystemFactoryInterface:QFactoryInterface) + +public: + QAudioSystemPlugin(QObject *parent = 0); + ~QAudioSystemPlugin(); + + virtual QStringList keys() const = 0; + virtual QList availableDevices(QAudio::Mode) const = 0; + virtual QAbstractAudioInput* createInput(const QByteArray& device) = 0; + virtual QAbstractAudioOutput* createOutput(const QByteArray& device) = 0; + virtual QAbstractAudioDeviceInfo* createDeviceInfo(const QByteArray& device, QAudio::Mode mode) = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIOSYSTEMPLUGIN_H diff --git a/src/multimediakit/effects/effects.pri b/src/multimediakit/effects/effects.pri new file mode 100644 index 000000000..911bd9b62 --- /dev/null +++ b/src/multimediakit/effects/effects.pri @@ -0,0 +1,32 @@ +INCLUDEPATH += effects + +unix:!mac:!symbian { + contains(pulseaudio_enabled, yes) { + CONFIG += link_pkgconfig + PKGCONFIG += libpulse + + DEFINES += QT_MULTIMEDIA_PULSEAUDIO + PRIVATE_HEADERS += effects/qsoundeffect_pulse_p.h + SOURCES += effects/qsoundeffect_pulse_p.cpp + !maemo*:DEFINES += QTM_PULSEAUDIO_DEFAULTBUFFER + } else { + DEFINES += QT_MULTIMEDIA_QMEDIAPLAYER + PRIVATE_HEADERS += effects/qsoundeffect_qmedia_p.h + SOURCES += effects/qsoundeffect_qmedia_p.cpp + } +} else { + PRIVATE_HEADERS += effects/qsoundeffect_qsound_p.h + SOURCES += effects/qsoundeffect_qsound_p.cpp +} + +PRIVATE_HEADERS += \ + effects/qsoundeffect_p.h \ + effects/qwavedecoder_p.h \ + effects/qsamplecache_p.h + +SOURCES += \ + effects/qsoundeffect.cpp \ + effects/qwavedecoder_p.cpp \ + effects/qsamplecache_p.cpp + +HEADERS += diff --git a/src/multimediakit/effects/qsamplecache_p.cpp b/src/multimediakit/effects/qsamplecache_p.cpp new file mode 100644 index 000000000..d86aa2493 --- /dev/null +++ b/src/multimediakit/effects/qsamplecache_p.cpp @@ -0,0 +1,398 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsamplecache_p.h" +#include "qwavedecoder_p.h" +#include + +//#define QT_SAMPLECACHE_DEBUG + +QT_BEGIN_NAMESPACE + + +/*! + \class QSampleCache + \internal + + When you want to get a sound sample data, you need to request the QSample reference from QSampleCache. + + \since 1.1 + + \code + QSample *m_sample; // class member. + + private Q_SLOTS: + void decoderError(); + void sampleReady(); + \endcode + + \code + Q_GLOBAL_STATIC(QSampleCache, sampleCache) //declare a singleton manager + \endcode + + \code + m_sample = sampleCache()->requestSample(url); + switch(m_sample->state()) { + case QSample::Ready: + sampleReady(); + break; + case QSample::Error: + decoderError(); + break; + default: + connect(m_sample, SIGNAL(error()), this, SLOT(decoderError())); + connect(m_sample, SIGNAL(ready()), this, SLOT(sampleReady())); + break; + } + \endcode + + When you no longer need the sound sample data, you need to release it: + + \code + if (m_sample) { + m_sample->release(); + m_sample = 0; + } + \endcode +*/ + +QSampleCache::QSampleCache() + : m_networkAccessManager(0) + , m_mutex(QMutex::Recursive) + , m_capacity(0) + , m_usage(0) +{ + m_loadingThread.setObjectName(QLatin1String("QSampleCache::LoadingThread")); +} + +QNetworkAccessManager& QSampleCache::networkAccessManager() +{ + if (!m_networkAccessManager) + m_networkAccessManager = new QNetworkAccessManager(); + return *m_networkAccessManager; +} + +QSampleCache::~QSampleCache() +{ + QMutexLocker m(&m_mutex); + + m_loadingThread.quit(); + m_loadingThread.wait(); + + // Killing the loading thread means that no samples can be + // deleted using deleteLater. And some samples that had deleteLater + // already called won't have been processed (m_staleSamples) + foreach (QSample* sample, m_samples) + delete sample; + + foreach (QSample* sample, m_staleSamples) + delete sample; // deleting a sample does affect the m_staleSamples list, but foreach copies it + + delete m_networkAccessManager; +} + +QSample* QSampleCache::requestSample(const QUrl& url) +{ + if (!m_loadingThread.isRunning()) + m_loadingThread.start(); +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "QSampleCache: request sample [" << url << "]"; +#endif + QMutexLocker locker(&m_mutex); + QMap::iterator it = m_samples.find(url); + QSample* sample; + if (it == m_samples.end()) { + sample = new QSample(url, this); + m_samples.insert(url, sample); + sample->moveToThread(&m_loadingThread); + } else { + sample = *it; + } + + sample->addRef(); + locker.unlock(); + + sample->loadIfNecessary(); + return sample; +} + +void QSampleCache::setCapacity(qint64 capacity) +{ + QMutexLocker locker(&m_mutex); + if (m_capacity == capacity) + return; +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "QSampleCache: capacity changes from " << m_capacity << "to " << capacity; +#endif + if (m_capacity > 0 && capacity <= 0) { //memory management strategy changed + for (QMap::iterator it = m_samples.begin(); it != m_samples.end();) { + QSample* sample = *it; + if (sample->m_ref == 0) { + unloadSample(sample); + it = m_samples.erase(it); + } else + it++; + } + } + + m_capacity = capacity; + refresh(0); +} + +// Called locked +void QSampleCache::unloadSample(QSample *sample) +{ + m_usage -= sample->m_soundData.size(); + m_staleSamples.insert(sample); + sample->deleteLater(); +} + +// Called in both threads +void QSampleCache::refresh(qint64 usageChange) +{ + QMutexLocker locker(&m_mutex); + m_usage += usageChange; + if (m_capacity <= 0 || m_usage <= m_capacity) + return; + +#ifdef QT_SAMPLECACHE_DEBUG + qint64 recoveredSize = 0; +#endif + + //free unused samples to keep usage under capacity limit. + for (QMap::iterator it = m_samples.begin(); it != m_samples.end();) { + QSample* sample = *it; + if (sample->m_ref > 0) { + ++it; + continue; + } +#ifdef QT_SAMPLECACHE_DEBUG + recoveredSize += sample->m_soundData.size(); +#endif + unloadSample(sample); + it = m_samples.erase(it); + if (m_usage <= m_capacity) + return; + } + +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "QSampleCache: refresh(" << usageChange + << ") recovered size =" << recoveredSize + << "new usage =" << m_usage; +#endif + + if (m_usage > m_capacity) + qWarning() << "QSampleCache: usage[" << m_usage << " out of limit[" << m_capacity << "]"; +} + +// Called in both threads +void QSampleCache::removeUnreferencedSample(QSample *sample) +{ + QMutexLocker m(&m_mutex); + m_staleSamples.remove(sample); +} + +// Called in loader thread (since this lives in that thread) +// Also called from application thread after loader thread dies. +QSample::~QSample() +{ + // Remove ourselves from our parent + m_parent->removeUnreferencedSample(this); + + QMutexLocker locker(&m_mutex); +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "~QSample" << this << ": deleted [" << m_url << "]" << QThread::currentThread(); +#endif + cleanup(); +} + +// Called in application thread +void QSample::loadIfNecessary() +{ + QMutexLocker locker(&m_mutex); + if (m_state == QSample::Error || m_state == QSample::Creating) { + m_state = QSample::Loading; + QMetaObject::invokeMethod(this, "load", Qt::QueuedConnection); + } +} + +// Called in both threads +bool QSampleCache::notifyUnreferencedSample(QSample* sample) +{ + QMutexLocker locker(&m_mutex); + if (m_capacity > 0) + return false; + m_samples.remove(sample->m_url); + m_staleSamples.insert(sample); + sample->deleteLater(); + return true; +} + +// Called in application threadd +void QSample::release() +{ + QMutexLocker locker(&m_mutex); +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "Sample:: release" << this << QThread::currentThread() << m_ref; +#endif + m_ref--; + if (m_ref == 0) + m_parent->notifyUnreferencedSample(this); +} + +// Called in dtor and when stream is loaded +// must be called locked. +void QSample::cleanup() +{ + delete m_waveDecoder; + delete m_stream; + m_waveDecoder = 0; + m_stream = 0; +} + +// Called in application thread +void QSample::addRef() +{ + m_ref++; +} + +// Called in loading thread +void QSample::readSample() +{ + Q_ASSERT(QThread::currentThread()->objectName() == "QSampleCache::LoadingThread"); + QMutexLocker m(&m_mutex); +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "QSample: readSample"; +#endif + qint64 read = m_waveDecoder->read(m_soundData.data() + m_sampleReadLength, + qMin(m_waveDecoder->bytesAvailable(), + qint64(m_waveDecoder->size() - m_sampleReadLength))); + if (read > 0) + m_sampleReadLength += read; + if (m_sampleReadLength < m_waveDecoder->size()) + return; + Q_ASSERT(m_sampleReadLength == qint64(m_soundData.size())); + onReady(); +} + +// Called in loading thread +void QSample::decoderReady() +{ + Q_ASSERT(QThread::currentThread()->objectName() == "QSampleCache::LoadingThread"); + QMutexLocker m(&m_mutex); +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "QSample: decoder ready"; +#endif + m_parent->refresh(m_waveDecoder->size()); + + m_soundData.resize(m_waveDecoder->size()); + m_sampleReadLength = 0; + qint64 read = m_waveDecoder->read(m_soundData.data(), m_waveDecoder->size()); + if (read > 0) + m_sampleReadLength += read; + if (m_sampleReadLength >= m_waveDecoder->size()) + onReady(); +} + +// Called in all threads +QSample::State QSample::state() const +{ + QMutexLocker m(&m_mutex); + return m_state; +} + +// Called in loading thread +// Essentially a second ctor, doesn't need locks (?) +void QSample::load() +{ + Q_ASSERT(QThread::currentThread()->objectName() == "QSampleCache::LoadingThread"); +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "QSample: load [" << m_url << "]"; +#endif + m_stream = m_parent->networkAccessManager().get(QNetworkRequest(m_url)); + connect(m_stream, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(decoderError())); + m_waveDecoder = new QWaveDecoder(m_stream); + connect(m_waveDecoder, SIGNAL(formatKnown()), SLOT(decoderReady())); + connect(m_waveDecoder, SIGNAL(invalidFormat()), SLOT(decoderError())); + connect(m_waveDecoder, SIGNAL(readyRead()), SLOT(readSample())); +} + +// Called in loading thread +void QSample::decoderError() +{ + Q_ASSERT(QThread::currentThread()->objectName() == "QSampleCache::LoadingThread"); + QMutexLocker m(&m_mutex); +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "QSample: decoder error"; +#endif + cleanup(); + m_state = QSample::Error; + emit error(); +} + +// Called in loading thread from decoder when sample is done. Locked already. +void QSample::onReady() +{ + Q_ASSERT(QThread::currentThread()->objectName() == "QSampleCache::LoadingThread"); +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "QSample: load ready"; +#endif + m_audioFormat = m_waveDecoder->audioFormat(); + cleanup(); + m_state = QSample::Ready; + emit ready(); +} + +// Called in application thread, then moved to loader thread +QSample::QSample(const QUrl& url, QSampleCache *parent) + : m_parent(parent) + , m_stream(0) + , m_waveDecoder(0) + , m_url(url) + , m_sampleReadLength(0) + , m_state(Creating) + , m_ref(0) +{ +} + +QT_END_NAMESPACE + +#include "moc_qsamplecache_p.cpp" diff --git a/src/multimediakit/effects/qsamplecache_p.h b/src/multimediakit/effects/qsamplecache_p.h new file mode 100644 index 000000000..327f3bd8e --- /dev/null +++ b/src/multimediakit/effects/qsamplecache_p.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSAMPLECACHE_P_H +#define QSAMPLECACHE_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 +#include +#include +#include +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QNetworkAccessManager; +class QSampleCache; +class QWaveDecoder; + +// Lives in application thread +class QSample : public QObject +{ + Q_OBJECT +public: + friend class QSampleCache; + enum State + { + Creating, + Loading, + Error, + Ready, + }; + + State state() const; + // These are not (currently) locked because they are only meant to be called after these + // variables are updated to their final states + const QByteArray& data() const { Q_ASSERT(state() == Ready); return m_soundData; } + const QAudioFormat& format() const { Q_ASSERT(state() == Ready); return m_audioFormat; } + void release(); + +Q_SIGNALS: + void error(); + void ready(); + +protected: + QSample(const QUrl& url, QSampleCache *parent); + +private Q_SLOTS: + void load(); + void decoderError(); + void readSample(); + void decoderReady(); + +private: + void onReady(); + void cleanup(); + void addRef(); + void loadIfNecessary(); + QSample(); + ~QSample(); + + mutable QMutex m_mutex; + QSampleCache *m_parent; + QByteArray m_soundData; + QAudioFormat m_audioFormat; + QIODevice *m_stream; + QWaveDecoder *m_waveDecoder; + QUrl m_url; + qint64 m_sampleReadLength; + State m_state; + int m_ref; +}; + +class QSampleCache +{ +public: + friend class QSample; + + QSampleCache(); + ~QSampleCache(); + + QSample* requestSample(const QUrl& url); + void setCapacity(qint64 capacity); + +private: + QMap m_samples; + QSet m_staleSamples; + QNetworkAccessManager *m_networkAccessManager; + QMutex m_mutex; + qint64 m_capacity; + qint64 m_usage; + QThread m_loadingThread; + + QNetworkAccessManager& networkAccessManager(); + void refresh(qint64 usageChange); + bool notifyUnreferencedSample(QSample* sample); + void removeUnreferencedSample(QSample* sample); + void unloadSample(QSample* sample); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSAMPLECACHE_P_H diff --git a/src/multimediakit/effects/qsoundeffect.cpp b/src/multimediakit/effects/qsoundeffect.cpp new file mode 100644 index 000000000..4d489871d --- /dev/null +++ b/src/multimediakit/effects/qsoundeffect.cpp @@ -0,0 +1,301 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsoundeffect_p.h" + +#if defined(QT_MULTIMEDIA_PULSEAUDIO) +#include "qsoundeffect_pulse_p.h" +#elif(QT_MULTIMEDIA_QMEDIAPLAYER) +#include "qsoundeffect_qmedia_p.h" +#else +#include "qsoundeffect_qsound_p.h" +#endif + +QT_BEGIN_NAMESPACE + +/*! + \qmlclass SoundEffect QSoundEffect + \brief The SoundEffect element provides a way to play sound effects in QML. + \since 1.0 + + \inmodule QtMultimediaKit + + This element is part of the \bold{QtMultimediaKit 1.1} module. + + The following example plays a WAV file on mouse click. + + \snippet doc/src/snippets/multimedia-snippets/soundeffect.qml complete snippet +*/ + +/*! + \qmlproperty url SoundEffect::source + \since 1.0 + + This property provides a way to control the sound to play. +*/ + +/*! + \qmlproperty int SoundEffect::loops + \since 1.0 + + This property provides a way to control the number of times to repeat the sound on each play(). + + Set to -1 (infinite) to enable infinite loop. +*/ + +/*! + \qmlproperty qreal SoundEffect::volume + \since 1.0 + + This property holds the volume of the playback, from 0.0 (silent) to 1.0 (maximum volume). + Note: Currently this has no effect on Mac OS X and Symbian. +*/ + +/*! + \qmlproperty bool SoundEffect::muted + \since 1.0 + + This property provides a way to control muting. +*/ + +/*! + \qmlproperty bool SoundEffect::playing + \since 1.1 + + This property indicates if the soundeffect is playing or not. +*/ + +/*! + \qmlproperty int SoundEffect::status + \since 1.0 + + This property indicates the following status of the soundeffect. + + Null: no source has been set or is null. + Loading: the soundeffect is trying to load the source. + Ready: the source is loaded and ready for play. + Error: some error happened during operation, such as failure of loading the source. +*/ + +/*! + \qmlsignal SoundEffect::sourceChanged() + \since 1.0 + + This handler is called when the source has changed. +*/ + +/*! + \qmlsignal SoundEffect::loopsChanged() + \since 1.0 + + This handler is called when the number of loops has changed. +*/ + +/*! + \qmlsignal SoundEffect::volumeChanged() + \since 1.0 + + This handler is called when the volume has changed. +*/ + +/*! + \qmlsignal SoundEffect::mutedChanged() + \since 1.0 + + This handler is called when the mute state has changed. +*/ + +/*! + \qmlsignal SoundEffect::playingChanged() + \since 1.0 + + This handler is called when the playing property has changed. +*/ + +/*! + \qmlsignal SoundEffect::statusChanged() + + This handler is called when the status property has changed. + \since 1.0 +*/ + + +/*! + \internal + \since 1.0 +*/ + +QSoundEffect::QSoundEffect(QObject *parent) : + QObject(parent) +{ + d = new QSoundEffectPrivate(this); + connect(d, SIGNAL(volumeChanged()), SIGNAL(volumeChanged())); + connect(d, SIGNAL(mutedChanged()), SIGNAL(mutedChanged())); + connect(d, SIGNAL(loadedChanged()), SIGNAL(loadedChanged())); + connect(d, SIGNAL(playingChanged()), SIGNAL(playingChanged())); + connect(d, SIGNAL(statusChanged()), SIGNAL(statusChanged())); +} + +QSoundEffect::~QSoundEffect() +{ + d->deleteLater(); +} + +QStringList QSoundEffect::supportedMimeTypes() +{ + return QSoundEffectPrivate::supportedMimeTypes(); +} + +QUrl QSoundEffect::source() const +{ + return d->source(); +} + +void QSoundEffect::setSource(const QUrl &url) +{ + if (d->source() == url) + return; + + d->setSource(url); + + emit sourceChanged(); +} + +int QSoundEffect::loopCount() const +{ + return d->loopCount(); +} + +void QSoundEffect::setLoopCount(int loopCount) +{ + if (loopCount < 0 && loopCount != Infinite) { + qWarning("SoundEffect: loops should be SoundEffect.Infinite, 0 or positive integer"); + return; + } + if (loopCount == 0) + loopCount = 1; + if (d->loopCount() == loopCount) + return; + + d->setLoopCount(loopCount); + emit loopCountChanged(); +} + +qreal QSoundEffect::volume() const +{ + return qreal(d->volume()) / 100; +} + +void QSoundEffect::setVolume(qreal volume) +{ + if (volume < 0 || volume > 1) { + qWarning("SoundEffect: volume should be between 0.0 and 1.0"); + return; + } + int iVolume = qRound(volume * 100); + if (d->volume() == iVolume) + return; + + d->setVolume(iVolume); +} + +bool QSoundEffect::isMuted() const +{ + return d->isMuted(); +} + +void QSoundEffect::setMuted(bool muted) +{ + if (d->isMuted() == muted) + return; + + d->setMuted(muted); +} + +bool QSoundEffect::isLoaded() const +{ + return d->isLoaded(); +} + +/*! + \qmlmethod SoundEffect::play() + + Start playback of the sound effect, looping the effect for the number of + times as specificed in the loops property. + + This is the default method for SoundEffect. + + \snippet doc/src/snippets/multimedia-snippets/soundeffect.qml play sound on click + \since 1.0 +*/ +void QSoundEffect::play() +{ + d->play(); +} + +bool QSoundEffect::isPlaying() const +{ + return d->isPlaying(); +} + +QSoundEffect::Status QSoundEffect::status() const +{ + return d->status(); +} + + +/*! + \qmlmethod SoundEffect::stop() + + Stop current playback. + Note that if the backend is PulseAudio, due to the limitation of the underlying API, + tis stop will only prevent next looping but will not be able to stop current playback immediately. + + \since 1.0 + */ +void QSoundEffect::stop() +{ + d->stop(); +} + +QT_END_NAMESPACE + +#include "moc_qsoundeffect_p.cpp" diff --git a/src/multimediakit/effects/qsoundeffect_p.h b/src/multimediakit/effects/qsoundeffect_p.h new file mode 100644 index 000000000..7f6b24a00 --- /dev/null +++ b/src/multimediakit/effects/qsoundeffect_p.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSOUNDEFFECT_P_H +#define QSOUNDEFFECT_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 +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QSoundEffectPrivate; + +class Q_MULTIMEDIA_EXPORT QSoundEffect : public QObject +{ + Q_OBJECT + Q_CLASSINFO("DefaultMethod", "play()") + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(int loops READ loopCount WRITE setLoopCount NOTIFY loopCountChanged) + Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) + Q_PROPERTY(bool playing READ isPlaying NOTIFY playingChanged) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) + Q_ENUMS(Loop) + Q_ENUMS(Status) + +public: + enum Loop + { + Infinite = -2, + }; + + enum Status + { + Null, + Loading, + Ready, + Error + }; + + explicit QSoundEffect(QObject *parent = 0); + ~QSoundEffect(); + + static QStringList supportedMimeTypes(); + + QUrl source() const; + void setSource(const QUrl &url); + + int loopCount() const; + void setLoopCount(int loopCount); + + qreal volume() const; + void setVolume(qreal volume); + + bool isMuted() const; + void setMuted(bool muted); + + bool isLoaded() const; + + bool isPlaying() const; + Status status() const; + +Q_SIGNALS: + void sourceChanged(); + void loopCountChanged(); + void volumeChanged(); + void mutedChanged(); + void loadedChanged(); + void playingChanged(); + void statusChanged(); + +public Q_SLOTS: + void play(); + void stop(); + +private: + Q_DISABLE_COPY(QSoundEffect) + QSoundEffectPrivate* d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QSOUNDEFFECT_H diff --git a/src/multimediakit/effects/qsoundeffect_pulse_p.cpp b/src/multimediakit/effects/qsoundeffect_pulse_p.cpp new file mode 100644 index 000000000..f6abf140e --- /dev/null +++ b/src/multimediakit/effects/qsoundeffect_pulse_p.cpp @@ -0,0 +1,955 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include +#include +#include +#include + +#include "qsoundeffect_pulse_p.h" + +#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) +#include +#endif + +#include + +//#define QT_PA_DEBUG +#ifndef QTM_PULSEAUDIO_DEFAULTBUFFER +#define QT_PA_STREAM_BUFFER_SIZE_MAX (1024 * 64) //64KB is a trade-off for balancing control latency and uploading overhead +#endif + +QT_BEGIN_NAMESPACE + +namespace +{ +inline pa_sample_spec audioFormatToSampleSpec(const QAudioFormat &format) +{ + pa_sample_spec spec; + + spec.rate = format.frequency(); + spec.channels = format.channels(); + + if (format.sampleSize() == 8) + spec.format = PA_SAMPLE_U8; + else if (format.sampleSize() == 16) { + switch (format.byteOrder()) { + case QAudioFormat::BigEndian: spec.format = PA_SAMPLE_S16BE; break; + case QAudioFormat::LittleEndian: spec.format = PA_SAMPLE_S16LE; break; + } + } + else if (format.sampleSize() == 32) { + switch (format.byteOrder()) { + case QAudioFormat::BigEndian: spec.format = PA_SAMPLE_S32BE; break; + case QAudioFormat::LittleEndian: spec.format = PA_SAMPLE_S32LE; break; + } + } + + return spec; +} + +class PulseDaemon : public QObject +{ + Q_OBJECT +public: + PulseDaemon(): m_prepared(false) + { + prepare(); + } + + ~PulseDaemon() + { + if (m_prepared) + release(); + } + + inline void lock() + { + pa_threaded_mainloop_lock(m_mainLoop); + } + + inline void unlock() + { + pa_threaded_mainloop_unlock(m_mainLoop); + } + + inline pa_context *context() const + { + return m_context; + } + + inline pa_cvolume * calcVolume(pa_cvolume *dest, int soundEffectVolume) + { + dest->channels = 2; + dest->values[0] = dest->values[1] = m_vol * soundEffectVolume / 100; + return dest; + } + + void updateStatus(const pa_cvolume& volume) + { + if (m_vol != pa_cvolume_max(&volume)) { + m_vol = pa_cvolume_max(&volume); + emit volumeChanged(); + } + } + +Q_SIGNALS: + void contextReady(); + void volumeChanged(); + +private: + void prepare() + { + m_vol = PA_VOLUME_NORM; + + m_mainLoop = pa_threaded_mainloop_new(); + if (m_mainLoop == 0) { + qWarning("PulseAudioService: unable to create pulseaudio mainloop"); + return; + } + + if (pa_threaded_mainloop_start(m_mainLoop) != 0) { + qWarning("PulseAudioService: unable to start pulseaudio mainloop"); + pa_threaded_mainloop_free(m_mainLoop); + return; + } + + m_mainLoopApi = pa_threaded_mainloop_get_api(m_mainLoop); + + lock(); + m_context = pa_context_new(m_mainLoopApi, QString(QLatin1String("QtPulseAudio:%1")).arg(::getpid()).toAscii().constData()); + + pa_context_set_state_callback(m_context, context_state_callback, this); + + if (m_context == 0) { + qWarning("PulseAudioService: Unable to create new pulseaudio context"); + pa_threaded_mainloop_free(m_mainLoop); + return; + } + + if (pa_context_connect(m_context, 0, (pa_context_flags_t)0, 0) < 0) { + qWarning("PulseAudioService: pa_context_connect() failed"); + pa_context_unref(m_context); + pa_threaded_mainloop_free(m_mainLoop); + return; + } + unlock(); + + m_prepared = true; + } + + void release() + { + if (!m_prepared) return; + pa_threaded_mainloop_stop(m_mainLoop); + pa_threaded_mainloop_free(m_mainLoop); + m_prepared = false; + } + + static void context_state_callback(pa_context *c, void *userdata) + { + PulseDaemon *self = reinterpret_cast(userdata); + switch (pa_context_get_state(c)) { + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + case PA_CONTEXT_READY: + #if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) + pa_ext_stream_restore_read(c, &stream_restore_info_callback, self); + pa_ext_stream_restore_set_subscribe_cb(c, &stream_restore_monitor_callback, self); + pa_ext_stream_restore_subscribe(c, 1, 0, self); + #endif + QMetaObject::invokeMethod(self, "contextReady", Qt::QueuedConnection); + break; + default: + break; + } + } + +#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) + + static void stream_restore_monitor_callback(pa_context *c, void *userdata) + { + PulseDaemon *self = reinterpret_cast(userdata); + pa_ext_stream_restore_read(c, &stream_restore_info_callback, self); + } + + static void stream_restore_info_callback(pa_context *c, + const pa_ext_stream_restore_info *info, + int eol, void *userdata) + { + Q_UNUSED(c) + + PulseDaemon *self = reinterpret_cast(userdata); + + if (!eol) { + if (QString(info->name).startsWith(QLatin1String("sink-input-by-media-role:x-maemo"))) { +#ifdef QT_PA_DEBUG + qDebug() << "x-maemo volume =(" << info->volume.values[0] * 100 / PA_VOLUME_NORM << "," + << info->volume.values[1] * 100 / PA_VOLUME_NORM << "), " + << "mute = " << info->mute; +#endif + self->updateStatus(info->volume); + } + } + } +#endif + + pa_volume_t m_vol; + + bool m_prepared; + pa_context *m_context; + pa_threaded_mainloop *m_mainLoop; + pa_mainloop_api *m_mainLoopApi; +}; + +} + +Q_GLOBAL_STATIC(PulseDaemon, daemon) +Q_GLOBAL_STATIC(QSampleCache, sampleCache) + +namespace +{ +class PulseDaemonLocker +{ +public: + PulseDaemonLocker() + { + daemon()->lock(); + } + + ~PulseDaemonLocker() + { + daemon()->unlock(); + } +}; +} + +QSoundEffectPrivate::QSoundEffectPrivate(QObject* parent): + QObject(parent), + m_pulseStream(0), + m_sinkInputId(-1), + m_emptying(false), + m_sampleReady(false), + m_playing(false), + m_status(QSoundEffect::Null), + m_muted(false), + m_playQueued(false), + m_stopping(false), + m_volume(100), + m_loopCount(1), + m_runningCount(0), + m_sample(0) , + m_position(0) +{ + pa_sample_spec_init(&m_pulseSpec); +} + +QSoundEffectPrivate::~QSoundEffectPrivate() +{ + unloadPulseStream(); + + if (m_sample) + m_sample->release(); +} + +QStringList QSoundEffectPrivate::supportedMimeTypes() +{ + QStringList supportedTypes; + supportedTypes << QLatin1String("audio/x-wav") << QLatin1String("audio/vnd.wave") ; + return supportedTypes; +} + +QUrl QSoundEffectPrivate::source() const +{ + return m_source; +} + +void QSoundEffectPrivate::setSource(const QUrl &url) +{ + Q_ASSERT(m_source != url); +#ifdef QT_PA_DEBUG + qDebug() << this << "setSource =" << url; +#endif + stop(); + if (m_sample) { + if (!m_sampleReady) { + disconnect(m_sample, SIGNAL(error()), this, SLOT(decoderError())); + disconnect(m_sample, SIGNAL(ready()), this, SLOT(sampleReady())); + } + m_sample->release(); + m_sample = 0; + } + + m_source = url; + m_sampleReady = false; + + PulseDaemonLocker locker; + m_runningCount = 0; + if (m_pulseStream && !pa_stream_is_corked(m_pulseStream)) { + pa_stream_set_write_callback(m_pulseStream, 0, 0); + pa_stream_set_underflow_callback(m_pulseStream, 0, 0); + pa_operation_unref(pa_stream_cork(m_pulseStream, 1, 0, 0)); + } + setPlaying(false); + + if (url.isEmpty()) { + setStatus(QSoundEffect::Null); + return; + } + + setStatus(QSoundEffect::Loading); + m_sample = sampleCache()->requestSample(url); + connect(m_sample, SIGNAL(error()), this, SLOT(decoderError())); + connect(m_sample, SIGNAL(ready()), this, SLOT(sampleReady())); + switch(m_sample->state()) { + case QSample::Ready: + sampleReady(); + break; + case QSample::Error: + decoderError(); + break; + } +} + +int QSoundEffectPrivate::loopCount() const +{ + return m_loopCount; +} + +void QSoundEffectPrivate::setLoopCount(int loopCount) +{ + if (loopCount == 0) + loopCount = 1; + m_loopCount = loopCount; +} + +int QSoundEffectPrivate::volume() const +{ + return m_volume; +} + +void QSoundEffectPrivate::setVolume(int volume) +{ + m_volume = volume; + emit volumeChanged(); + updateVolume(); +} + +void QSoundEffectPrivate::updateVolume() +{ + if (m_sinkInputId < 0) + return; + PulseDaemonLocker locker; + pa_cvolume volume; + pa_operation_unref(pa_context_set_sink_input_volume(daemon()->context(), m_sinkInputId, daemon()->calcVolume(&volume, m_volume), setvolume_callback, this)); + Q_ASSERT(pa_cvolume_valid(&volume)); +#ifdef QT_PA_DEBUG + qDebug() << this << "updateVolume =" << pa_cvolume_max(&volume); +#endif +} + +bool QSoundEffectPrivate::isMuted() const +{ + return m_muted; +} + +void QSoundEffectPrivate::setMuted(bool muted) +{ + m_muted = muted; + emit mutedChanged(); + updateMuted(); +} + +void QSoundEffectPrivate::updateMuted() +{ + if (m_sinkInputId < 0) + return; + PulseDaemonLocker locker; + pa_operation_unref(pa_context_set_sink_input_mute(daemon()->context(), m_sinkInputId, m_muted, setmuted_callback, this)); +#ifdef QT_PA_DEBUG + qDebug() << this << "updateMuted = " << daemon()->calcMuted(m_muted); +#endif +} + +bool QSoundEffectPrivate::isLoaded() const +{ + return m_status == QSoundEffect::Ready; +} + +bool QSoundEffectPrivate::isPlaying() const +{ + return m_playing; +} + +QSoundEffect::Status QSoundEffectPrivate::status() const +{ + return m_status; +} + +void QSoundEffectPrivate::setPlaying(bool playing) +{ +#ifdef QT_PA_DEBUG + qDebug() << this << "setPlaying(" << playing << ")"; +#endif + if (m_playing == playing) + return; + if (!playing) + m_playQueued = false; + m_playing = playing; + emit playingChanged(); +} + +void QSoundEffectPrivate::setStatus(QSoundEffect::Status status) +{ +#ifdef QT_PA_DEBUG + qDebug() << this << "setStatus" << status; +#endif + if (m_status == status) + return; + bool oldLoaded = isLoaded(); + m_status = status; + emit statusChanged(); + if (oldLoaded != isLoaded()) + emit loadedChanged(); +} + +void QSoundEffectPrivate::play() +{ +#ifdef QT_PA_DEBUG + qDebug() << this << "play"; +#endif + if (m_status == QSoundEffect::Null || m_status == QSoundEffect::Error || m_playQueued) + return; + + PulseDaemonLocker locker; + if (!m_sampleReady || m_stopping || m_emptying) { +#ifdef QT_PA_DEBUG + qDebug() << this << "play deferred"; +#endif + m_playQueued = true; + } else { + if (m_playing) { //restart playing from the beginning +#ifdef QT_PA_DEBUG + qDebug() << this << "restart playing"; +#endif + m_runningCount = 0; + m_playQueued = true; + Q_ASSERT(m_pulseStream); + emptyStream(); + return; + } + m_runningCount = m_loopCount; + playSample(); + } + + setPlaying(true); +} + +void QSoundEffectPrivate::emptyStream() +{ + m_emptying = true; + pa_stream_set_write_callback(m_pulseStream, 0, this); + pa_stream_set_underflow_callback(m_pulseStream, 0, this); + pa_operation_unref(pa_stream_flush(m_pulseStream, stream_flush_callback, this)); +} + +void QSoundEffectPrivate::emptyComplete() +{ + PulseDaemonLocker locker; + m_emptying = false; + pa_operation_unref(pa_stream_cork(m_pulseStream, 1, stream_cork_callback, this)); +} + +void QSoundEffectPrivate::sampleReady() +{ +#ifdef QT_PA_DEBUG + qDebug() << this << "sampleReady"; +#endif + disconnect(m_sample, SIGNAL(error()), this, SLOT(decoderError())); + disconnect(m_sample, SIGNAL(ready()), this, SLOT(sampleReady())); + pa_sample_spec newFormatSpec = audioFormatToSampleSpec(m_sample->format()); + + if (m_pulseStream && (memcmp(&m_pulseSpec, &newFormatSpec, sizeof(m_pulseSpec)) != 0)) { + unloadPulseStream(); + } + m_pulseSpec = newFormatSpec; + + m_sampleReady = true; + m_position = 0; + + if (m_name.isNull()) + m_name = QString(QLatin1String("QtPulseSample-%1-%2")).arg(::getpid()).arg(quintptr(this)).toUtf8(); + + PulseDaemonLocker locker; + if (m_pulseStream) { +#ifdef QT_PA_DEBUG + qDebug() << this << "reuse existing pulsestream"; +#endif +#ifdef QTM_PULSEAUDIO_DEFAULTBUFFER + const pa_buffer_attr *bufferAttr = pa_stream_get_buffer_attr(m_pulseStream); + if (bufferAttr->prebuf > uint32_t(m_sample->data().size())) { + pa_buffer_attr newBufferAttr; + newBufferAttr = *bufferAttr; + newBufferAttr.prebuf = m_sample->data().size(); + pa_stream_set_buffer_attr(m_pulseStream, &newBufferAttr, stream_adjust_prebuffer_callback, this); + } else { + streamReady(); + } +#else + const pa_buffer_attr *bufferAttr = pa_stream_get_buffer_attr(m_pulseStream); + if (bufferAttr->tlength < m_sample->data().size() && bufferAttr->tlength < QT_PA_STREAM_BUFFER_SIZE_MAX) { + pa_buffer_attr newBufferAttr; + newBufferAttr.maxlength = -1; + newBufferAttr.tlength = qMin(m_sample->data().size(), QT_PA_STREAM_BUFFER_SIZE_MAX); + newBufferAttr.minreq = bufferAttr->tlength / 2; + newBufferAttr.prebuf = -1; + newBufferAttr.fragsize = -1; + pa_stream_set_buffer_attr(m_pulseStream, &newBufferAttr, stream_reset_buffer_callback, this); + } else if (bufferAttr->prebuf > uint32_t(m_sample->data().size())) { + pa_buffer_attr newBufferAttr; + newBufferAttr = *bufferAttr; + newBufferAttr.prebuf = m_sample->data().size(); + pa_stream_set_buffer_attr(m_pulseStream, &newBufferAttr, stream_adjust_prebuffer_callback, this); + } else { + streamReady(); + } +#endif + } else { + if (pa_context_get_state(daemon()->context()) != PA_CONTEXT_READY) { + connect(daemon(), SIGNAL(contextReady()), SLOT(contextReady())); + return; + } + createPulseStream(); + } +} + +void QSoundEffectPrivate::decoderError() +{ + qWarning("QSoundEffect(pulseaudio): Error decoding source"); + disconnect(m_sample, SIGNAL(error()), this, SLOT(decoderError())); + bool playingDirty = false; + if (m_playing) { + m_playing = false; + playingDirty = true; + } + setStatus(QSoundEffect::Error); + if (playingDirty) + emit playingChanged(); +} + +void QSoundEffectPrivate::unloadPulseStream() +{ +#ifdef QT_PA_DEBUG + qDebug() << this << "unloadPulseStream"; +#endif + m_sinkInputId = -1; + PulseDaemonLocker locker; + if (m_pulseStream) { + pa_stream_set_state_callback(m_pulseStream, 0, 0); + pa_stream_set_write_callback(m_pulseStream, 0, 0); + pa_stream_set_underflow_callback(m_pulseStream, 0, 0); + pa_stream_disconnect(m_pulseStream); + pa_stream_unref(m_pulseStream); + disconnect(daemon(), SIGNAL(volumeChanged()), this, SLOT(updateVolume())); + m_pulseStream = 0; + } +} + +void QSoundEffectPrivate::prepare() +{ + if (!m_pulseStream || !m_sampleReady) + return; + PulseDaemonLocker locker; + pa_stream_set_write_callback(m_pulseStream, stream_write_callback, this); + pa_stream_set_underflow_callback(m_pulseStream, stream_underrun_callback, this); + m_stopping = false; + size_t writeBytes = size_t(qMin(m_pulseBufferSize, m_sample->data().size())); +#ifdef QT_PA_DEBUG + qDebug() << this << "prepare(): writable size =" << pa_stream_writable_size(m_pulseStream) + << "actual writeBytes =" << writeBytes + << "m_playQueued =" << m_playQueued; +#endif + m_position = int(writeBytes); + if (pa_stream_write(m_pulseStream, reinterpret_cast(const_cast(m_sample->data().data())), writeBytes, + stream_write_done_callback, 0, PA_SEEK_RELATIVE) != 0) { + qWarning("QSoundEffect(pulseaudio): pa_stream_write, error = %s", pa_strerror(pa_context_errno(daemon()->context()))); + } + if (m_playQueued) { + m_playQueued = false; + m_runningCount = m_loopCount; + playSample(); + } +} + +void QSoundEffectPrivate::uploadSample() +{ + if (m_runningCount == 0) { +#ifdef QT_PA_DEBUG + qDebug() << this << "uploadSample: return due to 0 m_runningCount"; +#endif + return; + } +#ifdef QT_PA_DEBUG + qDebug() << this << "uploadSample: m_runningCount =" << m_runningCount; +#endif + if (m_position == m_sample->data().size()) { + m_position = 0; + if (m_runningCount > 0) + m_runningCount--; + if (m_runningCount == 0) { + return; + } + } + + int writtenBytes = 0; + int writableSize = int(pa_stream_writable_size(m_pulseStream)); + int firstPartLength = qMin(m_sample->data().size() - m_position, writableSize); + if (pa_stream_write(m_pulseStream, reinterpret_cast(const_cast(m_sample->data().data()) + m_position), + firstPartLength, stream_write_done_callback, 0, PA_SEEK_RELATIVE) != 0) { + qWarning("QSoundEffect(pulseaudio): pa_stream_write, error = %s", pa_strerror(pa_context_errno(daemon()->context()))); + } + writtenBytes = firstPartLength; + m_position += firstPartLength; + if (m_position == m_sample->data().size()) { + m_position = 0; + if (m_runningCount > 0) + m_runningCount--; + if (m_runningCount != 0 && firstPartLength < writableSize) + { + while (writtenBytes < writableSize) { + int writeSize = qMin(writableSize - writtenBytes, m_sample->data().size()); + if (pa_stream_write(m_pulseStream, reinterpret_cast(const_cast(m_sample->data().data())), + writeSize, stream_write_done_callback, 0, PA_SEEK_RELATIVE) != 0) { + qWarning("QSoundEffect(pulseaudio): pa_stream_write, error = %s", pa_strerror(pa_context_errno(daemon()->context()))); + } + writtenBytes += writeSize; + if (writeSize < m_sample->data().size()) { + m_position = writeSize; + break; + } + if (m_runningCount > 0) + m_runningCount--; + if (m_runningCount == 0) + break; + } + } + } +#ifdef QT_PA_DEBUG + qDebug() << this << "uploadSample: use direct write, writeable size =" << writableSize + << "actual writtenBytes =" << writtenBytes; +#endif +} + +void QSoundEffectPrivate::playSample() +{ +#ifdef QT_PA_DEBUG + qDebug() << this << "playSample"; +#endif + Q_ASSERT(m_pulseStream); + pa_operation_unref(pa_stream_cork(m_pulseStream, 0, 0, 0)); +} + +void QSoundEffectPrivate::stop() +{ +#ifdef QT_PA_DEBUG + qDebug() << this << "stop"; +#endif + if (!m_playing) + return; + setPlaying(false); + PulseDaemonLocker locker; + m_stopping = true; + if (m_pulseStream) + emptyStream(); + m_runningCount = 0; + m_position = 0; + m_playQueued = false; +} + +void QSoundEffectPrivate::underRun() +{ + stop(); +} + +void QSoundEffectPrivate::streamReady() +{ +#ifdef QT_PA_DEBUG + qDebug() << this << "streamReady"; +#endif + PulseDaemonLocker locker; + m_sinkInputId = pa_stream_get_index(m_pulseStream); + updateMuted(); + updateVolume(); +#ifdef QT_PA_DEBUG + const pa_buffer_attr *realBufAttr = pa_stream_get_buffer_attr(m_pulseStream); + qDebug() << this << "m_sinkInputId =" << m_sinkInputId + << "tlength =" << realBufAttr->tlength << "maxlength =" << realBufAttr->maxlength + << "minreq = " << realBufAttr->minreq << "prebuf =" << realBufAttr->prebuf; +#endif + prepare(); + setStatus(QSoundEffect::Ready); +} + +void QSoundEffectPrivate::createPulseStream() +{ +#ifdef QT_PA_DEBUG + qDebug() << this << "createPulseStream"; +#endif + + pa_proplist *propList = pa_proplist_new(); + pa_proplist_sets(propList, PA_PROP_MEDIA_ROLE, "soundeffect"); + pa_stream *stream = pa_stream_new_with_proplist(daemon()->context(), m_name.constData(), &m_pulseSpec, 0, propList); + pa_proplist_free(propList); + + connect(daemon(), SIGNAL(volumeChanged()), this, SLOT(updateVolume())); + + if (stream == 0) { + qWarning("QSoundEffect(pulseaudio): Failed to create stream"); + m_pulseStream = 0; + setStatus(QSoundEffect::Error); + setPlaying(false); + return; + } + else { + pa_stream_set_state_callback(stream, stream_state_callback, this); + pa_stream_set_write_callback(stream, stream_write_callback, this); + pa_stream_set_underflow_callback(stream, stream_underrun_callback, this); + } + m_pulseStream = stream; + +#ifndef QTM_PULSEAUDIO_DEFAULTBUFFER + pa_buffer_attr bufferAttr; + bufferAttr.tlength = qMin(m_sample->data().size(), QT_PA_STREAM_BUFFER_SIZE_MAX); + bufferAttr.maxlength = -1; + bufferAttr.minreq = bufferAttr.tlength / 2; + bufferAttr.prebuf = -1; + bufferAttr.fragsize = -1; + if (pa_stream_connect_playback(m_pulseStream, 0, &bufferAttr, +#else + if (pa_stream_connect_playback(m_pulseStream, 0, 0, +#endif + m_muted ? pa_stream_flags_t(PA_STREAM_START_MUTED | PA_STREAM_START_CORKED) + : pa_stream_flags_t(PA_STREAM_START_UNMUTED | PA_STREAM_START_CORKED), + 0, 0) < 0) { + qWarning("QSoundEffect(pulseaudio): Failed to connect stream, error = %s", + pa_strerror(pa_context_errno(daemon()->context()))); + } +} + +void QSoundEffectPrivate::contextReady() +{ + disconnect(daemon(), SIGNAL(contextReady()), this, SLOT(contextReady())); + PulseDaemonLocker locker; + createPulseStream(); +} + +void QSoundEffectPrivate::stream_write_callback(pa_stream *s, size_t length, void *userdata) +{ + Q_UNUSED(length); + Q_UNUSED(s) + + QSoundEffectPrivate *self = reinterpret_cast(userdata); +#ifdef QT_PA_DEBUG + qDebug() << self << "stream_write_callback"; +#endif + self->uploadSample(); +} + +void QSoundEffectPrivate::stream_state_callback(pa_stream *s, void *userdata) +{ + QSoundEffectPrivate *self = reinterpret_cast(userdata); + switch (pa_stream_get_state(s)) { + case PA_STREAM_READY: + { +#ifdef QT_PA_DEBUG + qDebug() << self << "pulse stream ready"; +#endif + const pa_buffer_attr *bufferAttr = pa_stream_get_buffer_attr(self->m_pulseStream); + self->m_pulseBufferSize = bufferAttr->tlength; + if (bufferAttr->prebuf > uint32_t(self->m_sample->data().size())) { + pa_buffer_attr newBufferAttr; + newBufferAttr = *bufferAttr; + newBufferAttr.prebuf = self->m_sample->data().size(); + pa_stream_set_buffer_attr(self->m_pulseStream, &newBufferAttr, stream_adjust_prebuffer_callback, userdata); + } else { + QMetaObject::invokeMethod(self, "streamReady", Qt::QueuedConnection); + } + break; + } + case PA_STREAM_CREATING: +#ifdef QT_PA_DEBUG + qDebug() << self << "pulse stream creating"; +#endif + break; + case PA_STREAM_TERMINATED: +#ifdef QT_PA_DEBUG + qDebug() << self << "pulse stream terminated"; +#endif + break; + + case PA_STREAM_FAILED: + default: + qWarning("QSoundEffect(pulseaudio): Error in pulse audio stream"); + break; + } +} + +void QSoundEffectPrivate::stream_reset_buffer_callback(pa_stream *s, int success, void *userdata) +{ + Q_UNUSED(s); + if (!success) + qWarning("QSoundEffect(pulseaudio): faild to reset buffer attribute"); + QSoundEffectPrivate *self = reinterpret_cast(userdata); +#ifdef QT_PA_DEBUG + qDebug() << self << "stream_reset_buffer_callback"; +#endif + const pa_buffer_attr *bufferAttr = pa_stream_get_buffer_attr(self->m_pulseStream); + self->m_pulseBufferSize = bufferAttr->tlength; + if (bufferAttr->prebuf > uint32_t(self->m_sample->data().size())) { + pa_buffer_attr newBufferAttr; + newBufferAttr = *bufferAttr; + newBufferAttr.prebuf = self->m_sample->data().size(); + pa_stream_set_buffer_attr(self->m_pulseStream, &newBufferAttr, stream_adjust_prebuffer_callback, userdata); + } else { + QMetaObject::invokeMethod(self, "streamReady", Qt::QueuedConnection); + } +} + +void QSoundEffectPrivate::stream_adjust_prebuffer_callback(pa_stream *s, int success, void *userdata) +{ + Q_UNUSED(s); + if (!success) + qWarning("QSoundEffect(pulseaudio): faild to adjust pre-buffer attribute"); + QSoundEffectPrivate *self = reinterpret_cast(userdata); +#ifdef QT_PA_DEBUG + qDebug() << self << "stream_adjust_prebuffer_callback"; +#endif + QMetaObject::invokeMethod(self, "streamReady", Qt::QueuedConnection); +} + +void QSoundEffectPrivate::setvolume_callback(pa_context *c, int success, void *userdata) +{ + Q_UNUSED(c); + Q_UNUSED(userdata); +#ifdef QT_PA_DEBUG + qDebug() << reinterpret_cast(userdata) << "setvolume_callback"; +#endif + if (!success) { + qWarning("QSoundEffect(pulseaudio): faild to set volume"); + } +} + +void QSoundEffectPrivate::setmuted_callback(pa_context *c, int success, void *userdata) +{ + Q_UNUSED(c); + Q_UNUSED(userdata); +#ifdef QT_PA_DEBUG + qDebug() << reinterpret_cast(userdata) << "setmuted_callback"; +#endif + if (!success) { + qWarning("QSoundEffect(pulseaudio): faild to set muted"); + } +} + +void QSoundEffectPrivate::stream_underrun_callback(pa_stream *s, void *userdata) +{ + Q_UNUSED(s); + QSoundEffectPrivate *self = reinterpret_cast(userdata); +#ifdef QT_PA_DEBUG + qDebug() << self << "stream_underrun_callback"; +#endif + if (self->m_runningCount == 0 && !self->m_playQueued) + QMetaObject::invokeMethod(self, "underRun", Qt::QueuedConnection); +#ifdef QT_PA_DEBUG + else + qDebug() << "underun corked =" << pa_stream_is_corked(s); +#endif +} + +void QSoundEffectPrivate::stream_cork_callback(pa_stream *s, int success, void *userdata) +{ + Q_UNUSED(s); + if (!success) + qWarning("QSoundEffect(pulseaudio): faild to stop"); + QSoundEffectPrivate *self = reinterpret_cast(userdata); +#ifdef QT_PA_DEBUG + qDebug() << self << "stream_cork_callback"; +#endif + QMetaObject::invokeMethod(self, "prepare", Qt::QueuedConnection); +} + +void QSoundEffectPrivate::stream_flush_callback(pa_stream *s, int success, void *userdata) +{ + Q_UNUSED(s); + if (!success) + qWarning("QSoundEffect(pulseaudio): faild to drain"); + QSoundEffectPrivate *self = reinterpret_cast(userdata); +#ifdef QT_PA_DEBUG + qDebug() << self << "stream_flush_callback"; +#endif + QMetaObject::invokeMethod(self, "emptyComplete", Qt::QueuedConnection); +} + +void QSoundEffectPrivate::stream_write_done_callback(void *p) +{ + Q_UNUSED(p); +#ifdef QT_PA_DEBUG + qDebug() << "stream_write_done_callback"; +#endif +} + +QT_END_NAMESPACE + +#include "moc_qsoundeffect_pulse_p.cpp" +#include "qsoundeffect_pulse_p.moc" diff --git a/src/multimediakit/effects/qsoundeffect_pulse_p.h b/src/multimediakit/effects/qsoundeffect_pulse_p.h new file mode 100644 index 000000000..d07e9b184 --- /dev/null +++ b/src/multimediakit/effects/qsoundeffect_pulse_p.h @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSOUNDEFFECT_PULSE_H +#define QSOUNDEFFECT_PULSE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#include "qsoundeffect_p.h" + +#include +#include +#include +#include +#include "qsamplecache_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QSoundEffectPrivate : public QObject +{ + Q_OBJECT +public: + explicit QSoundEffectPrivate(QObject* parent); + ~QSoundEffectPrivate(); + + static QStringList supportedMimeTypes(); + + QUrl source() const; + void setSource(const QUrl &url); + int loopCount() const; + void setLoopCount(int loopCount); + int volume() const; + void setVolume(int volume); + bool isMuted() const; + void setMuted(bool muted); + bool isLoaded() const; + bool isPlaying() const; + QSoundEffect::Status status() const; + +public Q_SLOTS: + void play(); + void stop(); + +Q_SIGNALS: + void volumeChanged(); + void mutedChanged(); + void loadedChanged(); + void playingChanged(); + void statusChanged(); + +private Q_SLOTS: + void decoderError(); + void sampleReady(); + void uploadSample(); + void contextReady(); + void underRun(); + void prepare(); + void streamReady(); + void emptyComplete(); + void updateVolume(); + void updateMuted(); + +private: + void playSample(); + + void emptyStream(); + void createPulseStream(); + void unloadPulseStream(); + + void setPlaying(bool playing); + void setStatus(QSoundEffect::Status status); + + static void stream_write_callback(pa_stream *s, size_t length, void *userdata); + static void stream_state_callback(pa_stream *s, void *userdata); + static void stream_underrun_callback(pa_stream *s, void *userdata); + static void stream_cork_callback(pa_stream *s, int success, void *userdata); + static void stream_flush_callback(pa_stream *s, int success, void *userdata); + static void stream_write_done_callback(void *p); + static void stream_adjust_prebuffer_callback(pa_stream *s, int success, void *userdata); + static void stream_reset_buffer_callback(pa_stream *s, int success, void *userdata); + static void setvolume_callback(pa_context *c, int success, void *userdata); + static void setmuted_callback(pa_context *c, int success, void *userdata); + + pa_stream *m_pulseStream; + int m_sinkInputId; + pa_sample_spec m_pulseSpec; + int m_pulseBufferSize; + + bool m_emptying; + bool m_sampleReady; + bool m_playing; + QSoundEffect::Status m_status; + bool m_muted; + bool m_playQueued; + bool m_stopping; + int m_volume; + int m_loopCount; + int m_runningCount; + QUrl m_source; + QByteArray m_name; + + QSample *m_sample; + int m_position; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSOUNDEFFECT_PULSE_H diff --git a/src/multimediakit/effects/qsoundeffect_qmedia_p.cpp b/src/multimediakit/effects/qsoundeffect_qmedia_p.cpp new file mode 100644 index 000000000..242997191 --- /dev/null +++ b/src/multimediakit/effects/qsoundeffect_qmedia_p.cpp @@ -0,0 +1,233 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include "qsoundeffect_qmedia_p.h" + +#include + +#include "qmediacontent.h" +#include "qmediaplayer.h" + + +QT_BEGIN_NAMESPACE + +QSoundEffectPrivate::QSoundEffectPrivate(QObject* parent): + QObject(parent), + m_loopCount(1), + m_runningCount(0), + m_player(0), + m_status(QSoundEffect::Null), + m_playing(false) +{ + m_player = new QMediaPlayer(this, QMediaPlayer::LowLatency); + connect(m_player, SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(stateChanged(QMediaPlayer::State))); + connect(m_player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), SLOT(mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(m_player, SIGNAL(error(QMediaPlayer::Error)), SLOT(error(QMediaPlayer::Error))); + connect(m_player, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged())); + connect(m_player, SIGNAL(volumeChanged(int)), SIGNAL(volumeChanged())); +} + +QSoundEffectPrivate::~QSoundEffectPrivate() +{ +} + +QStringList QSoundEffectPrivate::supportedMimeTypes() +{ + return QMediaPlayer::supportedMimeTypes(); +} + +QUrl QSoundEffectPrivate::source() const +{ + return m_player->media().canonicalUrl(); +} + +void QSoundEffectPrivate::setSource(const QUrl &url) +{ + m_player->setMedia(url); +} + +int QSoundEffectPrivate::loopCount() const +{ + return m_loopCount; +} + +void QSoundEffectPrivate::setLoopCount(int loopCount) +{ + m_loopCount = loopCount; +} + +int QSoundEffectPrivate::volume() const +{ + return m_player->volume(); +} + +void QSoundEffectPrivate::setVolume(int volume) +{ + m_player->setVolume(volume); +} + +bool QSoundEffectPrivate::isMuted() const +{ + return m_player->isMuted(); +} + +void QSoundEffectPrivate::setMuted(bool muted) +{ + m_player->setMuted(muted); +} + +bool QSoundEffectPrivate::isLoaded() const +{ + return m_status == QSoundEffect::Ready; +} + +bool QSoundEffectPrivate::isPlaying() const +{ + return m_playing; +} + +QSoundEffect::Status QSoundEffectPrivate::status() const +{ + return m_status; +} + +void QSoundEffectPrivate::play() +{ + if (m_status == QSoundEffect::Null || m_status == QSoundEffect::Error) + return; + if (m_loopCount < 0) { + m_runningCount = -1; + } + else { + if (m_runningCount < 0) + m_runningCount = 0; + m_runningCount += m_loopCount; + } + m_player->play(); +} + +void QSoundEffectPrivate::stop() +{ + m_runningCount = 0; + m_player->stop(); +} + +void QSoundEffectPrivate::stateChanged(QMediaPlayer::State state) +{ + if (state == QMediaPlayer::StoppedState) { + if (m_runningCount < 0) { + m_player->play(); + } else if (m_runningCount == 0) { + setPlaying(false); + return; + } else if (--m_runningCount > 0) { + m_player->play(); + } else { + setPlaying(false); + } + } else { + setPlaying(true); + } +} + +void QSoundEffectPrivate::mediaStatusChanged(QMediaPlayer::MediaStatus status) +{ + switch(status) { + case QMediaPlayer::LoadingMedia: + setStatus(QSoundEffect::Loading); + break; + case QMediaPlayer::NoMedia: + setStatus(QSoundEffect::Null); + break; + case QMediaPlayer::InvalidMedia: + setStatus(QSoundEffect::Error); + break; + default: + setStatus(QSoundEffect::Ready); + break; + } +} + +void QSoundEffectPrivate::error(QMediaPlayer::Error err) +{ + bool playingDirty = false; + if (m_playing) { + m_playing = false; + playingDirty = true; + } + setStatus(QSoundEffect::Error); + if (playingDirty) + emit playingChanged(); +} + +void QSoundEffectPrivate::setStatus(QSoundEffect::Status status) +{ + if (m_status == status) + return; + bool oldLoaded = isLoaded(); + m_status = status; + emit statusChanged(); + if (oldLoaded != isLoaded()) + emit loadedChanged(); +} + +void QSoundEffectPrivate::setPlaying(bool playing) +{ + if (m_playing == playing) + return; + m_playing = playing; + emit playingChanged(); +} + +QT_END_NAMESPACE + +#include "moc_qsoundeffect_qmedia_p.cpp" diff --git a/src/multimediakit/effects/qsoundeffect_qmedia_p.h b/src/multimediakit/effects/qsoundeffect_qmedia_p.h new file mode 100644 index 000000000..7351350e6 --- /dev/null +++ b/src/multimediakit/effects/qsoundeffect_qmedia_p.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSOUNDEFFECT_QMEDIA_H +#define QSOUNDEFFECT_QMEDIA_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include "qmediaplayer.h" +#include "qsoundeffect_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QSoundEffectPrivate : public QObject +{ + Q_OBJECT +public: + + explicit QSoundEffectPrivate(QObject* parent); + ~QSoundEffectPrivate(); + + static QStringList supportedMimeTypes(); + + QUrl source() const; + void setSource(const QUrl &url); + int loopCount() const; + void setLoopCount(int loopCount); + int volume() const; + void setVolume(int volume); + bool isMuted() const; + void setMuted(bool muted); + bool isLoaded() const; + bool isPlaying() const; + QSoundEffect::Status status() const; + +public Q_SLOTS: + void play(); + void stop(); + +Q_SIGNALS: + void volumeChanged(); + void mutedChanged(); + void loadedChanged(); + void playingChanged(); + void statusChanged(); + +private Q_SLOTS: + void stateChanged(QMediaPlayer::State); + void mediaStatusChanged(QMediaPlayer::MediaStatus); + void error(QMediaPlayer::Error); + +private: + void setStatus(QSoundEffect::Status status); + void setPlaying(bool playing); + + int m_loopCount; + int m_runningCount; + bool m_playing; + QSoundEffect::Status m_status; + QMediaPlayer *m_player; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSOUNDEFFECT_QMEDIA_H diff --git a/src/multimediakit/effects/qsoundeffect_qsound_p.cpp b/src/multimediakit/effects/qsoundeffect_qsound_p.cpp new file mode 100644 index 000000000..7a753d18c --- /dev/null +++ b/src/multimediakit/effects/qsoundeffect_qsound_p.cpp @@ -0,0 +1,222 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include "qsoundeffect_qsound_p.h" + +#include +#include +#include + + +QT_BEGIN_NAMESPACE + +QSoundEffectPrivate::QSoundEffectPrivate(QObject* parent): + QObject(parent), + m_playing(false), + m_timerID(0), + m_muted(false), + m_loopCount(1), + m_volume(100), + m_status(QSoundEffect::Null), + m_sound(0) +{ + if (!QSound::isAvailable()) + qWarning("SoundEffect(qsound) : not available"); +} + +QSoundEffectPrivate::~QSoundEffectPrivate() +{ +} + +QStringList QSoundEffectPrivate::supportedMimeTypes() +{ + QStringList supportedTypes; + supportedTypes << QLatin1String("audio/x-wav") << QLatin1String("audio/vnd.wave") ; + return supportedTypes; +} + +QUrl QSoundEffectPrivate::source() const +{ + return m_source; +} + +void QSoundEffectPrivate::setSource(const QUrl &url) +{ + if (url.isEmpty()) { + m_source = QUrl(); + setStatus(QSoundEffect::Null); + return; + } + + if (url.scheme() != QLatin1String("file")) { + m_source = url; + setStatus(QSoundEffect::Error); + return; + } + + if (m_sound != 0) + delete m_sound; + + m_source = url; + m_sound = new QSound(m_source.toLocalFile(), this); + m_sound->setLoops(m_loopCount); + m_status = QSoundEffect::Ready; + emit statusChanged(); + emit loadedChanged(); +} + +int QSoundEffectPrivate::loopCount() const +{ + return m_loopCount; +} + +void QSoundEffectPrivate::setLoopCount(int lc) +{ + m_loopCount = lc; + if (m_sound) + m_sound->setLoops(lc); +} + +int QSoundEffectPrivate::volume() const +{ + return m_volume; +} + +void QSoundEffectPrivate::setVolume(int v) +{ + m_volume = v; +} + +bool QSoundEffectPrivate::isMuted() const +{ + return m_muted; +} + +void QSoundEffectPrivate::setMuted(bool muted) +{ + m_muted = muted; +} + +bool QSoundEffectPrivate::isLoaded() const +{ + return m_status == QSoundEffect::Ready; +} + +void QSoundEffectPrivate::play() +{ + if (m_status == QSoundEffect::Null || m_status == QSoundEffect::Error) + return; + if (m_timerID != 0) + killTimer(m_timerID); + m_timerID = startTimer(500); + m_sound->play(); + setPlaying(true); +} + + +void QSoundEffectPrivate::stop() +{ + if (m_timerID != 0) + killTimer(m_timerID); + m_timerID = 0; + m_sound->stop(); + setPlaying(false); +} + +bool QSoundEffectPrivate::isPlaying() +{ + if (m_playing && m_sound && m_sound->isFinished()) { + if (m_timerID != 0) + killTimer(m_timerID); + m_timerID = 0; + setPlaying(false); + } + return m_playing; +} + +QSoundEffect::Status QSoundEffectPrivate::status() const +{ + return m_status; +} + +void QSoundEffectPrivate::timerEvent(QTimerEvent *event) +{ + Q_UNUSED(event); + setPlaying(!m_sound->isFinished()); + if (isPlaying()) + return; + killTimer(m_timerID); + m_timerID = 0; +} + +void QSoundEffectPrivate::setStatus(QSoundEffect::Status status) +{ + if (m_status == status) + return; + bool oldLoaded = isLoaded(); + m_status = status; + emit statusChanged(); + if (oldLoaded != isLoaded()) + emit loadedChanged(); +} + +void QSoundEffectPrivate::setPlaying(bool playing) +{ + if (m_playing == playing) + return; + m_playing = playing; + emit playingChanged(); +} + +QT_END_NAMESPACE + +#include "moc_qsoundeffect_qsound_p.cpp" diff --git a/src/multimediakit/effects/qsoundeffect_qsound_p.h b/src/multimediakit/effects/qsoundeffect_qsound_p.h new file mode 100644 index 000000000..2a7691b23 --- /dev/null +++ b/src/multimediakit/effects/qsoundeffect_qsound_p.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSOUNDEFFECT_QSOUND_H +#define QSOUNDEFFECT_QSOUND_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#include +#include +#include "qsoundeffect_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QSound; + +class QSoundEffectPrivate : public QObject +{ + Q_OBJECT +public: + explicit QSoundEffectPrivate(QObject* parent); + ~QSoundEffectPrivate(); + + static QStringList supportedMimeTypes(); + + QUrl source() const; + void setSource(const QUrl &url); + int loopCount() const; + void setLoopCount(int loopCount); + int volume() const; + void setVolume(int volume); + bool isMuted() const; + void setMuted(bool muted); + bool isLoaded() const; + bool isPlaying(); + QSoundEffect::Status status() const; + +public Q_SLOTS: + void play(); + void stop(); + +Q_SIGNALS: + void volumeChanged(); + void mutedChanged(); + void loadedChanged(); + void playingChanged(); + void statusChanged(); + +private: + void setStatus(QSoundEffect::Status status); + void setPlaying(bool playing); + void timerEvent(QTimerEvent *event); + + bool m_playing; + int m_timerID; + bool m_muted; + int m_loopCount; + int m_volume; + QSoundEffect::Status m_status; + QSound *m_sound; + QUrl m_source; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSOUNDEFFECT_QSOUND_H diff --git a/src/multimediakit/effects/qwavedecoder_p.cpp b/src/multimediakit/effects/qwavedecoder_p.cpp new file mode 100644 index 000000000..992bb0996 --- /dev/null +++ b/src/multimediakit/effects/qwavedecoder_p.cpp @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwavedecoder_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +QWaveDecoder::QWaveDecoder(QIODevice *s, QObject *parent): + QIODevice(parent), + haveFormat(false), + dataSize(0), + remaining(0), + source(s), + state(QWaveDecoder::InitialState) +{ + open(QIODevice::ReadOnly | QIODevice::Unbuffered); + + if (enoughDataAvailable()) + QTimer::singleShot(0, this, SLOT(handleData())); + else + connect(source, SIGNAL(readyRead()), SLOT(handleData())); +} + +QWaveDecoder::~QWaveDecoder() +{ +} + +QAudioFormat QWaveDecoder::audioFormat() const +{ + return format; +} + +int QWaveDecoder::duration() const +{ + return size() * 1000 / (format.sampleSize() / 8) / format.channels() / format.frequency(); +} + +qint64 QWaveDecoder::size() const +{ + return haveFormat ? dataSize : 0; +} + +bool QWaveDecoder::isSequential() const +{ + return source->isSequential(); +} + +qint64 QWaveDecoder::bytesAvailable() const +{ + return haveFormat ? source->bytesAvailable() : 0; +} + +qint64 QWaveDecoder::readData(char *data, qint64 maxlen) +{ + return haveFormat ? source->read(data, maxlen) : 0; +} + +qint64 QWaveDecoder::writeData(const char *data, qint64 len) +{ + Q_UNUSED(data); + Q_UNUSED(len); + + return -1; +} + +void QWaveDecoder::handleData() +{ + if (state == QWaveDecoder::InitialState) { + if (source->bytesAvailable() < qint64(sizeof(RIFFHeader))) + return; + + RIFFHeader riff; + source->read(reinterpret_cast(&riff), sizeof(RIFFHeader)); + + if (qstrncmp(riff.descriptor.id, "RIFF", 4) != 0 || + qstrncmp(riff.type, "WAVE", 4) != 0) { + source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData())); + emit invalidFormat(); + + return; + } else { + state = QWaveDecoder::WaitingForFormatState; + } + } + + if (state == QWaveDecoder::WaitingForFormatState) { + if (findChunk("fmt ")) { + chunk descriptor; + source->peek(reinterpret_cast(&descriptor), sizeof(chunk)); + + if (source->bytesAvailable() < qint64(descriptor.size + sizeof(chunk))) + return; + + WAVEHeader wave; + source->read(reinterpret_cast(&wave), sizeof(WAVEHeader)); + if (descriptor.size > sizeof(WAVEHeader)) + discardBytes(descriptor.size - sizeof(WAVEHeader)); + + if (wave.audioFormat != 0 && wave.audioFormat != 1) { + source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData())); + emit invalidFormat(); + + return; + } else { + int bps = qFromLittleEndian(wave.bitsPerSample); + + format.setCodec(QLatin1String("audio/pcm")); + format.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt); + format.setByteOrder(QAudioFormat::LittleEndian); + format.setFrequency(qFromLittleEndian(wave.sampleRate)); + format.setSampleSize(bps); + format.setChannels(qFromLittleEndian(wave.numChannels)); + + state = QWaveDecoder::WaitingForDataState; + } + } + } + + if (state == QWaveDecoder::WaitingForDataState) { + if (findChunk("data")) { + source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData())); + + chunk descriptor; + source->read(reinterpret_cast(&descriptor), sizeof(chunk)); + dataSize = descriptor.size; + + haveFormat = true; + connect(source, SIGNAL(readyRead()), SIGNAL(readyRead())); + emit formatKnown(); + + return; + } + } + + if (source->atEnd()) { + source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData())); + emit invalidFormat(); + + return; + } + +} + +bool QWaveDecoder::enoughDataAvailable() +{ + if (source->bytesAvailable() < qint64(sizeof(chunk))) + return false; + + chunk descriptor; + source->peek(reinterpret_cast(&descriptor), sizeof(chunk)); + + if (source->bytesAvailable() < qint64(sizeof(chunk) + descriptor.size)) + return false; + + return true; +} + +bool QWaveDecoder::findChunk(const char *chunkId) +{ + if (source->bytesAvailable() < qint64(sizeof(chunk))) + return false; + + chunk descriptor; + source->peek(reinterpret_cast(&descriptor), sizeof(chunk)); + + if (qstrncmp(descriptor.id, chunkId, 4) == 0) + return true; + + while (source->bytesAvailable() >= qint64(sizeof(chunk) + descriptor.size)) { + discardBytes(sizeof(chunk) + descriptor.size); + + source->peek(reinterpret_cast(&descriptor), sizeof(chunk)); + + if (qstrncmp(descriptor.id, chunkId, 4) == 0) + return true; + } + + return false; +} + +void QWaveDecoder::discardBytes(qint64 numBytes) +{ + if (source->isSequential()) + source->read(numBytes); + else + source->seek(source->pos() + numBytes); +} + +QT_END_NAMESPACE + +#include "moc_qwavedecoder_p.cpp" diff --git a/src/multimediakit/effects/qwavedecoder_p.h b/src/multimediakit/effects/qwavedecoder_p.h new file mode 100644 index 000000000..90dfda811 --- /dev/null +++ b/src/multimediakit/effects/qwavedecoder_p.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WAVEDECODER_H +#define WAVEDECODER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QWaveDecoder : public QIODevice +{ + Q_OBJECT + +public: + explicit QWaveDecoder(QIODevice *source, QObject *parent = 0); + ~QWaveDecoder(); + + QAudioFormat audioFormat() const; + int duration() const; + + qint64 size() const; + bool isSequential() const; + qint64 bytesAvailable() const; + +Q_SIGNALS: + void formatKnown(); + void invalidFormat(); + +private Q_SLOTS: + void handleData(); + +private: + qint64 readData(char *data, qint64 maxlen); + qint64 writeData(const char *data, qint64 len); + + bool enoughDataAvailable(); + bool findChunk(const char *chunkId); + void discardBytes(qint64 numBytes); + + enum State { + InitialState, + WaitingForFormatState, + WaitingForDataState + }; + + struct chunk + { + char id[4]; + quint32 size; + }; + struct RIFFHeader + { + chunk descriptor; + char type[4]; + }; + struct WAVEHeader + { + chunk descriptor; + quint16 audioFormat; + quint16 numChannels; + quint32 sampleRate; + quint32 byteRate; + quint16 blockAlign; + quint16 bitsPerSample; + }; + + bool haveFormat; + qint64 dataSize; + qint64 remaining; + QAudioFormat format; + QIODevice *source; + State state; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // WAVEDECODER_H diff --git a/src/multimediakit/multimediakit.pro b/src/multimediakit/multimediakit.pro new file mode 100644 index 000000000..57d5af5f2 --- /dev/null +++ b/src/multimediakit/multimediakit.pro @@ -0,0 +1,217 @@ +load(qt_module) + +# distinct from QtMultimedia +TARGET = QtMultimediaKit +QPRO_PWD = $$PWD +QT = core network + +CONFIG += module +MODULE_PRI += ../../modules/qt_multimediakit.pri + +contains(QT_CONFIG, opengl) | contains(QT_CONFIG, opengles2): !symbian { + QT += opengl +} else { + DEFINES += QT_NO_OPENGL +} + +!static:DEFINES += QT_MAKEDLL +DEFINES += QT_BUILD_MULTIMEDIA_LIB + +load(qt_module_config) + +HEADERS += qtmultimediakitversion.h + +PRIVATE_HEADERS += \ + qmediacontrol_p.h \ + qmediaobject_p.h \ + qmediaservice_p.h \ + qmediaplaylist_p.h \ + qmediaplaylistprovider_p.h \ + qmediaimageviewerservice_p.h \ + qvideowidget_p.h \ + qmediapluginloader_p.h \ + qpaintervideosurface_p.h \ + qvideosurfaceoutput_p.h + +PUBLIC_HEADERS += \ + qmediacontrol.h \ + qmediaobject.h \ + qmediaservice.h \ + qmediabindableinterface.h \ + qlocalmediaplaylistprovider.h \ + qmediaimageviewer.h \ + qmediaplayer.h \ + qmediaplayercontrol.h \ + qmediaplaylist.h \ + qmediaplaylistnavigator.h \ + qmediaplaylistprovider.h \ + qmediaplaylistioplugin.h \ + qmediacontent.h \ + qmediaresource.h \ + qmediarecorder.h \ + qmediaencodersettings.h \ + qmediarecordercontrol.h \ + qmediaserviceprovider.h \ + qmediaserviceproviderplugin.h \ + qmetadatareadercontrol.h \ + qmetadatawritercontrol.h \ + qmediastreamscontrol.h \ + qradiotuner.h \ + qradiotunercontrol.h \ + qtmedianamespace.h \ + qvideowidget.h \ + qvideowindowcontrol.h \ + qvideowidgetcontrol.h \ + qaudioencodercontrol.h \ + qvideoencodercontrol.h \ + qimageencodercontrol.h \ + qaudiocapturesource.h \ + qmediacontainercontrol.h \ + qmediaplaylistcontrol.h \ + qmediaplaylistsourcecontrol.h \ + qaudioendpointselector.h \ + qvideodevicecontrol.h \ + qgraphicsvideoitem.h \ + qvideorenderercontrol.h \ + qmediatimerange.h \ + qmedianetworkaccesscontrol.h \ + qmediaenumdebug.h + +SOURCES += qmediacontrol.cpp \ + qmediaobject.cpp \ + qmediaservice.cpp \ + qmediabindableinterface.cpp \ + qlocalmediaplaylistprovider.cpp \ + qmediaimageviewer.cpp \ + qmediaimageviewerservice.cpp \ + qmediaplayer.cpp \ + qmediaplayercontrol.cpp \ + qmediaplaylist.cpp \ + qmediaplaylistioplugin.cpp \ + qmediaplaylistnavigator.cpp \ + qmediaplaylistprovider.cpp \ + qmediarecorder.cpp \ + qmediaencodersettings.cpp \ + qmediarecordercontrol.cpp \ + qmediacontent.cpp \ + qmediaresource.cpp \ + qmediaserviceprovider.cpp \ + qmetadatareadercontrol.cpp \ + qmetadatawritercontrol.cpp \ + qmediastreamscontrol.cpp \ + qradiotuner.cpp \ + qradiotunercontrol.cpp \ + qvideowidget.cpp \ + qvideowindowcontrol.cpp \ + qvideowidgetcontrol.cpp \ + qaudioencodercontrol.cpp \ + qvideoencodercontrol.cpp \ + qimageencodercontrol.cpp \ + qaudiocapturesource.cpp \ + qmediacontainercontrol.cpp \ + qmediaplaylistcontrol.cpp \ + qmediaplaylistsourcecontrol.cpp \ + qaudioendpointselector.cpp \ + qvideodevicecontrol.cpp \ + qmediapluginloader.cpp \ + qpaintervideosurface.cpp \ + qvideorenderercontrol.cpp \ + qmediatimerange.cpp \ + qmedianetworkaccesscontrol.cpp \ + qvideosurfaceoutput.cpp + +#Camera +PUBLIC_HEADERS += \ + qcamera.h \ + qcameraviewfinder.h \ + qcameraimagecapture.h \ + qcameraimagecapturecontrol.h \ + qcameraexposure.h \ + qcamerafocus.h \ + qcameraimageprocessing.h \ + qcameracontrol.h \ + qcameralockscontrol.h \ + qcameraexposurecontrol.h \ + qcamerafocuscontrol.h \ + qcameraflashcontrol.h \ + qcameraimageprocessingcontrol.h \ + qcameracapturedestinationcontrol.h \ + qcameracapturebufferformatcontrol.h + +SOURCES += \ + qcamera.cpp \ + qcameraviewfinder.cpp \ + qcameraexposure.cpp \ + qcamerafocus.cpp \ + qcameraimageprocessing.cpp \ + qcameraimagecapture.cpp \ + qcameraimagecapturecontrol.cpp \ + qcameracontrol.cpp \ + qcameralockscontrol.cpp \ + qcameraexposurecontrol.cpp \ + qcamerafocuscontrol.cpp \ + qcameraflashcontrol.cpp \ + qcameraimageprocessingcontrol.cpp \ + qcameracapturedestinationcontrol.cpp \ + qcameracapturebufferformatcontrol.cpp + +include(audio/audio.pri) +include(video/video.pri) +include(effects/effects.pri) + +mac { +!simulator { + HEADERS += qpaintervideosurface_mac_p.h + OBJECTIVE_SOURCES += qpaintervideosurface_mac.mm +} + LIBS += -framework AppKit -framework QuartzCore -framework QTKit +} + +maemo5 { + isEqual(QT_ARCH,armv6):QMAKE_CXXFLAGS += -march=armv7a -mcpu=cortex-a8 -mfloat-abi=softfp -mfpu=neon + HEADERS += qxvideosurface_maemo5_p.h + SOURCES += qxvideosurface_maemo5.cpp + SOURCES += qgraphicsvideoitem_maemo5.cpp + LIBS += -lXv -lX11 -lXext +} + +maemo6 { + isEqual(QT_ARCH,armv6) { + HEADERS += qeglimagetexturesurface_p.h + SOURCES += qeglimagetexturesurface.cpp + + SOURCES += qgraphicsvideoitem_maemo6.cpp + + LIBS += -lX11 + } else { + SOURCES += qgraphicsvideoitem.cpp + } +} + +symbian { + contains(surfaces_s60_enabled, yes) { + SOURCES += qgraphicsvideoitem_symbian.cpp + } else { + SOURCES += qgraphicsvideoitem_overlay.cpp + } +} + +!maemo*:!symbian { + SOURCES += qgraphicsvideoitem.cpp +} + +HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS + +symbian { + contains(S60_VERSION, 5.1) |contains (S60_VERSION, 3.2) | contains(S60_VERSION, 3.1): DEFINES += PRE_S60_52_PLATFORM + load(data_caging_paths) + QtMediaDeployment.sources = QtMultimediaKit.dll + QtMediaDeployment.path = /sys/bin + DEPLOYMENT += QtMediaDeployment + TARGET.UID3=0x2002AC77 + TARGET.CAPABILITY = ALL -TCB + LIBS += -lefsrv +} + +# CONFIG += middleware +# include(../../features/deploy.pri) diff --git a/src/multimediakit/qaudiocapturesource.cpp b/src/multimediakit/qaudiocapturesource.cpp new file mode 100644 index 000000000..55adda15d --- /dev/null +++ b/src/multimediakit/qaudiocapturesource.cpp @@ -0,0 +1,275 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaobject_p.h" +#include +#include "qaudioendpointselector.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QAudioCaptureSource + \brief The QAudioCaptureSource class provides an interface to query and select an audio input endpoint. + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + QAudioCaptureSource provides access to the audio inputs available on your system. + + You can query these inputs and select one to use. + + A typical implementation example: + \snippet doc/src/snippets/multimedia-snippets/media.cpp Audio capture source + + The audiocapturesource interface is then used to: + + - Get and Set the audio input to use. + + The capture interface is then used to: + + - Set the destination using setOutputLocation() + + - Set the format parameters using setAudioCodec(), + + - Control the recording using record(),stop() + + \sa QMediaRecorder +*/ + +class QAudioCaptureSourcePrivate : public QMediaObjectPrivate +{ +public: + Q_DECLARE_PUBLIC(QAudioCaptureSource) + + void initControls() + { + Q_Q(QAudioCaptureSource); + + if (service != 0) + audioEndpointSelector = qobject_cast(service->requestControl(QAudioEndpointSelector_iid)); + + if (audioEndpointSelector) { + q->connect(audioEndpointSelector, SIGNAL(activeEndpointChanged(const QString&)), + SIGNAL(activeAudioInputChanged(const QString&))); + q->connect(audioEndpointSelector, SIGNAL(availableEndpointsChanged()), + SIGNAL(availableAudioInputsChanged())); + q->connect(audioEndpointSelector, SIGNAL(availableEndpointsChanged()), + SLOT(statusChanged())); + errorState = QtMultimediaKit::NoError; + } + } + + QAudioCaptureSourcePrivate():provider(0), audioEndpointSelector(0), errorState(QtMultimediaKit::ServiceMissingError) {} + QMediaServiceProvider *provider; + QAudioEndpointSelector *audioEndpointSelector; + QtMultimediaKit::AvailabilityError errorState; +}; + +/*! + Construct a QAudioCaptureSource using the QMediaService from \a provider, with \a parent. + \since 1.0 +*/ + +QAudioCaptureSource::QAudioCaptureSource(QObject *parent, QMediaServiceProvider *provider): + QMediaObject(*new QAudioCaptureSourcePrivate, parent, provider->requestService(Q_MEDIASERVICE_AUDIOSOURCE)) +{ + Q_D(QAudioCaptureSource); + + d->provider = provider; + d->initControls(); +} + +/*! + Destroys the audiocapturesource object. +*/ + +QAudioCaptureSource::~QAudioCaptureSource() +{ + Q_D(QAudioCaptureSource); + + if (d->service && d->audioEndpointSelector) + d->service->releaseControl(d->audioEndpointSelector); + + if (d->provider) + d->provider->releaseService(d->service); +} + +/*! + Returns the error state of the audio capture service. + \since 1.0 +*/ + +QtMultimediaKit::AvailabilityError QAudioCaptureSource::availabilityError() const +{ + Q_D(const QAudioCaptureSource); + + return d->errorState; +} + +/*! + Returns true if the audio capture service is available, otherwise returns false. + \since 1.0 +*/ +bool QAudioCaptureSource::isAvailable() const +{ + Q_D(const QAudioCaptureSource); + + if (d->service != NULL) { + if (d->audioEndpointSelector && d->audioEndpointSelector->availableEndpoints().size() > 0) + return true; + } + return false; +} + + +/*! + Returns a list of available audio inputs + \since 1.0 +*/ + +QList QAudioCaptureSource::audioInputs() const +{ + Q_D(const QAudioCaptureSource); + + QList list; + if (d && d->audioEndpointSelector) + list <audioEndpointSelector->availableEndpoints(); + + return list; +} + +/*! + Returns the description of the audio input device with \a name. + \since 1.0 +*/ + +QString QAudioCaptureSource::audioDescription(const QString& name) const +{ + Q_D(const QAudioCaptureSource); + + if(d->audioEndpointSelector) + return d->audioEndpointSelector->endpointDescription(name); + else + return QString(); +} + +/*! + Returns the default audio input name. + \since 1.0 +*/ + +QString QAudioCaptureSource::defaultAudioInput() const +{ + Q_D(const QAudioCaptureSource); + + if(d->audioEndpointSelector) + return d->audioEndpointSelector->defaultEndpoint(); + else + return QString(); +} + +/*! + Returns the active audio input name. + \since 1.0 +*/ + +QString QAudioCaptureSource::activeAudioInput() const +{ + Q_D(const QAudioCaptureSource); + + if(d->audioEndpointSelector) + return d->audioEndpointSelector->activeEndpoint(); + else + return QString(); +} + +/*! + Set the active audio input to \a name. + \since 1.0 +*/ + +void QAudioCaptureSource::setAudioInput(const QString& name) +{ + Q_D(const QAudioCaptureSource); + + if(d->audioEndpointSelector) + return d->audioEndpointSelector->setActiveEndpoint(name); +} + +/*! + \fn QAudioCaptureSource::activeAudioInputChanged(const QString& name) + + Signal emitted when active audio input changes to \a name. + \since 1.0 +*/ + +/*! + \fn QAudioCaptureSource::availableAudioInputsChanged() + + Signal is emitted when the available audio inputs change. + \since 1.0 +*/ + +/*! + \internal + \since 1.0 +*/ +void QAudioCaptureSource::statusChanged() +{ + Q_D(QAudioCaptureSource); + + if (d->audioEndpointSelector) { + if (d->audioEndpointSelector->availableEndpoints().size() > 0) { + d->errorState = QtMultimediaKit::NoError; + emit availabilityChanged(true); + } else { + d->errorState = QtMultimediaKit::BusyError; + emit availabilityChanged(false); + } + } else { + d->errorState = QtMultimediaKit::ServiceMissingError; + emit availabilityChanged(false); + } +} + +#include "moc_qaudiocapturesource.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qaudiocapturesource.h b/src/multimediakit/qaudiocapturesource.h new file mode 100644 index 000000000..0ef75552a --- /dev/null +++ b/src/multimediakit/qaudiocapturesource.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAUDIOCAPTURESOURCE_H +#define QAUDIOCAPTURESOURCE_H + +#include +#include +#include + +#include + +#include "qmediarecorder.h" +#include "qmediacontrol.h" +#include "qmediaobject.h" +#include "qmediaservice.h" + +#include "qmediaserviceprovider.h" + +QT_BEGIN_NAMESPACE + +class QAudioCaptureSourcePrivate; + +class Q_MULTIMEDIA_EXPORT QAudioCaptureSource : public QMediaObject +{ + Q_OBJECT + +public: + QAudioCaptureSource(QObject *parent = 0, QMediaServiceProvider *service = QMediaServiceProvider::defaultServiceProvider()); + ~QAudioCaptureSource(); + + bool isAvailable() const; + QtMultimediaKit::AvailabilityError availabilityError() const; + + QList audioInputs() const; + + QString audioDescription(const QString& name) const; + QString defaultAudioInput() const; + QString activeAudioInput() const; + +public Q_SLOTS: + void setAudioInput(const QString& name); + +Q_SIGNALS: + void activeAudioInputChanged(const QString& name); + void availableAudioInputsChanged(); + +private Q_SLOTS: + void statusChanged(); + +private: + Q_DECLARE_PRIVATE(QAudioCaptureSource) +}; + +QT_END_NAMESPACE + +#endif // QAUDIOCAPTURESOURCE_H diff --git a/src/multimediakit/qaudioencodercontrol.cpp b/src/multimediakit/qaudioencodercontrol.cpp new file mode 100644 index 000000000..d836da94a --- /dev/null +++ b/src/multimediakit/qaudioencodercontrol.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaudioencodercontrol.h" +#include + +QT_BEGIN_NAMESPACE + + +/*! + \class QAudioEncoderControl + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + \brief The QAudioEncoderControl class provides access to the settings of a + media service that performs audio encoding. + + If a QMediaService supports encoding audio data it will implement + QAudioEncoderControl. This control provides information about the limits + of restricted audio encoder options and allows the selection of a set of + audio encoder settings as specified in a QAudioEncoderSettings object. + + The functionality provided by this control is exposed to application code through the + QMediaRecorder class. + + The interface name of QAudioEncoderControl is \c com.nokia.Qt.QAudioEncoderControl/1.0 as + defined in QAudioEncoderControl_iid. + + \sa QMediaService::requestControl(), QMediaRecorder +*/ + +/*! + \macro QAudioEncoderControl_iid + + \c com.nokia.Qt.AudioEncoderControl/1.0 + + Defines the interface name of the QAudioEncoderControl class. + + \relates QAudioEncoderControl +*/ + +/*! + Create a new audio encode control object with the given \a parent. +*/ +QAudioEncoderControl::QAudioEncoderControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys the audio encode control. +*/ +QAudioEncoderControl::~QAudioEncoderControl() +{ +} + +/*! + \fn QAudioEncoderControl::supportedAudioCodecs() const + + Returns the list of supported audio codec names. + \since 1.0 +*/ + +/*! + \fn QAudioEncoderControl::codecDescription(const QString &codec) const + + Returns description of audio \a codec. + \since 1.0 +*/ + +/*! + \fn QAudioEncoderControl::supportedSampleRates(const QAudioEncoderSettings &settings = QAudioEncoderSettings(), + bool *continuous) const + + Returns the list of supported audio sample rates, if known. + + If non null audio \a settings parameter is passed, + the returned list is reduced to sample rates supported with partial settings applied. + + It can be used for example to query the list of sample rates, supported by specific audio codec. + + If the encoder supports arbitrary sample rates within the supported rates range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + \since 1.0 +*/ + +/*! + \fn QAudioEncoderControl::supportedEncodingOptions(const QString &codec) const + + Returns the list of \a codec specific audio encoding options. + \since 1.0 +*/ + +/*! + \fn QAudioEncoderControl::encodingOption(const QString &codec, const QString &option) const + + Returns the value of audio encoding \a option for \a codec. + \since 1.0 +*/ + +/*! + \fn QAudioEncoderControl::setEncodingOption(const QString &codec, const QString &option, const QVariant &value) + + Set the \a codec specific \a option to \a value. + \since 1.0 +*/ + +/*! + \fn QAudioEncoderControl::audioSettings() const + + Returns the audio encoder settings. + + The returned value may be different tha passed to QAudioEncoderControl::setAudioSettings() + if the settings contains the default or undefined parameters. + In this case if the undefined parameters are already resolved, they should be returned. + \since 1.0 +*/ + +/*! + \fn QAudioEncoderControl::setAudioSettings(const QAudioEncoderSettings &settings) + + Sets the selected audio \a settings. + \since 1.0 +*/ + +#include "moc_qaudioencodercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qaudioencodercontrol.h b/src/multimediakit/qaudioencodercontrol.h new file mode 100644 index 000000000..06cff617e --- /dev/null +++ b/src/multimediakit/qaudioencodercontrol.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAUDIOENCODERCONTROL_H +#define QAUDIOENCODERCONTROL_H + +#include "qmediacontrol.h" +#include "qmediarecorder.h" +#include +#include + +QT_BEGIN_NAMESPACE +class QStringList; +class QAudioFormat; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QAudioEncoderControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QAudioEncoderControl(); + + virtual QStringList supportedAudioCodecs() const = 0; + virtual QString codecDescription(const QString &codecName) const = 0; + + virtual QList supportedSampleRates(const QAudioEncoderSettings &settings, + bool *continuous = 0) const = 0; + + virtual QAudioEncoderSettings audioSettings() const = 0; + virtual void setAudioSettings(const QAudioEncoderSettings&) = 0; + + virtual QStringList supportedEncodingOptions(const QString &codec) const = 0; + virtual QVariant encodingOption(const QString &codec, const QString &name) const = 0; + virtual void setEncodingOption( + const QString &codec, const QString &name, const QVariant &value) = 0; + +protected: + QAudioEncoderControl(QObject *parent = 0); +}; + +#define QAudioEncoderControl_iid "com.nokia.Qt.QAudioEncoderControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QAudioEncoderControl, QAudioEncoderControl_iid) + +QT_END_NAMESPACE + +#endif // QAUDIOCAPTUREPROPERTIESCONTROL_H diff --git a/src/multimediakit/qaudioendpointselector.cpp b/src/multimediakit/qaudioendpointselector.cpp new file mode 100644 index 000000000..1a09f3546 --- /dev/null +++ b/src/multimediakit/qaudioendpointselector.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaudioendpointselector.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QAudioEndpointSelector + + \brief The QAudioEndpointSelector class provides an audio endpoint selector media control. + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + The QAudioEndpointSelector class provides descriptions of the audio + endpoints available on a system and allows one to be selected as the audio + of a media service. + + XXX why do I care + + The interface name of QAudioEndpointSelector is \c com.nokia.Qt.QAudioEndpointSelector/1.0 as + defined in QAudioEndpointSelector_iid. + + \sa QMediaService::requestControl() +*/ + +/*! + \macro QAudioEndpointSelector_iid + + \c com.nokia.Qt.QAudioEndpointSelector/1.0 + + Defines the interface name of the QAudioEndpointSelector class. + + \relates QAudioEndpointSelector +*/ + +/*! + Constructs a new audio endpoint selector with the given \a parent. +*/ +QAudioEndpointSelector::QAudioEndpointSelector(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys an audio endpoint selector. +*/ +QAudioEndpointSelector::~QAudioEndpointSelector() +{ +} + +/*! + \fn QList QAudioEndpointSelector::availableEndpoints() const + + Returns a list of the names of the available audio endpoints. + \since 1.0 +*/ + +/*! + \fn QString QAudioEndpointSelector::endpointDescription(const QString& name) const + + Returns the description of the endpoint \a name. + \since 1.0 +*/ + +/*! + \fn QString QAudioEndpointSelector::defaultEndpoint() const + + Returns the name of the default audio endpoint. + \since 1.0 +*/ + +/*! + \fn QString QAudioEndpointSelector::activeEndpoint() const + + Returns the name of the currently selected audio endpoint. + \since 1.0 +*/ + +/*! + \fn QAudioEndpointSelector::setActiveEndpoint(const QString& name) + + Set the active audio endpoint to \a name. + \since 1.0 +*/ + +/*! + \fn QAudioEndpointSelector::activeEndpointChanged(const QString& name) + + Signals that the audio endpoint has changed to \a name. + \since 1.0 +*/ + +/*! + \fn QAudioEndpointSelector::availableEndpointsChanged() + + Signals that list of available endpoints has changed. + \since 1.0 +*/ + +#include "moc_qaudioendpointselector.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qaudioendpointselector.h b/src/multimediakit/qaudioendpointselector.h new file mode 100644 index 000000000..e28010c65 --- /dev/null +++ b/src/multimediakit/qaudioendpointselector.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAUDIOENDPOINTSELECTOR_H +#define QAUDIOENDPOINTSELECTOR_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QAudioEndpointSelector : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QAudioEndpointSelector(); + + virtual QList availableEndpoints() const = 0; + virtual QString endpointDescription(const QString& name) const = 0; + virtual QString defaultEndpoint() const = 0; + virtual QString activeEndpoint() const = 0; + +public Q_SLOTS: + virtual void setActiveEndpoint(const QString& name) = 0; + +Q_SIGNALS: + void activeEndpointChanged(const QString& name); + void availableEndpointsChanged(); + +protected: + QAudioEndpointSelector(QObject *parent = 0); +}; + +#define QAudioEndpointSelector_iid "com.nokia.Qt.QAudioEndpointSelector/1.0" +Q_MEDIA_DECLARE_CONTROL(QAudioEndpointSelector, QAudioEndpointSelector_iid) + +QT_END_NAMESPACE + +#endif // QAUDIOENDPOINTSELECTOR_H diff --git a/src/multimediakit/qaudionamespace.qdoc b/src/multimediakit/qaudionamespace.qdoc new file mode 100644 index 000000000..32ceb5c6c --- /dev/null +++ b/src/multimediakit/qaudionamespace.qdoc @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + + +/*! + \namespace QAudio + \brief The QAudio namespace contains enums used by the audio classes. + \inmodule QtMultimediaKit + \ingroup multimedia +*/ + +/* + \enum QAudio::Error + + Error states + + \value NoError No errors have occurred + \value OpenError An error opening the audio device + \value IOError An error occurred during read/write of audio device + \value UnderrunError Audio data is not being fed to the audio device at a fast enough rate + \value FatalError A non-recoverable error has occurred, the audio device is not usable at this time. +*/ + +/* + \enum QAudio::State + + Audio processing states + + \value ActiveState Audio data is being processed, this state is set after start() is called + and while audio data is available to be processed. + \value SuspendedState The audio device is in a suspended state, this state will only be entered + after suspend() is called. + \value StoppedState The audio device is closed, not processing any audio data + \value IdleState The QIODevice passed in has no data and audio system's buffer is empty, this state + is set after start() is called and while no audio data is available to be processed. +*/ + +/* + \enum QAudio::Mode + + Audio I/O modes + + \value AudioOutput audio output device + \value AudioInput audio input device +*/ diff --git a/src/multimediakit/qcamera.cpp b/src/multimediakit/qcamera.cpp new file mode 100644 index 000000000..94b7ac0a2 --- /dev/null +++ b/src/multimediakit/qcamera.cpp @@ -0,0 +1,1027 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_USE_NAMESPACE + +namespace +{ +class CameraRegisterMetaTypes +{ +public: + CameraRegisterMetaTypes() + { + qRegisterMetaType("QCamera::Error"); + qRegisterMetaType("QCamera::State"); + qRegisterMetaType("QCamera::Status"); + qRegisterMetaType("QCamera::CaptureMode"); + qRegisterMetaType("QCamera::LockType"); + qRegisterMetaType("QCamera::LockStatus"); + qRegisterMetaType("QCamera::LockChangeReason"); + } +} _registerCameraMetaTypes; +} + + +/*! + \class QCamera + + + \brief The QCamera class provides interface for system camera devices. + + \inmodule QtMultimediaKit + \ingroup camera + \since 1.1 + + QCamera can be used with QVideoWidget for viewfinder display, + QMediaRecorder for video recording and QCameraImageCapture for image taking. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Request control + +*/ + + +class QCameraPrivate : public QMediaObjectPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QCamera) +public: + QCameraPrivate(): + QMediaObjectPrivate(), + provider(0), + control(0), + deviceControl(0), + viewfinder(0), + capture(0), + state(QCamera::UnloadedState), + error(QCamera::NoError), + supportedLocks(QCamera::NoLock), + requestedLocks(QCamera::NoLock), + lockStatus(QCamera::Unlocked), + lockChangeReason(QCamera::UserRequest), + supressLockChangedSignal(false), + restartPending(false) + { + } + + void initControls(); + + QMediaServiceProvider *provider; + + QCameraControl *control; + QVideoDeviceControl *deviceControl; + QCameraLocksControl *locksControl; + + QCameraExposure *cameraExposure; + QCameraFocus *cameraFocus; + QCameraImageProcessing *imageProcessing; + + QObject *viewfinder; + QObject *capture; + + QCamera::State state; + + QCamera::Error error; + QString errorString; + + QCamera::LockTypes supportedLocks; + QCamera::LockTypes requestedLocks; + + QCamera::LockStatus lockStatus; + QCamera::LockChangeReason lockChangeReason; + bool supressLockChangedSignal; + + bool restartPending; + + QVideoSurfaceOutput surfaceViewfinder; + + void _q_error(int error, const QString &errorString); + void unsetError() { error = QCamera::NoError; errorString.clear(); } + + void setState(QCamera::State); + + void _q_updateLockStatus(QCamera::LockType, QCamera::LockStatus, QCamera::LockChangeReason); + void _q_updateState(QCamera::State newState); + void _q_preparePropertyChange(int changeType); + void _q_restartCamera(); + void updateLockStatus(); +}; + + +void QCameraPrivate::_q_error(int error, const QString &errorString) +{ + Q_Q(QCamera); + + this->error = QCamera::Error(error); + this->errorString = errorString; + + qWarning() << "Camera error:" << errorString; + + emit q->error(this->error); +} + +void QCameraPrivate::setState(QCamera::State newState) +{ + Q_Q(QCamera); + + unsetError(); + + if (!control) { + _q_error(QCamera::ServiceMissingError, q_ptr->tr("The camera service is missing")); + return; + } + + if (state == newState) + return; + + restartPending = false; + state = newState; + control->setState(state); + emit q->stateChanged(state); +} + +void QCameraPrivate::_q_updateState(QCamera::State newState) +{ + Q_Q(QCamera); + + //omit changins state to Loaded when the camera is temporarily + //stopped to apply shanges + if (restartPending) + return; + + if (newState != state) { + qDebug() << "Camera state changed:" << newState; + state = newState; + emit q->stateChanged(state); + } +} + +void QCameraPrivate::_q_preparePropertyChange(int changeType) +{ + if (!control) + return; + + QCamera::Status status = control->status(); + + //all the changes are allowed until the camera is starting + if (control->state() != QCamera::ActiveState) + return; + + if (control->canChangeProperty(QCameraControl::PropertyChangeType(changeType), status)) + return; + + restartPending = true; + control->setState(QCamera::LoadedState); + QMetaObject::invokeMethod(q_ptr, "_q_restartCamera", Qt::QueuedConnection); +} + +void QCameraPrivate::_q_restartCamera() +{ + if (restartPending) { + restartPending = false; + control->setState(QCamera::ActiveState); + } +} + +void QCameraPrivate::initControls() +{ + Q_Q(QCamera); + + supportedLocks = 0; + + if (service) { + control = qobject_cast(service->requestControl(QCameraControl_iid)); + locksControl = qobject_cast(service->requestControl(QCameraLocksControl_iid)); + deviceControl = qobject_cast(service->requestControl(QVideoDeviceControl_iid)); + + if (control) { + q->connect(control, SIGNAL(stateChanged(QCamera::State)), q, SLOT(_q_updateState(QCamera::State))); + q->connect(control, SIGNAL(statusChanged(QCamera::Status)), q, SIGNAL(statusChanged(QCamera::Status))); + q->connect(control, SIGNAL(captureModeChanged(QCamera::CaptureMode)), + q, SIGNAL(captureModeChanged(QCamera::CaptureMode))); + q->connect(control, SIGNAL(error(int,QString)), q, SLOT(_q_error(int,QString))); + + } + + if (locksControl) { + q->connect(locksControl, SIGNAL(lockStatusChanged(QCamera::LockType,QCamera::LockStatus,QCamera::LockChangeReason)), + q, SLOT(_q_updateLockStatus(QCamera::LockType,QCamera::LockStatus,QCamera::LockChangeReason))); + supportedLocks = locksControl->supportedLocks(); + } + + error = QCamera::NoError; + } else { + control = 0; + locksControl = 0; + deviceControl = 0; + + error = QCamera::ServiceMissingError; + errorString = QCamera::tr("The camera service is missing"); + } +} + +void QCameraPrivate::updateLockStatus() +{ + Q_Q(QCamera); + + QCamera::LockStatus oldStatus = lockStatus; + + QMap lockStatusPriority; + lockStatusPriority.insert(QCamera::Locked, 1); + lockStatusPriority.insert(QCamera::Searching, 2); + lockStatusPriority.insert(QCamera::Unlocked, 3); + + lockStatus = requestedLocks ? QCamera::Locked : QCamera::Unlocked; + int priority = 0; + + QList lockStatuses; + + if (requestedLocks & QCamera::LockFocus) + lockStatuses << q->lockStatus(QCamera::LockFocus); + + if (requestedLocks & QCamera::LockExposure) + lockStatuses << q->lockStatus(QCamera::LockExposure); + + if (requestedLocks & QCamera::LockWhiteBalance) + lockStatuses << q->lockStatus(QCamera::LockWhiteBalance); + + + foreach (QCamera::LockStatus currentStatus, lockStatuses) { + int currentPriority = lockStatusPriority.value(currentStatus, -1); + if (currentPriority > priority) { + priority = currentPriority; + lockStatus = currentStatus; + } + } + + if (!supressLockChangedSignal && oldStatus != lockStatus) { + emit q->lockStatusChanged(lockStatus, lockChangeReason); + + if (lockStatus == QCamera::Locked) + emit q->locked(); + else if (lockStatus == QCamera::Unlocked && lockChangeReason == QCamera::LockFailed) + emit q->lockFailed(); + } +/* + qDebug() << "Requested locks:" << (requestedLocks & QCamera::LockExposure ? 'e' : ' ') + << (requestedLocks & QCamera::LockFocus ? 'f' : ' ') + << (requestedLocks & QCamera::LockWhiteBalance ? 'w' : ' '); + qDebug() << "Lock status: f:" << q->lockStatus(QCamera::LockFocus) + << " e:" << q->lockStatus(QCamera::LockExposure) + << " w:" << q->lockStatus(QCamera::LockWhiteBalance) + << " composite:" << lockStatus; +*/ +} + +void QCameraPrivate::_q_updateLockStatus(QCamera::LockType type, QCamera::LockStatus status, QCamera::LockChangeReason reason) +{ + Q_Q(QCamera); + lockChangeReason = reason; + updateLockStatus(); + emit q->lockStatusChanged(type, status, reason); +} + + +/*! + Construct a QCamera from service \a provider and \a parent. +*/ + +QCamera::QCamera(QObject *parent, QMediaServiceProvider *provider): + QMediaObject(*new QCameraPrivate, parent, provider->requestService(Q_MEDIASERVICE_CAMERA)) +{ + Q_D(QCamera); + d->provider = provider; + d->initControls(); + d->cameraExposure = new QCameraExposure(this); + d->cameraFocus = new QCameraFocus(this); + d->imageProcessing = new QCameraImageProcessing(this); +} + +/*! + Construct a QCamera from device name \a device and \a parent. +*/ + +QCamera::QCamera(const QByteArray& device, QObject *parent): + QMediaObject(*new QCameraPrivate, parent, + QMediaServiceProvider::defaultServiceProvider()->requestService(Q_MEDIASERVICE_CAMERA, QMediaServiceProviderHint(device))) +{ + Q_D(QCamera); + d->provider = QMediaServiceProvider::defaultServiceProvider(); + d->initControls(); + + if (d->service != 0) { + //pass device name to service + if (d->deviceControl) { + QString deviceName(device); + + for (int i=0; ideviceControl->deviceCount(); i++) { + if (d->deviceControl->deviceName(i) == deviceName) { + d->deviceControl->setSelectedDevice(i); + break; + } + } + } + } + + d->cameraExposure = new QCameraExposure(this); + d->cameraFocus = new QCameraFocus(this); + d->imageProcessing = new QCameraImageProcessing(this); +} + +/*! + Destroys the camera object. +*/ + +QCamera::~QCamera() +{ + Q_D(QCamera); + delete d->cameraExposure; + d->cameraExposure = 0; + delete d->cameraFocus; + d->cameraFocus = 0; + delete d->imageProcessing; + d->imageProcessing = 0; + + if (d->service) { + if (d->control) + d->service->releaseControl(d->control); + if (d->locksControl) + d->service->releaseControl(d->locksControl); + if (d->deviceControl) + d->service->releaseControl(d->deviceControl); + + d->provider->releaseService(d->service); + } +} + + +/*! + Return true if the camera service is ready to use. + \since 1.1 +*/ +bool QCamera::isAvailable() const +{ + return availabilityError() == QtMultimediaKit::NoError; +} + +/*! + Returns the error state of the camera service. + \since 1.1 +*/ + +QtMultimediaKit::AvailabilityError QCamera::availabilityError() const +{ + Q_D(const QCamera); + if (d->control == NULL) + return QtMultimediaKit::ServiceMissingError; + + if (d->deviceControl && d->deviceControl->deviceCount() == 0) + return QtMultimediaKit::ResourceError; + + if (d->error != QCamera::NoError) + return QtMultimediaKit::ResourceError; + + return QtMultimediaKit::NoError; +} + + +/*! + Returns the camera exposure control object. + \since 1.1 +*/ +QCameraExposure *QCamera::exposure() const +{ + return d_func()->cameraExposure; +} + +/*! + Returns the camera focus control object. + \since 1.1 +*/ +QCameraFocus *QCamera::focus() const +{ + return d_func()->cameraFocus; +} + +/*! + Returns the camera image processing control object. + \since 1.1 +*/ +QCameraImageProcessing *QCamera::imageProcessing() const +{ + return d_func()->imageProcessing; +} + +/*! + Sets the QVideoWidget based camera \a viewfinder. + The previously set viewfinder is detached. + \since 1.1 +*/ +void QCamera::setViewfinder(QVideoWidget *viewfinder) +{ + Q_D(QCamera); + d->_q_preparePropertyChange(QCameraControl::Viewfinder); + + if (d->viewfinder) + unbind(d->viewfinder); + + d->viewfinder = viewfinder && bind(viewfinder) ? viewfinder : 0; +} + +/*! + Sets the QGraphicsVideoItem based camera \a viewfinder. + The previously set viewfinder is detached. + \since 1.1 +*/ +void QCamera::setViewfinder(QGraphicsVideoItem *viewfinder) +{ + Q_D(QCamera); + d->_q_preparePropertyChange(QCameraControl::Viewfinder); + + if (d->viewfinder) + unbind(d->viewfinder); + + d->viewfinder = viewfinder && bind(viewfinder) ? viewfinder : 0; +} + +/*! + Sets a video \a surface as the viewfinder of a camera. + + If a viewfinder has already been set on the camera the new surface + will replace it. + \since 1.2 +*/ + +void QCamera::setViewfinder(QAbstractVideoSurface *surface) +{ + Q_D(QCamera); + + d->surfaceViewfinder.setVideoSurface(surface); + + if (d->viewfinder != &d->surfaceViewfinder) { + if (d->viewfinder) + unbind(d->viewfinder); + + d->viewfinder = bind(&d->surfaceViewfinder) ? &d->surfaceViewfinder : 0; + } +} + +/*! + Returns the error state of the object. + \since 1.1 +*/ + +QCamera::Error QCamera::error() const +{ + return d_func()->error; +} + +/*! + Returns a string describing a camera's error state. + \since 1.1 +*/ +QString QCamera::errorString() const +{ + return d_func()->errorString; +} + + +/*! + Returns true if the capture \a mode is suported. + \since 1.1 +*/ +bool QCamera::isCaptureModeSupported(QCamera::CaptureMode mode) const +{ + return d_func()->control ? d_func()->control->isCaptureModeSupported(mode) : false; +} + +/*! + \property QCamera::captureMode + + The type of media (video or still images), + the camera is configured to capture. + + It's allowed to change capture mode in any camera state, + but if the camera is currently active, + chaging capture mode is likely to lead to camera status + chaged to QCamera::LoadedStatus, QCamera::LoadingStatus, + and when the camera is ready to QCamera::ActiveStatus. + \since 1.1 +*/ + +QCamera::CaptureMode QCamera::captureMode() const +{ + return d_func()->control ? d_func()->control->captureMode() : QCamera::CaptureStillImage; +} + +void QCamera::setCaptureMode(QCamera::CaptureMode mode) +{ + Q_D(QCamera); + + if (mode != captureMode()) { + if (d->control) { + d->_q_preparePropertyChange(QCameraControl::CaptureMode); + d->control->setCaptureMode(mode); + } + } +} + + +/*! + Starts the camera. + + State is changed to QCamera::ActiveState if camera is started + successfully, otherwise error() signal is emitted. + + While the camera state is changed to QCamera::ActiveState, + starting the camera service can be asynchronous with the actual + status reported with QCamera::status property. + \since 1.1 +*/ +void QCamera::start() +{ + Q_D(QCamera); + d->setState(QCamera::ActiveState); +} + +/*! + Stops the camera. + The camera state is changed from QCamera::ActiveState to QCamera::LoadedState. + \since 1.1 +*/ +void QCamera::stop() +{ + Q_D(QCamera); + d->setState(QCamera::LoadedState); +} + +/*! + Open the camera device. + The camera state is changed to QCamera::LoadedStatus. + + It's not necessary to explcitly load the camera, + unless unless the application have to read the supported camera + settings and change the default depending on the camera capabilities. + + In all the other cases it's possible to start the camera directly + from unloaded state. + \since 1.1 +*/ +void QCamera::load() +{ + Q_D(QCamera); + d->setState(QCamera::LoadedState); +} + +/*! + Close the camera device and deallocate the related resources. + The camera state is changed to QCamera::UnloadedStatus. + \since 1.1 +*/ +void QCamera::unload() +{ + Q_D(QCamera); + d->setState(QCamera::UnloadedState); +} + + +/*! + Returns a list of camera device's available from the default service provider. + \since 1.1 +*/ + +QList QCamera::availableDevices() +{ + return QMediaServiceProvider::defaultServiceProvider()->devices(QByteArray(Q_MEDIASERVICE_CAMERA)); +} + +/*! + Returns the description of the \a device. + \since 1.1 +*/ + +QString QCamera::deviceDescription(const QByteArray &device) +{ + return QMediaServiceProvider::defaultServiceProvider()->deviceDescription(QByteArray(Q_MEDIASERVICE_CAMERA), device); +} + +QCamera::State QCamera::state() const +{ + return d_func()->state; +} + +QCamera::Status QCamera::status() const +{ + if(d_func()->control) + return (QCamera::Status)d_func()->control->status(); + + return QCamera::UnavailableStatus; +} + + +/*! + Returns the lock types, camera supports. + \since 1.1 +*/ +QCamera::LockTypes QCamera::supportedLocks() const +{ + return d_func()->supportedLocks; +} + +/*! + Returns the requested lock types. + \since 1.1 +*/ +QCamera::LockTypes QCamera::requestedLocks() const +{ + return d_func()->requestedLocks; +} + +/*! + Returns the status of requested camera settings locks. + \since 1.1 +*/ +QCamera::LockStatus QCamera::lockStatus() const +{ + return d_func()->lockStatus; +} + +/*! + Returns the status of camera settings \a lock. + \since 1.1 +*/ +QCamera::LockStatus QCamera::lockStatus(QCamera::LockType lockType) const +{ + const QCameraPrivate *d = d_func(); + + if (!(lockType & d->supportedLocks)) + return lockType & d->requestedLocks ? QCamera::Locked : QCamera::Unlocked; + + if (!(lockType & d->requestedLocks)) + return QCamera::Unlocked; + + if (d->locksControl) + return d->locksControl->lockStatus(lockType); + + return QCamera::Unlocked; +} + +/*! + \fn void QCamera::searchAndLock(QCamera::LockTypes locks) + + Locks the camera settings with the requested \a locks, including focusing in the single autofocus mode, + exposure and white balance if the exposure and white balance modes are not manual. + + The camera settings are usually locked before taking one or multiple still images, + in responce to the shutter button being half pressed. + + The QCamera::locked() signal is emitted when camera settings are successfully locked, + otherwise QCamera::lockFailed() is emitted. + + QCamera also emits lockStatusChanged(QCamera::LockType, QCamera::LockStatus) + on individual lock status changes and lockStatusChanged(QCamera::LockStatus) signal on composite status changes. + + Locking serves two roles: it initializes calculation of automatic parameter + (focusing, calculating the correct exposure and white balance) and allows + to keep some or all of those parameters during number of shots. + + If the camera doesn't support keeping one of parameters between shots, the related + lock state changes to QCamera::Unlocked. + + It's also acceptable to relock already locked settings, + depending on the lock parameter this initiates new focusing, exposure or white balance calculation. + \since 1.1 + */ +void QCamera::searchAndLock(QCamera::LockTypes locks) +{ + Q_D(QCamera); + + QCamera::LockStatus oldStatus = d->lockStatus; + d->supressLockChangedSignal = true; + + d->requestedLocks |= locks; + + locks &= d->supportedLocks; + + if (d->locksControl) + d->locksControl->searchAndLock(locks); + + d->supressLockChangedSignal = false; + + d->lockStatus = oldStatus; + d->updateLockStatus(); +} + +/*! + Lock all the supported camera settings. + \since 1.1 + */ +void QCamera::searchAndLock() +{ + searchAndLock(LockExposure | LockWhiteBalance | LockFocus); +} + +/*! + Unlocks the camera settings specified with \a locks or cancel the current locking if one is active. + \since 1.1 + */ +void QCamera::unlock(QCamera::LockTypes locks) +{ + Q_D(QCamera); + + QCamera::LockStatus oldStatus = d->lockStatus; + d->supressLockChangedSignal = true; + + d->requestedLocks &= ~locks; + + locks &= d->supportedLocks; + + if (d->locksControl) + d->locksControl->unlock(locks); + + d->supressLockChangedSignal = false; + + d->lockStatus = oldStatus; + d->updateLockStatus(); +} + +/*! + Unlock all the requested camera locks. + \since 1.1 + */ +void QCamera::unlock() +{ + unlock(d_func()->requestedLocks); +} + + +/*! + \enum QCamera::State + \value UnloadedState + The initial camera state, with camera not loaded, + the camera capabilities except of supported capture modes + are unknown. + + While the supported settings are unknown in this state, + it's allowed to set the camera capture settings like codec, + resolution, or frame rate. + + \value LoadedState + The camera is loaded and ready to be configured. + + In the Idle state it's allowed to query camera capabilities, + set capture resolution, codecs, etc. + + The viewfinder is not active in the loaded state. + + \value ActiveState + In the active state as soon as camera is started + the viewfinder displays video frames and the + camera is ready for capture. +*/ + + +/*! + \property QCamera::state + \brief The current state of the camera object. + \since 1.1 +*/ + +/*! + \enum QCamera::Status + \value ActiveStatus + The camera has been started and can produce data. + The viewfinder displays video frames in active state. + + Depending on backend, changing some camera settings like + capture mode, codecs or resolution in ActiveState may lead + to changing the camera status to LoadedStatus and StartingStatus while + the settings are applied and back to ActiveStatus when the camera is ready. + + \value StartingStatus + The camera is starting in result of state transition to QCamera::ActiveState. + The camera service is not ready to capture yet. + + \value StandbyStatus + The camera is in the power saving standby mode. + The camera may come to the standby mode after some time of inactivity + in the QCamera::LoadedState state. + + \value LoadedStatus + The camera is loaded and ready to be configured. + This status indicates the camera device is opened and + it's possible to query for supported image and video capture settings, + like resolution, framerate and codecs. + + \value LoadingStatus + The camera device loading in result of state transition from + QCamera::UnloadedState to QCamera::LoadedState or QCamera::ActiveState. + + \value UnloadedStatus + The initial camera status, with camera not loaded. + The camera capabilities including supported capture settings may be unknown. + + \value UnavailableStatus + The camera or camera backend is not available. +*/ + + +/*! + \property QCamera::status + \brief The current status of the camera object. + \since 1.1 +*/ + + +/*! + \enum QCamera::CaptureMode + \value CaptureStillImage Camera is configured for still frames capture. + \value CaptureVideo Camera is configured for video capture. + \since 1.1 +*/ + +/*! + \enum QCamera::LockType + + \value NoLock + \value LockExposure + Lock camera exposure. + \value LockWhiteBalance + Lock the white balance. + \value LockFocus + Lock camera focus. +*/ + + +/*! + \property QCamera::lockStatus + \brief The overall status for all the requested camera locks. + \since 1.1 +*/ + +/*! + \fn void QCamera::locked() + + Signals all the requested camera settings are locked. + \since 1.1 +*/ + +/*! + \fn void QCamera::lockFailed() + + Signals locking of at least one requested camera settings failed. + \since 1.1 +*/ + +/*! + \fn QCamera::lockStatusChanged(QCamera::LockStatus status, QCamera::LockChangeReason reason) + + Signals the overall \a status for all the requested camera locks was changed with specified \a reason. + \since 1.1 +*/ + +/*! + \fn QCamera::lockStatusChanged(QCamera::LockType lock, QCamera::LockStatus status, QCamera::LockChangeReason reason) + Signals the \a lock \a status was changed with specified \a reason. + \since 1.1 +*/ + +/*! + \enum QCamera::LockStatus + \value Unlocked + The application is not interested in camera settings value. + The camera may keep this parameter without changes, this is common with camera focus, + or adjust exposure and white balance constantly to keep the viewfinder image nice. + + \value Searching + The application has requested the camera focus, exposure or white balance lock with + QCamera::searchAndLock(). This state indicates the camera is focusing or calculating exposure and white balance. + + \value Locked + The camera focus, exposure or white balance is locked. + The camera is ready to capture, application may check the exposure parameters. + + The locked state usually means the requested parameter stays the same, + except of the cases when the parameter is requested to be constantly updated. + For example in continuous focusing mode, the focus is considered locked as long + and the object is in focus, even while the actual focusing distance may be constantly changing. +*/ + +/*! + \enum QCamera::LockChangeReason + + \value UserRequest + The lock status changed in result of user request, usually to unlock camera settings. + \value LockAcquired + The lock status successfuly changed to QCamera::Locked. + \value LockFailed + The camera failed to acquire the requested lock in result of + autofocus failure, exposure out of supported range, etc. + \value LockLost + The camera is not able to maintain the requested lock any more. + Lock status is changed to QCamera::Unlocked. + \value LockTemporaryLost + The lock is lost, but the camera is working hard to reacquire it. + This value may be used in continuous focusing mode, + when the camera loses the focus, the focus lock state is changed to Qcamera::Searching + with LockTemporaryLost reason. +*/ + +/*! + \enum QCamera::Error + + \value NoError No errors have occurred. + \value CameraError An error has occurred. + \value InvalidRequestError System resource doesn't support requested functionality. + \value ServiceMissingError No camera service available. + \value NotSupportedFeatureError The feature is not supported. +*/ + +/*! + \fn void QCamera::error(QCamera::Error value) + + Signal emitted when error state changes to \a value. + \since 1.1 +*/ + +/*! + \fn void QCamera::captureModeChanged(QCamera::CaptureMode mode) + + Signals the capture \a mode has changed. + \since 1.1 +*/ + +/*! + \fn QCamera::stateChanged(QCamera::State state) + + Signals the camera \a state has changed. + + Usually the state changes is caused by calling + load(), unload(), start() and stop(), + but the state can also be changed change as a result of camera error. + \since 1.1 +*/ + +/*! + \fn QCamera::statusChanged(QCamera::Status status) + + Signals the camera \a status has changed. + + \since 1.1 +*/ + + +#include "moc_qcamera.cpp" diff --git a/src/multimediakit/qcamera.h b/src/multimediakit/qcamera.h new file mode 100644 index 000000000..b6fd163a5 --- /dev/null +++ b/src/multimediakit/qcamera.h @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERA_H +#define QCAMERA_H + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QAbstractVideoSurface; +class QVideoWidget; +class QGraphicsVideoItem; + +class QCameraPrivate; +class Q_MULTIMEDIA_EXPORT QCamera : public QMediaObject +{ + Q_OBJECT + Q_PROPERTY(QCamera::State state READ state NOTIFY stateChanged) + Q_PROPERTY(QCamera::Status status READ status NOTIFY statusChanged) + Q_PROPERTY(QCamera::CaptureMode captureMode READ captureMode WRITE setCaptureMode NOTIFY captureModeChanged) + Q_PROPERTY(QCamera::LockStatus lockStatus READ lockStatus NOTIFY lockStatusChanged) + + Q_ENUMS(Status) + Q_ENUMS(State) + Q_ENUMS(CaptureMode) + Q_ENUMS(Error) + Q_ENUMS(LockStatus) + Q_ENUMS(LockChangeReason) + Q_ENUMS(LockType) +public: + enum Status { + UnavailableStatus, + UnloadedStatus, + LoadingStatus, + LoadedStatus, + StandbyStatus, + StartingStatus, + ActiveStatus + }; + + enum State { + UnloadedState, + LoadedState, + ActiveState + }; + + enum CaptureMode + { + CaptureStillImage, + CaptureVideo + }; + + enum Error + { + NoError, + CameraError, + InvalidRequestError, + ServiceMissingError, + NotSupportedFeatureError + }; + + enum LockStatus + { + Unlocked, + Searching, + Locked + }; + + enum LockChangeReason { + UserRequest, + LockAcquired, + LockFailed, + LockLost, + LockTemporaryLost + }; + + enum LockType + { + NoLock = 0, + LockExposure = 0x01, + LockWhiteBalance = 0x02, + LockFocus = 0x04 + }; + Q_DECLARE_FLAGS(LockTypes, LockType) + + QCamera(QObject *parent = 0, QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider()); + QCamera(const QByteArray& device, QObject *parent = 0); + ~QCamera(); + + static QList availableDevices(); + static QString deviceDescription(const QByteArray &device); + + bool isAvailable() const; + QtMultimediaKit::AvailabilityError availabilityError() const; + + State state() const; + Status status() const; + + CaptureMode captureMode() const; + bool isCaptureModeSupported(CaptureMode mode) const; + + QCameraExposure *exposure() const; + QCameraFocus *focus() const; + QCameraImageProcessing *imageProcessing() const; + + void setViewfinder(QVideoWidget *viewfinder); + void setViewfinder(QGraphicsVideoItem *viewfinder); + void setViewfinder(QAbstractVideoSurface *surface); + + Error error() const; + QString errorString() const; + + QCamera::LockTypes supportedLocks() const; + QCamera::LockTypes requestedLocks() const; + + QCamera::LockStatus lockStatus() const; + QCamera::LockStatus lockStatus(QCamera::LockType lock) const; + +public Q_SLOTS: + void setCaptureMode(QCamera::CaptureMode mode); + + void load(); + void unload(); + + void start(); + void stop(); + + void searchAndLock(); + void unlock(); + + void searchAndLock(QCamera::LockTypes locks); + void unlock(QCamera::LockTypes locks); + +Q_SIGNALS: + void stateChanged(QCamera::State); + void captureModeChanged(QCamera::CaptureMode); + void statusChanged(QCamera::Status); + + void locked(); + void lockFailed(); + + void lockStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason); + void lockStatusChanged(QCamera::LockType, QCamera::LockStatus, QCamera::LockChangeReason); + + void error(QCamera::Error); + +private: + Q_DISABLE_COPY(QCamera) + Q_DECLARE_PRIVATE(QCamera) + Q_PRIVATE_SLOT(d_func(), void _q_preparePropertyChange(int)) + Q_PRIVATE_SLOT(d_func(), void _q_restartCamera()) + Q_PRIVATE_SLOT(d_func(), void _q_error(int, const QString &)) + Q_PRIVATE_SLOT(d_func(), void _q_updateLockStatus(QCamera::LockType, QCamera::LockStatus, QCamera::LockChangeReason)) + Q_PRIVATE_SLOT(d_func(), void _q_updateState(QCamera::State)) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QCamera::LockTypes) + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QCamera::State) +Q_DECLARE_METATYPE(QCamera::Status) +Q_DECLARE_METATYPE(QCamera::Error) +Q_DECLARE_METATYPE(QCamera::CaptureMode) +Q_DECLARE_METATYPE(QCamera::LockType) +Q_DECLARE_METATYPE(QCamera::LockStatus) +Q_DECLARE_METATYPE(QCamera::LockChangeReason) + +Q_MEDIA_ENUM_DEBUG(QCamera, State) +Q_MEDIA_ENUM_DEBUG(QCamera, Status) +Q_MEDIA_ENUM_DEBUG(QCamera, Error) +Q_MEDIA_ENUM_DEBUG(QCamera, CaptureMode) +Q_MEDIA_ENUM_DEBUG(QCamera, LockType) +Q_MEDIA_ENUM_DEBUG(QCamera, LockStatus) +Q_MEDIA_ENUM_DEBUG(QCamera, LockChangeReason) + +#endif // QCAMERA_H diff --git a/src/multimediakit/qcameracapturebufferformatcontrol.cpp b/src/multimediakit/qcameracapturebufferformatcontrol.cpp new file mode 100644 index 000000000..06602abe8 --- /dev/null +++ b/src/multimediakit/qcameracapturebufferformatcontrol.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraCaptureBufferFormatControl + + \brief The QCameraCaptureBufferFormatControl class provides a control for setting the capture buffer format. + + The format is of type QVideoFrame::PixelFormat. + + \inmodule QtMultimediaKit + \ingroup camera + + The interface name of QCameraCaptureBufferFormatControl is \c com.nokia.Qt.QCameraCaptureBufferFormatControl/1.0 as + defined in QCameraCaptureBufferFormatControl_iid. + + \sa QMediaService::requestControl() + \since QtMobility 1.2 +*/ + +/*! + \macro QCameraCaptureBufferFormatControl_iid + + \c com.nokia.Qt.QCameraCaptureBufferFormatControl/1.0 + + Defines the interface name of the QCameraCaptureBufferFormatControl class. + + \relates QCameraCaptureBufferFormatControl +*/ + +/*! + Constructs a new image buffer capture format control object with the given \a parent +*/ +QCameraCaptureBufferFormatControl::QCameraCaptureBufferFormatControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys an image buffer capture format control. +*/ +QCameraCaptureBufferFormatControl::~QCameraCaptureBufferFormatControl() +{ +} + +/*! + \fn QCameraCaptureBufferFormatControl::supportedBufferFormats() const + + Returns the list of the supported buffer capture formats. + \since 1.2 +*/ + +/*! + \fn QCameraCaptureBufferFormatControl::bufferFormat() const + + Returns the current buffer capture format. + \since 1.2 +*/ + +/*! + \fn QCameraCaptureBufferFormatControl::setBufferFormat(QVideoFrame::PixelFormat format) + + Sets the buffer capture \a format. + \since 1.2 +*/ + +/*! + \fn QCameraCaptureBufferFormatControl::bufferFormatChanged(QVideoFrame::PixelFormat format) + + Signals the buffer image capture format changed to \a format. + \since 1.2 +*/ + +#include "moc_qcameracapturebufferformatcontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qcameracapturebufferformatcontrol.h b/src/multimediakit/qcameracapturebufferformatcontrol.h new file mode 100644 index 000000000..27835b35f --- /dev/null +++ b/src/multimediakit/qcameracapturebufferformatcontrol.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERACAPTUREBUFFERFORMATCONTROL_H +#define QCAMERACAPTUREBUFFERFORMATCONTROL_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QCameraCaptureBufferFormatControl : public QMediaControl +{ + Q_OBJECT +public: + ~QCameraCaptureBufferFormatControl(); + + virtual QList supportedBufferFormats() const = 0; + virtual QVideoFrame::PixelFormat bufferFormat() const = 0; + virtual void setBufferFormat(QVideoFrame::PixelFormat format) = 0; + +Q_SIGNALS: + void bufferFormatChanged(QVideoFrame::PixelFormat); + +protected: + QCameraCaptureBufferFormatControl(QObject* parent = 0); +}; + +#define QCameraCaptureBufferFormatControl_iid "com.nokia.Qt.QCameraCaptureBufferFormatControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QCameraCaptureBufferFormatControl, QCameraCaptureBufferFormatControl_iid) + +QT_END_NAMESPACE + +#endif + diff --git a/src/multimediakit/qcameracapturedestinationcontrol.cpp b/src/multimediakit/qcameracapturedestinationcontrol.cpp new file mode 100644 index 000000000..3899d8d8c --- /dev/null +++ b/src/multimediakit/qcameracapturedestinationcontrol.cpp @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraCaptureDestinationControl + + \brief The QCameraCaptureDestinationControl class provides a control for setting capture destination. + + Depending on backend capabilities capture to file, buffer or both can be supported. + + \inmodule QtMultimediaKit + \ingroup camera + + + + The interface name of QCameraCaptureDestinationControl is \c com.nokia.Qt.QCameraCaptureDestinationControl/1.0 as + defined in QCameraCaptureDestinationControl_iid. + + + \sa QMediaService::requestControl() + \since QtMobility 1.2 +*/ + +/*! + \macro QCameraCaptureDestinationControl_iid + + \c com.nokia.Qt.QCameraCaptureDestinationControl/1.0 + + Defines the interface name of the QCameraCaptureDestinationControl class. + + \relates QCameraCaptureDestinationControl +*/ + +/*! + Constructs a new image capture destination control object with the given \a parent +*/ +QCameraCaptureDestinationControl::QCameraCaptureDestinationControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys an image capture destination control. +*/ +QCameraCaptureDestinationControl::~QCameraCaptureDestinationControl() +{ +} + +/*! + \fn QCameraCaptureDestinationControl::isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const + + Returns true if the capture \a destination is supported; and false if it is not. + \since 1.2 +*/ + +/*! + \fn QCameraCaptureDestinationControl::captureDestination() const + + Returns the current capture \a destination. The default destination is QCameraImageCapture::CaptureToFile. + \since 1.2 +*/ + +/*! + \fn QCameraCaptureDestinationControl::setCaptureDestination(QCameraImageCapture::CaptureDestinations destination) + + Sets the capture \a destination. + \since 1.2 +*/ + +/*! + \fn QCameraCaptureDestinationControl::captureDestinationChanged(QCameraImageCapture::CaptureDestinations destination) + + Signals the image capture \a destination changed. + \since 1.2 +*/ + +#include "moc_qcameracapturedestinationcontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qcameracapturedestinationcontrol.h b/src/multimediakit/qcameracapturedestinationcontrol.h new file mode 100644 index 000000000..f53fad5e6 --- /dev/null +++ b/src/multimediakit/qcameracapturedestinationcontrol.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERACAPTUREDESTINATIONCONTROL_H +#define QCAMERACAPTUREDESTINATIONCONTROL_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QCameraCaptureDestinationControl : public QMediaControl +{ + Q_OBJECT +public: + ~QCameraCaptureDestinationControl(); + + virtual bool isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const = 0; + virtual QCameraImageCapture::CaptureDestinations captureDestination() const = 0; + virtual void setCaptureDestination(QCameraImageCapture::CaptureDestinations destination) = 0; + +Q_SIGNALS: + void captureDestinationChanged(QCameraImageCapture::CaptureDestinations); + +protected: + QCameraCaptureDestinationControl(QObject* parent = 0); +}; + +#define QCameraCaptureDestinationControl_iid "com.nokia.Qt.QCameraCaptureDestinationControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QCameraCaptureDestinationControl, QCameraCaptureDestinationControl_iid) + +QT_END_NAMESPACE + +#endif + diff --git a/src/multimediakit/qcameracontrol.cpp b/src/multimediakit/qcameracontrol.cpp new file mode 100644 index 000000000..fdeb1d29a --- /dev/null +++ b/src/multimediakit/qcameracontrol.cpp @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraControl + + + + \brief The QCameraControl class is an abstract base class for + classes that control still cameras or video cameras. + + \inmodule QtMultimediaKit + \ingroup camera + \since 1.1 + + This service is provided by a QMediaService object via + QMediaService::control(). It is used by QCamera. + + The interface name of QCameraControl is \c com.nokia.Qt.QCameraControl/1.0 as + defined in QCameraControl_iid. + + + + \sa QMediaService::requestControl(), QCamera +*/ + +/*! + \macro QCameraControl_iid + + \c com.nokia.Qt.QCameraControl/1.0 + + Defines the interface name of the QCameraControl class. + + \relates QCameraControl +*/ + +/*! + Constructs a camera control object with \a parent. +*/ + +QCameraControl::QCameraControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destruct the camera control object. +*/ + +QCameraControl::~QCameraControl() +{ +} + +/*! + \fn QCameraControl::state() const + + Returns the state of the camera service. + + \since 1.1 + \sa QCamera::state +*/ + +/*! + \fn QCameraControl::setState(QCamera::State state) + + Sets the camera \a state. + + State changes are synchronous and indicate user intention, + while camera status is used as a feedback mechanism to inform application about backend status. + Status changes are reported asynchronously with QCameraControl::statusChanged() signal. + + \since 1.1 + \sa QCamera::State +*/ + +/*! + \fn void QCameraControl::stateChanged(QCamera::State state) + + Signal emitted when the camera \a state changes. + + In most cases the state chage is caused by QCameraControl::setState(), + but if critical error has occurred the state changes to QCamera::UnloadedState. + \since 1.1 +*/ + +/*! + \fn QCameraControl::status() const + + Returns the status of the camera service. + + \since 1.1 + \sa QCamera::state +*/ + +/*! + \fn void QCameraControl::statusChanged(QCamera::Status status) + + Signal emitted when the camera \a status changes. + \since 1.1 +*/ + + +/*! + \fn void QCameraControl::error(int error, const QString &errorString) + + Signal emitted when an error occurs with error code \a error and + a description of the error \a errorString. + \since 1.1 +*/ + +/*! + \fn Camera::CaptureMode QCameraControl::captureMode() const = 0 + + Returns the current capture mode. + \since 1.1 +*/ + +/*! + \fn void QCameraControl::setCaptureMode(QCamera::CaptureMode mode) = 0; + + Sets the current capture \a mode. + + The capture mode changes are synchronous and allowed in any camera state. + + If the capture mode is changed while camera is active, + it's recommended to change status to QCamera::LoadedStatus + and start activating the camera in the next event loop + with the status changed to QCamera::StartingStatus. + This allows the capture settings to be applied before camera is started. + Than change the status to QCamera::StartedStatus when the capture mode change is done. + \since 1.1 +*/ + +/*! + \fn bool QCameraControl::isCaptureModeSupported(QCamera::CaptureMode mode) const = 0; + + Returns true if the capture \a mode is suported. + \since 1.1 +*/ + +/*! + \fn QCameraControl::captureModeChanged(QCamera::CaptureMode mode) + + Signal emitted when the camera capture \a mode changes. + \since 1.1 + */ + +/*! + \fn bool QCameraControl::canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const + + Returns true if backend can effectively apply changing camera properties of \a changeType type + while the camera state is QCamera::Active and camera status matches \a status parameter. + + If backend doesn't support applying this change in the active state, it will be stopped + before the settings are changed and restarted after. + Otherwise the backend should apply the change in the current state, + with the camera status indicating the progress, if necessary. + \since 1.1 +*/ + +/*! + \enum QCameraControl::PropertyChangeType + + \value CaptureMode Indicates the capture mode is changed. + \value ImageEncodingSettings Image encoder settings are changed, including resolution. + \value VideoEncodingSettings + Video encoder settings are changed, including audio, video and container settings. + \value Viewfinder Viewfinder is changed. +*/ + +#include "moc_qcameracontrol.cpp" +QT_END_NAMESPACE diff --git a/src/multimediakit/qcameracontrol.h b/src/multimediakit/qcameracontrol.h new file mode 100644 index 000000000..a1830a5a3 --- /dev/null +++ b/src/multimediakit/qcameracontrol.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERACONTROL_H +#define QCAMERACONTROL_H + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QCameraControl : public QMediaControl +{ + Q_OBJECT + +public: + enum PropertyChangeType { + CaptureMode = 1, + ImageEncodingSettings = 2, + VideoEncodingSettings = 3, + Viewfinder = 4 + }; + + ~QCameraControl(); + + virtual QCamera::State state() const = 0; + virtual void setState(QCamera::State state) = 0; + + virtual QCamera::Status status() const = 0; + + virtual QCamera::CaptureMode captureMode() const = 0; + virtual void setCaptureMode(QCamera::CaptureMode) = 0; + virtual bool isCaptureModeSupported(QCamera::CaptureMode mode) const = 0; + + virtual bool canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const = 0; + +Q_SIGNALS: + void stateChanged(QCamera::State); + void statusChanged(QCamera::Status); + void error(int error, const QString &errorString); + void captureModeChanged(QCamera::CaptureMode); + +protected: + QCameraControl(QObject* parent = 0); +}; + +#define QCameraControl_iid "com.nokia.Qt.QCameraControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QCameraControl, QCameraControl_iid) + +QT_END_NAMESPACE + +#endif // QCAMERACONTROL_H + diff --git a/src/multimediakit/qcameraexposure.cpp b/src/multimediakit/qcameraexposure.cpp new file mode 100644 index 000000000..73266b5c1 --- /dev/null +++ b/src/multimediakit/qcameraexposure.cpp @@ -0,0 +1,646 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraExposure + + + \brief The QCameraExposure class provides interface for exposure related camera settings. + + \inmodule QtMultimediaKit + \ingroup camera + \since 1.1 + +*/ + +//#define DEBUG_EXPOSURE_CHANGES 1 + +#ifdef DEBUG_EXPOSURE_CHANGES +#define ENUM_NAME(c,e,v) (c::staticMetaObject.enumerator(c::staticMetaObject.indexOfEnumerator(e)).valueToKey((v))) +#endif + +namespace +{ +class CameraExposureRegisterMetaTypes +{ +public: + CameraExposureRegisterMetaTypes() + { + qRegisterMetaType("QCameraExposure::ExposureMode"); + qRegisterMetaType("QCameraExposure::FlashModes"); + qRegisterMetaType("QCameraExposure::MeteringMode"); + } +} _registerCameraExposureMetaTypes; +} + + + +class QCameraExposurePrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QCameraExposure) +public: + void initControls(); + QCameraExposure *q_ptr; + + QCamera *camera; + QCameraExposureControl *exposureControl; + QCameraFlashControl *flashControl; + + void _q_exposureParameterChanged(int parameter); + void _q_exposureParameterRangeChanged(int parameter); +}; + +void QCameraExposurePrivate::initControls() +{ + Q_Q(QCameraExposure); + + QMediaService *service = camera->service(); + exposureControl = 0; + flashControl = 0; + if (service) { + exposureControl = qobject_cast(service->requestControl(QCameraExposureControl_iid)); + flashControl = qobject_cast(service->requestControl(QCameraFlashControl_iid)); + } + if (exposureControl) { + q->connect(exposureControl, SIGNAL(exposureParameterChanged(int)), + q, SLOT(_q_exposureParameterChanged(int))); + q->connect(exposureControl, SIGNAL(exposureParameterRangeChanged(int)), + q, SLOT(_q_exposureParameterRangeChanged(int))); + } + + if (flashControl) + q->connect(flashControl, SIGNAL(flashReady(bool)), q, SIGNAL(flashReady(bool))); +} + +void QCameraExposurePrivate::_q_exposureParameterChanged(int parameter) +{ + Q_Q(QCameraExposure); + +#if DEBUG_EXPOSURE_CHANGES + qDebug() << "Exposure parameter changed:" + << ENUM_NAME(QCameraExposureControl, "ExposureParameter", parameter) + << exposureControl->exposureParameter(QCameraExposureControl::ExposureParameter(parameter)); +#endif + + switch (parameter) { + case QCameraExposureControl::ISO: + emit q->isoSensitivityChanged(q->isoSensitivity()); + break; + case QCameraExposureControl::Aperture: + emit q->apertureChanged(q->aperture()); + break; + case QCameraExposureControl::ShutterSpeed: + emit q->shutterSpeedChanged(q->shutterSpeed()); + break; + case QCameraExposureControl::ExposureCompensation: + emit q->exposureCompensationChanged(q->exposureCompensation()); + break; + } +} + +void QCameraExposurePrivate::_q_exposureParameterRangeChanged(int parameter) +{ + Q_Q(QCameraExposure); + + switch (parameter) { + case QCameraExposureControl::Aperture: + emit q->apertureRangeChanged(); + break; + case QCameraExposureControl::ShutterSpeed: + emit q->shutterSpeedRangeChanged(); + break; + } +} + +/*! + Construct a QCameraExposure from service \a provider and \a parent. +*/ + +QCameraExposure::QCameraExposure(QCamera *parent): + QObject(parent), d_ptr(new QCameraExposurePrivate) +{ + Q_D(QCameraExposure); + d->camera = parent; + d->q_ptr = this; + d->initControls(); +} + + +/*! + Destroys the camera exposure object. +*/ + +QCameraExposure::~QCameraExposure() +{ + Q_D(QCameraExposure); + if (d->exposureControl) + d->camera->service()->releaseControl(d->exposureControl); +} + +/*! + Returns true if exposure settings are supported by this camera. + \since 1.1 +*/ +bool QCameraExposure::isAvailable() const +{ + return d_func()->exposureControl != 0; +} + + +/*! + \property QCameraExposure::flashMode + \brief The flash mode being used. + + Usually the single QCameraExposure::FlashMode flag is used, + but some non conflicting flags combination are also allowed, + like QCameraExposure::FlashManual | QCameraExposure::FlashSlowSyncRearCurtain. + + \since 1.1 + \sa QCameraExposure::isFlashModeSupported(), QCameraExposure::isFlashReady() +*/ + +QCameraExposure::FlashModes QCameraExposure::flashMode() const +{ + return d_func()->flashControl ? d_func()->flashControl->flashMode() : QCameraExposure::FlashOff; +} + +void QCameraExposure::setFlashMode(QCameraExposure::FlashModes mode) +{ + if (d_func()->flashControl) + d_func()->flashControl->setFlashMode(mode); +} + +/*! + Returns true if the flash \a mode is supported. + \since 1.1 +*/ + +bool QCameraExposure::isFlashModeSupported(QCameraExposure::FlashModes mode) const +{ + return d_func()->flashControl ? d_func()->flashControl->isFlashModeSupported(mode) : false; +} + +/*! + Returns true if flash is charged. +*/ + +bool QCameraExposure::isFlashReady() const +{ + return d_func()->flashControl ? d_func()->flashControl->isFlashReady() : false; +} + + +/*! + \property QCameraExposure::exposureMode + \brief The exposure mode being used. + + \since 1.1 + \sa QCameraExposure::isExposureModeSupported() +*/ + +QCameraExposure::ExposureMode QCameraExposure::exposureMode() const +{ + return d_func()->exposureControl ? d_func()->exposureControl->exposureMode() : QCameraExposure::ExposureAuto; +} + +void QCameraExposure::setExposureMode(QCameraExposure::ExposureMode mode) +{ + if (d_func()->exposureControl) + d_func()->exposureControl->setExposureMode(mode); +} + +/*! + Returns true if the exposure \a mode is supported. + \since 1.1 +*/ + +bool QCameraExposure::isExposureModeSupported(QCameraExposure::ExposureMode mode) const +{ + return d_func()->exposureControl ? + d_func()->exposureControl->isExposureModeSupported(mode) : false; +} + +/*! + \property QCameraExposure::exposureCompensation + \brief Exposure compensation in EV units. + + Exposure compensation property allows to adjust the automatically calculated exposure. + \since 1.1 +*/ + +qreal QCameraExposure::exposureCompensation() const +{ + if (d_func()->exposureControl) + return d_func()->exposureControl->exposureParameter(QCameraExposureControl::ExposureCompensation).toReal(); + else + return 0; +} + +void QCameraExposure::setExposureCompensation(qreal ev) +{ + if (d_func()->exposureControl) + d_func()->exposureControl->setExposureParameter(QCameraExposureControl::ExposureCompensation, QVariant(ev)); +} + +/*! + \property QCameraExposure::meteringMode + \brief The metering mode being used. + + \since 1.1 + \sa QCameraExposure::isMeteringModeSupported() +*/ + +QCameraExposure::MeteringMode QCameraExposure::meteringMode() const +{ + return d_func()->exposureControl ? d_func()->exposureControl->meteringMode() : QCameraExposure::MeteringMatrix; +} + +void QCameraExposure::setMeteringMode(QCameraExposure::MeteringMode mode) +{ + if (d_func()->exposureControl) + d_func()->exposureControl->setMeteringMode(mode); +} + +/*! + Returns true if the metering \a mode is supported. + \since 1.1 +*/ +bool QCameraExposure::isMeteringModeSupported(QCameraExposure::MeteringMode mode) const +{ + return d_func()->exposureControl ? d_func()->exposureControl->isMeteringModeSupported(mode) : false; +} + +int QCameraExposure::isoSensitivity() const +{ + if (d_func()->exposureControl) + return d_func()->exposureControl->exposureParameter(QCameraExposureControl::ISO).toInt(); + + return -1; +} + +/*! + Returns the list of ISO senitivities camera supports. + + If the camera supports arbitrary ISO sensitivities within the supported range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + \since 1.1 +*/ +QList QCameraExposure::supportedIsoSensitivities(bool *continuous) const +{ + QList res; + QCameraExposureControl *control = d_func()->exposureControl; + + if (!control) + return res; + + foreach (const QVariant &value, + control->supportedParameterRange(QCameraExposureControl::ISO)) { + bool ok = false; + int intValue = value.toInt(&ok); + if (ok) + res.append(intValue); + else + qWarning() << "Incompatible ISO value type, int is expected"; + } + + if (continuous) + *continuous = control->exposureParameterFlags(QCameraExposureControl::ISO) & + QCameraExposureControl::ContinuousRange; + + return res; +} + +/*! + \fn QCameraExposure::setManualIsoSensitivity(int iso) + Sets the manual sensitivity to \a iso + \since 1.1 +*/ + +void QCameraExposure::setManualIsoSensitivity(int iso) +{ + if (d_func()->exposureControl) + d_func()->exposureControl->setExposureParameter(QCameraExposureControl::ISO, QVariant(iso)); +} + +/*! + \fn QCameraExposure::setAutoIsoSensitivity() + Turn on auto sensitivity + \since 1.1 +*/ + +void QCameraExposure::setAutoIsoSensitivity() +{ + if (d_func()->exposureControl) + d_func()->exposureControl->setExposureParameter(QCameraExposureControl::ISO, QVariant()); +} + +/*! + \property QCameraExposure::shutterSpeed + \brief Camera's shutter speed in seconds. + + \since 1.1 + \sa supportedShutterSpeeds(), setAutoShutterSpeed(), setManualShutterSpeed() +*/ + +/*! + \fn QCameraExposure::shutterSpeedChanged(qreal speed) + + Signals that a camera's shutter \a speed has changed. + \since 1.1 +*/ + +/*! + \property QCameraExposure::isoSensitivity + \brief The sensor ISO sensitivity. + + \sa supportedIsoSensitivities(), setAutoIsoSensitivity(), setManualIsoSensitivity() + \since 1.1 +*/ + +/*! + \property QCameraExposure::aperture + \brief Lens aperture is specified as an F number, the ratio of the focal length to effective aperture diameter. + + \since 1.1 + \sa supportedApertures(), setAutoAperture(), setManualAperture() +*/ + + +qreal QCameraExposure::aperture() const +{ + if (d_func()->exposureControl) + return d_func()->exposureControl->exposureParameter(QCameraExposureControl::Aperture).toReal(); + + return -1.0; +} + +/*! + Returns the list of aperture values camera supports. + The apertures list can change depending on the focal length, + in such a case the apertureRangeChanged() signal is emitted. + + If the camera supports arbitrary aperture values within the supported range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + \since 1.1 +*/ +QList QCameraExposure::supportedApertures(bool * continuous) const +{ + QList res; + QCameraExposureControl *control = d_func()->exposureControl; + + if (!control) + return res; + + foreach (const QVariant &value, + control->supportedParameterRange(QCameraExposureControl::Aperture)) { + bool ok = false; + qreal realValue = value.toReal(&ok); + if (ok) + res.append(realValue); + else + qWarning() << "Incompatible aperture value type, qreal is expected"; + } + + if (continuous) + *continuous = control->exposureParameterFlags(QCameraExposureControl::Aperture) & + QCameraExposureControl::ContinuousRange; + + return res; +} + +/*! + \fn QCameraExposure::setManualAperture(qreal aperture) + Sets the manual camera \a aperture value. + \since 1.1 +*/ + +void QCameraExposure::setManualAperture(qreal aperture) +{ + if (d_func()->exposureControl) + d_func()->exposureControl->setExposureParameter(QCameraExposureControl::Aperture, QVariant(aperture)); +} + +/*! + \fn QCameraExposure::setAutoAperture() + Turn on auto aperture + \since 1.1 +*/ + +void QCameraExposure::setAutoAperture() +{ + if (d_func()->exposureControl) + d_func()->exposureControl->setExposureParameter(QCameraExposureControl::Aperture, QVariant()); +} + +/*! + Returns the current shutter speed in seconds. + \since 1.1 +*/ + +qreal QCameraExposure::shutterSpeed() const +{ + if (d_func()->exposureControl) + return d_func()->exposureControl->exposureParameter(QCameraExposureControl::ShutterSpeed).toReal(); + + return -1.0; +} + +/*! + Returns the list of shutter speed values in seconds camera supports. + + If the camera supports arbitrary shutter speed values within the supported range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + \since 1.1 +*/ +QList QCameraExposure::supportedShutterSpeeds(bool *continuous) const +{ + QList res; + + QCameraExposureControl *control = d_func()->exposureControl; + if (!control) + return res; + + foreach (const QVariant &value, + control->supportedParameterRange(QCameraExposureControl::ShutterSpeed)) { + bool ok = false; + qreal realValue = value.toReal(&ok); + if (ok) + res.append(realValue); + else + qWarning() << "Incompatible shutter speed value type, qreal is expected"; + } + + if (continuous) + *continuous = control->exposureParameterFlags(QCameraExposureControl::ShutterSpeed) & + QCameraExposureControl::ContinuousRange; + + return res; +} + +/*! + Set the manual shutter speed to \a seconds + \since 1.1 +*/ + +void QCameraExposure::setManualShutterSpeed(qreal seconds) +{ + if (d_func()->exposureControl) + d_func()->exposureControl->setExposureParameter(QCameraExposureControl::ShutterSpeed, QVariant(seconds)); +} + +/*! + Turn on auto shutter speed + \since 1.1 +*/ + +void QCameraExposure::setAutoShutterSpeed() +{ + if (d_func()->exposureControl) + d_func()->exposureControl->setExposureParameter(QCameraExposureControl::ShutterSpeed, QVariant()); +} + + +/*! + \enum QCameraExposure::FlashMode + + \value FlashOff Flash is Off. + \value FlashOn Flash is On. + \value FlashAuto Automatic flash. + \value FlashRedEyeReduction Red eye reduction flash. + \value FlashFill Use flash to fillin shadows. + \value FlashTorch Constant light source, useful for focusing and video capture. + \value FlashSlowSyncFrontCurtain + Use the flash in conjunction with a slow shutter speed. + This mode allows better exposure of distant objects and/or motion blur effect. + \value FlashSlowSyncRearCurtain + The similar mode to FlashSlowSyncFrontCurtain but flash is fired at the end of exposure. + \value FlashManual Flash power is manualy set. +*/ + +/*! + \enum QCameraExposure::ExposureMode + + \value ExposureManual Manual mode. + \value ExposureAuto Automatic mode. + \value ExposureNight Night mode. + \value ExposureBacklight Backlight exposure mode. + \value ExposureSpotlight Spotlight exposure mode. + \value ExposureSports Spots exposure mode. + \value ExposureSnow Snow exposure mode. + \value ExposureBeach Beach exposure mode. + \value ExposureLargeAperture Use larger aperture with small depth of field. + \value ExposureSmallAperture Use smaller aperture. + \value ExposurePortrait Portrait exposure mode. + \value ExposureModeVendor The base value for device specific exposure modes. +*/ + +/*! + \enum QCameraExposure::MeteringMode + + \value MeteringAverage Center weighted average metering mode. + \value MeteringSpot Spot metering mode. + \value MeteringMatrix Matrix metering mode. +*/ + +/*! + \property QCameraExposure::flashReady + \brief Indicates if the flash is charged and ready to use. + \since 1.1 +*/ + +/*! + \fn void QCameraExposure::flashReady(bool ready) + + Signal the flash \a ready status has changed. + \since 1.1 +*/ + +/*! + \fn void QCameraExposure::apertureChanged(qreal value) + + Signal emitted when aperature changes to \a value. + \since 1.1 +*/ + +/*! + \fn void QCameraExposure::apertureRangeChanged() + + Signal emitted when aperature range has changed. + \since 1.1 +*/ + + +/*! + \fn void QCameraExposure::shutterSpeedRangeChanged() + + Signal emitted when the shutter speed range has changed. + \since 1.1 +*/ + + +/*! + \fn void QCameraExposure::isoSensitivityChanged(int value) + + Signal emitted when sensitivity changes to \a value. + \since 1.1 +*/ + +/*! + \fn void QCameraExposure::exposureCompensationChanged(qreal value) + + Signal emitted when the exposure compensation changes to \a value. + \since 1.1 +*/ + +#include "moc_qcameraexposure.cpp" +QT_END_NAMESPACE diff --git a/src/multimediakit/qcameraexposure.h b/src/multimediakit/qcameraexposure.h new file mode 100644 index 000000000..6da69afa2 --- /dev/null +++ b/src/multimediakit/qcameraexposure.h @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAEXPOSURE_H +#define QCAMERAEXPOSURE_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class QCamera; +class QCameraExposurePrivate; + +class Q_MULTIMEDIA_EXPORT QCameraExposure : public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal aperture READ aperture NOTIFY apertureChanged) + Q_PROPERTY(qreal shutterSpeed READ shutterSpeed NOTIFY shutterSpeedChanged) + Q_PROPERTY(int isoSensitivity READ isoSensitivity NOTIFY isoSensitivityChanged) + Q_PROPERTY(qreal exposureCompensation READ exposureCompensation WRITE setExposureCompensation NOTIFY exposureCompensationChanged) + Q_PROPERTY(bool flashReady READ isFlashReady NOTIFY flashReady) + Q_PROPERTY(QCameraExposure::FlashModes flashMode READ flashMode WRITE setFlashMode) + Q_PROPERTY(QCameraExposure::ExposureMode exposureMode READ exposureMode WRITE setExposureMode) + Q_PROPERTY(QCameraExposure::MeteringMode meteringMode READ meteringMode WRITE setMeteringMode) + + Q_ENUMS(FlashMode) + Q_ENUMS(ExposureMode) + Q_ENUMS(MeteringMode) +public: + enum FlashMode { + FlashAuto = 0x1, + FlashOff = 0x2, + FlashOn = 0x4, + FlashRedEyeReduction = 0x8, + FlashFill = 0x10, + FlashTorch = 0x20, + FlashSlowSyncFrontCurtain = 0x40, + FlashSlowSyncRearCurtain = 0x80, + FlashManual = 0x100 + }; + Q_DECLARE_FLAGS(FlashModes, FlashMode) + + enum ExposureMode { + ExposureAuto = 0, + ExposureManual = 1, + ExposurePortrait = 2, + ExposureNight = 3, + ExposureBacklight = 4, + ExposureSpotlight = 5, + ExposureSports = 6, + ExposureSnow = 7, + ExposureBeach = 8, + ExposureLargeAperture = 9, + ExposureSmallAperture = 10, + ExposureModeVendor = 1000 + }; + + enum MeteringMode { + MeteringMatrix = 1, + MeteringAverage = 2, + MeteringSpot = 3 + }; + + bool isAvailable() const; + + FlashModes flashMode() const; + bool isFlashModeSupported(FlashModes mode) const; + bool isFlashReady() const; + + ExposureMode exposureMode() const; + bool isExposureModeSupported(ExposureMode mode) const; + + qreal exposureCompensation() const; + + MeteringMode meteringMode() const; + + bool isMeteringModeSupported(MeteringMode mode) const; + + int isoSensitivity() const; + QList supportedIsoSensitivities(bool *continuous = 0) const; + + qreal aperture() const; + QList supportedApertures(bool *continuous = 0) const; + + qreal shutterSpeed() const; + QList supportedShutterSpeeds(bool *continuous = 0) const; + +public Q_SLOTS: + void setFlashMode(FlashModes mode); + void setExposureMode(ExposureMode mode); + + void setExposureCompensation(qreal ev); + + void setMeteringMode(MeteringMode mode); + + void setManualIsoSensitivity(int iso); + void setAutoIsoSensitivity(); + + void setManualAperture(qreal aperture); + void setAutoAperture(); + + void setManualShutterSpeed(qreal seconds); + void setAutoShutterSpeed(); + +Q_SIGNALS: + void flashReady(bool); + + void apertureChanged(qreal); + void apertureRangeChanged(); + void shutterSpeedChanged(qreal); + void shutterSpeedRangeChanged(); + void isoSensitivityChanged(int); + void exposureCompensationChanged(qreal); + +private: + friend class QCamera; + explicit QCameraExposure(QCamera *parent = 0); + virtual ~QCameraExposure(); + + Q_DISABLE_COPY(QCameraExposure) + Q_DECLARE_PRIVATE(QCameraExposure) + Q_PRIVATE_SLOT(d_func(), void _q_exposureParameterChanged(int)) + Q_PRIVATE_SLOT(d_func(), void _q_exposureParameterRangeChanged(int)) + QCameraExposurePrivate *d_ptr; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QCameraExposure::FlashModes) + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QCameraExposure::ExposureMode) +Q_DECLARE_METATYPE(QCameraExposure::FlashModes) +Q_DECLARE_METATYPE(QCameraExposure::MeteringMode) + +Q_MEDIA_ENUM_DEBUG(QCameraExposure, ExposureMode) +Q_MEDIA_ENUM_DEBUG(QCameraExposure, FlashMode) +Q_MEDIA_ENUM_DEBUG(QCameraExposure, MeteringMode) + +#endif // QCAMERAEXPOSURE_H diff --git a/src/multimediakit/qcameraexposurecontrol.cpp b/src/multimediakit/qcameraexposurecontrol.cpp new file mode 100644 index 000000000..5df107e75 --- /dev/null +++ b/src/multimediakit/qcameraexposurecontrol.cpp @@ -0,0 +1,252 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraExposureControl + + \brief The QCameraExposureControl class allows controlling camera exposure parameters. + + \inmodule QtMultimediaKit + \ingroup camera + \since 1.1 + + You can adjust a number of parameters that will affect images and video taken with + the corresponding QCamera object. + + There are a number of different parameters that can be adjusted, including: + + \table + \row + \header + \ + + \endtable + + The interface name of QCameraExposureControl is \c com.nokia.Qt.QCameraExposureControl/1.0 as + defined in QCameraExposureControl_iid. + + \sa QCamera +*/ + +/*! + \macro QCameraExposureControl_iid + + \c com.nokia.Qt.QCameraExposureControl/1.0 + + Defines the interface name of the QCameraExposureControl class. + + \relates QCameraExposureControl +*/ + +/*! + Constructs a camera exposure control object with \a parent. +*/ +QCameraExposureControl::QCameraExposureControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroys the camera control object. +*/ +QCameraExposureControl::~QCameraExposureControl() +{ +} + +/*! + \fn QCamera::ExposureMode QCameraExposureControl::exposureMode() const + + Returns the exposure mode. + \since 1.1 +*/ + + +/*! + \fn void QCameraExposureControl::setExposureMode(QCameraExposure::ExposureMode mode) + + Set the exposure mode to \a mode. + \since 1.1 +*/ + + +/*! + \fn bool QCameraExposureControl::isExposureModeSupported(QCameraExposure::ExposureMode mode) const + + Returns true if the exposure \a mode is supported. + \since 1.1 +*/ + + +/*! + \fn QCameraExposure::MeteringMode QCameraExposureControl::meteringMode() const + Returns the current metering mode. + \since 1.1 +*/ + +/*! + \fn void QCameraExposureControl::setMeteringMode(QCameraExposure::MeteringMode mode) + + Set the metering mode to \a mode. + \since 1.1 +*/ + + +/*! + \fn bool QCameraExposureControl::isMeteringModeSupported(QCameraExposure::MeteringMode mode) const + Returns true if the metering \a mode is supported. + \since 1.1 +*/ + +/*! + \enum QCameraExposureControl::ExposureParameter + \value InvalidParameter + Parameter is invalid. + \value ISO + Camera ISO sensitivity, specified as integer value. + \value Aperture + Lens aperture is specified as an qreal F number. + The supported apertures list can change depending on the focal length, + in such a case the exposureParameterRangeChanged() signal is emitted. + \value ShutterSpeed + Shutter speed in seconds, specified as qreal. + \value ExposureCompensation + Exposure compensation, specified as qreal EV value. + \value FlashPower + Manual flash power, specified as qreal value. + Accepted power range is [0..1.0], + with 0 value means no flash and 1.0 corresponds to full flash power. + + This value is only used in the \l{QCameraExposure::FlashManual}{manual flash mode}. + \value FlashCompensation + Flash compensation, specified as qreal EV value. + \value ExtendedExposureParameter + The base value for platform specific extended parameters. + For such parameters the sequential values starting from ExtendedExposureParameter shuld be used. +*/ + +/*! + \enum QCameraExposureControl::ParameterFlag + \value AutomaticValue + Use the automatic values for parameters. + \value ReadOnly + Parameters are read only. + \value ContinuousRange + Parameters are continuous in their range. +*/ + +/*! + \fn QCameraExposureControl::isParameterSupported(ExposureParameter parameter) const + + Returns true is exposure \a parameter is supported by backend. + \since 1.1 +*/ + +/*! + \fn QCameraExposureControl::exposureParameter(ExposureParameter parameter) const + + Returns the exposure \a parameter value, or invalid QVariant() if the value is unknown or not supported. + \since 1.1 +*/ + +/*! + \fn QCameraExposureControl::exposureParameterFlags(ExposureParameter parameter) const + + Returns the properties of exposure \a parameter. + \since 1.1 +*/ + + +/*! + \fn QCameraExposureControl::supportedParameterRange(ExposureParameter parameter) const + + Returns the list of supported \a parameter values; + \since 1.1 +*/ + +/*! + \fn bool QCameraExposureControl::setExposureParameter(ExposureParameter parameter, const QVariant& value) + + Set the exposure \a parameter to \a value. + If a null or invalid QVariant is passed, backend should choose the value automatically, + and if possible report the actual value to user with QCameraExposureControl::exposureParameter(). + + Returns true if parameter is supported and value is correct. + \since 1.1 +*/ + +/*! + \fn QCameraExposureControl::extendedParameterName(ExposureParameter parameter) + + Returns the extended exposure \a parameter name. + \since 1.1 +*/ + +/*! + \fn void QCameraExposureControl::flashReady(bool ready) + + Signal emitted when flash state changes, flash is charged \a ready. + \since 1.1 +*/ + +/*! + \fn void QCameraExposureControl::exposureParameterChanged(int parameter) + + Signal emitted when the exposure \a parameter has changed. + \since 1.1 +*/ + +/*! + + \fn void QCameraExposureControl::exposureParameterRangeChanged(int parameter) + + Signal emitted when the exposure \a parameter range has changed. + \since 1.1 +*/ + + +#include "moc_qcameraexposurecontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qcameraexposurecontrol.h b/src/multimediakit/qcameraexposurecontrol.h new file mode 100644 index 000000000..5d8a59c67 --- /dev/null +++ b/src/multimediakit/qcameraexposurecontrol.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAEXPOSURECONTROL_H +#define QCAMERAEXPOSURECONTROL_H + +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QCameraExposureControl : public QMediaControl +{ + Q_OBJECT + Q_ENUMS(ExposureParameter) + +public: + ~QCameraExposureControl(); + + enum ExposureParameter { + InvalidParameter = 0, + ISO = 1, + Aperture = 2, + ShutterSpeed = 3, + ExposureCompensation = 4, + FlashPower = 5, + FlashCompensation = 6, + ExtendedExposureParameter = 1000 + }; + + enum ParameterFlag { + AutomaticValue = 0x01, + ReadOnly = 0x02, + ContinuousRange = 0x04 + }; + Q_DECLARE_FLAGS(ParameterFlags, ParameterFlag) + + virtual QCameraExposure::ExposureMode exposureMode() const = 0; + virtual void setExposureMode(QCameraExposure::ExposureMode mode) = 0; + virtual bool isExposureModeSupported(QCameraExposure::ExposureMode mode) const = 0; + + virtual QCameraExposure::MeteringMode meteringMode() const = 0; + virtual void setMeteringMode(QCameraExposure::MeteringMode mode) = 0; + virtual bool isMeteringModeSupported(QCameraExposure::MeteringMode mode) const = 0; + + virtual bool isParameterSupported(ExposureParameter parameter) const = 0; + virtual QVariant exposureParameter(ExposureParameter parameter) const = 0; + virtual ParameterFlags exposureParameterFlags(ExposureParameter parameter) const = 0; + virtual QVariantList supportedParameterRange(ExposureParameter parameter) const = 0; + virtual bool setExposureParameter(ExposureParameter parameter, const QVariant& value) = 0; + + virtual QString extendedParameterName(ExposureParameter parameter) = 0; + +Q_SIGNALS: + void flashReady(bool); + + void exposureParameterChanged(int parameter); + void exposureParameterRangeChanged(int parameter); + +protected: + QCameraExposureControl(QObject* parent = 0); +}; + +#define QCameraExposureControl_iid "com.nokia.Qt.QCameraExposureControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QCameraExposureControl, QCameraExposureControl_iid) + +Q_DECLARE_OPERATORS_FOR_FLAGS(QCameraExposureControl::ParameterFlags) + +Q_MEDIA_ENUM_DEBUG(QCameraExposureControl, ExposureParameter) + +QT_END_NAMESPACE + +#endif // QCAMERAEXPOSURECONTROL_H + diff --git a/src/multimediakit/qcameraflashcontrol.cpp b/src/multimediakit/qcameraflashcontrol.cpp new file mode 100644 index 000000000..000cd28af --- /dev/null +++ b/src/multimediakit/qcameraflashcontrol.cpp @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraFlashControl + + \brief The QCameraFlashControl class allows controlling a camera's flash. + + \ingroup camera + \inmodule QtMultimediaKit + \since 1.1 + + \inmodule QtMultimediaKit + + You can set the type of flash effect used when an image is captured, and test to see + if the flash hardware is ready to fire. + + You can retrieve this control from the camera object in the usual way: + + XXX snippet for retrieving control + + Some camera devices may not have flash hardware, or may not be configurable. In that + case, there will be no QCameraFlashControl available. + + The interface name of QCameraFlashControl is \c com.nokia.Qt.QCameraFlashControl/1.0 as + defined in QCameraFlashControl_iid. + + \sa QCamera +*/ + +/*! + \macro QCameraFlashControl_iid + + \c com.nokia.Qt.QCameraFlashControl/1.0 + + Defines the interface name of the QCameraFlashControl class. + + \relates QCameraFlashControl +*/ + +/*! + Constructs a camera flash control object with \a parent. +*/ +QCameraFlashControl::QCameraFlashControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroys the camera control object. +*/ +QCameraFlashControl::~QCameraFlashControl() +{ +} + +/*! + \fn QCamera::FlashModes QCameraFlashControl::flashMode() const + + Returns the current flash mode. + \since 1.1 +*/ + +/*! + \fn void QCameraFlashControl::setFlashMode(QCameraExposure::FlashModes mode) + + Set the current flash \a mode. + + Usually a single QCameraExposure::FlashMode flag is used, + but some non conflicting flags combination are also allowed, + like QCameraExposure::FlashManual | QCameraExposure::FlashSlowSyncRearCurtain. + \since 1.1 +*/ + + +/*! + \fn QCameraFlashControl::isFlashModeSupported(QCameraExposure::FlashModes mode) const + + Return true if the reqested flash \a mode is supported. + Some QCameraExposure::FlashMode values can be combined, + for example QCameraExposure::FlashManual | QCameraExposure::FlashSlowSyncRearCurtain + \since 1.1 +*/ + +/*! + \fn bool QCameraFlashControl::isFlashReady() const + + Returns true if flash is charged. + \since 1.1 +*/ + +/*! + \fn void QCameraFlashControl::flashReady(bool ready) + + Signal emitted when flash state changes to \a ready. + \since 1.1 +*/ + +#include "moc_qcameraflashcontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qcameraflashcontrol.h b/src/multimediakit/qcameraflashcontrol.h new file mode 100644 index 000000000..8f203ae89 --- /dev/null +++ b/src/multimediakit/qcameraflashcontrol.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAFLASHCONTROL_H +#define QCAMERAFLASHCONTROL_H + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QCameraFlashControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QCameraFlashControl(); + + virtual QCameraExposure::FlashModes flashMode() const = 0; + virtual void setFlashMode(QCameraExposure::FlashModes mode) = 0; + virtual bool isFlashModeSupported(QCameraExposure::FlashModes mode) const = 0; + + virtual bool isFlashReady() const = 0; + +Q_SIGNALS: + void flashReady(bool); + +protected: + QCameraFlashControl(QObject* parent = 0); +}; + +#define QCameraFlashControl_iid "com.nokia.Qt.QCameraFlashControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QCameraFlashControl, QCameraFlashControl_iid) + +QT_END_NAMESPACE + +#endif // QCAMERAFLASHCONTROL_H + diff --git a/src/multimediakit/qcamerafocus.cpp b/src/multimediakit/qcamerafocus.cpp new file mode 100644 index 000000000..ccb157c0e --- /dev/null +++ b/src/multimediakit/qcamerafocus.cpp @@ -0,0 +1,478 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace +{ +class CameraFocusRegisterMetaTypes +{ +public: + CameraFocusRegisterMetaTypes() + { + qRegisterMetaType("QCameraFocus::FocusModes"); + qRegisterMetaType("QCameraFocus::FocusPointMode"); + } +} _registerCameraFocusMetaTypes; +} + + +class QCameraFocusZoneData : public QSharedData +{ +public: + QCameraFocusZoneData(): + status(QCameraFocusZone::Invalid) + { + + } + + QCameraFocusZoneData(const QRectF &_area, QCameraFocusZone::FocusZoneStatus _status): + area(_area), + status(_status) + { + + } + + + QCameraFocusZoneData(const QCameraFocusZoneData &other): + QSharedData(other), + area(other.area), + status(other.status) + { + } + + QCameraFocusZoneData& operator=(const QCameraFocusZoneData &other) + { + area = other.area; + status = other.status; + return *this; + } + + QRectF area; + QCameraFocusZone::FocusZoneStatus status; +}; + +QCameraFocusZone::QCameraFocusZone() + :d(new QCameraFocusZoneData) +{ + +} + +QCameraFocusZone::QCameraFocusZone(const QRectF &area, QCameraFocusZone::FocusZoneStatus status) + :d(new QCameraFocusZoneData(area, status)) +{ +} + +QCameraFocusZone::QCameraFocusZone(const QCameraFocusZone &other) + :d(other.d) +{ + +} + +QCameraFocusZone::~QCameraFocusZone() +{ + +} + +QCameraFocusZone& QCameraFocusZone::operator=(const QCameraFocusZone &other) +{ + d = other.d; + return *this; +} + +bool QCameraFocusZone::operator==(const QCameraFocusZone &other) const +{ + return d == other.d || + (d->area == other.d->area && d->status == other.d->status); +} + +bool QCameraFocusZone::operator!=(const QCameraFocusZone &other) const +{ + return !(*this == other); +} + +bool QCameraFocusZone::isValid() const +{ + return d->status != Invalid && !d->area.isValid(); +} + +QRectF QCameraFocusZone::area() const +{ + return d->area; +} + +QCameraFocusZone::FocusZoneStatus QCameraFocusZone::status() const +{ + return d->status; +} + +void QCameraFocusZone::setStatus(QCameraFocusZone::FocusZoneStatus status) +{ + d->status = status; +} + + +/*! + \class QCameraFocus + + + \brief The QCameraFocus class provides interface for + focus and zoom related camera settings. + + \inmodule QtMultimediaKit + \ingroup camera + \since 1.1 + +*/ + + +class QCameraFocusPrivate : public QMediaObjectPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QCameraFocus) +public: + void initControls(); + + QCameraFocus *q_ptr; + + QCamera *camera; + QCameraFocusControl *focusControl; +}; + + +void QCameraFocusPrivate::initControls() +{ + Q_Q(QCameraFocus); + + focusControl = 0; + + QMediaService *service = camera->service(); + if (service) + focusControl = qobject_cast(service->requestControl(QCameraFocusControl_iid)); + + if (focusControl) { + q->connect(focusControl, SIGNAL(opticalZoomChanged(qreal)), q, SIGNAL(opticalZoomChanged(qreal))); + q->connect(focusControl, SIGNAL(digitalZoomChanged(qreal)), q, SIGNAL(digitalZoomChanged(qreal))); + q->connect(focusControl, SIGNAL(maximumOpticalZoomChanged(qreal)), + q, SIGNAL(maximumOpticalZoomChanged(qreal))); + q->connect(focusControl, SIGNAL(maximumDigitalZoomChanged(qreal)), + q, SIGNAL(maximumDigitalZoomChanged(qreal))); + q->connect(focusControl, SIGNAL(focusZonesChanged()), q, SIGNAL(focusZonesChanged())); + } +} + +/*! + Construct a QCameraFocus for \a camera. +*/ + +QCameraFocus::QCameraFocus(QCamera *camera): + QObject(camera), d_ptr(new QCameraFocusPrivate) +{ + Q_D(QCameraFocus); + d->camera = camera; + d->q_ptr = this; + d->initControls(); +} + + +/*! + Destroys the camera focus object. +*/ + +QCameraFocus::~QCameraFocus() +{ +} + +/*! + Returns true if focus related settings are supported by this camera. + \since 1.1 +*/ +bool QCameraFocus::isAvailable() const +{ + return d_func()->focusControl != 0; +} + +/*! + \property QCameraFocus::focusMode + \brief The current camera focus mode. + + \since 1.1 + \sa QCameraFocus::isFocusModeSupported() +*/ + +QCameraFocus::FocusMode QCameraFocus::focusMode() const +{ + return d_func()->focusControl ? d_func()->focusControl->focusMode() : QCameraFocus::AutoFocus; +} + +void QCameraFocus::setFocusMode(QCameraFocus::FocusMode mode) +{ + if (d_func()->focusControl) + d_func()->focusControl->setFocusMode(mode); +} + +/*! + Returns true if the focus \a mode is supported by camera. + \since 1.1 +*/ + +bool QCameraFocus::isFocusModeSupported(QCameraFocus::FocusMode mode) const +{ + return d_func()->focusControl ? d_func()->focusControl->isFocusModeSupported(mode) : false; +} + +/*! + \property QCameraFocus::focusPointMode + \brief The current camera focus point selection mode. + + \sa QCameraFocus::isFocusPointModeSupported() + \since 1.1 +*/ + +QCameraFocus::FocusPointMode QCameraFocus::focusPointMode() const +{ + return d_func()->focusControl ? + d_func()->focusControl->focusPointMode() : + QCameraFocus::FocusPointAuto; +} + +void QCameraFocus::setFocusPointMode(QCameraFocus::FocusPointMode mode) +{ + if (d_func()->focusControl) + d_func()->focusControl->setFocusPointMode(mode); + else + qWarning("Focus points mode selection is not supported"); +} + +/*! + Returns true if focus point \a mode is supported. + \since 1.1 + */ +bool QCameraFocus::isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const +{ + return d_func()->focusControl ? + d_func()->focusControl->isFocusPointModeSupported(mode) : + false; + +} + +/*! + \property QCameraFocus::customFocusPoint + + Position of custom focus point, in relative frame coordinates: + QPointF(0,0) points to the left top frame point, QPointF(0.5,0.5) points to the frame center. + + Custom focus point is used only in FocusPointCustom focus mode. + \since 1.1 + */ + +QPointF QCameraFocus::customFocusPoint() const +{ + return d_func()->focusControl ? + d_func()->focusControl->customFocusPoint() : + QPointF(0.5,0.5); +} + +void QCameraFocus::setCustomFocusPoint(const QPointF &point) +{ + if (d_func()->focusControl) + d_func()->focusControl->setCustomFocusPoint(point); + else + qWarning("Focus points selection is not supported"); + +} + +/*! + \property QCameraFocus::focusZones + + Returns the list of active focus zones. + + If QCamera::FocusPointAuto or QCamera::FocusPointFaceDetection focus mode is selected + this method returns the list of zones the camera is actually focused on. + + The coordinates system is the same as for custom focus points: + QPointF(0,0) points to the left top frame point, QPointF(0.5,0.5) points to the frame center. + \since 1.1 + */ +QCameraFocusZoneList QCameraFocus::focusZones() const +{ + return d_func()->focusControl ? + d_func()->focusControl->focusZones() : + QCameraFocusZoneList(); +} + +/*! + Returns the maximum optical zoom + \since 1.1 +*/ + +qreal QCameraFocus::maximumOpticalZoom() const +{ + return d_func()->focusControl ? d_func()->focusControl->maximumOpticalZoom() : 1.0; +} + +/*! + Returns the maximum digital zoom + \since 1.1 +*/ + +qreal QCameraFocus::maximumDigitalZoom() const +{ + return d_func()->focusControl ? d_func()->focusControl->maximumDigitalZoom() : 1.0; +} + +/*! + \property QCameraFocus::opticalZoom + \brief The current optical zoom value. + + \since 1.1 + \sa QCameraFocus::digitalZoom +*/ + +qreal QCameraFocus::opticalZoom() const +{ + return d_func()->focusControl ? d_func()->focusControl->opticalZoom() : 1.0; +} + +/*! + \property QCameraFocus::digitalZoom + \brief The current digital zoom value. + + \since 1.1 + \sa QCameraFocus::opticalZoom +*/ +qreal QCameraFocus::digitalZoom() const +{ + return d_func()->focusControl ? d_func()->focusControl->digitalZoom() : 1.0; +} + + +/*! + Set the camera \a optical and \a digital zoom values. + \since 1.1 +*/ +void QCameraFocus::zoomTo(qreal optical, qreal digital) +{ + if (d_func()->focusControl) + d_func()->focusControl->zoomTo(optical, digital); + else + qWarning("The camera doesn't support zooming."); +} + +/*! + \enum QCameraFocus::FocusMode + + \value ManualFocus Manual or fixed focus mode. + \value AutoFocus One-shot auto focus mode. + \value ContinuousFocus Continuous auto focus mode. + \value InfinityFocus Focus strictly to infinity. + \value HyperfocalFocus Focus to hyperfocal distance, with with the maximum depth of field achieved. + All objects at distances from half of this + distance out to infinity will be acceptably sharp. + \value MacroFocus One shot auto focus to objects close to camera. +*/ + +/*! + \enum QCameraFocus::FocusPointMode + + \value FocusPointAuto Automatically select one or multiple focus points. + \value FocusPointCenter Focus to the frame center. + \value FocusPointFaceDetection Focus on faces in the frame. + \value FocusPointCustom Focus to the custom point, defined by QCameraFocus::customFocusPoint property. +*/ + +/*! + \fn void QCameraFocus::opticalZoomChanged(qreal value) + + Signal emitted when optical zoom value changes to new \a value. + \since 1.1 +*/ + +/*! + \fn void QCameraFocus::digitalZoomChanged(qreal value) + + Signal emitted when digital zoom value changes to new \a value. + \since 1.1 +*/ + +/*! + \fn void QCameraFocus::maximumOpticalZoomChanged(qreal zoom) + + Signal emitted when the maximum supported optical \a zoom value changed. + \since 1.1 +*/ + +/*! + \fn void QCameraFocus::maximumDigitalZoomChanged(qreal zoom) + + Signal emitted when the maximum supported digital \a zoom value changed. + + The maximum supported zoom value can depend on other camera settings, + like capture mode or resolution. + \since 1.1 +*/ + + + +/*! + \fn QCameraFocus::focusZonesChanged() + + Signal is emitted when the set of zones, camera focused on is changed. + + Usually the zones list is changed when the camera is focused. + \since 1.1 +*/ + + +#include "moc_qcamerafocus.cpp" +QT_END_NAMESPACE diff --git a/src/multimediakit/qcamerafocus.h b/src/multimediakit/qcamerafocus.h new file mode 100644 index 000000000..dcc8111e1 --- /dev/null +++ b/src/multimediakit/qcamerafocus.h @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAFOCUS_H +#define QCAMERAFOCUS_H + +#include +#include +#include +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QCamera; + +class QCameraFocusZoneData; + +class Q_MULTIMEDIA_EXPORT QCameraFocusZone { +public: + enum FocusZoneStatus { + Invalid, + Unused, + Selected, + Focused + }; + + QCameraFocusZone(); + QCameraFocusZone(const QRectF &area, FocusZoneStatus status = Selected); + QCameraFocusZone(const QCameraFocusZone &other); + + QCameraFocusZone& operator=(const QCameraFocusZone &other); + bool operator==(const QCameraFocusZone &other) const; + bool operator!=(const QCameraFocusZone &other) const; + + ~QCameraFocusZone(); + + bool isValid() const; + + QRectF area() const; + + FocusZoneStatus status() const; + void setStatus(FocusZoneStatus status); + +private: + QSharedDataPointer d; +}; + +typedef QList QCameraFocusZoneList; + + +class QCameraFocusPrivate; +class Q_MULTIMEDIA_EXPORT QCameraFocus : public QObject +{ + Q_OBJECT + + Q_PROPERTY(FocusMode focusMode READ focusMode WRITE setFocusMode) + Q_PROPERTY(FocusPointMode focusPointMode READ focusPointMode WRITE setFocusPointMode) + Q_PROPERTY(QPointF customFocusPoint READ customFocusPoint WRITE setCustomFocusPoint) + Q_PROPERTY(QCameraFocusZoneList focusZones READ focusZones NOTIFY focusZonesChanged) + Q_PROPERTY(qreal opticalZoom READ opticalZoom NOTIFY opticalZoomChanged) + Q_PROPERTY(qreal digitalZoom READ digitalZoom NOTIFY digitalZoomChanged) + + Q_ENUMS(FocusMode) + Q_ENUMS(FocusPointMode) +public: + enum FocusMode { + ManualFocus = 0x1, + HyperfocalFocus = 0x02, + InfinityFocus = 0x04, + AutoFocus = 0x8, + ContinuousFocus = 0x10, + MacroFocus = 0x20 + }; + Q_DECLARE_FLAGS(FocusModes, FocusMode) + + enum FocusPointMode { + FocusPointAuto, + FocusPointCenter, + FocusPointFaceDetection, + FocusPointCustom + }; + + bool isAvailable() const; + + FocusMode focusMode() const; + void setFocusMode(FocusMode mode); + bool isFocusModeSupported(FocusMode mode) const; + + FocusPointMode focusPointMode() const; + void setFocusPointMode(FocusPointMode mode); + bool isFocusPointModeSupported(FocusPointMode) const; + QPointF customFocusPoint() const; + void setCustomFocusPoint(const QPointF &point); + + QCameraFocusZoneList focusZones() const; + + qreal maximumOpticalZoom() const; + qreal maximumDigitalZoom() const; + qreal opticalZoom() const; + qreal digitalZoom() const; + + void zoomTo(qreal opticalZoom, qreal digitalZoom); + +Q_SIGNALS: + void opticalZoomChanged(qreal); + void digitalZoomChanged(qreal); + + void focusZonesChanged(); + + void maximumOpticalZoomChanged(qreal); + void maximumDigitalZoomChanged(qreal); + +private: + friend class QCamera; + QCameraFocus(QCamera *camera); + ~QCameraFocus(); + + Q_DISABLE_COPY(QCameraFocus) + Q_DECLARE_PRIVATE(QCameraFocus) + QCameraFocusPrivate *d_ptr; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QCameraFocus::FocusModes) + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QCameraFocus::FocusModes) +Q_DECLARE_METATYPE(QCameraFocus::FocusPointMode) + +Q_MEDIA_ENUM_DEBUG(QCameraFocus, FocusMode) +Q_MEDIA_ENUM_DEBUG(QCameraFocus, FocusPointMode) + +#endif // QCAMERAFOCUS_H diff --git a/src/multimediakit/qcamerafocuscontrol.cpp b/src/multimediakit/qcamerafocuscontrol.cpp new file mode 100644 index 000000000..1a30a9c21 --- /dev/null +++ b/src/multimediakit/qcamerafocuscontrol.cpp @@ -0,0 +1,253 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraFocusControl + + + \brief The QCameraFocusControl class supplies control for + focusing related camera parameters. + + \inmodule QtMultimediaKit + \ingroup camera + \since 1.1 + + The interface name of QCameraFocusControl is \c com.nokia.Qt.QCameraFocusControl/1.0 as + defined in QCameraFocusControl_iid. + + + \sa QMediaService::requestControl(), QCamera +*/ + +/*! + \macro QCameraFocusControl_iid + + \c com.nokia.Qt.QCameraFocusControl/1.0 + + Defines the interface name of the QCameraFocusControl class. + + \relates QCameraFocusControl +*/ + +/*! + Constructs a camera control object with \a parent. +*/ + +QCameraFocusControl::QCameraFocusControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destruct the camera control object. +*/ + +QCameraFocusControl::~QCameraFocusControl() +{ +} + + +/*! + \fn QCameraFocus::FocusMode QCameraFocusControl::focusMode() const + + Returns the focus mode being used. + \since 1.1 +*/ + + +/*! + \fn void QCameraFocusControl::setFocusMode(QCameraFocus::FocusMode mode) + + Set the focus mode to \a mode. + \since 1.1 +*/ + + +/*! + \fn bool QCameraFocusControl::isFocusModeSupported(QCameraFocus::FocusMode mode) const + + Returns true if focus \a mode is supported. + \since 1.1 +*/ + + +/*! + \fn qreal QCameraFocusControl::maximumOpticalZoom() const + + Returns the maximum optical zoom value, or 1.0 if optical zoom is not supported. + \since 1.1 +*/ + + +/*! + \fn qreal QCameraFocusControl::maximumDigitalZoom() const + + Returns the maximum digital zoom value, or 1.0 if digital zoom is not supported. + \since 1.1 +*/ + + +/*! + \fn qreal QCameraFocusControl::opticalZoom() const + + Return the current optical zoom value. + \since 1.1 +*/ + +/*! + \fn qreal QCameraFocusControl::digitalZoom() const + + Return the current digital zoom value. + \since 1.1 +*/ + + +/*! + \fn void QCameraFocusControl::zoomTo(qreal optical, qreal digital) + + Sets \a optical and \a digital zoom values. + \since 1.1 +*/ + +/*! + \fn QCameraFocusControl::focusPointMode() const + + Returns the camera focus point selection mode. + \since 1.1 +*/ + +/*! + \fn QCameraFocusControl::setFocusPointMode(QCameraFocus::FocusPointMode mode) + + Sets the camera focus point selection \a mode. + \since 1.1 +*/ + +/*! + \fn QCameraFocusControl::isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const + + Returns true if the camera focus point \a mode is supported. + \since 1.1 +*/ + +/*! + \fn QCameraFocusControl::customFocusPoint() const + + Return the position of custom focus point, in relative frame coordinates: + QPointF(0,0) points to the left top frame point, QPointF(0.5,0.5) points to the frame center. + + Custom focus point is used only in FocusPointCustom focus mode. + \since 1.1 +*/ + +/*! + \fn QCameraFocusControl::setCustomFocusPoint(const QPointF &point) + + Sets the custom focus \a point. + + If camera supports fixed set of focus points, + it should use the nearest supported focus point, + and return the actual focus point with QCameraFocusControl::focusZones(). + + \since 1.1 + \sa QCameraFocusControl::customFocusPoint(), QCameraFocusControl::focusZones() +*/ + +/*! + \fn QCameraFocusControl::focusZones() const + + Returns the list of zones, the camera is using for focusing or focused on. + \since 1.1 +*/ + +/*! + \fn void QCameraFocusControl::opticalZoomChanged(qreal zoom) + + Signal emitted when the optical \a zoom value changed. + \since 1.1 +*/ + +/*! + \fn void QCameraFocusControl::digitalZoomChanged(qreal zoom) + + Signal emitted when the digital \a zoom value changed. + \since 1.1 +*/ + +/*! + \fn void QCameraFocusControl::maximumOpticalZoomChanged(qreal zoom) + + Signal emitted when the maximum supported optical \a zoom value changed. + \since 1.1 +*/ + +/*! + \fn void QCameraFocusControl::maximumDigitalZoomChanged(qreal zoom) + + Signal emitted when the maximum supported digital \a zoom value changed. + + The maximum supported zoom value can depend on other camera settings, + like capture mode or resolution. + \since 1.1 +*/ + + +/*! + \fn QCameraFocusControl::focusZonesChanged() + + Signal is emitted when the set of zones, camera focused on is changed. + + Usually the zones list is changed when the camera is focused. + + \since 1.1 + \sa QCameraFocusControl::focusZones() +*/ + + + +#include "moc_qcamerafocuscontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qcamerafocuscontrol.h b/src/multimediakit/qcamerafocuscontrol.h new file mode 100644 index 000000000..23b930115 --- /dev/null +++ b/src/multimediakit/qcamerafocuscontrol.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAFOCUSCONTROL_H +#define QCAMERAFOCUSCONTROL_H + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QCameraFocusControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QCameraFocusControl(); + + virtual QCameraFocus::FocusMode focusMode() const = 0; + virtual void setFocusMode(QCameraFocus::FocusMode mode) = 0; + virtual bool isFocusModeSupported(QCameraFocus::FocusMode mode) const = 0; + + virtual qreal maximumOpticalZoom() const = 0; + virtual qreal maximumDigitalZoom() const = 0; + virtual qreal opticalZoom() const = 0; + virtual qreal digitalZoom() const = 0; + + virtual void zoomTo(qreal optical, qreal digital) = 0; + + virtual QCameraFocus::FocusPointMode focusPointMode() const = 0; + virtual void setFocusPointMode(QCameraFocus::FocusPointMode mode) = 0; + virtual bool isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const = 0; + virtual QPointF customFocusPoint() const = 0; + virtual void setCustomFocusPoint(const QPointF &point) = 0; + + virtual QCameraFocusZoneList focusZones() const = 0; + +Q_SIGNALS: + void opticalZoomChanged(qreal opticalZoom); + void digitalZoomChanged(qreal digitalZoom); + void focusZonesChanged(); + void maximumOpticalZoomChanged(qreal); + void maximumDigitalZoomChanged(qreal); + +protected: + QCameraFocusControl(QObject* parent = 0); +}; + +#define QCameraFocusControl_iid "com.nokia.Qt.QCameraFocusingControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QCameraFocusControl, QCameraFocusControl_iid) + +QT_END_NAMESPACE + +#endif // QCAMERAFOCUSCONTROL_H + diff --git a/src/multimediakit/qcameraimagecapture.cpp b/src/multimediakit/qcameraimagecapture.cpp new file mode 100644 index 000000000..5fad8313a --- /dev/null +++ b/src/multimediakit/qcameraimagecapture.cpp @@ -0,0 +1,668 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraImageCapture + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.1 + + + \brief The QCameraImageCapture class is used for the recording of media content. + + The QCameraImageCapture class is a high level images recording class. + It's not intended to be used alone but for accessing the media + recording functions of other media objects, like QCamera. + + \snippet doc/src/snippets/multimedia-snippets/camera.cpp Camera + + \snippet doc/src/snippets/multimedia-snippets/camera.cpp Camera keys + + \sa QCamera +*/ + +namespace +{ +class MediaRecorderRegisterMetaTypes +{ +public: + MediaRecorderRegisterMetaTypes() + { + qRegisterMetaType("QCameraImageCapture::Error"); + qRegisterMetaType("QCameraImageCapture::CaptureDestination"); + qRegisterMetaType("QCameraImageCapture::CaptureDestinations"); + } +} _registerRecorderMetaTypes; +} + + +class QCameraImageCapturePrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QCameraImageCapture) +public: + QCameraImageCapturePrivate(); + + QMediaObject *mediaObject; + + QCameraImageCaptureControl *control; + QImageEncoderControl *encoderControl; + QCameraCaptureDestinationControl *captureDestinationControl; + QCameraCaptureBufferFormatControl *bufferFormatControl; + + QCameraImageCapture::Error error; + QString errorString; + + void _q_error(int id, int error, const QString &errorString); + void _q_readyChanged(bool); + + void unsetError() { error = QCameraImageCapture::NoError; errorString.clear(); } + + QCameraImageCapture *q_ptr; +}; + +QCameraImageCapturePrivate::QCameraImageCapturePrivate(): + mediaObject(0), + control(0), + encoderControl(0), + captureDestinationControl(0), + bufferFormatControl(0), + error(QCameraImageCapture::NoError) +{ +} + +void QCameraImageCapturePrivate::_q_error(int id, int error, const QString &errorString) +{ + Q_Q(QCameraImageCapture); + + this->error = QCameraImageCapture::Error(error); + this->errorString = errorString; + + emit q->error(id, this->error, errorString); +} + +void QCameraImageCapturePrivate::_q_readyChanged(bool ready) +{ + Q_Q(QCameraImageCapture); + emit q->readyForCaptureChanged(ready); +} + + +/*! + Constructs a media recorder which records the media produced by \a mediaObject. + + The \a parent is passed to QMediaObject. +*/ + +QCameraImageCapture::QCameraImageCapture(QMediaObject *mediaObject, QObject *parent): + QObject(parent), d_ptr(new QCameraImageCapturePrivate) +{ + Q_D(QCameraImageCapture); + + d->q_ptr = this; + + if (mediaObject) + mediaObject->bind(this); +} + +/*! + Destroys images capture object. +*/ + +QCameraImageCapture::~QCameraImageCapture() +{ + Q_D(QCameraImageCapture); + + if (d->mediaObject) + d->mediaObject->unbind(this); +} + +/*! + \reimp + \since 1.1 +*/ +QMediaObject *QCameraImageCapture::mediaObject() const +{ + return d_func()->mediaObject; +} + +/*! + \reimp + \since 1.1 +*/ +bool QCameraImageCapture::setMediaObject(QMediaObject *mediaObject) +{ + Q_D(QCameraImageCapture); + + if (d->mediaObject) { + if (d->control) { + disconnect(d->control, SIGNAL(imageExposed(int)), + this, SIGNAL(imageExposed(int))); + disconnect(d->control, SIGNAL(imageCaptured(int,QImage)), + this, SIGNAL(imageCaptured(int,QImage))); + disconnect(d->control, SIGNAL(imageAvailable(int,QVideoFrame)), + this, SIGNAL(imageAvailable(int,QVideoFrame))); + disconnect(d->control, SIGNAL(imageMetadataAvailable(int,QtMultimediaKit::MetaData,QVariant)), + this, SIGNAL(imageMetadataAvailable(int,QtMultimediaKit::MetaData,QVariant))); + disconnect(d->control, SIGNAL(imageMetadataAvailable(int,QString,QVariant)), + this, SIGNAL(imageMetadataAvailable(int,QString,QVariant))); + disconnect(d->control, SIGNAL(imageSaved(int,QString)), + this, SIGNAL(imageSaved(int,QString))); + disconnect(d->control, SIGNAL(readyForCaptureChanged(bool)), + this, SLOT(_q_readyChanged(bool))); + disconnect(d->control, SIGNAL(error(int,int,QString)), + this, SLOT(_q_error(int,int,QString))); + + if (d->captureDestinationControl) { + disconnect(d->captureDestinationControl, SIGNAL(captureDestinationChanged(QCameraImageCapture::CaptureDestinations)), + this, SIGNAL(captureDestinationChanged(QCameraImageCapture::CaptureDestinations))); + } + + if (d->bufferFormatControl) { + disconnect(d->bufferFormatControl, SIGNAL(bufferFormatChanged(QVideoFrame::PixelFormat)), + this, SIGNAL(bufferFormatChanged(QVideoFrame::PixelFormat))); + } + + QMediaService *service = d->mediaObject->service(); + service->releaseControl(d->control); + if (d->encoderControl) + service->releaseControl(d->encoderControl); + if (d->captureDestinationControl) + service->releaseControl(d->captureDestinationControl); + if (d->bufferFormatControl) + service->releaseControl(d->bufferFormatControl); + } + } + + d->mediaObject = mediaObject; + + if (d->mediaObject) { + QMediaService *service = mediaObject->service(); + if (service) { + d->control = qobject_cast(service->requestControl(QCameraImageCaptureControl_iid)); + + if (d->control) { + d->encoderControl = qobject_cast(service->requestControl(QImageEncoderControl_iid)); + d->captureDestinationControl = qobject_cast( + service->requestControl(QCameraCaptureDestinationControl_iid)); + d->bufferFormatControl = qobject_cast( + service->requestControl(QCameraCaptureBufferFormatControl_iid)); + + connect(d->control, SIGNAL(imageExposed(int)), + this, SIGNAL(imageExposed(int))); + connect(d->control, SIGNAL(imageCaptured(int,QImage)), + this, SIGNAL(imageCaptured(int,QImage))); + connect(d->control, SIGNAL(imageMetadataAvailable(int,QtMultimediaKit::MetaData,QVariant)), + this, SIGNAL(imageMetadataAvailable(int,QtMultimediaKit::MetaData,QVariant))); + connect(d->control, SIGNAL(imageMetadataAvailable(int,QString,QVariant)), + this, SIGNAL(imageMetadataAvailable(int,QString,QVariant))); + connect(d->control, SIGNAL(imageAvailable(int,QVideoFrame)), + this, SIGNAL(imageAvailable(int,QVideoFrame))); + connect(d->control, SIGNAL(imageSaved(int, QString)), + this, SIGNAL(imageSaved(int, QString))); + connect(d->control, SIGNAL(readyForCaptureChanged(bool)), + this, SLOT(_q_readyChanged(bool))); + connect(d->control, SIGNAL(error(int,int,QString)), + this, SLOT(_q_error(int,int,QString))); + + if (d->captureDestinationControl) { + connect(d->captureDestinationControl, SIGNAL(captureDestinationChanged(QCameraImageCapture::CaptureDestinations)), + this, SIGNAL(captureDestinationChanged(QCameraImageCapture::CaptureDestinations))); + } + + if (d->bufferFormatControl) { + connect(d->bufferFormatControl, SIGNAL(bufferFormatChanged(QVideoFrame::PixelFormat)), + this, SIGNAL(bufferFormatChanged(QVideoFrame::PixelFormat))); + } + + return true; + } + } + } + + // without QCameraImageCaptureControl discard the media object + d->mediaObject = 0; + d->control = 0; + d->encoderControl = 0; + d->captureDestinationControl = 0; + d->bufferFormatControl = 0; + + return false; +} + +/*! + Returns true if the images capture service ready to use. + \since 1.1 +*/ +bool QCameraImageCapture::isAvailable() const +{ + if (d_func()->control != NULL) + return true; + else + return false; +} + +/*! + Returns the availability error code. + \since 1.1 +*/ +QtMultimediaKit::AvailabilityError QCameraImageCapture::availabilityError() const +{ + if (d_func()->control != NULL) + return QtMultimediaKit::NoError; + else + return QtMultimediaKit::ServiceMissingError; +} + +/*! + Returns the current error state. + + \since 1.1 + \sa errorString() +*/ + +QCameraImageCapture::Error QCameraImageCapture::error() const +{ + return d_func()->error; +} + +/*! + Returns a string describing the current error state. + + \since 1.1 + \sa error() +*/ + +QString QCameraImageCapture::errorString() const +{ + return d_func()->errorString; +} + + +/*! + Returns a list of supported image codecs. + \since 1.1 +*/ +QStringList QCameraImageCapture::supportedImageCodecs() const +{ + return d_func()->encoderControl ? + d_func()->encoderControl->supportedImageCodecs() : QStringList(); +} + +/*! + Returns a description of an image \a codec. + \since 1.1 +*/ +QString QCameraImageCapture::imageCodecDescription(const QString &codec) const +{ + return d_func()->encoderControl ? + d_func()->encoderControl->imageCodecDescription(codec) : QString(); +} + +/*! + Returns a list of resolutions images can be encoded at. + + If non null image \a settings parameter is passed, + the returned list is reduced to resolution supported with partial settings like image codec or quality applied. + + If the encoder supports arbitrary resolutions within the supported range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + + \since 1.1 + \sa QImageEncoderSettings::resolution() +*/ +QList QCameraImageCapture::supportedResolutions(const QImageEncoderSettings &settings, bool *continuous) const +{ + if (continuous) + *continuous = false; + + return d_func()->encoderControl ? + d_func()->encoderControl->supportedResolutions(settings, continuous) : QList(); +} + +/*! + Returns the image encoder settings being used. + + \since 1.1 + \sa setEncodingSettings() +*/ + +QImageEncoderSettings QCameraImageCapture::encodingSettings() const +{ + return d_func()->encoderControl ? + d_func()->encoderControl->imageSettings() : QImageEncoderSettings(); +} + +/*! + Sets the image encoding \a settings. + + If some parameters are not specified, or null settings are passed, + the encoder choose the default encoding parameters. + + \since 1.1 + \sa encodingSettings() +*/ + +void QCameraImageCapture::setEncodingSettings(const QImageEncoderSettings &settings) +{ + Q_D(QCameraImageCapture); + + if (d->encoderControl) { + QCamera *camera = qobject_cast(d->mediaObject); + if (camera && camera->captureMode() == QCamera::CaptureStillImage) { + QMetaObject::invokeMethod(camera, + "_q_preparePropertyChange", + Qt::DirectConnection, + Q_ARG(int, QCameraControl::ImageEncodingSettings)); + } + + d->encoderControl->setImageSettings(settings); + } +} + +/*! + Returns the list of supported buffer image capture formats. + + \since 1.1 + \sa bufferFormat() setBufferFormat() +*/ +QList QCameraImageCapture::supportedBufferFormats() const +{ + if (d_func()->bufferFormatControl) + return d_func()->bufferFormatControl->supportedBufferFormats(); + else + return QList(); +} + +/*! + Returns the buffer image capture format being used. + + \since 1.2 + \sa supportedBufferCaptureFormats() setBufferCaptureFormat() +*/ +QVideoFrame::PixelFormat QCameraImageCapture::bufferFormat() const +{ + if (d_func()->bufferFormatControl) + return d_func()->bufferFormatControl->bufferFormat(); + else + return QVideoFrame::Format_Invalid; +} + +/*! + Sets the buffer image capture format to be used. + + \since 1.2 + \sa bufferCaptureFormat() supportedBufferCaptureFormats() captureDestination() +*/ +void QCameraImageCapture::setBufferFormat(const QVideoFrame::PixelFormat format) +{ + if (d_func()->bufferFormatControl) + d_func()->bufferFormatControl->setBufferFormat(format); +} + +/*! + Returns true if the image capture \a destination is supported; otherwise returns false. + + \since 1.2 + \sa captureDestination() setCaptureDestination() +*/ +bool QCameraImageCapture::isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const +{ + if (d_func()->captureDestinationControl) + return d_func()->captureDestinationControl->isCaptureDestinationSupported(destination); + else + return destination == CaptureToFile; +} + +/*! + Returns the image capture destination being used. + + \since 1.2 + \sa isCaptureDestinationSupported() setCaptureDestination() +*/ +QCameraImageCapture::CaptureDestinations QCameraImageCapture::captureDestination() const +{ + if (d_func()->captureDestinationControl) + return d_func()->captureDestinationControl->captureDestination(); + else + return CaptureToFile; +} + +/*! + Sets the capture \a destination to be used. + + \since 1.2 + \sa isCaptureDestinationSupported() captureDestination() +*/ +void QCameraImageCapture::setCaptureDestination(QCameraImageCapture::CaptureDestinations destination) +{ + Q_D(QCameraImageCapture); + + if (d->captureDestinationControl) + d->captureDestinationControl->setCaptureDestination(destination); +} + +/*! + \property QCameraImageCapture::readyForCapture + Indicates the service is ready to capture a an image immediately. + \since 1.1 +*/ + +bool QCameraImageCapture::isReadyForCapture() const +{ + if (d_func()->control) + return d_func()->control->isReadyForCapture(); + else + return false; +} + +/*! + \fn QCameraImageCapture::readyForCaptureChanged(bool ready) + + Signals that a camera's \a ready for capture state has changed. + \since 1.1 +*/ + + +/*! + Capture the image and save it to \a file. + This operation is asynchronous in majority of cases, + followed by signals QCameraImageCapture::imageCaptured(), QCameraImageCapture::imageSaved() + or QCameraImageCapture::error(). + + If an empty \a file is passed, the camera backend choses + the default location and naming scheme for photos on the system, + if only file name without full path is specified, the image will be saved to + the default directory, with a full path reported with imageCaptured() and imageSaved() signals. + + QCameraImageCapture::capture returns the capture Id parameter, used with + imageExposed(), imageCaptured() and imageSaved() signals. + \since 1.1 +*/ +int QCameraImageCapture::capture(const QString &file) +{ + Q_D(QCameraImageCapture); + + d->unsetError(); + + if (d->control) { + return d->control->capture(file); + } else { + d->error = NotSupportedFeatureError; + d->errorString = tr("Device does not support images capture."); + + emit error(-1, d->error, d->errorString); + } + + return -1; +} + +/*! + Cancel incomplete capture requests. + Already captured and queused for proicessing images may be discarded. + \since 1.1 +*/ +void QCameraImageCapture::cancelCapture() +{ + Q_D(QCameraImageCapture); + + d->unsetError(); + + if (d->control) { + d->control->cancelCapture(); + } else { + d->error = NotSupportedFeatureError; + d->errorString = tr("Device does not support images capture."); + + emit error(-1, d->error, d->errorString); + } +} + + +/*! + \enum QCameraImageCapture::Error + + \value NoError No Errors. + \value NotReadyError The service is not ready for capture yet. + \value ResourceError Device is not ready or not available. + \value NotSupportedFeatureError Device does not support stillimages capture. + \value FormatError Current format is not supported. + \value OutOfSpaceError No space left on device. +*/ + +/*! + \enum QCameraImageCapture::DriveMode + + \value SingleImageCapture Drive mode is capturing a single picture. +*/ + +/*! + \fn QCameraImageCapture::error(int id, QCameraImageCapture::Error error, const QString &errorString) + + Signals that the capture request \a id has failed with an \a error + and \a errorString description. + \since 1.1 +*/ + +/*! + \fn QCameraImageCapture::bufferFormatChanged(QVideoFrame::PixelFormat format) + + Signal emitted when the buffer \a format for the buffer image capture has changed. + \since 1.2 +*/ + +/*! + \fn QCameraImageCapture::captureDestinationChanged(CaptureDestinations destination) + + Signal emitted when the capture \a destination has changed. + \since 1.2 +*/ + +/*! + \fn QCameraImageCapture::imageExposed(int id) + + Signal emitted when the frame with request \a id was exposed. + \since 1.1 +*/ + +/*! + \fn QCameraImageCapture::imageCaptured(int id, const QImage &preview); + + Signal emitted when the frame with request \a id was captured, but not processed and saved yet. + Frame \a preview can be displayed to user. + \since 1.1 +*/ + +/*! + \fn QCameraImageCapture::imageMetadataAvailable(int id, QtMultimediaKit::MetaData key, const QVariant &value) + + Signals that a metadata for an image with request \a id is available. + This signal is emitted for metadata \a value with a \a key listed in QtMultimediaKit::MetaData enum. + + This signal is emitted between imageExposed and imageSaved signals. + \since 1.2 +*/ + +/*! + \fn QCameraImageCapture::imageMetadataAvailable(int id, const QString &key, const QVariant &value) + + Signals that a metadata for an image with request \a id is available. + This signal is emitted for extended metadata \a value with a \a key not listed in QtMultimediaKit::MetaData enum. + + This signal is emitted between imageExposed and imageSaved signals. + \since 1.2 +*/ + + +/*! + \fn QCameraImageCapture::imageAvailable(int id, const QVideoFrame &buffer) + + Signal emitted when the frame with request \a id is available as \a buffer. + \since 1.2 +*/ + +/*! + \fn QCameraImageCapture::imageSaved(int id, const QString &fileName) + + Signal emitted when the frame with request \a id was saved to \a fileName. + \since 1.1 +*/ + + +#include "moc_qcameraimagecapture.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qcameraimagecapture.h b/src/multimediakit/qcameraimagecapture.h new file mode 100644 index 000000000..09d4d67b4 --- /dev/null +++ b/src/multimediakit/qcameraimagecapture.h @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAIMAGECAPTURE_H +#define QCAMERAIMAGECAPTURE_H + +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE +class QSize; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class QImageEncoderSettings; + +class QCameraImageCapturePrivate; +class Q_MULTIMEDIA_EXPORT QCameraImageCapture : public QObject, public QMediaBindableInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaBindableInterface) + Q_ENUMS(Error) + Q_ENUMS(CaptureDestination) + Q_PROPERTY(bool readyForCapture READ isReadyForCapture NOTIFY readyForCaptureChanged) +public: + enum Error + { + NoError, + NotReadyError, + ResourceError, + OutOfSpaceError, + NotSupportedFeatureError, + FormatError + }; + + enum DriveMode + { + SingleImageCapture + }; + + enum CaptureDestination + { + CaptureToFile = 0x01, + CaptureToBuffer = 0x02 + }; + Q_DECLARE_FLAGS(CaptureDestinations, CaptureDestination) + + QCameraImageCapture(QMediaObject *mediaObject, QObject *parent = 0); + ~QCameraImageCapture(); + + bool isAvailable() const; + QtMultimediaKit::AvailabilityError availabilityError() const; + + QMediaObject *mediaObject() const; + + Error error() const; + QString errorString() const; + + bool isReadyForCapture() const; + + QStringList supportedImageCodecs() const; + QString imageCodecDescription(const QString &codecName) const; + + QList supportedResolutions(const QImageEncoderSettings &settings = QImageEncoderSettings(), + bool *continuous = 0) const; + + QImageEncoderSettings encodingSettings() const; + void setEncodingSettings(const QImageEncoderSettings& settings); + + QList supportedBufferFormats() const; + QVideoFrame::PixelFormat bufferFormat() const; + void setBufferFormat(QVideoFrame::PixelFormat format); + + bool isCaptureDestinationSupported(CaptureDestinations destination) const; + CaptureDestinations captureDestination() const; + void setCaptureDestination(CaptureDestinations destination); + +public Q_SLOTS: + int capture(const QString &location = QString()); + void cancelCapture(); + +Q_SIGNALS: + void error(int id, QCameraImageCapture::Error error, const QString &errorString); + + void readyForCaptureChanged(bool); + void bufferFormatChanged(QVideoFrame::PixelFormat); + void captureDestinationChanged(QCameraImageCapture::CaptureDestinations); + + void imageExposed(int id); + void imageCaptured(int id, const QImage &preview); + void imageMetadataAvailable(int id, QtMultimediaKit::MetaData key, const QVariant &value); + void imageMetadataAvailable(int id, const QString &key, const QVariant &value); + void imageAvailable(int id, const QVideoFrame &image); + void imageSaved(int id, const QString &fileName); + +protected: + bool setMediaObject(QMediaObject *); + + QCameraImageCapturePrivate *d_ptr; +private: + Q_DISABLE_COPY(QCameraImageCapture) + Q_DECLARE_PRIVATE(QCameraImageCapture) + Q_PRIVATE_SLOT(d_func(), void _q_error(int, int, const QString &)) + Q_PRIVATE_SLOT(d_func(), void _q_readyChanged(bool)) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QCameraImageCapture::CaptureDestinations) + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QCameraImageCapture::Error) +Q_DECLARE_METATYPE(QCameraImageCapture::CaptureDestination) +Q_DECLARE_METATYPE(QCameraImageCapture::CaptureDestinations) + +Q_MEDIA_ENUM_DEBUG(QCameraImageCapture, Error) +Q_MEDIA_ENUM_DEBUG(QCameraImageCapture, CaptureDestination) + +#endif + diff --git a/src/multimediakit/qcameraimagecapturecontrol.cpp b/src/multimediakit/qcameraimagecapturecontrol.cpp new file mode 100644 index 000000000..9733cfb61 --- /dev/null +++ b/src/multimediakit/qcameraimagecapturecontrol.cpp @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraImageCaptureControl + + \brief The QCameraImageCaptureControl class provides a control interface + for image capture services. + + \inmodule QtMultimediaKit + \ingroup camera + \since 1.1 + + + + The interface name of QCameraImageCaptureControl is \c com.nokia.Qt.QCameraImageCaptureControl/1.0 as + defined in QCameraImageCaptureControl_iid. + + + \sa QMediaService::requestControl() +*/ + +/*! + \macro QCameraImageCaptureControl_iid + + \c com.nokia.Qt.QCameraImageCaptureControl/1.0 + + Defines the interface name of the QCameraImageCaptureControl class. + + \relates QCameraImageCaptureControl +*/ + +/*! + Constructs a new image capture control object with the given \a parent +*/ +QCameraImageCaptureControl::QCameraImageCaptureControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys an image capture control. +*/ +QCameraImageCaptureControl::~QCameraImageCaptureControl() +{ +} + +/*! + \fn QCameraImageCaptureControl::isReadyForCapture() const + + Identifies if a capture control is ready to perform a capture + immediately (all the resources necessary for image capture are allocated, + hardware initialized, flash is charged, etc). + + Returns true if the camera is ready for capture; and false if it is not. + \since 1.1 +*/ + +/*! + \fn QCameraImageCaptureControl::readyForCaptureChanged(bool ready) + + Signals that a capture control's \a ready state has changed. + \since 1.1 +*/ + +/*! + \fn QCameraImageCaptureControl::capture(const QString &fileName) + + Initiates the capture of an image to \a fileName. + The \a fileName can be relative or empty, + in this case the service should use the system specific place + and file naming scheme. + + Returns the capture request id number, which is used later + with imageExposed(), imageCaptured() and imageSaved() signals. + \since 1.1 +*/ + +/*! + \fn QCameraImageCaptureControl::cancelCapture() + + Cancel pending capture requests. + \since 1.1 +*/ + +/*! + \fn QCameraImageCaptureControl::imageExposed(int requestId) + + Signals that an image with it \a requestId + has just been exposed. + This signal can be used for the shutter sound or other indicaton. + \since 1.1 +*/ + +/*! + \fn QCameraImageCaptureControl::imageCaptured(int requestId, const QImage &preview) + + Signals that an image with it \a requestId + has been captured and a \a preview is available. + \since 1.1 +*/ + +/*! + \fn QCameraImageCaptureControl::imageMetadataAvailable(int id, QtMultimediaKit::MetaData key, const QVariant &value) + + Signals that a metadata for an image with request \a id is available. + This signal is emitted for metadata \a value with a \a key listed in QtMultimediaKit::MetaData enum. + + This signal should be emitted between imageExposed and imageSaved signals. + \since 1.2 +*/ + +/*! + \fn QCameraImageCaptureControl::imageMetadataAvailable(int id, const QString &key, const QVariant &value) + + Signals that a metadata for an image with request \a id is available. + This signal is emitted for extended metadata \a value with a \a key not listed in QtMultimediaKit::MetaData enum. + + This signal should be emitted between imageExposed and imageSaved signals. + \since 1.2 +*/ + +/*! + \fn QCameraImageCaptureControl::imageAvailable(int requestId, const QVideoFrame &buffer) + + Signals that a captured \a buffer with a \a requestId is available. + \since 1.2 +*/ + +/*! + \fn QCameraImageCaptureControl::imageSaved(int requestId, const QString &fileName) + + Signals that a captured image with a \a requestId has been saved + to \a fileName. + \since 1.1 +*/ + +/*! + \fn QCameraImageCaptureControl::driveMode() const + + Returns the current camera drive mode. + \since 1.1 +*/ + +/*! + \fn QCameraImageCaptureControl::setDriveMode(QCameraImageCapture::DriveMode mode) + + Sets the current camera drive \a mode. + \since 1.1 +*/ + + +/*! + \fn QCameraImageCaptureControl::error(int id, int error, const QString &errorString) + + Signals the capture request \a id failed with \a error code and message \a errorString. + + \since 1.1 + \sa QCameraImageCapture::Error +*/ + + +#include "moc_qcameraimagecapturecontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qcameraimagecapturecontrol.h b/src/multimediakit/qcameraimagecapturecontrol.h new file mode 100644 index 000000000..a33dd1bf8 --- /dev/null +++ b/src/multimediakit/qcameraimagecapturecontrol.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAIMAGECAPTURECONTROL_H +#define QCAMERAIMAGECAPTURECONTROL_H + +#include +#include + +QT_BEGIN_NAMESPACE +class QImage; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QCameraImageCaptureControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QCameraImageCaptureControl(); + + virtual bool isReadyForCapture() const = 0; + + virtual QCameraImageCapture::DriveMode driveMode() const = 0; + virtual void setDriveMode(QCameraImageCapture::DriveMode mode) = 0; + + virtual int capture(const QString &fileName) = 0; + virtual void cancelCapture() = 0; + +Q_SIGNALS: + void readyForCaptureChanged(bool); + + void imageExposed(int id); + void imageCaptured(int id, const QImage &preview); + void imageMetadataAvailable(int id, QtMultimediaKit::MetaData key, const QVariant &value); + void imageMetadataAvailable(int id, const QString &key, const QVariant &value); + void imageAvailable(int id, const QVideoFrame &buffer); + void imageSaved(int id, const QString &fileName); + + void error(int id, int error, const QString &errorString); + +protected: + QCameraImageCaptureControl(QObject* parent = 0); +}; + +#define QCameraImageCaptureControl_iid "com.nokia.Qt.QCameraImageCaptureControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QCameraImageCaptureControl, QCameraImageCaptureControl_iid) + +QT_END_NAMESPACE + +#endif // QCAMERAIMAGECAPTURECONTROL_H + diff --git a/src/multimediakit/qcameraimageprocessing.cpp b/src/multimediakit/qcameraimageprocessing.cpp new file mode 100644 index 000000000..ee19911e5 --- /dev/null +++ b/src/multimediakit/qcameraimageprocessing.cpp @@ -0,0 +1,353 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraImageProcessing + + + \brief The QCameraImageProcessing class provides interface for + focus and zoom related camera settings. + + \inmodule QtMultimediaKit + \ingroup camera + \since 1.1 + +*/ + + +class QCameraImageProcessingPrivate : public QMediaObjectPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QCameraImageProcessing) +public: + void initControls(); + + QCameraImageProcessing *q_ptr; + + QCamera *camera; + QCameraImageProcessingControl *imageControl; +}; + + +void QCameraImageProcessingPrivate::initControls() +{ + imageControl = 0; + + QMediaService *service = camera->service(); + if (service) + imageControl = qobject_cast(service->requestControl(QCameraImageProcessingControl_iid)); +} + +/*! + Construct a QCameraImageProcessing for \a camera. +*/ + +QCameraImageProcessing::QCameraImageProcessing(QCamera *camera): + QObject(camera), d_ptr(new QCameraImageProcessingPrivate) +{ + Q_D(QCameraImageProcessing); + d->camera = camera; + d->q_ptr = this; + d->initControls(); +} + + +/*! + Destroys the camera focus object. +*/ + +QCameraImageProcessing::~QCameraImageProcessing() +{ +} + + +/*! + Returns true if image processing related settings are supported by this camera. + \since 1.1 +*/ +bool QCameraImageProcessing::isAvailable() const +{ + return d_func()->imageControl != 0; +} + + +/*! + Returns the white balance mode being used. + \since 1.1 +*/ + +QCameraImageProcessing::WhiteBalanceMode QCameraImageProcessing::whiteBalanceMode() const +{ + return d_func()->imageControl ? d_func()->imageControl->whiteBalanceMode() : QCameraImageProcessing::WhiteBalanceAuto; +} + +/*! + Sets the white balance to \a mode. + \since 1.1 +*/ + +void QCameraImageProcessing::setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode) +{ + if (d_func()->imageControl) + d_func()->imageControl->setWhiteBalanceMode(mode); +} + +/*! + Returns true if the white balance \a mode is supported. + \since 1.1 +*/ + +bool QCameraImageProcessing::isWhiteBalanceModeSupported(QCameraImageProcessing::WhiteBalanceMode mode) const +{ + return d_func()->imageControl ? d_func()->imageControl->isWhiteBalanceModeSupported(mode) : false; +} + +/*! + Returns the current color temperature if the + manual white balance is active, otherwise the + return value is undefined. + \since 1.1 +*/ + +int QCameraImageProcessing::manualWhiteBalance() const +{ + QVariant value; + + if (d_func()->imageControl) + value = d_func()->imageControl->processingParameter(QCameraImageProcessingControl::ColorTemperature); + + return value.toInt(); +} + +/*! + Sets manual white balance to \a colorTemperature + \since 1.1 +*/ + +void QCameraImageProcessing::setManualWhiteBalance(int colorTemperature) +{ + if (d_func()->imageControl) { + d_func()->imageControl->setProcessingParameter( + QCameraImageProcessingControl::ColorTemperature, + QVariant(colorTemperature)); + } +} + +/*! + Return the contrast. + \since 1.1 +*/ +int QCameraImageProcessing::contrast() const +{ + QVariant value; + + if (d_func()->imageControl) + value = d_func()->imageControl->processingParameter(QCameraImageProcessingControl::Contrast); + + return value.toInt(); +} + +/*! + Set the contrast to \a value. + + Valid contrast values range between -100 and 100, the default is 0. + \since 1.1 +*/ +void QCameraImageProcessing::setContrast(int value) +{ + if (d_func()->imageControl) + d_func()->imageControl->setProcessingParameter(QCameraImageProcessingControl::Contrast, + QVariant(value)); +} + +/*! + Returns the saturation value. + \since 1.1 +*/ +int QCameraImageProcessing::saturation() const +{ + QVariant value; + + if (d_func()->imageControl) + value = d_func()->imageControl->processingParameter(QCameraImageProcessingControl::Saturation); + + return value.toInt(); +} + +/*! + Sets the saturation value to \a value. + + Valid saturation values range between -100 and 100, the default is 0. + \since 1.1 +*/ + +void QCameraImageProcessing::setSaturation(int value) +{ + if (d_func()->imageControl) + d_func()->imageControl->setProcessingParameter(QCameraImageProcessingControl::Saturation, + QVariant(value)); +} + +/*! + Identifies if sharpening is supported. + + Returns true if sharpening is supported; and false if it is not. + \since 1.1 +*/ +bool QCameraImageProcessing::isSharpeningSupported() const +{ + if (d_func()->imageControl) + return d_func()->imageControl->isProcessingParameterSupported(QCameraImageProcessingControl::Sharpening); + else + return false; +} + +/*! + Returns the sharpening level. + \since 1.1 +*/ +int QCameraImageProcessing::sharpeningLevel() const +{ + QVariant value; + + if (d_func()->imageControl) + value = d_func()->imageControl->processingParameter(QCameraImageProcessingControl::Sharpening); + + if (value.isNull()) + return -1; + else + return value.toInt(); +} + +/*! + Sets the sharpening \a level. + + Valid sharpening level values range between -1 for default sharpening level, + 0 for sharpening disabled and 100 for maximum sharpening applied. + \since 1.1 +*/ + +void QCameraImageProcessing::setSharpeningLevel(int level) +{ + Q_D(QCameraImageProcessing); + if (d->imageControl) + d->imageControl->setProcessingParameter(QCameraImageProcessingControl::Sharpening, + level == -1 ? QVariant() : QVariant(level)); +} + +/*! + Returns true if denoising is supported. + \since 1.1 +*/ +bool QCameraImageProcessing::isDenoisingSupported() const +{ + if (d_func()->imageControl) + return d_func()->imageControl->isProcessingParameterSupported(QCameraImageProcessingControl::Denoising); + else + return false; +} + +/*! + Returns the denoising level. + \since 1.1 +*/ +int QCameraImageProcessing::denoisingLevel() const +{ + QVariant value; + + if (d_func()->imageControl) + value = d_func()->imageControl->processingParameter(QCameraImageProcessingControl::Denoising); + + if (value.isNull()) + return -1; + else + return value.toInt(); +} + +/*! + Sets the denoising \a level. + + Valid denoising level values range between -1 for default denoising level, + 0 for denoising disabled and 100 for maximum denoising applied. + \since 1.1 +*/ +void QCameraImageProcessing::setDenoisingLevel(int level) +{ + Q_D(QCameraImageProcessing); + if (d->imageControl) + d->imageControl->setProcessingParameter(QCameraImageProcessingControl::Denoising, + level == -1 ? QVariant() : QVariant(level)); +} + + +/*! + \enum QCameraImageProcessing::WhiteBalanceMode + + \value WhiteBalanceManual Manual white balance. In this mode the white balance should be set with + setManualWhiteBalance() + \value WhiteBalanceAuto Auto white balance mode. + \value WhiteBalanceSunlight Sunlight white balance mode. + \value WhiteBalanceCloudy Cloudy white balance mode. + \value WhiteBalanceShade Shade white balance mode. + \value WhiteBalanceTungsten Tungsten white balance mode. + \value WhiteBalanceFluorescent Fluorescent white balance mode. + \value WhiteBalanceIncandescent Incandescent white balance mode. + \value WhiteBalanceFlash Flash white balance mode. + \value WhiteBalanceSunset Sunset white balance mode. + \value WhiteBalanceVendor Vendor defined white balance mode. +*/ + +#include "moc_qcameraimageprocessing.cpp" +QT_END_NAMESPACE diff --git a/src/multimediakit/qcameraimageprocessing.h b/src/multimediakit/qcameraimageprocessing.h new file mode 100644 index 000000000..76c36975d --- /dev/null +++ b/src/multimediakit/qcameraimageprocessing.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAIMAGEPROCESSING_H +#define QCAMERAIMAGEPROCESSING_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QCamera; + +class QCameraImageProcessingPrivate; +class Q_MULTIMEDIA_EXPORT QCameraImageProcessing : public QObject +{ + Q_OBJECT + Q_ENUMS(WhiteBalanceMode) +public: + enum WhiteBalanceMode { + WhiteBalanceAuto = 0, + WhiteBalanceManual = 1, + WhiteBalanceSunlight = 2, + WhiteBalanceCloudy = 3, + WhiteBalanceShade = 4, + WhiteBalanceTungsten = 5, + WhiteBalanceFluorescent = 6, + WhiteBalanceIncandescent = 7, + WhiteBalanceFlash = 8, + WhiteBalanceSunset = 9, + WhiteBalanceVendor = 1000 + }; + + bool isAvailable() const; + + WhiteBalanceMode whiteBalanceMode() const; + void setWhiteBalanceMode(WhiteBalanceMode mode); + bool isWhiteBalanceModeSupported(WhiteBalanceMode mode) const; + int manualWhiteBalance() const; + void setManualWhiteBalance(int colorTemperature); + + int contrast() const; + void setContrast(int value); + + int saturation() const; + void setSaturation(int value); + + bool isSharpeningSupported() const; + int sharpeningLevel() const; + void setSharpeningLevel(int value); + + bool isDenoisingSupported() const; + int denoisingLevel() const; + void setDenoisingLevel(int value); + +private: + friend class QCamera; + QCameraImageProcessing(QCamera *camera); + ~QCameraImageProcessing(); + + Q_DISABLE_COPY(QCameraImageProcessing) + Q_DECLARE_PRIVATE(QCameraImageProcessing) + QCameraImageProcessingPrivate *d_ptr; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QCameraImageProcessing::WhiteBalanceMode) + +Q_MEDIA_ENUM_DEBUG(QCameraImageProcessing, WhiteBalanceMode) + +#endif // QCAMERAIMAGEPROCESSING_H diff --git a/src/multimediakit/qcameraimageprocessingcontrol.cpp b/src/multimediakit/qcameraimageprocessingcontrol.cpp new file mode 100644 index 000000000..1b7007180 --- /dev/null +++ b/src/multimediakit/qcameraimageprocessingcontrol.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraImageProcessingControl + \inmodule QtMultimediaKit + \ingroup multimedia-serv + \since 1.1 + + + \brief The QCameraImageProcessingControl class provides an abstract class + for controlling image processing parameters, like white balance, + contrast, saturation, sharpening and denoising. + + The interface name of QCameraImageProcessingControl is \c com.nokia.Qt.QCameraImageProcessingControl/1.0 as + defined in QCameraImageProcessingControl_iid. + + + + \sa QMediaService::requestControl(), QCamera +*/ + +/*! + \macro QCameraImageProcessingControl_iid + + \c com.nokia.Qt.QCameraImageProcessingControl/1.0 + + Defines the interface name of the QCameraImageProcessingControl class. + + \relates QCameraImageProcessingControl +*/ + +/*! + Constructs an image processing control object with \a parent. +*/ + +QCameraImageProcessingControl::QCameraImageProcessingControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destruct the image processing control object. +*/ + +QCameraImageProcessingControl::~QCameraImageProcessingControl() +{ +} + + +/*! + \fn QCameraImageProcessingControl::whiteBalanceMode() const + Return the white balance mode being used. + \since 1.1 +*/ + +/*! + \fn QCameraImageProcessingControl::setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode) + Set the white balance mode to \a mode + \since 1.1 +*/ + +/*! + \fn QCameraImageProcessingControl::isWhiteBalanceModeSupported(QCameraImageProcessing::WhiteBalanceMode mode) const + Returns true if the white balance \a mode is supported. + The backend should support at least QCameraImageProcessing::WhiteBalanceAuto mode. + \since 1.1 +*/ + +/*! + \fn bool QCameraImageProcessingControl::isProcessingParameterSupported(ProcessingParameter parameter) const + + Returns true if the camera supports adjusting image processing \a parameter. + + Usually the the supported settings is static, + but some parameter may not be available depending on other + camera settings, like presets. + In such case the currently supported parameters should be returned. + \since 1.1 +*/ + +/*! + \fn QCameraImageProcessingControl::processingParameter(ProcessingParameter parameter) const + Returns the image processing \a parameter value. + \since 1.1 +*/ + +/*! + \fn QCameraImageProcessingControl::setProcessingParameter(ProcessingParameter parameter, QVariant value) + + Sets the image processing \a parameter \a value. + Passing the null or invalid QVariant value allows + backend to choose the suitable parameter value. + + The valid values range depends on the parameter type, + for contrast, saturation and brightness value should be + between -100 and 100, the default is 0, + + For sharpening and denoising the range is 0..100, + 0 for sharpening or denoising disabled + and 100 for maximum sharpening/denoising applied. + \since 1.1 +*/ + +/*! + \enum QCameraImageProcessingControl::ProcessingParameter + + \value Contrast + Image contrast. + \value Saturation + Image saturation. + \value Brightness + Image brightness. + \value Sharpening + Amount of sharpening applied. + \value Denoising + Amount of denoising applied. + \value ColorTemperature + Color temperature in K. This value is used when the manual white balance mode is selected. + \value ExtendedParameter + The base value for platform specific extended parameters. + */ + +#include "moc_qcameraimageprocessingcontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qcameraimageprocessingcontrol.h b/src/multimediakit/qcameraimageprocessingcontrol.h new file mode 100644 index 000000000..6a1c920e3 --- /dev/null +++ b/src/multimediakit/qcameraimageprocessingcontrol.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAIMAGEPROCESSINGCONTROL_H +#define QCAMERAIMAGEPROCESSINGCONTROL_H + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QCameraImageProcessingControl : public QMediaControl +{ + Q_OBJECT + Q_ENUMS(ProcessingParameter) + +public: + ~QCameraImageProcessingControl(); + + enum ProcessingParameter { + Contrast = 0, + Saturation = 1, + Brightness = 2, + Sharpening = 3, + Denoising = 4, + ColorTemperature = 5, + ExtendedParameter = 1000 + }; + + virtual QCameraImageProcessing::WhiteBalanceMode whiteBalanceMode() const = 0; + virtual void setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode) = 0; + virtual bool isWhiteBalanceModeSupported(QCameraImageProcessing::WhiteBalanceMode) const = 0; + + virtual bool isProcessingParameterSupported(ProcessingParameter) const = 0; + virtual QVariant processingParameter(ProcessingParameter parameter) const = 0; + virtual void setProcessingParameter(ProcessingParameter parameter, QVariant value) = 0; + +protected: + QCameraImageProcessingControl(QObject* parent = 0); +}; + +#define QCameraImageProcessingControl_iid "com.nokia.Qt.QCameraImageProcessingControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QCameraImageProcessingControl, QCameraImageProcessingControl_iid) + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QCameraImageProcessingControl::ProcessingParameter) + +Q_MEDIA_ENUM_DEBUG(QCameraImageProcessingControl, ProcessingParameter) + +#endif + diff --git a/src/multimediakit/qcameralockscontrol.cpp b/src/multimediakit/qcameralockscontrol.cpp new file mode 100644 index 000000000..f254fdd61 --- /dev/null +++ b/src/multimediakit/qcameralockscontrol.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraLocksControl + + + + \brief The QCameraLocksControl class is an abstract base class for + classes that control still cameras or video cameras. + + \inmodule QtMultimediaKit + \ingroup camera + \since 1.1 + + This service is provided by a QMediaService object via + QMediaService::control(). It is used by QCamera. + + The interface name of QCameraLocksControl is \c com.nokia.Qt.QCameraLocksControl/1.0 as + defined in QCameraLocksControl_iid. + + + \sa QMediaService::requestControl(), QCamera +*/ + +/*! + \macro QCameraLocksControl_iid + + \c com.nokia.Qt.QCameraLocksControl/1.0 + + Defines the interface name of the QCameraLocksControl class. + + \relates QCameraLocksControl +*/ + +/*! + Constructs a camera locks control object with \a parent. +*/ + +QCameraLocksControl::QCameraLocksControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destruct the camera locks control object. +*/ + +QCameraLocksControl::~QCameraLocksControl() +{ +} + +/*! + \fn QCameraLocksControl::supportedLocks() const + + Returns the lock types, the camera supports. + \since 1.1 +*/ + +/*! + \fn QCameraLocksControl::lockStatus(QCamera::LockType lock) const + + Returns the camera \a lock status. + \since 1.1 +*/ + +/*! + \fn QCameraLocksControl::searchAndLock(QCamera::LockTypes locks) + + Request camera \a locks. + \since 1.1 +*/ + +/*! + \fn QCameraLocksControl::unlock(QCamera::LockTypes locks) + + Unlock camera \a locks. + \since 1.1 +*/ + +/*! + \fn QCameraLocksControl::lockStatusChanged(QCamera::LockType lock, QCamera::LockStatus status, QCamera::LockChangeReason reason) + + Signals the \a lock \a status was changed with a specified \a reason. + \since 1.1 +*/ + + + +#include "moc_qcameralockscontrol.cpp" +QT_END_NAMESPACE diff --git a/src/multimediakit/qcameralockscontrol.h b/src/multimediakit/qcameralockscontrol.h new file mode 100644 index 000000000..02da2ef97 --- /dev/null +++ b/src/multimediakit/qcameralockscontrol.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERALOCKSCONTROL_H +#define QCAMERALOCKSCONTROL_H + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QCameraLocksControl : public QMediaControl +{ + Q_OBJECT +public: + ~QCameraLocksControl(); + + virtual QCamera::LockTypes supportedLocks() const = 0; + + virtual QCamera::LockStatus lockStatus(QCamera::LockType lock) const = 0; + + virtual void searchAndLock(QCamera::LockTypes locks) = 0; + virtual void unlock(QCamera::LockTypes locks) = 0; + +Q_SIGNALS: + void lockStatusChanged(QCamera::LockType type, QCamera::LockStatus status, QCamera::LockChangeReason reason); + +protected: + QCameraLocksControl(QObject* parent = 0); +}; + +#define QCameraLocksControl_iid "com.nokia.Qt.QCameraLocksControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QCameraLocksControl, QCameraLocksControl_iid) + +QT_END_NAMESPACE + +#endif // QCAMERALOCKSCONTROL_H + diff --git a/src/multimediakit/qcameraviewfinder.cpp b/src/multimediakit/qcameraviewfinder.cpp new file mode 100644 index 000000000..dc779c60d --- /dev/null +++ b/src/multimediakit/qcameraviewfinder.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include + +#include +#include +#include +#include + +QT_USE_NAMESPACE + +/*! + \class QCameraViewfinder + + + \brief The QCameraViewfinder class provides a camera viewfinder widget. + + \inmodule QtMultimediaKit + \ingroup camera + \since 1.1 + + \snippet doc/src/snippets/multimedia-snippets/camera.cpp Camera + +*/ + +class QCameraViewfinderPrivate : public QVideoWidgetPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QCameraViewfinder) +public: + QCameraViewfinderPrivate(): + QVideoWidgetPrivate() + { + } +}; + +/*! + Constructs a new camera viewfinder widget. + + The \a parent is passed to QVideoWidget. +*/ + +QCameraViewfinder::QCameraViewfinder(QWidget *parent) + :QVideoWidget(*new QCameraViewfinderPrivate, parent) +{ +} + +/*! + Destroys a camera viewfinder widget. +*/ +QCameraViewfinder::~QCameraViewfinder() +{ +} + +/*! + \reimp + \since 1.1 +*/ +QMediaObject *QCameraViewfinder::mediaObject() const +{ + return QVideoWidget::mediaObject(); +} + +/*! + \reimp + \since 1.1 +*/ +bool QCameraViewfinder::setMediaObject(QMediaObject *object) +{ + Q_D(QCameraViewfinder); + + return QVideoWidget::setMediaObject(object); +} + +#include "moc_qcameraviewfinder.cpp" diff --git a/src/multimediakit/qcameraviewfinder.h b/src/multimediakit/qcameraviewfinder.h new file mode 100644 index 000000000..6602b0b03 --- /dev/null +++ b/src/multimediakit/qcameraviewfinder.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAVIEWFINDER_H +#define QCAMERAVIEWFINDER_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QCamera; + +class QCameraViewfinderPrivate; +class Q_MULTIMEDIA_EXPORT QCameraViewfinder : public QVideoWidget +{ + Q_OBJECT +public: + QCameraViewfinder(QWidget *parent = 0); + ~QCameraViewfinder(); + + QMediaObject *mediaObject() const; + +protected: + bool setMediaObject(QMediaObject *object); + +private: + Q_DISABLE_COPY(QCameraViewfinder) + Q_DECLARE_PRIVATE(QCameraViewfinder) +}; + +QT_END_NAMESPACE + +#endif // QCAMERA_H diff --git a/src/multimediakit/qeglimagetexturesurface.cpp b/src/multimediakit/qeglimagetexturesurface.cpp new file mode 100644 index 000000000..d4b10dcce --- /dev/null +++ b/src/multimediakit/qeglimagetexturesurface.cpp @@ -0,0 +1,554 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include +#include + + +QT_BEGIN_NAMESPACE + +//#define DEBUG_OMAPFB_SURFACE + +const QAbstractVideoBuffer::HandleType EGLImageTextureHandle = +QAbstractVideoBuffer::HandleType(QAbstractVideoBuffer::UserHandle+3434); + +/*! + \class QOmapFbVideoSurface + \internal + \since 1.2 +*/ + +/*! +*/ +QEglImageTextureSurface::QEglImageTextureSurface(QObject *parent) + : QAbstractVideoSurface(parent) + , m_context(0) + , m_program(0) + , m_pixelFormat(QVideoFrame::Format_Invalid) + , m_ready(false) + , m_colorKey(49,0,49) + , m_fallbackSurface(0) + , m_fallbackSurfaceActive(false) +{ + m_fallbackSurface = new QPainterVideoSurface(this); +} + +/*! +*/ +QEglImageTextureSurface::~QEglImageTextureSurface() +{ + if (isActive()) + stop(); +} + +/*! + \since 1.2 +*/ +QList QEglImageTextureSurface::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ +#ifdef DEBUG_OMAPFB_SURFACE + qDebug() << Q_FUNC_INFO << handleType; +#endif + + if (handleType == EGLImageTextureHandle) { + return QList() + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_ARGB32; + } + + return m_fallbackSurface->supportedPixelFormats(handleType); +} + +const char *qt_glsl_eglTextureVertexShaderProgram = + "attribute highp vec4 vertexCoordArray;\n" + "attribute mediump vec2 textureCoordArray;\n" + "uniform highp mat4 positionMatrix;\n" + "varying mediump vec2 textureCoord;\n" + "void main (void)\n" + "{\n" + " gl_Position = positionMatrix * vertexCoordArray;\n" + " textureCoord = textureCoordArray;\n" + "}"; + +static const char* qt_glsl_eglTextureShaderProgram = + "#extension GL_OES_EGL_image_external: enable\n" + "\n" + "uniform samplerExternalOES texRgb;\n" + "varying mediump vec2 textureCoord;\n" + "\n" + "void main (void)\n" + "{\n" + " gl_FragColor = texture2D(texRgb, textureCoord);\n" + "}"; + + +/*! + \since 1.2 +*/ +bool QEglImageTextureSurface::start(const QVideoSurfaceFormat &format) +{ +#ifdef DEBUG_OMAPFB_SURFACE + qDebug() << Q_FUNC_INFO << format; +#endif + + m_fallbackSurfaceActive = false; + if (format.handleType() != EGLImageTextureHandle) { + qWarning() << Q_FUNC_INFO << "Non EGLImageTextureHandle based format requested, fallback to QPainterVideoSurface"; + connect(m_fallbackSurface, SIGNAL(activeChanged(bool)), + this, SIGNAL(activeChanged(bool))); + connect(m_fallbackSurface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + this, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat))); + connect(m_fallbackSurface, SIGNAL(supportedFormatsChanged()), + this, SIGNAL(supportedFormatsChanged())); + connect(m_fallbackSurface, SIGNAL(nativeResolutionChanged(QSize)), + this, SIGNAL(nativeResolutionChanged(QSize))); + connect(m_fallbackSurface, SIGNAL(frameChanged()), + this, SIGNAL(frameChanged())); + + if (m_fallbackSurface->start(format)) { + m_fallbackSurfaceActive = true; + QAbstractVideoSurface::start(format); + } else { + qWarning() << Q_FUNC_INFO << "failed to start video surface:" << m_fallbackSurface->error(); + setError(m_fallbackSurface->error()); + + disconnect(m_fallbackSurface, SIGNAL(activeChanged(bool)), + this, SIGNAL(activeChanged(bool))); + disconnect(m_fallbackSurface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + this, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat))); + disconnect(m_fallbackSurface, SIGNAL(supportedFormatsChanged()), + this, SIGNAL(supportedFormatsChanged())); + disconnect(m_fallbackSurface, SIGNAL(nativeResolutionChanged(QSize)), + this, SIGNAL(nativeResolutionChanged(QSize))); + disconnect(m_fallbackSurface, SIGNAL(frameChanged()), + this, SIGNAL(frameChanged())); + } + + return m_fallbackSurfaceActive; + } + + QAbstractVideoSurface::Error error = NoError; + + if (isActive()) + stop(); + + if (format.frameSize().isEmpty()) { + setError(UnsupportedFormatError); + } else if (m_context) { + m_context->makeCurrent(); + m_program = new QGLShaderProgram(m_context, this); + + if (!m_program->addShaderFromSourceCode(QGLShader::Vertex, qt_glsl_eglTextureVertexShaderProgram)) { + qWarning("QOmapFbVideoSurface: Vertex shader compile error %s", + qPrintable(m_program->log())); + error = ResourceError; + } + + if (error == NoError + && !m_program->addShaderFromSourceCode(QGLShader::Fragment, qt_glsl_eglTextureShaderProgram)) { + qWarning("QOmapFbVideoSurface: Vertex shader compile error %s", + qPrintable(m_program->log())); + error = QAbstractVideoSurface::ResourceError; + } + + if (error == NoError) { + m_program->bindAttributeLocation("textureCoordArray", 1); + if(!m_program->link()) { + qWarning("QOmapFbVideoSurface: Shader link error %s", qPrintable(m_program->log())); + m_program->removeAllShaders(); + error = QAbstractVideoSurface::ResourceError; + } + } + + if (error != QAbstractVideoSurface::NoError) { + delete m_program; + m_program = 0; + } + } + + if (error == QAbstractVideoSurface::NoError) { + m_scanLineDirection = format.scanLineDirection(); + m_frameSize = format.frameSize(); + m_pixelFormat = format.pixelFormat(); + m_frameSize = format.frameSize(); + m_sourceRect = format.viewport(); + m_ready = true; + + return QAbstractVideoSurface::start(format); + } + + QAbstractVideoSurface::stop(); + return false; +} + +/*! + \since 1.2 +*/ +void QEglImageTextureSurface::stop() +{ +#ifdef DEBUG_OMAPFB_SURFACE + qDebug() << Q_FUNC_INFO; +#endif + + if (m_fallbackSurfaceActive) { + m_fallbackSurface->stop(); + m_fallbackSurfaceActive = false; + + disconnect(m_fallbackSurface, SIGNAL(activeChanged(bool)), + this, SIGNAL(activeChanged(bool))); + disconnect(m_fallbackSurface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + this, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat))); + disconnect(m_fallbackSurface, SIGNAL(supportedFormatsChanged()), + this, SIGNAL(supportedFormatsChanged())); + disconnect(m_fallbackSurface, SIGNAL(nativeResolutionChanged(QSize)), + this, SIGNAL(nativeResolutionChanged(QSize))); + disconnect(m_fallbackSurface, SIGNAL(frameChanged()), + this, SIGNAL(frameChanged())); + + m_ready = false; + QAbstractVideoSurface::stop(); + } + + if (isActive()) { + if (m_context) + m_context->makeCurrent(); + m_frame = QVideoFrame(); + + m_program->removeAllShaders(); + delete m_program; + m_program = 0; + m_ready = false; + + QAbstractVideoSurface::stop(); + } +} + +/*! + \since 1.2 +*/ +bool QEglImageTextureSurface::present(const QVideoFrame &frame) +{ + if (m_fallbackSurfaceActive) { + if (m_fallbackSurface->present(frame)) { + return true; + } else { + setError(m_fallbackSurface->error()); + stop(); + return false; + } + } + + if (!m_ready) { + if (!isActive()) + setError(StoppedError); + else + m_frame = frame; + } else if (frame.isValid() + && (frame.pixelFormat() != m_pixelFormat || frame.size() != m_frameSize)) { + setError(IncorrectFormatError); + qWarning() << "Received frame of incorrect format, stopping the surface"; + + stop(); + } else { + if (m_context) + m_context->makeCurrent(); + m_frame = frame; + m_ready = false; + emit frameChanged(); + return true; + } + return false; +} + +/*! + \since 1.2 +*/ +int QEglImageTextureSurface::brightness() const +{ + return m_fallbackSurface->brightness(); +} + +/*! + \since 1.2 +*/ +void QEglImageTextureSurface::setBrightness(int brightness) +{ + m_fallbackSurface->setBrightness(brightness); +} + +/*! + \since 1.2 +*/ +int QEglImageTextureSurface::contrast() const +{ + return m_fallbackSurface->contrast(); +} + +/*! + \since 1.2 +*/ +void QEglImageTextureSurface::setContrast(int contrast) +{ + m_fallbackSurface->setContrast(contrast); +} + +/*! + \since 1.2 +*/ +int QEglImageTextureSurface::hue() const +{ + return m_fallbackSurface->hue(); +} + +/*! + \since 1.2 +*/ +void QEglImageTextureSurface::setHue(int hue) +{ + m_fallbackSurface->setHue(hue); +} + +/*! + \since 1.2 +*/ +int QEglImageTextureSurface::saturation() const +{ + return m_fallbackSurface->saturation(); +} + +/*! + \since 1.2 +*/ +void QEglImageTextureSurface::setSaturation(int saturation) +{ + m_fallbackSurface->setSaturation(saturation); +} + +/*! + \since 1.2 +*/ +bool QEglImageTextureSurface::isReady() const +{ + return m_fallbackSurfaceActive ? m_fallbackSurface->isReady() : m_ready; +} + +/*! + \since 1.2 +*/ +void QEglImageTextureSurface::setReady(bool ready) +{ + m_ready = ready; + if (m_fallbackSurfaceActive) + m_fallbackSurface->setReady(ready); +} + +/*! + \since 1.2 +*/ +void QEglImageTextureSurface::paint(QPainter *painter, const QRectF &target, const QRectF &sourceRect) +{ + if (m_fallbackSurfaceActive) { + m_fallbackSurface->paint(painter, target, sourceRect); + return; + } + + if (!isActive() || !m_frame.isValid()) { + painter->fillRect(target, QBrush(Qt::black)); + } else { + const QRectF source( + m_sourceRect.x() + m_sourceRect.width() * sourceRect.x(), + m_sourceRect.y() + m_sourceRect.height() * sourceRect.y(), + m_sourceRect.width() * sourceRect.width(), + m_sourceRect.height() * sourceRect.height()); + + bool stencilTestEnabled = glIsEnabled(GL_STENCIL_TEST); + bool scissorTestEnabled = glIsEnabled(GL_SCISSOR_TEST); + + painter->beginNativePainting(); + + if (stencilTestEnabled) + glEnable(GL_STENCIL_TEST); + if (scissorTestEnabled) + glEnable(GL_SCISSOR_TEST); + + const int width = QGLContext::currentContext()->device()->width(); + const int height = QGLContext::currentContext()->device()->height(); + + const QTransform transform = painter->deviceTransform(); + + const GLfloat wfactor = 2.0 / width; + const GLfloat hfactor = -2.0 / height; + + const GLfloat positionMatrix[4][4] = + { + { + /*(0,0)*/ GLfloat(wfactor * transform.m11() - transform.m13()), + /*(0,1)*/ GLfloat(hfactor * transform.m12() + transform.m13()), + /*(0,2)*/ 0.0, + /*(0,3)*/ GLfloat(transform.m13()) + }, { + /*(1,0)*/ GLfloat(wfactor * transform.m21() - transform.m23()), + /*(1,1)*/ GLfloat(hfactor * transform.m22() + transform.m23()), + /*(1,2)*/ 0.0, + /*(1,3)*/ GLfloat(transform.m23()) + }, { + /*(2,0)*/ 0.0, + /*(2,1)*/ 0.0, + /*(2,2)*/ -1.0, + /*(2,3)*/ 0.0 + }, { + /*(3,0)*/ GLfloat(wfactor * transform.dx() - transform.m33()), + /*(3,1)*/ GLfloat(hfactor * transform.dy() + transform.m33()), + /*(3,2)*/ 0.0, + /*(3,3)*/ GLfloat(transform.m33()) + } + }; + + const GLfloat vTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? target.top() + : target.bottom() + 1; + const GLfloat vBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? target.bottom() + 1 + : target.top(); + + + const GLfloat vertexCoordArray[] = + { + GLfloat(target.left()) , GLfloat(vBottom), + GLfloat(target.right() + 1), GLfloat(vBottom), + GLfloat(target.left()) , GLfloat(vTop), + GLfloat(target.right() + 1), GLfloat(vTop) + }; + + const GLfloat txLeft = source.left() / m_frameSize.width(); + const GLfloat txRight = source.right() / m_frameSize.width(); + const GLfloat txTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.top() / m_frameSize.height() + : source.bottom() / m_frameSize.height(); + const GLfloat txBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.bottom() / m_frameSize.height() + : source.top() / m_frameSize.height(); + + const GLfloat textureCoordArray[] = + { + txLeft , txBottom, + txRight, txBottom, + txLeft , txTop, + txRight, txTop + }; + + m_program->bind(); + + m_program->enableAttributeArray("vertexCoordArray"); + m_program->enableAttributeArray("textureCoordArray"); + m_program->setAttributeArray("vertexCoordArray", vertexCoordArray, 2); + m_program->setAttributeArray("textureCoordArray", textureCoordArray, 2); + m_program->setUniformValue("positionMatrix", positionMatrix); + m_program->setUniformValue("texRgb", 0); + + //map() binds the external texture + m_frame.map(QAbstractVideoBuffer::ReadOnly); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + //it's necessary to unbind the external texture + m_frame.unmap(); + + m_program->release(); + + painter->endNativePainting(); + } +} + +/*! + \fn QOmapFbVideoSurface::frameChanged() + \since 1.2 +*/ + +/*! + \since 1.2 +*/ +const QGLContext *QEglImageTextureSurface::glContext() const +{ + return m_context; +} + +/*! + \since 1.2 +*/ +void QEglImageTextureSurface::setGLContext(QGLContext *context) +{ + if (m_context == context) + return; + + stop(); + + m_context = context; + + m_fallbackSurface->setGLContext(context); + if (m_fallbackSurface->supportedShaderTypes() & QPainterVideoSurface::GlslShader) { + m_fallbackSurface->setShaderType(QPainterVideoSurface::GlslShader); + } else { + m_fallbackSurface->setShaderType(QPainterVideoSurface::FragmentProgramShader); + } + + emit supportedFormatsChanged(); +} + +void QEglImageTextureSurface::viewportDestroyed() +{ + m_context = 0; + m_fallbackSurface->viewportDestroyed(); + + setError(ResourceError); + stop(); +} + +#include "moc_qeglimagetexturesurface_p.cpp" +QT_END_NAMESPACE diff --git a/src/multimediakit/qeglimagetexturesurface_p.h b/src/multimediakit/qeglimagetexturesurface_p.h new file mode 100644 index 000000000..f193692ce --- /dev/null +++ b/src/multimediakit/qeglimagetexturesurface_p.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEGLIMAGETEXTURESURFACE_P_H +#define QEGLIMAGETEXTURESURFACE_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 +#include +#include +#include +#include + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QGLContext; +class QGLShaderProgram; +class QPainterVideoSurface; + +class QEglImageTextureSurface : public QAbstractVideoSurface +{ + Q_OBJECT +public: + explicit QEglImageTextureSurface(QObject *parent = 0); + ~QEglImageTextureSurface(); + + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const; + + bool start(const QVideoSurfaceFormat &format); + void stop(); + + bool present(const QVideoFrame &frame); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + bool isReady() const; + void setReady(bool ready); + + void paint(QPainter *painter, const QRectF &target, const QRectF &source = QRectF(0, 0, 1, 1)); + + const QGLContext *glContext() const; + void setGLContext(QGLContext *context); + + bool isOverlayEnabled() const; + void setOverlayEnabled(bool enabled); + + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + +public Q_SLOTS: + void viewportDestroyed(); + +Q_SIGNALS: + void frameChanged(); + +private: + QGLContext *m_context; + QGLShaderProgram *m_program; + + QVideoFrame m_frame; + + QVideoFrame::PixelFormat m_pixelFormat; + QVideoSurfaceFormat::Direction m_scanLineDirection; + QSize m_frameSize; + QRect m_sourceRect; + bool m_ready; + + QRect m_viewport; + QRect m_displayRect; + QColor m_colorKey; + + QPainterVideoSurface *m_fallbackSurface; + bool m_fallbackSurfaceActive; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/qgraphicsvideoitem.cpp b/src/multimediakit/qgraphicsvideoitem.cpp new file mode 100644 index 000000000..00d0f1c59 --- /dev/null +++ b/src/multimediakit/qgraphicsvideoitem.cpp @@ -0,0 +1,432 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgraphicsvideoitem.h" + +#include +#include +#include +#include + +#include +#include + +#include + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) +#include +#endif + +Q_DECLARE_METATYPE(QVideoSurfaceFormat) + +QT_BEGIN_NAMESPACE + +class QGraphicsVideoItemPrivate +{ +public: + QGraphicsVideoItemPrivate() + : q_ptr(0) + , surface(0) + , mediaObject(0) + , service(0) + , rendererControl(0) + , aspectRatioMode(Qt::KeepAspectRatio) + , updatePaintDevice(true) + , rect(0.0, 0.0, 320, 240) + { + } + + QGraphicsVideoItem *q_ptr; + + QPainterVideoSurface *surface; + QPointer mediaObject; + QMediaService *service; + QVideoRendererControl *rendererControl; + Qt::AspectRatioMode aspectRatioMode; + bool updatePaintDevice; + QRectF rect; + QRectF boundingRect; + QRectF sourceRect; + QSizeF nativeSize; + + void clearService(); + void updateRects(); + + void _q_present(); + void _q_formatChanged(const QVideoSurfaceFormat &format); + void _q_updateNativeSize(); + void _q_serviceDestroyed(); +}; + +void QGraphicsVideoItemPrivate::clearService() +{ + if (rendererControl) { + surface->stop(); + rendererControl->setSurface(0); + service->releaseControl(rendererControl); + rendererControl = 0; + } + if (service) { + QObject::disconnect(service, SIGNAL(destroyed()), q_ptr, SLOT(_q_serviceDestroyed())); + service = 0; + } +} + +void QGraphicsVideoItemPrivate::updateRects() +{ + q_ptr->prepareGeometryChange(); + + if (nativeSize.isEmpty()) { + //this is necessary for item to receive the + //first paint event and configure video surface. + boundingRect = rect; + } else if (aspectRatioMode == Qt::IgnoreAspectRatio) { + boundingRect = rect; + sourceRect = QRectF(0, 0, 1, 1); + } else if (aspectRatioMode == Qt::KeepAspectRatio) { + QSizeF size = nativeSize; + size.scale(rect.size(), Qt::KeepAspectRatio); + + boundingRect = QRectF(0, 0, size.width(), size.height()); + boundingRect.moveCenter(rect.center()); + + sourceRect = QRectF(0, 0, 1, 1); + } else if (aspectRatioMode == Qt::KeepAspectRatioByExpanding) { + boundingRect = rect; + + QSizeF size = rect.size(); + size.scale(nativeSize, Qt::KeepAspectRatio); + + sourceRect = QRectF( + 0, 0, size.width() / nativeSize.width(), size.height() / nativeSize.height()); + sourceRect.moveCenter(QPointF(0.5, 0.5)); + } +} + +void QGraphicsVideoItemPrivate::_q_present() +{ + if (q_ptr->isObscured()) { + q_ptr->update(boundingRect); + surface->setReady(true); + } else { + q_ptr->update(boundingRect); + } +} + +void QGraphicsVideoItemPrivate::_q_updateNativeSize() +{ + const QSize &size = surface->surfaceFormat().sizeHint(); + if (nativeSize != size) { + nativeSize = size; + + updateRects(); + emit q_ptr->nativeSizeChanged(nativeSize); + } +} + +void QGraphicsVideoItemPrivate::_q_serviceDestroyed() +{ + rendererControl = 0; + service = 0; + + surface->stop(); +} + + +/*! + \class QGraphicsVideoItem + + \brief The QGraphicsVideoItem class provides a graphics item which display video produced by a QMediaObject. + + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + Attaching a QGraphicsVideoItem to a QMediaObject allows it to display + the video or image output of that media object. A QGraphicsVideoItem + is attached to a media object by passing a pointer to the QMediaObject + to the setMediaObject() function. + + \snippet doc/src/snippets/multimedia-snippets/video.cpp Video graphics item + + \bold {Note}: Only a single display output can be attached to a media + object at one time. + + \sa QMediaObject, QMediaPlayer, QVideoWidget +*/ + +/*! + Constructs a graphics item that displays video. + + The \a parent is passed to QGraphicsItem. +*/ +QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent) + : QGraphicsObject(parent) + , d_ptr(new QGraphicsVideoItemPrivate) +{ + d_ptr->q_ptr = this; + d_ptr->surface = new QPainterVideoSurface; + + qRegisterMetaType(); + + connect(d_ptr->surface, SIGNAL(frameChanged()), this, SLOT(_q_present())); + connect(d_ptr->surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + this, SLOT(_q_updateNativeSize()), Qt::QueuedConnection); +} + +/*! + Destroys a video graphics item. +*/ +QGraphicsVideoItem::~QGraphicsVideoItem() +{ + if (d_ptr->rendererControl) { + d_ptr->rendererControl->setSurface(0); + d_ptr->service->releaseControl(d_ptr->rendererControl); + } + + delete d_ptr->surface; + delete d_ptr; +} + +/*! + \property QGraphicsVideoItem::mediaObject + \brief the media object which provides the video displayed by a graphics + item. + \since 1.0 +*/ + +QMediaObject *QGraphicsVideoItem::mediaObject() const +{ + return d_func()->mediaObject; +} + +/*! + \internal + \since 1.0 +*/ +bool QGraphicsVideoItem::setMediaObject(QMediaObject *object) +{ + Q_D(QGraphicsVideoItem); + + if (object == d->mediaObject) + return true; + + d->clearService(); + + d->mediaObject = object; + + if (d->mediaObject) { + d->service = d->mediaObject->service(); + + if (d->service) { + QMediaControl *control = d->service->requestControl(QVideoRendererControl_iid); + if (control) { + d->rendererControl = qobject_cast(control); + + if (d->rendererControl) { + //don't set the surface untill the item is painted + //at least once and the surface is configured + if (!d->updatePaintDevice) + d->rendererControl->setSurface(d->surface); + else + update(boundingRect()); + + connect(d->service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed())); + + return true; + } + if (control) + d->service->releaseControl(control); + } + } + } + + d->mediaObject = 0; + return false; +} + +/*! + \property QGraphicsVideoItem::aspectRatioMode + \brief how a video is scaled to fit the graphics item's size. + \since 1.0 +*/ + +Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode() const +{ + return d_func()->aspectRatioMode; +} + +void QGraphicsVideoItem::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + Q_D(QGraphicsVideoItem); + + d->aspectRatioMode = mode; + d->updateRects(); +} + +/*! + \property QGraphicsVideoItem::offset + \brief the video item's offset. + + QGraphicsVideoItem will draw video using the offset for its top left + corner. + \since 1.0 +*/ + +QPointF QGraphicsVideoItem::offset() const +{ + return d_func()->rect.topLeft(); +} + +void QGraphicsVideoItem::setOffset(const QPointF &offset) +{ + Q_D(QGraphicsVideoItem); + + d->rect.moveTo(offset); + d->updateRects(); +} + +/*! + \property QGraphicsVideoItem::size + \brief the video item's size. + + QGraphicsVideoItem will draw video scaled to fit size according to its + fillMode. + \since 1.0 +*/ + +QSizeF QGraphicsVideoItem::size() const +{ + return d_func()->rect.size(); +} + +void QGraphicsVideoItem::setSize(const QSizeF &size) +{ + Q_D(QGraphicsVideoItem); + + d->rect.setSize(size.isValid() ? size : QSizeF(0, 0)); + d->updateRects(); +} + +/*! + \property QGraphicsVideoItem::nativeSize + \brief the native size of the video. + \since 1.0 +*/ + +QSizeF QGraphicsVideoItem::nativeSize() const +{ + return d_func()->nativeSize; +} + +/*! + \fn QGraphicsVideoItem::nativeSizeChanged(const QSizeF &size) + + Signals that the native \a size of the video has changed. + \since 1.0 +*/ + +/*! + \reimp + \since 1.0 +*/ +QRectF QGraphicsVideoItem::boundingRect() const +{ + return d_func()->boundingRect; +} + +/*! + \reimp + \since 1.0 +*/ +void QGraphicsVideoItem::paint( + QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_D(QGraphicsVideoItem); + + Q_UNUSED(option); + Q_UNUSED(widget); + + if (d->surface && d->updatePaintDevice) { + d->updatePaintDevice = false; +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + if (widget) + connect(widget, SIGNAL(destroyed()), d->surface, SLOT(viewportDestroyed())); + + d->surface->setGLContext(const_cast(QGLContext::currentContext())); + if (d->surface->supportedShaderTypes() & QPainterVideoSurface::GlslShader) { + d->surface->setShaderType(QPainterVideoSurface::GlslShader); + } else { + d->surface->setShaderType(QPainterVideoSurface::FragmentProgramShader); + } +#endif + if (d->rendererControl && d->rendererControl->surface() != d->surface) + d->rendererControl->setSurface(d->surface); + } + + if (d->surface && d->surface->isActive()) { + d->surface->paint(painter, d->boundingRect, d->sourceRect); + d->surface->setReady(true); + } +} + +/*! + \reimp + + \internal + \since 1.0 +*/ +QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value) +{ + return QGraphicsItem::itemChange(change, value); +} + +/*! + \internal + \since 1.0 +*/ +void QGraphicsVideoItem::timerEvent(QTimerEvent *event) +{ + QGraphicsObject::timerEvent(event); +} + +#include "moc_qgraphicsvideoitem.cpp" +QT_END_NAMESPACE diff --git a/src/multimediakit/qgraphicsvideoitem.h b/src/multimediakit/qgraphicsvideoitem.h new file mode 100644 index 000000000..fd39ab90a --- /dev/null +++ b/src/multimediakit/qgraphicsvideoitem.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGRAPHICSVIDEOITEM_H +#define QGRAPHICSVIDEOITEM_H + +#include + +#include +#include + +QT_BEGIN_NAMESPACE +class QVideoSurfaceFormat; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class QGraphicsVideoItemPrivate; +class Q_MULTIMEDIA_EXPORT QGraphicsVideoItem : public QGraphicsObject, public QMediaBindableInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaBindableInterface) + Q_PROPERTY(QMediaObject* mediaObject READ mediaObject WRITE setMediaObject) + Q_PROPERTY(Qt::AspectRatioMode aspectRatioMode READ aspectRatioMode WRITE setAspectRatioMode) + Q_PROPERTY(QPointF offset READ offset WRITE setOffset) + Q_PROPERTY(QSizeF size READ size WRITE setSize) + Q_PROPERTY(QSizeF nativeSize READ nativeSize NOTIFY nativeSizeChanged) +public: + QGraphicsVideoItem(QGraphicsItem *parent = 0); + ~QGraphicsVideoItem(); + + QMediaObject *mediaObject() const; + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + + QPointF offset() const; + void setOffset(const QPointF &offset); + + QSizeF size() const; + void setSize(const QSizeF &size); + + QSizeF nativeSize() const; + + QRectF boundingRect() const; + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + +Q_SIGNALS: + void nativeSizeChanged(const QSizeF &size); + +protected: + void timerEvent(QTimerEvent *event); + QVariant itemChange(GraphicsItemChange change, const QVariant &value); + + bool setMediaObject(QMediaObject *object); + + QGraphicsVideoItemPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QGraphicsVideoItem) + Q_PRIVATE_SLOT(d_func(), void _q_present()) + Q_PRIVATE_SLOT(d_func(), void _q_updateNativeSize()) + Q_PRIVATE_SLOT(d_func(), void _q_serviceDestroyed()) +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/qgraphicsvideoitem_maemo5.cpp b/src/multimediakit/qgraphicsvideoitem_maemo5.cpp new file mode 100644 index 000000000..8551b313d --- /dev/null +++ b/src/multimediakit/qgraphicsvideoitem_maemo5.cpp @@ -0,0 +1,647 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qgraphicsvideoitem.h" + +#include +#include +#include +#include + +#include + +#include "qxvideosurface_maemo5_p.h" + + +QT_BEGIN_NAMESPACE + +//#define DEBUG_GFX_VIDEO_ITEM + +//update overlay geometry slightly later, +//to ensure color key is alredy replaced with static frame +#define GEOMETRY_UPDATE_DELAY 20 +//this is necessary to prevent flickering, see maemo bug 8798 +//on geometry changes, the color key is replaced with static image frame +//until the overlay is re-initialized +#define SOFTWARE_RENDERING_DURATION 150 + +#ifdef __ARM_NEON__ + +/* +* ARM NEON optimized implementation of UYVY -> RGB16 convertor +*/ +static void uyvy422_to_rgb16_line_neon (uint8_t * dst, const uint8_t * src, int n) +{ + /* and this is the NEON code itself */ + static __attribute__ ((aligned (16))) uint16_t acc_r[8] = { + 22840, 22840, 22840, 22840, 22840, 22840, 22840, 22840, + }; + static __attribute__ ((aligned (16))) uint16_t acc_g[8] = { + 17312, 17312, 17312, 17312, 17312, 17312, 17312, 17312, + }; + static __attribute__ ((aligned (16))) uint16_t acc_b[8] = { + 28832, 28832, 28832, 28832, 28832, 28832, 28832, 28832, + }; + /* + * Registers: + * q0, q1 : d0, d1, d2, d3 - are used for initial loading of YUV data + * q2 : d4, d5 - are used for storing converted RGB data + * q3 : d6, d7 - are used for temporary storage + * + * q6 : d12, d13 - are used for converting to RGB16 + * q7 : d14, d15 - are used for storing RGB16 data + * q4-q5 - reserved + * + * q8, q9 : d16, d17, d18, d19 - are used for expanded Y data + * q10 : d20, d21 + * q11 : d22, d23 + * q12 : d24, d25 + * q13 : d26, d27 + * q13, q14, q15 - various constants (#16, #149, #204, #50, #104, #154) + */ + asm volatile (".macro convert_macroblock size\n" + /* load up to 16 source pixels in UYVY format */ + ".if \\size == 16\n" + "pld [%[src], #128]\n" + "vld1.32 {d0, d1, d2, d3}, [%[src]]!\n" + ".elseif \\size == 8\n" + "vld1.32 {d0, d1}, [%[src]]!\n" + ".elseif \\size == 4\n" + "vld1.32 {d0}, [%[src]]!\n" + ".elseif \\size == 2\n" + "vld1.32 {d0[0]}, [%[src]]!\n" + ".else\n" ".error \"unsupported macroblock size\"\n" ".endif\n" + /* convert from 'packed' to 'planar' representation */ + "vuzp.8 d0, d1\n" /* d1 - separated Y data (first 8 bytes) */ + "vuzp.8 d2, d3\n" /* d3 - separated Y data (next 8 bytes) */ + "vuzp.8 d0, d2\n" /* d0 - separated U data, d2 - separated V data */ + /* split even and odd Y color components */ + "vuzp.8 d1, d3\n" /* d1 - evenY, d3 - oddY */ + /* clip upper and lower boundaries */ + "vqadd.u8 q0, q0, q4\n" + "vqadd.u8 q1, q1, q4\n" + "vqsub.u8 q0, q0, q5\n" + "vqsub.u8 q1, q1, q5\n" + "vshr.u8 d4, d2, #1\n" /* d4 = V >> 1 */ + "vmull.u8 q8, d1, d27\n" /* q8 = evenY * 149 */ + "vmull.u8 q9, d3, d27\n" /* q9 = oddY * 149 */ + "vld1.16 {d20, d21}, [%[acc_r], :128]\n" /* q10 - initialize accumulator for red */ + "vsubw.u8 q10, q10, d4\n" /* red acc -= (V >> 1) */ + "vmlsl.u8 q10, d2, d28\n" /* red acc -= V * 204 */ + "vld1.16 {d22, d23}, [%[acc_g], :128]\n" /* q11 - initialize accumulator for green */ + "vmlsl.u8 q11, d2, d30\n" /* green acc -= V * 104 */ + "vmlsl.u8 q11, d0, d29\n" /* green acc -= U * 50 */ + "vld1.16 {d24, d25}, [%[acc_b], :128]\n" /* q12 - initialize accumulator for blue */ + "vmlsl.u8 q12, d0, d30\n" /* blue acc -= U * 104 */ + "vmlsl.u8 q12, d0, d31\n" /* blue acc -= U * 154 */ + "vhsub.s16 q3, q8, q10\n" /* calculate even red components */ + "vhsub.s16 q10, q9, q10\n" /* calculate odd red components */ + "vqshrun.s16 d0, q3, #6\n" /* right shift, narrow and saturate even red components */ + "vqshrun.s16 d3, q10, #6\n" /* right shift, narrow and saturate odd red components */ + "vhadd.s16 q3, q8, q11\n" /* calculate even green components */ + "vhadd.s16 q11, q9, q11\n" /* calculate odd green components */ + "vqshrun.s16 d1, q3, #6\n" /* right shift, narrow and saturate even green components */ + "vqshrun.s16 d4, q11, #6\n" /* right shift, narrow and saturate odd green components */ + "vhsub.s16 q3, q8, q12\n" /* calculate even blue components */ + "vhsub.s16 q12, q9, q12\n" /* calculate odd blue components */ + "vqshrun.s16 d2, q3, #6\n" /* right shift, narrow and saturate even blue components */ + "vqshrun.s16 d5, q12, #6\n" /* right shift, narrow and saturate odd blue components */ + "vzip.8 d0, d3\n" /* join even and odd red components */ + "vzip.8 d1, d4\n" /* join even and odd green components */ + "vzip.8 d2, d5\n" /* join even and odd blue components */ + "vshll.u8 q7, d0, #8\n" //red + "vshll.u8 q6, d1, #8\n" //greed + "vsri.u16 q7, q6, #5\n" + "vshll.u8 q6, d2, #8\n" //blue + "vsri.u16 q7, q6, #11\n" //now there is rgb16 in q7 + ".if \\size == 16\n" + "vst1.16 {d14, d15}, [%[dst]]!\n" + //"vst3.8 {d0, d1, d2}, [%[dst]]!\n" + "vshll.u8 q7, d3, #8\n" //red + "vshll.u8 q6, d4, #8\n" //greed + "vsri.u16 q7, q6, #5\n" + "vshll.u8 q6, d5, #8\n" //blue + "vsri.u16 q7, q6, #11\n" //now there is rgb16 in q7 + //"vst3.8 {d3, d4, d5}, [%[dst]]!\n" + "vst1.16 {d14, d15}, [%[dst]]!\n" + ".elseif \\size == 8\n" + "vst1.16 {d14, d15}, [%[dst]]!\n" + //"vst3.8 {d0, d1, d2}, [%[dst]]!\n" + ".elseif \\size == 4\n" + "vst1.8 {d14}, [%[dst]]!\n" + ".elseif \\size == 2\n" + "vst1.8 {d14[0]}, [%[dst]]!\n" + "vst1.8 {d14[1]}, [%[dst]]!\n" + ".else\n" + ".error \"unsupported macroblock size\"\n" + ".endif\n" + ".endm\n" + "vmov.u8 d8, #15\n" /* add this to U/V to saturate upper boundary */ + "vmov.u8 d9, #20\n" /* add this to Y to saturate upper boundary */ + "vmov.u8 d10, #31\n" /* sub this from U/V to saturate lower boundary */ + "vmov.u8 d11, #36\n" /* sub this from Y to saturate lower boundary */ + "vmov.u8 d26, #16\n" + "vmov.u8 d27, #149\n" + "vmov.u8 d28, #204\n" + "vmov.u8 d29, #50\n" + "vmov.u8 d30, #104\n" + "vmov.u8 d31, #154\n" + "subs %[n], %[n], #16\n" + "blt 2f\n" + "1:\n" + "convert_macroblock 16\n" + "subs %[n], %[n], #16\n" + "bge 1b\n" + "2:\n" + "tst %[n], #8\n" + "beq 3f\n" + "convert_macroblock 8\n" + "3:\n" + "tst %[n], #4\n" + "beq 4f\n" + "convert_macroblock 4\n" + "4:\n" + "tst %[n], #2\n" + "beq 5f\n" + "convert_macroblock 2\n" + "5:\n" + ".purgem convert_macroblock\n":[src] "+&r" (src),[dst] "+&r" (dst), + [n] "+&r" (n) + :[acc_r] "r" (&acc_r[0]),[acc_g] "r" (&acc_g[0]),[acc_b] "r" (&acc_b[0]) + :"cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", + "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", + "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"); +} + +#endif + +class QGraphicsVideoItemPrivate +{ +public: + QGraphicsVideoItemPrivate() + : q_ptr(0) + , surface(0) + , mediaObject(0) + , service(0) + , rendererControl(0) + , savedViewportUpdateMode(QGraphicsView::FullViewportUpdate) + , aspectRatioMode(Qt::KeepAspectRatio) + , rect(0.0, 0.0, 320, 240) + , softwareRenderingEnabled(false) + { + } + + QGraphicsVideoItem *q_ptr; + + QXVideoSurface *surface; + QMediaObject *mediaObject; + QMediaService *service; + QVideoRendererControl *rendererControl; + QPointer currentView; + QGraphicsView::ViewportUpdateMode savedViewportUpdateMode; + + Qt::AspectRatioMode aspectRatioMode; + QRectF rect; + QRectF boundingRect; + QRectF sourceRect; + QSizeF nativeSize; + + QPixmap lastFrame; + QBasicTimer softwareRenderingTimer; + QBasicTimer geometryUpdateTimer; + bool softwareRenderingEnabled; + QRect overlayRect; + + void clearService(); + void updateRects(); + void updateLastFrame(); + + void _q_present(); + void _q_updateNativeSize(); + void _q_serviceDestroyed(); + void _q_mediaObjectDestroyed(); +}; + +void QGraphicsVideoItemPrivate::clearService() +{ + if (rendererControl) { + surface->stop(); + rendererControl->setSurface(0); + service->releaseControl(rendererControl); + rendererControl = 0; + } + + if (service) { + QObject::disconnect(service, SIGNAL(destroyed()), q_ptr, SLOT(_q_serviceDestroyed())); + service = 0; + } +} + +void QGraphicsVideoItemPrivate::updateRects() +{ + q_ptr->prepareGeometryChange(); + + if (nativeSize.isEmpty()) { + boundingRect = QRectF(); + } else if (aspectRatioMode == Qt::IgnoreAspectRatio) { + boundingRect = rect; + sourceRect = QRectF(0, 0, 1, 1); + } else if (aspectRatioMode == Qt::KeepAspectRatio) { + QSizeF size = nativeSize; + size.scale(rect.size(), Qt::KeepAspectRatio); + + boundingRect = QRectF(0, 0, size.width(), size.height()); + boundingRect.moveCenter(rect.center()); + + sourceRect = QRectF(0, 0, 1, 1); + } else if (aspectRatioMode == Qt::KeepAspectRatioByExpanding) { + boundingRect = rect; + + QSizeF size = rect.size(); + size.scale(nativeSize, Qt::KeepAspectRatio); + + sourceRect = QRectF( + 0, 0, size.width() / nativeSize.width(), size.height() / nativeSize.height()); + sourceRect.moveCenter(QPointF(0.5, 0.5)); + } +} + +void QGraphicsVideoItemPrivate::updateLastFrame() +{ + lastFrame = QPixmap(); + + if (!softwareRenderingEnabled) + return; + + QVideoFrame lastVideoFrame = surface->lastFrame(); + + if (!lastVideoFrame.isValid()) + return; + + if (lastVideoFrame.map(QAbstractVideoBuffer::ReadOnly)) { + +#ifdef __ARM_NEON__ + if (lastVideoFrame.pixelFormat() == QVideoFrame::Format_UYVY) { + QImage lastImage(lastVideoFrame.size(), QImage::Format_RGB16); + + const uchar *src = lastVideoFrame.bits(); + uchar *dst = lastImage.bits(); + const int srcLineStep = lastVideoFrame.bytesPerLine(); + const int dstLineStep = lastImage.bytesPerLine(); + const int h = lastVideoFrame.height(); + const int w = lastVideoFrame.width(); + + for (int y=0; yupdate(boundingRect); +} + +void QGraphicsVideoItemPrivate::_q_updateNativeSize() +{ + const QSize &size = surface->surfaceFormat().sizeHint(); + if (nativeSize != size) { + lastFrame = QPixmap(); + nativeSize = size; + + updateRects(); + emit q_ptr->nativeSizeChanged(nativeSize); + } +} + +void QGraphicsVideoItemPrivate::_q_serviceDestroyed() +{ + rendererControl = 0; + service = 0; + + surface->stop(); +} + +void QGraphicsVideoItemPrivate::_q_mediaObjectDestroyed() +{ + mediaObject = 0; + + clearService(); +} + +QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent) + : QGraphicsObject(parent) + , d_ptr(new QGraphicsVideoItemPrivate) +{ + d_ptr->q_ptr = this; + d_ptr->surface = new QXVideoSurface; + + setCacheMode(NoCache); + setFlag(QGraphicsItem::ItemIgnoresParentOpacity); + setFlag(QGraphicsItem::ItemSendsGeometryChanges); + setFlag(QGraphicsItem::ItemSendsScenePositionChanges); + + connect(d_ptr->surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + this, SLOT(_q_updateNativeSize())); + + connect(d_ptr->surface, SIGNAL(activeChanged(bool)), this, SLOT(_q_present())); +} + +QGraphicsVideoItem::~QGraphicsVideoItem() +{ + if (d_ptr->rendererControl) { + d_ptr->rendererControl->setSurface(0); + d_ptr->service->releaseControl(d_ptr->rendererControl); + } + + if (d_ptr->currentView) + d_ptr->currentView->setViewportUpdateMode(d_ptr->savedViewportUpdateMode); + + delete d_ptr->surface; + delete d_ptr; +} + +QMediaObject *QGraphicsVideoItem::mediaObject() const +{ + return d_func()->mediaObject; +} + +bool QGraphicsVideoItem::setMediaObject(QMediaObject *object) +{ + Q_D(QGraphicsVideoItem); + + if (object == d->mediaObject) + return true; + + d->clearService(); + + d->mediaObject = object; + + if (d->mediaObject) { + d->service = d->mediaObject->service(); + + if (d->service) { + d->rendererControl = qobject_cast( + d->service->requestControl(QVideoRendererControl_iid)); + + if (d->rendererControl != 0) { + connect(d->service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed())); + d->rendererControl->setSurface(d->surface); + return true; + } + + } + } + + return false; +} + +Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode() const +{ + return d_func()->aspectRatioMode; +} + +void QGraphicsVideoItem::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + Q_D(QGraphicsVideoItem); + + d->aspectRatioMode = mode; + d->updateRects(); +} + +QPointF QGraphicsVideoItem::offset() const +{ + return d_func()->rect.topLeft(); +} + +void QGraphicsVideoItem::setOffset(const QPointF &offset) +{ + Q_D(QGraphicsVideoItem); + + d->rect.moveTo(offset); + d->updateRects(); +} + +QSizeF QGraphicsVideoItem::size() const +{ + return d_func()->rect.size(); +} + +void QGraphicsVideoItem::setSize(const QSizeF &size) +{ + Q_D(QGraphicsVideoItem); + + d->rect.setSize(size.isValid() ? size : QSizeF(0, 0)); + d->updateRects(); +} + +QSizeF QGraphicsVideoItem::nativeSize() const +{ + return d_func()->nativeSize; +} + +QRectF QGraphicsVideoItem::boundingRect() const +{ + return d_func()->boundingRect; +} + +void QGraphicsVideoItem::paint( + QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ +#ifdef DEBUG_GFX_VIDEO_ITEM + qDebug() << "QGraphicsVideoItem::paint"; +#endif + + Q_UNUSED(option); + Q_D(QGraphicsVideoItem); + + QGraphicsView *view = 0; + if (scene() && !scene()->views().isEmpty()) + view = scene()->views().first(); + + //it's necessary to switch vieport update mode to FullViewportUpdate + //otherwise the video item area can be just scrolled without notifying overlay + //about geometry changes + if (view != d->currentView) { + if (d->currentView) { + d->currentView->setViewportUpdateMode(d->savedViewportUpdateMode); + } + + d->currentView = view; + if (view) { + d->savedViewportUpdateMode = view->viewportUpdateMode(); + view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); + } + } + + QColor colorKey = Qt::black; + bool geometryChanged = false; + + if (d->surface) { + if (widget) + d->surface->setWinId(widget->winId()); + + QTransform transform = painter->combinedTransform(); + QRect overlayRect = transform.mapRect(boundingRect()).toRect(); + QRect currentSurfaceRect = d->surface->displayRect(); + + if (widget) { + //workaround for xvideo issue with U/V planes swapped + QPoint topLeft = widget->mapToGlobal(overlayRect.topLeft()); + if ((topLeft.x() & 1) == 0 && topLeft.x() != 0) + overlayRect.moveLeft(overlayRect.left()-1); + } + + d->overlayRect = overlayRect; + + if (currentSurfaceRect != overlayRect) { + if (!d->surface->displayRect().isEmpty()) { + if (d->softwareRenderingEnabled) { + //recalculate scaled frame pixmap if area is resized + if (currentSurfaceRect.size() != overlayRect.size()) { + d->updateLastFrame(); + d->surface->setDisplayRect( overlayRect ); + } + } else { + d->softwareRenderingEnabled = true; + d->updateLastFrame(); + + //don't set new geometry right now, + //but with small delay, to ensure the frame is already + //rendered on top of color key + if (!d->geometryUpdateTimer.isActive()) + d->geometryUpdateTimer.start(GEOMETRY_UPDATE_DELAY, this); + } + } else + d->surface->setDisplayRect( overlayRect ); + + geometryChanged = true; + d->softwareRenderingTimer.start(SOFTWARE_RENDERING_DURATION, this); + +#ifdef DEBUG_GFX_VIDEO_ITEM + qDebug() << "set video display rect:" << overlayRect; +#endif + + } + + colorKey = d->surface->colorKey(); + } + + + if (!d->softwareRenderingEnabled) { + painter->fillRect(d->boundingRect, colorKey); + } else { + if (!d->lastFrame.isNull()) { + painter->drawPixmap(d->boundingRect.topLeft(), d->lastFrame ); + + } else + painter->fillRect(d->boundingRect, Qt::black); + } +} + +QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value) +{ + Q_D(QGraphicsVideoItem); + + if (change == ItemScenePositionHasChanged) { + update(boundingRect()); + } else { + return QGraphicsItem::itemChange(change, value); + } + + return value; +} + +void QGraphicsVideoItem::timerEvent(QTimerEvent *event) +{ + Q_D(QGraphicsVideoItem); + + if (event->timerId() == d->softwareRenderingTimer.timerId() && d->softwareRenderingEnabled) { + d->softwareRenderingTimer.stop(); + d->softwareRenderingEnabled = false; + d->updateLastFrame(); + // repaint last frame, to ensure geometry change is applyed in paused state + d->surface->repaintLastFrame(); + d->_q_present(); + } else if ((event->timerId() == d->geometryUpdateTimer.timerId())) { + d->geometryUpdateTimer.stop(); + //slightly delayed geometry update, + //to avoid flicker at the first geometry change + d->surface->setDisplayRect( d->overlayRect ); + } + + QGraphicsObject::timerEvent(event); +} + +#include "moc_qgraphicsvideoitem.cpp" +QT_END_NAMESPACE diff --git a/src/multimediakit/qgraphicsvideoitem_maemo6.cpp b/src/multimediakit/qgraphicsvideoitem_maemo6.cpp new file mode 100644 index 000000000..de71daf1b --- /dev/null +++ b/src/multimediakit/qgraphicsvideoitem_maemo6.cpp @@ -0,0 +1,498 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgraphicsvideoitem.h" + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) +#include +#endif + +//#define ENABLE_OVERLAY + +namespace +{ +//XInitThreads is necessary for gltexturesink element. +//To ensure it's called before main() it's better to link to +//libQtMultimediaKit.so directly, not when QML multimedia plugin is loaded. +class InitThreads +{ +public: + InitThreads() + { + XInitThreads(); + } +} _initThreads; +} + +Q_DECLARE_METATYPE(QVideoSurfaceFormat) + +QT_BEGIN_NAMESPACE + +class QGraphicsVideoItemPrivate +{ +public: + QGraphicsVideoItemPrivate() + : q_ptr(0) + , surface(0) + , mediaObject(0) + , service(0) + , rendererControl(0) + , aspectRatioMode(Qt::KeepAspectRatio) + , updatePaintDevice(true) + , rect(0.0, 0.0, 320, 240) + { + } + + QGraphicsVideoItem *q_ptr; + + QEglImageTextureSurface *surface; + QPointer mediaObject; + QMediaService *service; + QVideoRendererControl *rendererControl; + Qt::AspectRatioMode aspectRatioMode; + bool updatePaintDevice; + QRectF rect; + QRectF boundingRect; + QRectF sourceRect; + QSizeF nativeSize; + + void clearService(); + void updateRects(); + + void _q_present(); + void _q_formatChanged(const QVideoSurfaceFormat &format); + void _q_updateNativeSize(); + void _q_serviceDestroyed(); +}; + +void QGraphicsVideoItemPrivate::clearService() +{ + if (rendererControl) { + surface->stop(); + rendererControl->setSurface(0); + service->releaseControl(rendererControl); + rendererControl = 0; + } + if (service) { + QObject::disconnect(service, SIGNAL(destroyed()), q_ptr, SLOT(_q_serviceDestroyed())); + service = 0; + } +} + +void QGraphicsVideoItemPrivate::updateRects() +{ + q_ptr->prepareGeometryChange(); + + if (nativeSize.isEmpty()) { + //this is necessary for item to receive the + //first paint event and configure video surface. + boundingRect = rect; + } else if (aspectRatioMode == Qt::IgnoreAspectRatio) { + boundingRect = rect; + sourceRect = QRectF(0, 0, 1, 1); + } else if (aspectRatioMode == Qt::KeepAspectRatio) { + QSizeF size = nativeSize; + size.scale(rect.size(), Qt::KeepAspectRatio); + + boundingRect = QRectF(0, 0, size.width(), size.height()); + boundingRect.moveCenter(rect.center()); + + sourceRect = QRectF(0, 0, 1, 1); + } else if (aspectRatioMode == Qt::KeepAspectRatioByExpanding) { + boundingRect = rect; + + QSizeF size = rect.size(); + size.scale(nativeSize, Qt::KeepAspectRatio); + + sourceRect = QRectF( + 0, 0, size.width() / nativeSize.width(), size.height() / nativeSize.height()); + sourceRect.moveCenter(QPointF(0.5, 0.5)); + } +} + +void QGraphicsVideoItemPrivate::_q_present() +{ + if (q_ptr->isObscured()) { + q_ptr->update(boundingRect); + surface->setReady(true); + } else { + q_ptr->update(boundingRect); + } +} + +void QGraphicsVideoItemPrivate::_q_updateNativeSize() +{ + QSize size = surface->surfaceFormat().sizeHint(); + if (size.isEmpty()) + size = rendererControl->property("nativeSize").toSize(); + + if (nativeSize != size) { + nativeSize = size; + + updateRects(); + emit q_ptr->nativeSizeChanged(nativeSize); + } +} + +void QGraphicsVideoItemPrivate::_q_serviceDestroyed() +{ + rendererControl = 0; + service = 0; + + surface->stop(); +} + + +/*! + \class QGraphicsVideoItem + + \brief The QGraphicsVideoItem class provides a graphics item which display video produced by a QMediaObject. + + \inmodule QtMultimediaKit + \ingroup multimedia + + Attaching a QGraphicsVideoItem to a QMediaObject allows it to display + the video or image output of that media object. A QGraphicsVideoItem + is attached to a media object by passing a pointer to the QMediaObject + to the setMediaObject() function. + + \code + player = new QMediaPlayer(this); + + QGraphicsVideoItem *item = new QGraphicsVideoItem; + player->setVideoOutput(item); + graphicsView->scene()->addItem(item); + graphicsView->show(); + + player->setMedia(video); + player->play(); + \endcode + + \bold {Note}: Only a single display output can be attached to a media + object at one time. + + \sa QMediaObject, QMediaPlayer, QVideoWidget +*/ + +/*! + Constructs a graphics item that displays video. + + The \a parent is passed to QGraphicsItem. +*/ +QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent) + : QGraphicsObject(parent) + , d_ptr(new QGraphicsVideoItemPrivate) +{ + d_ptr->q_ptr = this; + d_ptr->surface = new QEglImageTextureSurface(this); + + qRegisterMetaType(); + + connect(d_ptr->surface, SIGNAL(frameChanged()), this, SLOT(_q_present())); + connect(d_ptr->surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + this, SLOT(_q_updateNativeSize()), Qt::QueuedConnection); +} + +/*! + Destroys a video graphics item. +*/ +QGraphicsVideoItem::~QGraphicsVideoItem() +{ + if (d_ptr->rendererControl) { + d_ptr->rendererControl->setSurface(0); + d_ptr->service->releaseControl(d_ptr->rendererControl); + } + + delete d_ptr->surface; + delete d_ptr; +} + +/*! + \property QGraphicsVideoItem::mediaObject + \brief the media object which provides the video displayed by a graphics + item. +*/ + +QMediaObject *QGraphicsVideoItem::mediaObject() const +{ + return d_func()->mediaObject; +} + +/*! + \internal +*/ +bool QGraphicsVideoItem::setMediaObject(QMediaObject *object) +{ + Q_D(QGraphicsVideoItem); + + if (object == d->mediaObject) + return true; + + d->clearService(); + + d->mediaObject = object; + + if (d->mediaObject) { + d->service = d->mediaObject->service(); + + if (d->service) { + QMediaControl *control = d->service->requestControl(QVideoRendererControl_iid); + if (control) { + d->rendererControl = qobject_cast(control); + + if (d->rendererControl) { + connect(d->rendererControl, SIGNAL(nativeSizeChanged()), + this, SLOT(_q_updateNativeSize()), Qt::QueuedConnection); + d->_q_updateNativeSize(); + //don't set the surface untill the item is painted + //at least once and the surface is configured + if (!d->updatePaintDevice) + d->rendererControl->setSurface(d->surface); + else + update(boundingRect()); + + connect(d->service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed())); + + return true; + } + if (control) + d->service->releaseControl(control); + } + } + } + + d->mediaObject = 0; + return false; +} + +/*! + \property QGraphicsVideoItem::aspectRatioMode + \brief how a video is scaled to fit the graphics item's size. +*/ + +Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode() const +{ + return d_func()->aspectRatioMode; +} + +void QGraphicsVideoItem::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + Q_D(QGraphicsVideoItem); + + d->aspectRatioMode = mode; + d->updateRects(); +} + +/*! + \property QGraphicsVideoItem::offset + \brief the video item's offset. + + QGraphicsVideoItem will draw video using the offset for its top left + corner. +*/ + +QPointF QGraphicsVideoItem::offset() const +{ + return d_func()->rect.topLeft(); +} + +void QGraphicsVideoItem::setOffset(const QPointF &offset) +{ + Q_D(QGraphicsVideoItem); + + d->rect.moveTo(offset); + d->updateRects(); +} + +/*! + \property QGraphicsVideoItem::size + \brief the video item's size. + + QGraphicsVideoItem will draw video scaled to fit size according to its + fillMode. +*/ + +QSizeF QGraphicsVideoItem::size() const +{ + return d_func()->rect.size(); +} + +void QGraphicsVideoItem::setSize(const QSizeF &size) +{ + Q_D(QGraphicsVideoItem); + + d->rect.setSize(size.isValid() ? size : QSizeF(0, 0)); + d->updateRects(); +} + +/*! + \property QGraphicsVideoItem::nativeSize + \brief the native size of the video. +*/ + +QSizeF QGraphicsVideoItem::nativeSize() const +{ + return d_func()->nativeSize; +} + +/*! + \fn QGraphicsVideoItem::nativeSizeChanged(const QSizeF &size) + + Signals that the native \a size of the video has changed. +*/ + +/*! + \reimp +*/ +QRectF QGraphicsVideoItem::boundingRect() const +{ + return d_func()->boundingRect; +} + +/*! + \reimp +*/ +void QGraphicsVideoItem::paint( + QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_D(QGraphicsVideoItem); + + Q_UNUSED(option); + Q_UNUSED(widget); + + if (d->surface && d->rendererControl && d->updatePaintDevice) { + d->updatePaintDevice = false; + + if (widget) + d->rendererControl->setProperty("winId", qulonglong(widget->winId())); + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + if (widget) + connect(widget, SIGNAL(destroyed()), d->surface, SLOT(viewportDestroyed())); + + d->surface->setGLContext(const_cast(QGLContext::currentContext())); +#endif + if (d->rendererControl->surface() != d->surface) + d->rendererControl->setSurface(d->surface); + } + + + //overlay doesn't work reliably + + //check if the item is obscured: +#ifdef ENABLE_OVERLAY + if (!isObscured()) { + bool obscured = false; + + if (scene()) { + foreach (QGraphicsItem *item, + scene()->items(mapToScene(boundingRect()), Qt::IntersectsItemBoundingRect) ) { + if (item->flags() & QGraphicsItem::ItemHasNoContents) + continue; + + if (item == this) + break; + + if (collidesWithItem(item)) { + obscured = true; + break; + } + } + } + + d->rendererControl->setProperty("overlayEnabled", !obscured); + } + + if (d->rendererControl->property("overlayEnabled").toBool()) { + QTransform transform = painter->combinedTransform(); + QRect overlayRect = transform.mapRect(d->boundingRect).toRect(); + + d->rendererControl->setProperty("overlayGeometry", overlayRect); + QMetaObject::invokeMethod(d->rendererControl, "repaintOverlay"); + + painter->fillRect(d->boundingRect, + d->rendererControl->property("colorKey").value()); + } else +#endif //ENABLE_OVERLAY + { + if (d->surface && d->surface->isActive()) { + d->surface->paint(painter, d->boundingRect, d->sourceRect); + d->surface->setReady(true); + } + } +} + +/*! + \reimp + + \internal +*/ +QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value) +{ + return QGraphicsItem::itemChange(change, value); +} + +/*! + \internal +*/ +void QGraphicsVideoItem::timerEvent(QTimerEvent *event) +{ + QGraphicsObject::timerEvent(event); +} + +#include "moc_qgraphicsvideoitem.cpp" +QT_END_NAMESPACE diff --git a/src/multimediakit/qgraphicsvideoitem_overlay.cpp b/src/multimediakit/qgraphicsvideoitem_overlay.cpp new file mode 100644 index 000000000..f09d25ebb --- /dev/null +++ b/src/multimediakit/qgraphicsvideoitem_overlay.cpp @@ -0,0 +1,436 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qgraphicsvideoitem.h" + +#ifdef Q_OS_SYMBIAN +#define QGRAPHICSVIDEOITEM_ROTATION_SUPPORT +#endif + +#include +#include +#include + + +QT_BEGIN_NAMESPACE + +#define DEBUG_GFX_VIDEO_ITEM + +class QGraphicsVideoItemPrivate : public QObject +{ +public: + QGraphicsVideoItemPrivate() + : q_ptr(0) + , mediaObject(0) + , service(0) + , windowControl(0) + , savedViewportUpdateMode(QGraphicsView::FullViewportUpdate) + , aspectRatioMode(Qt::KeepAspectRatio) + , rect(0.0, 0.0, 320, 240) + , videoWidget(0) + { + } + + QGraphicsVideoItem *q_ptr; + + QMediaObject *mediaObject; + QMediaService *service; + QVideoWindowControl *windowControl; + QPointer currentView; + QList > eventFilterTargets; + QGraphicsView::ViewportUpdateMode savedViewportUpdateMode; + + Qt::AspectRatioMode aspectRatioMode; + QRectF rect; + QRectF boundingRect; + QRectF displayRect; + QSizeF nativeSize; + + QWidget *videoWidget; + + bool eventFilter(QObject *object, QEvent *event); + void updateEventFilters(); + + void setWidget(QWidget *widget); + void clearService(); + void updateRects(); + void updateLastFrame(); + + void _q_present(); + void _q_updateNativeSize(); + void _q_serviceDestroyed(); + void _q_mediaObjectDestroyed(); +}; + +void QGraphicsVideoItemPrivate::_q_present() +{ + +} + +bool QGraphicsVideoItemPrivate::eventFilter(QObject *object, QEvent *event) +{ + if (windowControl && object == videoWidget && QEvent::WinIdChange == event->type()) { + windowControl->setWinId(videoWidget->effectiveWinId()); + } else { + bool updateEventFiltersRequired = false; + bool refreshDisplayRequired = false; + foreach (QPointer target, eventFilterTargets) { + if (object == target.data()) { + switch (event->type()) { + case QEvent::ParentChange: + updateEventFiltersRequired = true; + refreshDisplayRequired = true; + break; + case QEvent::Move: + case QEvent::Resize: + refreshDisplayRequired = true; + break; + } + } + } + if (updateEventFiltersRequired) + updateEventFilters(); +#ifdef Q_OS_SYMBIAN + if (refreshDisplayRequired && windowControl) + QMetaObject::invokeMethod(windowControl, "refreshDisplay"); +#endif + } + return false; +} + +void QGraphicsVideoItemPrivate::setWidget(QWidget *widget) +{ + if (videoWidget != widget) { + videoWidget = widget; + if (widget) { + windowControl->setWinId(widget->winId()); + widget->installEventFilter(this); + } + } +} + +void QGraphicsVideoItemPrivate::clearService() +{ + if (windowControl) { + QObject::disconnect(windowControl, SIGNAL(nativeSizeChanged()), q_ptr, SLOT(_q_updateNativeSize())); + service->releaseControl(windowControl); + windowControl = 0; + } + + if (service) { + QObject::disconnect(service, SIGNAL(destroyed()), q_ptr, SLOT(_q_serviceDestroyed())); + service = 0; + } +} + +void QGraphicsVideoItemPrivate::updateRects() +{ + q_ptr->prepareGeometryChange(); + QSizeF videoSize; + if (nativeSize.isEmpty()) { + videoSize = rect.size(); + } else if (aspectRatioMode == Qt::IgnoreAspectRatio) { + videoSize = rect.size(); + } else { + // KeepAspectRatio or KeepAspectRatioByExpanding + videoSize = nativeSize; + videoSize.scale(rect.size(), aspectRatioMode); + } + displayRect = QRectF(QPointF(0, 0), videoSize); + displayRect.moveCenter(rect.center()); + boundingRect = displayRect.intersected(rect); +} + +void QGraphicsVideoItemPrivate::updateLastFrame() +{ +} + +void QGraphicsVideoItemPrivate::updateEventFilters() +{ + // In order to determine when the absolute screen position of the item + // changes, we need to receive move events sent to m_currentView + // or any of its ancestors. + foreach (QPointer target, eventFilterTargets) + if (target) + target->removeEventFilter(this); + eventFilterTargets.clear(); + QObject *target = currentView; + while (target) { + target->installEventFilter(this); + eventFilterTargets.append(target); + target = target->parent(); + } +} + +void QGraphicsVideoItemPrivate::_q_updateNativeSize() +{ + const QSize size = windowControl->nativeSize(); + if (nativeSize != size) { + nativeSize = size; + + updateRects(); + emit q_ptr->nativeSizeChanged(nativeSize); + } +} + +void QGraphicsVideoItemPrivate::_q_serviceDestroyed() +{ + windowControl = 0; + service = 0; +} + +void QGraphicsVideoItemPrivate::_q_mediaObjectDestroyed() +{ + mediaObject = 0; + + clearService(); +} + +QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent) + : QGraphicsObject(parent) + , d_ptr(new QGraphicsVideoItemPrivate) +{ + d_ptr->q_ptr = this; + + setCacheMode(NoCache); + setFlag(QGraphicsItem::ItemIgnoresParentOpacity); + setFlag(QGraphicsItem::ItemSendsGeometryChanges); + setFlag(QGraphicsItem::ItemSendsScenePositionChanges); +} + +QGraphicsVideoItem::~QGraphicsVideoItem() +{ + if (d_ptr->windowControl) { + d_ptr->service->releaseControl(d_ptr->windowControl); + } + + if (d_ptr->currentView) + d_ptr->currentView->setViewportUpdateMode(d_ptr->savedViewportUpdateMode); + + delete d_ptr; +} + +QMediaObject *QGraphicsVideoItem::mediaObject() const +{ + return d_func()->mediaObject; +} + +bool QGraphicsVideoItem::setMediaObject(QMediaObject *object) +{ + Q_D(QGraphicsVideoItem); + + if (object == d->mediaObject) + return true; + + d->clearService(); + + d->mediaObject = object; + + if (d->mediaObject) { + d->service = d->mediaObject->service(); + + if (d->service) { + d->windowControl = qobject_cast( + d->service->requestControl(QVideoWindowControl_iid)); + + if (d->windowControl != 0) { + connect(d->service, SIGNAL(destroyed()), SLOT(_q_serviceDestroyed())); + connect(d->windowControl, SIGNAL(nativeSizeChanged()), SLOT(_q_updateNativeSize())); + d->windowControl->setAspectRatioMode(Qt::IgnoreAspectRatio); + //d->windowControl->setProperty("colorKey", QVariant(QColor(16,7,2))); + d->windowControl->setProperty("autopaintColorKey", QVariant(false)); + + d->updateRects(); + return true; + } else { + qWarning() << "Service doesn't support QVideoWindowControl, overlay item failed"; + } + } + } + + d->mediaObject = 0; + return false; +} + +Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode() const +{ + return d_func()->aspectRatioMode; +} + +void QGraphicsVideoItem::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + Q_D(QGraphicsVideoItem); + + d->aspectRatioMode = mode; + d->updateRects(); +} + +QPointF QGraphicsVideoItem::offset() const +{ + return d_func()->rect.topLeft(); +} + +void QGraphicsVideoItem::setOffset(const QPointF &offset) +{ + Q_D(QGraphicsVideoItem); + + d->rect.moveTo(offset); + d->updateRects(); +} + +QSizeF QGraphicsVideoItem::size() const +{ + return d_func()->rect.size(); +} + +void QGraphicsVideoItem::setSize(const QSizeF &size) +{ + Q_D(QGraphicsVideoItem); + + d->rect.setSize(size.isValid() ? size : QSizeF(0, 0)); + d->updateRects(); +} + +QSizeF QGraphicsVideoItem::nativeSize() const +{ + return d_func()->nativeSize; +} + +QRectF QGraphicsVideoItem::boundingRect() const +{ + return d_func()->boundingRect; +} + +void QGraphicsVideoItem::paint( + QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ +#ifdef DEBUG_GFX_VIDEO_ITEM + qDebug() << "QGraphicsVideoItem::paint"; +#endif + + Q_UNUSED(option); + Q_D(QGraphicsVideoItem); + + QGraphicsView *view = 0; + if (scene() && !scene()->views().isEmpty()) + view = scene()->views().first(); + + //it's necessary to switch vieport update mode to FullViewportUpdate + //otherwise the video item area can be just scrolled without notifying overlay + //about geometry changes + if (view != d->currentView) { + if (d->currentView) { + d->currentView->setViewportUpdateMode(d->savedViewportUpdateMode); + } + + d->currentView = view; + if (view) { + d->savedViewportUpdateMode = view->viewportUpdateMode(); + view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); + } + d->updateEventFilters(); + } + + QColor colorKey = Qt::black; + + if (d->windowControl != 0 && widget != 0) { + d->setWidget(widget); + + QTransform transform = painter->combinedTransform(); + QRect overlayRect = transform.mapRect(d->displayRect).toRect(); + QRect currentSurfaceRect = d->windowControl->displayRect(); + + if (currentSurfaceRect != overlayRect) { +#ifdef DEBUG_GFX_VIDEO_ITEM + qDebug() << "set video display rect:" << overlayRect; +#endif + d->windowControl->setDisplayRect(overlayRect); + } + + colorKey = d->windowControl->property("colorKey").value(); +#ifdef QGRAPHICSVIDEOITEM_ROTATION_SUPPORT + const qreal angle = transform.map(QLineF(0, 0, 1, 0)).angle(); + d->windowControl->setProperty("rotation", QVariant::fromValue(angle)); +#endif + } + + if (colorKey.alpha() != 255) + painter->setCompositionMode(QPainter::CompositionMode_Source); + painter->fillRect(d->boundingRect, colorKey); +} + +QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value) +{ + Q_D(QGraphicsVideoItem); + + switch (change) { + case ItemScenePositionHasChanged: + update(boundingRect()); + break; + case ItemVisibleChange: + //move overlay out of the screen if video item becomes invisible + if (d->windowControl != 0 && !value.toBool()) + d->windowControl->setDisplayRect(QRect(-1,-1,1,1)); + break; + default: + break; + } + + return QGraphicsItem::itemChange(change, value); +} + +void QGraphicsVideoItem::timerEvent(QTimerEvent *event) +{ + QGraphicsObject::timerEvent(event); +} + +#include "moc_qgraphicsvideoitem.cpp" +QT_END_NAMESPACE diff --git a/src/multimediakit/qgraphicsvideoitem_symbian.cpp b/src/multimediakit/qgraphicsvideoitem_symbian.cpp new file mode 100644 index 000000000..48b2f5daa --- /dev/null +++ b/src/multimediakit/qgraphicsvideoitem_symbian.cpp @@ -0,0 +1,604 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include + +#include +#include +#include +#include +#include +#include + +#include "qgraphicsvideoitem.h" + +#include +#include +#include + +Q_DECLARE_METATYPE(WId) + +static const QEvent::Type UpdateViewportTransparencyEvent = + static_cast(QEvent::registerEventType()); + +QT_BEGIN_NAMESPACE + +class QGraphicsVideoItemPrivate : public QObject +{ + Q_OBJECT + +public: + QGraphicsVideoItemPrivate(QGraphicsVideoItem *parent); + ~QGraphicsVideoItemPrivate(); + QMediaObject *mediaObject() const; + bool setMediaObject(QMediaObject *mediaObject); + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + QPointF offset() const; + void setOffset(const QPointF &offset); + QSizeF size() const; + void setSize(const QSizeF &size); + QRectF rect() const; + QRectF boundingRect() const; + QSize nativeSize() const; + void setCurrentView(QGraphicsView *view); + void setVisible(bool visible); + void setZValue(int zValue); + void setTransform(const QTransform &transform); + void setWithinViewBounds(bool within); + + bool eventFilter(QObject *watched, QEvent *event); + void customEvent(QEvent *event); + + void _q_present(); + void _q_updateNativeSize(); + void _q_serviceDestroyed(); + void _q_mediaObjectDestroyed(); + +public slots: + void updateWidgetOrdinalPosition(); + void updateItemAncestors(); + +private: + void clearService(); + QWidget *videoWidget() const; + void updateGeometry(); + void updateViewportAncestorEventFilters(); + void updateWidgetVisibility(); + void updateTopWinId(); + +private: + QGraphicsVideoItem *q_ptr; + QMediaService *m_service; + QMediaObject *m_mediaObject; + QVideoWidgetControl *m_widgetControl; + QPointer m_currentView; + QList > m_viewportAncestors; + QList > m_itemAncestors; + QGraphicsView::ViewportUpdateMode m_savedViewportUpdateMode; + Qt::AspectRatioMode m_aspectRatioMode; + QRectF m_rect; + QRectF m_boundingRect; + QSize m_nativeSize; + QPointF m_offset; + QTransform m_transform; + bool m_visible; + bool m_withinViewBounds; +}; + + +QGraphicsVideoItemPrivate::QGraphicsVideoItemPrivate(QGraphicsVideoItem *parent) +: q_ptr(parent) +, m_service(0) +, m_mediaObject(0) +, m_widgetControl(0) +, m_savedViewportUpdateMode(QGraphicsView::FullViewportUpdate) +, m_aspectRatioMode(Qt::KeepAspectRatio) +, m_rect(0.0, 0.0, 320.0, 240.0) +, m_visible(false) +, m_withinViewBounds(false) +{ + qRegisterMetaType("WId"); + updateItemAncestors(); +} + +QGraphicsVideoItemPrivate::~QGraphicsVideoItemPrivate() +{ + if (m_widgetControl) + m_service->releaseControl(m_widgetControl); + setCurrentView(0); +} + +QMediaObject *QGraphicsVideoItemPrivate::mediaObject() const +{ + return m_mediaObject; +} + +bool QGraphicsVideoItemPrivate::setMediaObject(QMediaObject *mediaObject) +{ + bool bound = false; + if (m_mediaObject != mediaObject) { + clearService(); + m_mediaObject = mediaObject; + if (m_mediaObject) { + m_service = m_mediaObject->service(); + if (m_service) { + connect(m_service, SIGNAL(destroyed()), q_ptr, SLOT(_q_serviceDestroyed())); + m_widgetControl = qobject_cast( + m_service->requestControl(QVideoWidgetControl_iid)); + if (m_widgetControl) { + connect(m_widgetControl, SIGNAL(nativeSizeChanged()), q_ptr, SLOT(_q_updateNativeSize())); + m_widgetControl->setAspectRatioMode(Qt::IgnoreAspectRatio); + updateGeometry(); + updateTopWinId(); + updateWidgetOrdinalPosition(); + updateWidgetVisibility(); + bound = true; + } + } + } + } + return bound; +} + +Qt::AspectRatioMode QGraphicsVideoItemPrivate::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void QGraphicsVideoItemPrivate::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + if (mode != m_aspectRatioMode) { + m_aspectRatioMode = mode; + updateGeometry(); + } +} + +QPointF QGraphicsVideoItemPrivate::offset() const +{ + return m_rect.topLeft(); +} + +void QGraphicsVideoItemPrivate::setOffset(const QPointF &offset) +{ + if (m_offset != offset) { + m_offset = offset; + updateGeometry(); + } +} + +QSizeF QGraphicsVideoItemPrivate::size() const +{ + return m_rect.size(); +} + +void QGraphicsVideoItemPrivate::setSize(const QSizeF &size) +{ + if (m_rect.size() != size) { + m_rect.setSize(size.isValid() ? size : QSizeF(0, 0)); + updateGeometry(); + } +} + +QRectF QGraphicsVideoItemPrivate::rect() const +{ + return m_rect; +} + +QRectF QGraphicsVideoItemPrivate::boundingRect() const +{ + return m_boundingRect; +} + +QSize QGraphicsVideoItemPrivate::nativeSize() const +{ + return m_nativeSize; +} + +void QGraphicsVideoItemPrivate::setCurrentView(QGraphicsView *view) +{ + if (m_currentView != view) { + if (m_currentView) + m_currentView->setViewportUpdateMode(m_savedViewportUpdateMode); + m_currentView = view; + updateTopWinId(); + if (m_currentView) { + m_savedViewportUpdateMode = m_currentView->viewportUpdateMode(); + m_currentView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); + updateWidgetOrdinalPosition(); + updateGeometry(); + } + updateViewportAncestorEventFilters(); + } +} + +void QGraphicsVideoItemPrivate::setVisible(bool visible) +{ + if (m_visible != visible) { + m_visible = visible; + updateWidgetVisibility(); + } +} + +void QGraphicsVideoItemPrivate::setTransform(const QTransform &transform) +{ + if (m_transform != transform) { + m_transform = transform; + updateGeometry(); + } +} + +void QGraphicsVideoItemPrivate::setWithinViewBounds(bool within) +{ + if (m_withinViewBounds != within) { + m_withinViewBounds = within; + updateWidgetVisibility(); + } +} + +bool QGraphicsVideoItemPrivate::eventFilter(QObject *watched, QEvent *event) +{ + bool updateViewportAncestorEventFiltersRequired = false; + bool updateGeometryRequired = false; + foreach (QPointer target, m_viewportAncestors) { + if (watched == target.data()) { + switch (event->type()) { + case QEvent::ParentChange: + updateViewportAncestorEventFiltersRequired = true; + break; + case QEvent::WinIdChange: + updateViewportAncestorEventFiltersRequired = true; + updateTopWinId(); + break; + case QEvent::Move: + case QEvent::Resize: + updateGeometryRequired = true; + break; + } + } + } + if (updateViewportAncestorEventFiltersRequired) + updateViewportAncestorEventFilters(); + if (updateGeometryRequired) + updateGeometry(); + if (watched == m_currentView) { + switch (event->type()) { + case QEvent::Show: + setVisible(true); + break; + case QEvent::Hide: + setVisible(false); + break; + } + } + return QObject::eventFilter(watched, event); +} + +void QGraphicsVideoItemPrivate::customEvent(QEvent *event) +{ + if (event->type() == UpdateViewportTransparencyEvent && m_currentView) { + m_currentView->window()->setAttribute(Qt::WA_TranslucentBackground); + m_currentView->window()->update(); + } + QObject::customEvent(event); +} + +void QGraphicsVideoItemPrivate::clearService() +{ + if (m_widgetControl) { + m_service->releaseControl(m_widgetControl); + m_widgetControl = 0; + } + if (m_service) { + m_service->disconnect(q_ptr); + m_service = 0; + } +} + +QWidget *QGraphicsVideoItemPrivate::videoWidget() const +{ + return m_widgetControl ? m_widgetControl->videoWidget() : 0; +} + +void QGraphicsVideoItemPrivate::updateViewportAncestorEventFilters() +{ + // In order to determine when the absolute screen position of the item + // changes, we need to receive move events sent to m_currentView + // or any of its ancestors. + foreach (QPointer target, m_viewportAncestors) + if (target) + target->removeEventFilter(this); + m_viewportAncestors.clear(); + QObject *target = m_currentView; + while (target) { + target->installEventFilter(this); + m_viewportAncestors.append(target); + target = target->parent(); + } +} + +void QGraphicsVideoItemPrivate::updateItemAncestors() +{ + // We need to monitor the ancestors of this item to check for zOrder + // changes and reparenting, both of which influence the stacking order + // of this item and so require changes to the backend window ordinal position. + foreach (QPointer target, m_itemAncestors) { + if (target) { + disconnect(target, SIGNAL(zChanged()), this, SLOT(updateWidgetOrdinalPosition())); + disconnect(target, SIGNAL(parentChanged()), this, SLOT(updateItemAncestors())); + disconnect(target, SIGNAL(parentChanged()), this, SLOT(updateWidgetOrdinalPosition())); + } + } + m_itemAncestors.clear(); + QGraphicsItem *item = q_ptr; + while (item) { + if (QGraphicsObject *object = item->toGraphicsObject()) { + connect(object, SIGNAL(zChanged()), this, SLOT(updateWidgetOrdinalPosition())); + connect(object, SIGNAL(parentChanged()), this, SLOT(updateItemAncestors())); + connect(object, SIGNAL(parentChanged()), this, SLOT(updateWidgetOrdinalPosition())); + m_itemAncestors.append(object); + } + item = item->parentItem(); + } +} + +void QGraphicsVideoItemPrivate::updateGeometry() +{ + q_ptr->prepareGeometryChange(); + QSizeF videoSize; + if (m_nativeSize.isEmpty()) { + videoSize = m_rect.size(); + } else if (m_aspectRatioMode == Qt::IgnoreAspectRatio) { + videoSize = m_rect.size(); + } else { + // KeepAspectRatio or KeepAspectRatioByExpanding + videoSize = m_nativeSize; + videoSize.scale(m_rect.size(), m_aspectRatioMode); + } + QRectF displayRect(QPointF(0, 0), videoSize); + displayRect.moveCenter(m_rect.center()); + m_boundingRect = displayRect.intersected(m_rect); + if (QWidget *widget = videoWidget()) { + QRect widgetGeometry; + QRect extent; + if (m_currentView) { + const QRectF viewRectF = m_transform.mapRect(displayRect); + const QRect viewRect(viewRectF.topLeft().toPoint(), viewRectF.size().toSize()); + // Without this, a line of transparent pixels is visible round the edge of the + // item. This is probably down to an error in conversion between scene and + // screen coordinates, but the root cause has not yet been tracked down. + static const QPoint positionFudgeFactor(-1, -1); + static const QSize sizeFudgeFactor(4, 4); + const QRect videoGeometry(m_currentView->mapToGlobal(viewRect.topLeft()) + positionFudgeFactor, + viewRect.size() + sizeFudgeFactor); + QRect viewportGeometry = QRect(m_currentView->viewport()->mapToGlobal(QPoint(0, 0)), + m_currentView->viewport()->size()); + widgetGeometry = videoGeometry.intersected(viewportGeometry); + extent = QRect(videoGeometry.topLeft() - widgetGeometry.topLeft(), + videoGeometry.size()); + } + setWithinViewBounds(!widgetGeometry.size().isEmpty()); + widget->setGeometry(widgetGeometry); + m_widgetControl->setProperty("extentRect", QVariant::fromValue(extent)); + const qreal angle = m_transform.map(QLineF(0, 0, 1, 0)).angle(); + m_widgetControl->setProperty("rotation", QVariant::fromValue(angle)); + } +} + +void QGraphicsVideoItemPrivate::updateWidgetVisibility() +{ + if (QWidget *widget = videoWidget()) + widget->setVisible(m_visible && m_withinViewBounds); +} + +void QGraphicsVideoItemPrivate::updateTopWinId() +{ + if (m_widgetControl) { + WId topWinId = m_currentView ? m_currentView->effectiveWinId() : 0; + // Set custom property + m_widgetControl->setProperty("topWinId", QVariant::fromValue(topWinId)); + } +} + +void QGraphicsVideoItemPrivate::updateWidgetOrdinalPosition() +{ + if (m_currentView) { + QGraphicsScene *scene = m_currentView->scene(); + const QGraphicsScene::ItemIndexMethod indexMethod = scene->itemIndexMethod(); + scene->setItemIndexMethod(QGraphicsScene::BspTreeIndex); + const QList items = m_currentView->items(); + QList graphicsVideoItems; + foreach (QGraphicsItem *item, items) + if (QGraphicsVideoItem *x = qobject_cast(item->toGraphicsObject())) + graphicsVideoItems.append(x); + int ordinalPosition = 1; + foreach (QGraphicsVideoItem *item, graphicsVideoItems) + if (QVideoWidgetControl *widgetControl = item->d_ptr->m_widgetControl) + widgetControl->setProperty("ordinalPosition", ordinalPosition++); + scene->setItemIndexMethod(indexMethod); + } +} + +void QGraphicsVideoItemPrivate::_q_present() +{ + // Not required for this implementation of QGraphicsVideoItem +} + +void QGraphicsVideoItemPrivate::_q_updateNativeSize() +{ + const QSize size = m_widgetControl ? m_widgetControl->property("nativeSize").value() : QSize(); + if (!size.isEmpty() && m_nativeSize != size) { + m_nativeSize = size; + updateGeometry(); + emit q_ptr->nativeSizeChanged(m_nativeSize); + } +} + +void QGraphicsVideoItemPrivate::_q_serviceDestroyed() +{ + m_widgetControl = 0; + m_service = 0; +} + +void QGraphicsVideoItemPrivate::_q_mediaObjectDestroyed() +{ + m_mediaObject = 0; + clearService(); +} + +QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent) +: QGraphicsObject(parent) +, d_ptr(new QGraphicsVideoItemPrivate(this)) +{ + setCacheMode(NoCache); + setFlag(QGraphicsItem::ItemIgnoresParentOpacity); + setFlag(QGraphicsItem::ItemSendsGeometryChanges); + setFlag(QGraphicsItem::ItemSendsScenePositionChanges); +} + +QGraphicsVideoItem::~QGraphicsVideoItem() +{ + delete d_ptr; +} + +QMediaObject *QGraphicsVideoItem::mediaObject() const +{ + return d_func()->mediaObject(); +} + +bool QGraphicsVideoItem::setMediaObject(QMediaObject *object) +{ + return d_func()->setMediaObject(object); +} + +Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode() const +{ + return d_func()->aspectRatioMode(); +} + +void QGraphicsVideoItem::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + d_func()->setAspectRatioMode(mode); +} + +QPointF QGraphicsVideoItem::offset() const +{ + return d_func()->offset(); +} + +void QGraphicsVideoItem::setOffset(const QPointF &offset) +{ + d_func()->setOffset(offset); +} + +QSizeF QGraphicsVideoItem::size() const +{ + return d_func()->size(); +} + +void QGraphicsVideoItem::setSize(const QSizeF &size) +{ + d_func()->setSize(size); +} + +QSizeF QGraphicsVideoItem::nativeSize() const +{ + return d_func()->nativeSize(); +} + +QRectF QGraphicsVideoItem::boundingRect() const +{ + return d_func()->boundingRect(); +} + +void QGraphicsVideoItem::paint( + QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_D(QGraphicsVideoItem); + QGraphicsView *view = 0; + if (scene() && !scene()->views().isEmpty()) + view = scene()->views().first(); + d->setCurrentView(view); + d->setTransform(painter->combinedTransform()); + if (widget && !widget->window()->testAttribute(Qt::WA_TranslucentBackground)) { + // On Symbian, setting Qt::WA_TranslucentBackground can cause the + // current window surface to be replaced. Because of this, it cannot + // safely be changed from the context of the viewport paintEvent(), so we + // queue a custom event to set the attribute. + QEvent *event = new QEvent(UpdateViewportTransparencyEvent); + QCoreApplication::instance()->postEvent(d, event); + } + const QPainter::CompositionMode oldCompositionMode = painter->compositionMode(); + painter->setCompositionMode(QPainter::CompositionMode_Source); + painter->fillRect(d->boundingRect(), Qt::transparent); + painter->setCompositionMode(oldCompositionMode); +} + +QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value) +{ + Q_D(QGraphicsVideoItem); + switch (change) { + case ItemScenePositionHasChanged: + update(boundingRect()); + break; + case ItemVisibleChange: + d->setVisible(value.toBool()); + break; + case ItemZValueHasChanged: + d->updateWidgetOrdinalPosition(); + break; + default: + break; + } + return QGraphicsItem::itemChange(change, value); +} + +void QGraphicsVideoItem::timerEvent(QTimerEvent *event) +{ + QGraphicsObject::timerEvent(event); +} + +#include "qgraphicsvideoitem_symbian.moc" +#include "moc_qgraphicsvideoitem.cpp" + +QT_END_NAMESPACE diff --git a/src/multimediakit/qimageencodercontrol.cpp b/src/multimediakit/qimageencodercontrol.cpp new file mode 100644 index 000000000..3c05bab88 --- /dev/null +++ b/src/multimediakit/qimageencodercontrol.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qimageencodercontrol.h" +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QImageEncoderControl + + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + \brief The QImageEncoderControl class provides access to the settings of a media service that + performs image encoding. + + If a QMediaService supports encoding image data it will implement QImageEncoderControl. + This control allows to \l {setImageSettings()}{set image encoding settings} and + provides functions for quering supported image \l {supportedImageCodecs()}{codecs} and + \l {supportedResolutions()}{resolutions}. + + The interface name of QImageEncoderControl is \c com.nokia.Qt.QImageEncoderControl/1.0 as + defined in QImageEncoderControl_iid. + + \sa QImageEncoderSettings, QMediaService::requestControl() +*/ + +/*! + \macro QImageEncoderControl_iid + + \c com.nokia.Qt.QImageEncoderControl/1.0 + + Defines the interface name of the QImageEncoderControl class. + + \relates QImageEncoderControl +*/ + +/*! + Constructs a new image encoder control object with the given \a parent +*/ +QImageEncoderControl::QImageEncoderControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys the image encoder control. +*/ +QImageEncoderControl::~QImageEncoderControl() +{ +} + +/*! + \fn QImageEncoderControl::supportedResolutions(const QImageEncoderSettings &settings = QImageEncoderSettings(), + bool *continuous = 0) const + + Returns a list of supported resolutions. + + If non null image \a settings parameter is passed, + the returned list is reduced to resolutions supported with partial settings applied. + It can be used to query the list of resolutions, supported by specific image codec. + + If the encoder supports arbitrary resolutions within the supported resolutions range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + \since 1.0 +*/ + +/*! + \fn QImageEncoderControl::supportedImageCodecs() const + + Returns a list of supported image codecs. + \since 1.0 +*/ + +/*! + \fn QImageEncoderControl::imageCodecDescription(const QString &codec) const + + Returns a description of an image \a codec. + \since 1.0 +*/ + +/*! + \fn QImageEncoderControl::imageSettings() const + + Returns the currently used image encoder settings. + + The returned value may be different tha passed to QImageEncoderControl::setImageSettings() + if the settings contains the default or undefined parameters. + In this case if the undefined parameters are already resolved, they should be returned. + \since 1.0 +*/ + +/*! + \fn QImageEncoderControl::setImageSettings(const QImageEncoderSettings &settings) + + Sets the selected image encoder \a settings. + \since 1.0 +*/ + +#include "moc_qimageencodercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qimageencodercontrol.h b/src/multimediakit/qimageencodercontrol.h new file mode 100644 index 000000000..71bf65729 --- /dev/null +++ b/src/multimediakit/qimageencodercontrol.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QIMAGEENCODERCONTROL_H +#define QIMAGEENCODERCONTROL_H + +#include "qmediacontrol.h" +#include "qmediarecorder.h" +#include "qmediaencodersettings.h" + +#include + +QT_BEGIN_NAMESPACE +class QByteArray; +class QStringList; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QImageEncoderControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QImageEncoderControl(); + + virtual QStringList supportedImageCodecs() const = 0; + virtual QString imageCodecDescription(const QString &codecName) const = 0; + + virtual QList supportedResolutions(const QImageEncoderSettings &settings, + bool *continuous = 0) const = 0; + + virtual QImageEncoderSettings imageSettings() const = 0; + virtual void setImageSettings(const QImageEncoderSettings &settings) = 0; + +protected: + QImageEncoderControl(QObject *parent = 0); +}; + +#define QImageEncoderControl_iid "com.nokia.Qt.QImageEncoderControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QImageEncoderControl, QImageEncoderControl_iid) + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/qlocalmediaplaylistprovider.cpp b/src/multimediakit/qlocalmediaplaylistprovider.cpp new file mode 100644 index 000000000..1bbb2ff64 --- /dev/null +++ b/src/multimediakit/qlocalmediaplaylistprovider.cpp @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlocalmediaplaylistprovider.h" +#include "qmediaplaylistprovider_p.h" +#include "qmediacontent.h" + +QT_BEGIN_NAMESPACE + +class QLocalMediaPlaylistProviderPrivate: public QMediaPlaylistProviderPrivate +{ +public: + QList resources; +}; + +QLocalMediaPlaylistProvider::QLocalMediaPlaylistProvider(QObject *parent) + :QMediaPlaylistProvider(*new QLocalMediaPlaylistProviderPrivate, parent) +{ +} + +QLocalMediaPlaylistProvider::~QLocalMediaPlaylistProvider() +{ +} + +bool QLocalMediaPlaylistProvider::isReadOnly() const +{ + return false; +} + +int QLocalMediaPlaylistProvider::mediaCount() const +{ + return d_func()->resources.size(); +} + +QMediaContent QLocalMediaPlaylistProvider::media(int pos) const +{ + return d_func()->resources.value(pos); +} + +bool QLocalMediaPlaylistProvider::addMedia(const QMediaContent &content) +{ + Q_D(QLocalMediaPlaylistProvider); + + int pos = d->resources.count(); + + emit mediaAboutToBeInserted(pos, pos); + d->resources.append(content); + emit mediaInserted(pos, pos); + + return true; +} + +bool QLocalMediaPlaylistProvider::addMedia(const QList &items) +{ + Q_D(QLocalMediaPlaylistProvider); + + if (items.isEmpty()) + return true; + + int pos = d->resources.count(); + int end = pos+items.count()-1; + + emit mediaAboutToBeInserted(pos, end); + d->resources.append(items); + emit mediaInserted(pos, end); + + return true; +} + + +bool QLocalMediaPlaylistProvider::insertMedia(int pos, const QMediaContent &content) +{ + Q_D(QLocalMediaPlaylistProvider); + + emit mediaAboutToBeInserted(pos, pos); + d->resources.insert(pos, content); + emit mediaInserted(pos,pos); + + return true; +} + +bool QLocalMediaPlaylistProvider::insertMedia(int pos, const QList &items) +{ + Q_D(QLocalMediaPlaylistProvider); + + if (items.isEmpty()) + return true; + + const int last = pos+items.count()-1; + + emit mediaAboutToBeInserted(pos, last); + for (int i=0; iresources.insert(pos+i, items.at(i)); + emit mediaInserted(pos, last); + + return true; +} + +bool QLocalMediaPlaylistProvider::removeMedia(int fromPos, int toPos) +{ + Q_D(QLocalMediaPlaylistProvider); + + Q_ASSERT(fromPos >= 0); + Q_ASSERT(fromPos <= toPos); + Q_ASSERT(toPos < mediaCount()); + + emit mediaAboutToBeRemoved(fromPos, toPos); + d->resources.erase(d->resources.begin()+fromPos, d->resources.begin()+toPos+1); + emit mediaRemoved(fromPos, toPos); + + return true; +} + +bool QLocalMediaPlaylistProvider::removeMedia(int pos) +{ + Q_D(QLocalMediaPlaylistProvider); + + emit mediaAboutToBeRemoved(pos, pos); + d->resources.removeAt(pos); + emit mediaRemoved(pos, pos); + + return true; +} + +bool QLocalMediaPlaylistProvider::clear() +{ + Q_D(QLocalMediaPlaylistProvider); + if (!d->resources.isEmpty()) { + int lastPos = mediaCount()-1; + emit mediaAboutToBeRemoved(0, lastPos); + d->resources.clear(); + emit mediaRemoved(0, lastPos); + } + + return true; +} + +void QLocalMediaPlaylistProvider::shuffle() +{ + Q_D(QLocalMediaPlaylistProvider); + if (!d->resources.isEmpty()) { + QList resources; + + while (!d->resources.isEmpty()) { + resources.append(d->resources.takeAt(qrand() % d->resources.size())); + } + + d->resources = resources; + emit mediaChanged(0, mediaCount()-1); + } + +} + +#include "moc_qlocalmediaplaylistprovider.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qlocalmediaplaylistprovider.h b/src/multimediakit/qlocalmediaplaylistprovider.h new file mode 100644 index 000000000..9ce590f25 --- /dev/null +++ b/src/multimediakit/qlocalmediaplaylistprovider.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOCALMEDIAPAYLISTPROVIDER_H +#define QLOCALMEDIAPAYLISTPROVIDER_H + +#include "qmediaplaylistprovider.h" + +QT_BEGIN_NAMESPACE + +class QLocalMediaPlaylistProviderPrivate; +class Q_MULTIMEDIA_EXPORT QLocalMediaPlaylistProvider : public QMediaPlaylistProvider +{ + Q_OBJECT +public: + QLocalMediaPlaylistProvider(QObject *parent=0); + virtual ~QLocalMediaPlaylistProvider(); + + virtual int mediaCount() const; + virtual QMediaContent media(int pos) const; + + virtual bool isReadOnly() const; + + virtual bool addMedia(const QMediaContent &content); + virtual bool addMedia(const QList &items); + virtual bool insertMedia(int pos, const QMediaContent &content); + virtual bool insertMedia(int pos, const QList &items); + virtual bool removeMedia(int pos); + virtual bool removeMedia(int start, int end); + virtual bool clear(); + +public Q_SLOTS: + virtual void shuffle(); + +private: + Q_DECLARE_PRIVATE(QLocalMediaPlaylistProvider) +}; + +QT_END_NAMESPACE + +#endif // QLOCALMEDIAPAYLISTSOURCE_H diff --git a/src/multimediakit/qmediabindableinterface.cpp b/src/multimediakit/qmediabindableinterface.cpp new file mode 100644 index 000000000..391d00d2b --- /dev/null +++ b/src/multimediakit/qmediabindableinterface.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaBindableInterface + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + + \brief The QMediaBindableInterface class is the base class for objects extending media objects functionality. + + \sa +*/ + +/*! + Destroys a media helper object. +*/ + +QMediaBindableInterface::~QMediaBindableInterface() +{ +} + +/*! + \fn QMediaBindableInterface::mediaObject() const; + + Return the currently attached media object. + \since 1.0 +*/ + + +/*! + \fn QMediaBindableInterface::setMediaObject(QMediaObject *object); + + Attaches to the media \a object. + Returns true if attached successfully, otherwise returns false. + \since 1.0 +*/ + + + +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediabindableinterface.h b/src/multimediakit/qmediabindableinterface.h new file mode 100644 index 000000000..09f6d6e3a --- /dev/null +++ b/src/multimediakit/qmediabindableinterface.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIABINDABLEINTERFACE_H +#define QMEDIABINDABLEINTERFACE_H + +#include + +QT_BEGIN_NAMESPACE + +class QMediaObject; + +class Q_MULTIMEDIA_EXPORT QMediaBindableInterface +{ +public: + virtual ~QMediaBindableInterface(); + + virtual QMediaObject *mediaObject() const = 0; + +protected: + friend class QMediaObject; + virtual bool setMediaObject(QMediaObject *object) = 0; +}; + +#define QMediaBindableInterface_iid \ + "com.nokia.Qt.QMediaBindableInterface/1.0" +Q_DECLARE_INTERFACE(QMediaBindableInterface, QMediaBindableInterface_iid) + +QT_END_NAMESPACE + +#endif // QMEDIABINDABLEINTERFACE_H diff --git a/src/multimediakit/qmediacontainercontrol.cpp b/src/multimediakit/qmediacontainercontrol.cpp new file mode 100644 index 000000000..512c96211 --- /dev/null +++ b/src/multimediakit/qmediacontainercontrol.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qmediacontainercontrol.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaContainerControl + + \brief The QMediaContainerControl class provides access to the output container format of a QMediaService + + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + If a QMediaService supports writing encoded data it will implement + QMediaContainerControl. This control provides information about the output + containers supported by a media service and allows one to be selected as + the current output containers. + + The functionality provided by this control is exposed to application code + through the QMediaRecorder class. + + The interface name of QMediaContainerControl is \c com.nokia.Qt.QMediaContainerControl/1.0 as + defined in QMediaContainerControl_iid. + + \sa QMediaService::requestControl(), QMediaRecorder +*/ + +/*! + \macro QMediaContainerControl_iid + + \c com.nokia.Qt.QMediaContainerControl/1.0 + + Defines the interface name of the QMediaContainerControl class. + + \relates QMediaContainerControl +*/ + +/*! + Constructs a new media container control with the given \a parent. +*/ +QMediaContainerControl::QMediaContainerControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys a media container control. +*/ +QMediaContainerControl::~QMediaContainerControl() +{ +} + + +/*! + \fn QMediaContainerControl::supportedContainers() const + + Returns a list of MIME types of supported container formats. + \since 1.0 +*/ + +/*! + \fn QMediaContainerControl::containerMimeType() const + + Returns the MIME type of the selected container format. + \since 1.0 +*/ + +/*! + \fn QMediaContainerControl::setContainerMimeType(const QString &mimeType) + + Sets the current container format to the format identified by the given \a mimeType. + \since 1.0 +*/ + +/*! + \fn QMediaContainerControl::containerDescription(const QString &mimeType) const + + Returns a description of the container format identified by the given \a mimeType. + \since 1.0 +*/ + +#include "moc_qmediacontainercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediacontainercontrol.h b/src/multimediakit/qmediacontainercontrol.h new file mode 100644 index 000000000..de26fc480 --- /dev/null +++ b/src/multimediakit/qmediacontainercontrol.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMEDIACONTAINERCONTROL_H +#define QMEDIACONTAINERCONTROL_H + +#include "qmediacontrol.h" + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QMediaContainerControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QMediaContainerControl(); + + virtual QStringList supportedContainers() const = 0; + virtual QString containerMimeType() const = 0; + virtual void setContainerMimeType(const QString &formatMimeType) = 0; + + virtual QString containerDescription(const QString &formatMimeType) const = 0; + +protected: + QMediaContainerControl(QObject *parent = 0); +}; + +#define QMediaContainerControl_iid "com.nokia.Qt.QMediaContainerControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaContainerControl, QMediaContainerControl_iid) + +QT_END_NAMESPACE + +#endif // QMEDIACONTAINERCONTROL_H diff --git a/src/multimediakit/qmediacontent.cpp b/src/multimediakit/qmediacontent.cpp new file mode 100644 index 000000000..d8ead6326 --- /dev/null +++ b/src/multimediakit/qmediacontent.cpp @@ -0,0 +1,254 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "qmediacontent.h" + +QT_BEGIN_NAMESPACE + + +class QMediaContentPrivate : public QSharedData +{ +public: + QMediaContentPrivate() {} + QMediaContentPrivate(const QMediaResourceList &r): + resources(r) {} + + QMediaContentPrivate(const QMediaContentPrivate &other): + QSharedData(other), + resources(other.resources) + {} + + bool operator ==(const QMediaContentPrivate &other) const + { + return resources == other.resources; + } + + QMediaResourceList resources; +private: + QMediaContentPrivate& operator=(const QMediaContentPrivate &other); +}; + + +/*! + \class QMediaContent + + \brief The QMediaContent class provides access to the resources relating to a media content. + + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + QMediaContent is used within the multimedia framework as the logical handle + to media content. A QMediaContent object is composed of one or more + \l {QMediaResource}s where each resource provides the URL and format + information of a different encoding of the content. + + A non-null QMediaContent will always have a primary or canonical reference to + the content available through the canonicalUrl() or canonicalResource() + methods, any additional resources are optional. +*/ + + +/*! + Constructs a null QMediaContent. +*/ + +QMediaContent::QMediaContent() +{ +} + +/*! + Constructs a media content with \a url providing a reference to the content. + \since 1.0 +*/ + +QMediaContent::QMediaContent(const QUrl &url): + d(new QMediaContentPrivate) +{ + d->resources << QMediaResource(url); +} + +/*! + Constructs a media content with \a request providing a reference to the content. + + This constructor can be used to reference media content via network protocols such as HTTP. + This may include additional information required to obtain the resource, such as Cookies or HTTP headers. + \since 1.0 +*/ + +QMediaContent::QMediaContent(const QNetworkRequest &request): + d(new QMediaContentPrivate) +{ + d->resources << QMediaResource(request); +} + +/*! + Constructs a media content with \a resource providing a reference to the content. + \since 1.0 +*/ + +QMediaContent::QMediaContent(const QMediaResource &resource): + d(new QMediaContentPrivate) +{ + d->resources << resource; +} + +/*! + Constructs a media content with \a resources providing a reference to the content. + \since 1.0 +*/ + +QMediaContent::QMediaContent(const QMediaResourceList &resources): + d(new QMediaContentPrivate(resources)) +{ +} + +/*! + Constructs a copy of the media content \a other. + \since 1.0 +*/ + +QMediaContent::QMediaContent(const QMediaContent &other): + d(other.d) +{ +} + +/*! + Destroys the media content object. +*/ + +QMediaContent::~QMediaContent() +{ +} + +/*! + Assigns the value of \a other to this media content. + \since 1.0 +*/ + +QMediaContent& QMediaContent::operator=(const QMediaContent &other) +{ + d = other.d; + return *this; +} + +/*! + Returns true if \a other is equivalent to this media content; false otherwise. + \since 1.0 +*/ + +bool QMediaContent::operator==(const QMediaContent &other) const +{ + return (d.constData() == 0 && other.d.constData() == 0) || + (d.constData() != 0 && other.d.constData() != 0 && + *d.constData() == *other.d.constData()); +} + +/*! + Returns true if \a other is not equivalent to this media content; false otherwise. + \since 1.0 +*/ + +bool QMediaContent::operator!=(const QMediaContent &other) const +{ + return !(*this == other); +} + +/*! + Returns true if this media content is null (uninitialized); false otherwise. + \since 1.0 +*/ + +bool QMediaContent::isNull() const +{ + return d.constData() == 0; +} + +/*! + Returns a QUrl that represents that canonical resource for this media content. + \since 1.0 +*/ + +QUrl QMediaContent::canonicalUrl() const +{ + return canonicalResource().url(); +} + +/*! + Returns a QNetworkRequest that represents that canonical resource for this media content. + \since 1.0 +*/ + +QNetworkRequest QMediaContent::canonicalRequest() const +{ + return canonicalResource().request(); +} + +/*! + Returns a QMediaResource that represents that canonical resource for this media content. + \since 1.0 +*/ + +QMediaResource QMediaContent::canonicalResource() const +{ + return d.constData() != 0 + ? d->resources.value(0) + : QMediaResource(); +} + +/*! + Returns a list of alternative resources for this media content. The first item in this list + is always the canonical resource. + \since 1.0 +*/ + +QMediaResourceList QMediaContent::resources() const +{ + return d.constData() != 0 + ? d->resources + : QMediaResourceList(); +} + +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediacontent.h b/src/multimediakit/qmediacontent.h new file mode 100644 index 000000000..66db3d02f --- /dev/null +++ b/src/multimediakit/qmediacontent.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIACONTENT_H +#define QMEDIACONTENT_H + +#include +#include + +#include "qmediaresource.h" + +#include + + +QT_BEGIN_NAMESPACE + +class QMediaContentPrivate; +class Q_MULTIMEDIA_EXPORT QMediaContent +{ +public: + QMediaContent(); + QMediaContent(const QUrl &contentUrl); + QMediaContent(const QNetworkRequest &contentRequest); + QMediaContent(const QMediaResource &contentResource); + QMediaContent(const QMediaResourceList &resources); + QMediaContent(const QMediaContent &other); + ~QMediaContent(); + + QMediaContent& operator=(const QMediaContent &other); + + bool operator==(const QMediaContent &other) const; + bool operator!=(const QMediaContent &other) const; + + bool isNull() const; + + QUrl canonicalUrl() const; + QNetworkRequest canonicalRequest() const; + QMediaResource canonicalResource() const; + + QMediaResourceList resources() const; + +private: + QSharedDataPointer d; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QMediaContent) + + + +#endif // QMEDIACONTENT_H diff --git a/src/multimediakit/qmediacontrol.cpp b/src/multimediakit/qmediacontrol.cpp new file mode 100644 index 000000000..2e624d2df --- /dev/null +++ b/src/multimediakit/qmediacontrol.cpp @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "qmediacontrol.h" +#include "qmediacontrol_p.h" + + + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaControl + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + + \brief The QMediaControl class provides a base interface for media service controls. + + Media controls provide an interface to individual features provided by a + media service. Most services implement a principal control which exposes + the core functionality of the service and a number of optional controls which + expose any additional functionality. + + XXX concrete example of this relationship + + A pointer to a control implemented by a media service can be obtained using + the \l {QMediaService::requestControl()} member of QMediaService. If the + service doesn't implement a control it will instead return a null pointer. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Request control + + Alternatively if the IId of the control has been declared using + Q_MEDIA_DECLARE_CONTROL the template version of + QMediaService::requestControl() can be used to request the service without + explicitly passing the IId or using qobject_cast(). + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Request control templated + + Most application code will not interface directly with a media service's + controls, instead the QMediaObject which owns the service acts as an + intermediary between one or more controls and the application. + + \sa QMediaService, QMediaObject +*/ + +/*! + \macro Q_MEDIA_DECLARE_CONTROL(Class, IId) + \relates QMediaControl + + The Q_MEDIA_DECLARE_CONTROL macro declares an \a IId for a \a Class that + inherits from QMediaControl. + + Declaring an IId for a QMediaControl allows an instance of that control to + be requested from QMediaService::requestControl() without explicitly + passing the IId. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Request control templated + + \sa QMediaService::requestControl() +*/ + +/*! + Destroys a media control. +*/ + +QMediaControl::~QMediaControl() +{ + delete d_ptr; +} + +/*! + Constructs a media control with the given \a parent. + \since 1.0 +*/ + +QMediaControl::QMediaControl(QObject *parent) + : QObject(parent) + , d_ptr(new QMediaControlPrivate) +{ + d_ptr->q_ptr = this; +} + +/*! + \internal + \since 1.0 +*/ + +QMediaControl::QMediaControl(QMediaControlPrivate &dd, QObject *parent) + : QObject(parent) + , d_ptr(&dd) + +{ + d_ptr->q_ptr = this; +} + +#include "moc_qmediacontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediacontrol.h b/src/multimediakit/qmediacontrol.h new file mode 100644 index 000000000..f330122d8 --- /dev/null +++ b/src/multimediakit/qmediacontrol.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTMEDIACONTROL_H +#define QABSTRACTMEDIACONTROL_H + +#include + +#include +#include +#include + + +QT_BEGIN_NAMESPACE + +class QMediaControlPrivate; +class Q_MULTIMEDIA_EXPORT QMediaControl : public QObject +{ + Q_OBJECT + +public: + ~QMediaControl(); + +protected: + QMediaControl(QObject *parent = 0); + QMediaControl(QMediaControlPrivate &dd, QObject *parent = 0); + + QMediaControlPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QMediaControl) +}; + +template const char *qmediacontrol_iid() { return 0; } + +#define Q_MEDIA_DECLARE_CONTROL(Class, IId) \ + template <> inline const char *qmediacontrol_iid() { return IId; } + +QT_END_NAMESPACE + +#endif // QABSTRACTMEDIACONTROL_H diff --git a/src/multimediakit/qmediacontrol_p.h b/src/multimediakit/qmediacontrol_p.h new file mode 100644 index 000000000..e7e5b6160 --- /dev/null +++ b/src/multimediakit/qmediacontrol_p.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTMEDIACONTROL_P_H +#define QABSTRACTMEDIACONTROL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QMediaControl; + +class QMediaControlPrivate +{ +public: + virtual ~QMediaControlPrivate() {} + + QMediaControl *q_ptr; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/qmediaencodersettings.cpp b/src/multimediakit/qmediaencodersettings.cpp new file mode 100644 index 000000000..b67324fc5 --- /dev/null +++ b/src/multimediakit/qmediaencodersettings.cpp @@ -0,0 +1,822 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaencodersettings.h" + +QT_BEGIN_NAMESPACE + +class QAudioEncoderSettingsPrivate : public QSharedData +{ +public: + QAudioEncoderSettingsPrivate() : + isNull(true), + encodingMode(QtMultimediaKit::ConstantQualityEncoding), + bitrate(-1), + sampleRate(-1), + channels(-1), + quality(QtMultimediaKit::NormalQuality) + { + } + + QAudioEncoderSettingsPrivate(const QAudioEncoderSettingsPrivate &other): + QSharedData(other), + isNull(other.isNull), + encodingMode(other.encodingMode), + codec(other.codec), + bitrate(other.bitrate), + sampleRate(other.sampleRate), + channels(other.channels), + quality(other.quality) + { + } + + bool isNull; + QtMultimediaKit::EncodingMode encodingMode; + QString codec; + int bitrate; + int sampleRate; + int channels; + QtMultimediaKit::EncodingQuality quality; + +private: + QAudioEncoderSettingsPrivate& operator=(const QAudioEncoderSettingsPrivate &other); +}; + +/*! + \class QAudioEncoderSettings + + \brief The QAudioEncoderSettings class provides a set of audio encoder settings. + + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + A audio encoder settings object is used to specify the audio encoder + settings used by QMediaRecorder. Audio encoder settings are selected by + constructing a QAudioEncoderSettings object, setting the desired properties + and then passing it to a QMediaRecorder instance using the + QMediaRecorder::setEncodingSettings() function. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Audio encoder settings + + \sa QMediaRecorder, QAudioEncoderControl +*/ + +/*! + Construct a null audio encoder settings object. +*/ +QAudioEncoderSettings::QAudioEncoderSettings() + :d(new QAudioEncoderSettingsPrivate) +{ +} + +/*! + Constructs a copy of the audio encoder settings object \a other. + \since 1.0 +*/ + +QAudioEncoderSettings::QAudioEncoderSettings(const QAudioEncoderSettings& other) + :d(other.d) +{ +} + +/*! + Destroys an audio encoder settings object. +*/ + +QAudioEncoderSettings::~QAudioEncoderSettings() +{ +} + +/*! + Assigns the value of \a other to an audio encoder settings object. + \since 1.0 +*/ + +QAudioEncoderSettings& QAudioEncoderSettings::operator=(const QAudioEncoderSettings &other) +{ + d = other.d; + return *this; +} + +/*! + Determines if \a other is of equal value to an audio encoder settings + object. + + Returns true if the settings objects are of equal value, and false if they + are not of equal value. + \since 1.0 +*/ + +bool QAudioEncoderSettings::operator==(const QAudioEncoderSettings &other) const +{ + return (d == other.d) || + (d->isNull == other.d->isNull && + d->encodingMode == other.d->encodingMode && + d->bitrate == other.d->bitrate && + d->sampleRate == other.d->sampleRate && + d->channels == other.d->channels && + d->quality == other.d->quality && + d->codec == other.d->codec); +} + +/*! + Determines if \a other is of equal value to an audio encoder settings + object. + + Returns true if the settings objects are not of equal value, and true if + they are of equal value. + \since 1.0 +*/ + +bool QAudioEncoderSettings::operator!=(const QAudioEncoderSettings &other) const +{ + return !(*this == other); +} + +/*! + Identifies if an audio settings object is initialized. + + Returns true if the settings object is null, and false if it is not. + \since 1.0 +*/ + +bool QAudioEncoderSettings::isNull() const +{ + return d->isNull; +} + +/*! + Returns the audio encoding mode. + + \since 1.0 + \sa QtMultimediaKit::EncodingMode +*/ +QtMultimediaKit::EncodingMode QAudioEncoderSettings::encodingMode() const +{ + return d->encodingMode; +} + +/*! + Sets the audio encoding \a mode setting. + + If QtMultimediaKit::ConstantQualityEncoding is set, the quality + encoding parameter is used and bit rate is ignored, + otherwise the bitrate is used. + + The audio codec, channels count and sample rate settings are used in all + the encoding modes. + + \since 1.0 + \sa encodingMode(), QtMultimediaKit::EncodingMode +*/ +void QAudioEncoderSettings::setEncodingMode(QtMultimediaKit::EncodingMode mode) +{ + d->encodingMode = mode; +} + +/*! + Returns the audio codec. + \since 1.0 +*/ +QString QAudioEncoderSettings::codec() const +{ + return d->codec; +} + +/*! + Sets the audio \a codec. + \since 1.0 +*/ +void QAudioEncoderSettings::setCodec(const QString& codec) +{ + d->isNull = false; + d->codec = codec; +} + +/*! + Returns the bit rate of the compressed audio stream in bits per second. + \since 1.0 +*/ +int QAudioEncoderSettings::bitRate() const +{ + return d->bitrate; +} + +/*! + Returns the number of audio channels. + \since 1.0 +*/ +int QAudioEncoderSettings::channelCount() const +{ + return d->channels; +} + +/*! + Sets the number of audio \a channels. + + A value of -1 indicates the encoder should make an optimal choice based on + what is available from the audio source and the limitations of the codec. + \since 1.0 +*/ +void QAudioEncoderSettings::setChannelCount(int channels) +{ + d->isNull = false; + d->channels = channels; +} + +/*! + Sets the audio bit \a rate in bits per second. + \since 1.0 +*/ +void QAudioEncoderSettings::setBitRate(int rate) +{ + d->isNull = false; + d->bitrate = rate; +} + +/*! + Returns the audio sample rate in Hz. + \since 1.0 +*/ +int QAudioEncoderSettings::sampleRate() const +{ + return d->sampleRate; +} + +/*! + Sets the audio sample \a rate in Hz. + + A value of -1 indicates the encoder should make an optimal choice based on what is avaialbe + from the audio source and the limitations of the codec. + \since 1.0 + */ +void QAudioEncoderSettings::setSampleRate(int rate) +{ + d->isNull = false; + d->sampleRate = rate; +} + +/*! + Returns the audio encoding quality. + \since 1.0 +*/ + +QtMultimediaKit::EncodingQuality QAudioEncoderSettings::quality() const +{ + return d->quality; +} + +/*! + Set the audio encoding \a quality. + + Setting the audio quality parameter allows backend to choose the balanced + set of encoding parameters to achieve the desired quality level. + + The \a quality settings parameter is only used in the + \l {QtMultimediaKit::ConstantQualityEncoding}{constant quality} \l{encodingMode()}{encoding mode}. + \since 1.0 +*/ +void QAudioEncoderSettings::setQuality(QtMultimediaKit::EncodingQuality quality) +{ + d->isNull = false; + d->quality = quality; +} + +class QVideoEncoderSettingsPrivate : public QSharedData +{ +public: + QVideoEncoderSettingsPrivate() : + isNull(true), + encodingMode(QtMultimediaKit::ConstantQualityEncoding), + bitrate(-1), + frameRate(0), + quality(QtMultimediaKit::NormalQuality) + { + } + + QVideoEncoderSettingsPrivate(const QVideoEncoderSettingsPrivate &other): + QSharedData(other), + isNull(other.isNull), + encodingMode(other.encodingMode), + codec(other.codec), + bitrate(other.bitrate), + resolution(other.resolution), + frameRate(other.frameRate), + quality(other.quality) + { + } + + bool isNull; + QtMultimediaKit::EncodingMode encodingMode; + QString codec; + int bitrate; + QSize resolution; + qreal frameRate; + QtMultimediaKit::EncodingQuality quality; + +private: + QVideoEncoderSettingsPrivate& operator=(const QVideoEncoderSettingsPrivate &other); +}; + +/*! + \class QVideoEncoderSettings + + \brief The QVideoEncoderSettings class provides a set of video encoder settings. + \since 1.0 + + A video encoder settings object is used to specify the video encoder + settings used by QMediaRecorder. Video encoder settings are selected by + constructing a QVideoEncoderSettings object, setting the desired properties + and then passing it to a QMediaRecorder instance using the + QMediaRecorder::setEncodingSettings() function. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Video encoder settings + + \sa QMediaRecorder, QVideoEncoderControl +*/ + +/*! + Constructs a null video encoder settings object. +*/ + +QVideoEncoderSettings::QVideoEncoderSettings() + :d(new QVideoEncoderSettingsPrivate) +{ +} + +/*! + Constructs a copy of the video encoder settings object \a other. + \since 1.0 +*/ + +QVideoEncoderSettings::QVideoEncoderSettings(const QVideoEncoderSettings& other) + :d(other.d) +{ +} + +/*! + Destroys a video encoder settings object. +*/ + +QVideoEncoderSettings::~QVideoEncoderSettings() +{ +} + +/*! + Assigns the value of \a other to a video encoder settings object. + \since 1.0 +*/ +QVideoEncoderSettings &QVideoEncoderSettings::operator=(const QVideoEncoderSettings &other) +{ + d = other.d; + return *this; +} + +/*! + Determines if \a other is of equal value to a video encoder settings object. + + Returns true if the settings objects are of equal value, and false if they + are not of equal value. + \since 1.0 +*/ +bool QVideoEncoderSettings::operator==(const QVideoEncoderSettings &other) const +{ + return (d == other.d) || + (d->isNull == other.d->isNull && + d->encodingMode == other.d->encodingMode && + d->bitrate == other.d->bitrate && + d->quality == other.d->quality && + d->codec == other.d->codec && + d->resolution == other.d->resolution && + qFuzzyCompare(d->frameRate, other.d->frameRate)); +} + +/*! + Determines if \a other is of equal value to a video encoder settings object. + + Returns true if the settings objects are not of equal value, and false if + they are of equal value. + \since 1.0 +*/ +bool QVideoEncoderSettings::operator!=(const QVideoEncoderSettings &other) const +{ + return !(*this == other); +} + +/*! + Identifies if a video encoder settings object is uninitalized. + + Returns true if the settings are null, and false if they are not. + \since 1.0 +*/ +bool QVideoEncoderSettings::isNull() const +{ + return d->isNull; +} + +/*! + Returns the video encoding mode. + + \since 1.0 + \sa QtMultimediaKit::EncodingMode +*/ +QtMultimediaKit::EncodingMode QVideoEncoderSettings::encodingMode() const +{ + return d->encodingMode; +} + +/*! + Sets the video encoding \a mode. + + If QtMultimediaKit::ConstantQualityEncoding is set, + the quality encoding parameter is used and bit rate is ignored, + otherwise the bitrate is used. + + The rest of encoding settings are respected regardless of encoding mode. + + \since 1.0 + \sa QtMultimediaKit::EncodingMode +*/ +void QVideoEncoderSettings::setEncodingMode(QtMultimediaKit::EncodingMode mode) +{ + d->isNull = false; + d->encodingMode = mode; +} + +/*! + Returns the video codec. + \since 1.0 +*/ + +QString QVideoEncoderSettings::codec() const +{ + return d->codec; +} + +/*! + Sets the video \a codec. + \since 1.0 +*/ +void QVideoEncoderSettings::setCodec(const QString& codec) +{ + d->isNull = false; + d->codec = codec; +} + +/*! + Returns bit rate of the encoded video stream in bits per second. + \since 1.0 +*/ +int QVideoEncoderSettings::bitRate() const +{ + return d->bitrate; +} + +/*! + Sets the bit rate of the encoded video stream to \a value. + \since 1.0 +*/ + +void QVideoEncoderSettings::setBitRate(int value) +{ + d->isNull = false; + d->bitrate = value; +} + +/*! + Returns the video frame rate. + \since 1.0 +*/ +qreal QVideoEncoderSettings::frameRate() const +{ + return d->frameRate; +} + +/*! + \fn QVideoEncoderSettings::setFrameRate(qreal rate) + + Sets the video frame \a rate. + + A value of 0 indicates the encoder should make an optimal choice based on what is available + from the video source and the limitations of the codec. + \since 1.0 +*/ + +void QVideoEncoderSettings::setFrameRate(qreal rate) +{ + d->isNull = false; + d->frameRate = rate; +} + +/*! + Returns the resolution of the encoded video. + \since 1.0 +*/ + +QSize QVideoEncoderSettings::resolution() const +{ + return d->resolution; +} + +/*! + Sets the \a resolution of the encoded video. + + An empty QSize indicates the encoder should make an optimal choice based on + what is available from the video source and the limitations of the codec. + \since 1.0 +*/ + +void QVideoEncoderSettings::setResolution(const QSize &resolution) +{ + d->isNull = false; + d->resolution = resolution; +} + +/*! + Sets the \a width and \a height of the resolution of the encoded video. + + \overload + \since 1.0 +*/ + +void QVideoEncoderSettings::setResolution(int width, int height) +{ + d->isNull = false; + d->resolution = QSize(width, height); +} + +/*! + Returns the video encoding quality. + \since 1.0 +*/ + +QtMultimediaKit::EncodingQuality QVideoEncoderSettings::quality() const +{ + return d->quality; +} + +/*! + Sets the video encoding \a quality. + + Setting the video quality parameter allows backend to choose the balanced + set of encoding parameters to achieve the desired quality level. + + The \a quality settings parameter is only used in the + \l {QtMultimediaKit::ConstantQualityEncoding}{constant quality} \l{encodingMode()}{encoding mode}. + The \a quality settings parameter is only used in the \l + {QtMultimediaKit::ConstantQualityEncoding}{constant quality} + \l{encodingMode()}{encoding mode}. + \since 1.0 +*/ + +void QVideoEncoderSettings::setQuality(QtMultimediaKit::EncodingQuality quality) +{ + d->isNull = false; + d->quality = quality; +} + + + +class QImageEncoderSettingsPrivate : public QSharedData +{ +public: + QImageEncoderSettingsPrivate() : + isNull(true), + quality(QtMultimediaKit::NormalQuality) + { + } + + QImageEncoderSettingsPrivate(const QImageEncoderSettingsPrivate &other): + QSharedData(other), + isNull(other.isNull), + codec(other.codec), + resolution(other.resolution), + quality(other.quality) + { + } + + bool isNull; + QString codec; + QSize resolution; + QtMultimediaKit::EncodingQuality quality; + +private: + QImageEncoderSettingsPrivate& operator=(const QImageEncoderSettingsPrivate &other); +}; + +/*! + \class QImageEncoderSettings + + + \brief The QImageEncoderSettings class provides a set of image encoder + settings. + \since 1.0 + + A image encoder settings object is used to specify the image encoder + settings used by QCameraImageCapture. Image encoder settings are selected + by constructing a QImageEncoderSettings object, setting the desired + properties and then passing it to a QCameraImageCapture instance using the + QCameraImageCapture::setImageSettings() function. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Image encoder settings + + \sa QImageEncoderControl +*/ + +/*! + Constructs a null image encoder settings object. +*/ + +QImageEncoderSettings::QImageEncoderSettings() + :d(new QImageEncoderSettingsPrivate) +{ +} + +/*! + Constructs a copy of the image encoder settings object \a other. + \since 1.0 +*/ + +QImageEncoderSettings::QImageEncoderSettings(const QImageEncoderSettings& other) + :d(other.d) +{ +} + +/*! + Destroys a image encoder settings object. +*/ + +QImageEncoderSettings::~QImageEncoderSettings() +{ +} + +/*! + Assigns the value of \a other to a image encoder settings object. + \since 1.0 +*/ +QImageEncoderSettings &QImageEncoderSettings::operator=(const QImageEncoderSettings &other) +{ + d = other.d; + return *this; +} + +/*! + Determines if \a other is of equal value to a image encoder settings + object. + + Returns true if the settings objects are of equal value, and false if they + are not of equal value. + \since 1.0 +*/ +bool QImageEncoderSettings::operator==(const QImageEncoderSettings &other) const +{ + return (d == other.d) || + (d->isNull == other.d->isNull && + d->quality == other.d->quality && + d->codec == other.d->codec && + d->resolution == other.d->resolution); + +} + +/*! + Determines if \a other is of equal value to a image encoder settings + object. + + Returns true if the settings objects are not of equal value, and false if + they are of equal value. + \since 1.0 +*/ +bool QImageEncoderSettings::operator!=(const QImageEncoderSettings &other) const +{ + return !(*this == other); +} + +/*! + Identifies if a image encoder settings object is uninitalized. + + Returns true if the settings are null, and false if they are not. + \since 1.0 +*/ +bool QImageEncoderSettings::isNull() const +{ + return d->isNull; +} + +/*! + Returns the image codec. + \since 1.0 +*/ + +QString QImageEncoderSettings::codec() const +{ + return d->codec; +} + +/*! + Sets the image \a codec. + \since 1.0 +*/ +void QImageEncoderSettings::setCodec(const QString& codec) +{ + d->isNull = false; + d->codec = codec; +} + +/*! + Returns the resolution of the encoded image. + \since 1.0 +*/ + +QSize QImageEncoderSettings::resolution() const +{ + return d->resolution; +} + +/*! + Sets the \a resolution of the encoded image. + + An empty QSize indicates the encoder should make an optimal choice based on + what is available from the image source and the limitations of the codec. + \since 1.0 +*/ + +void QImageEncoderSettings::setResolution(const QSize &resolution) +{ + d->isNull = false; + d->resolution = resolution; +} + +/*! + Sets the \a width and \a height of the resolution of the encoded image. + + \overload + \since 1.0 +*/ + +void QImageEncoderSettings::setResolution(int width, int height) +{ + d->isNull = false; + d->resolution = QSize(width, height); +} + +/*! + Returns the image encoding quality. + \since 1.0 +*/ + +QtMultimediaKit::EncodingQuality QImageEncoderSettings::quality() const +{ + return d->quality; +} + +/*! + Sets the image encoding \a quality. + \since 1.0 +*/ + +void QImageEncoderSettings::setQuality(QtMultimediaKit::EncodingQuality quality) +{ + d->isNull = false; + d->quality = quality; +} +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediaencodersettings.h b/src/multimediakit/qmediaencodersettings.h new file mode 100644 index 000000000..1662b59c3 --- /dev/null +++ b/src/multimediakit/qmediaencodersettings.h @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAENCODERSETTINGS_H +#define QMEDIAENCODERSETTINGS_H + +#include +#include +#include +#include +#include "qtmedianamespace.h" + +QT_BEGIN_NAMESPACE + + +class QAudioEncoderSettingsPrivate; +class Q_MULTIMEDIA_EXPORT QAudioEncoderSettings +{ +public: + QAudioEncoderSettings(); + QAudioEncoderSettings(const QAudioEncoderSettings& other); + + ~QAudioEncoderSettings(); + + QAudioEncoderSettings& operator=(const QAudioEncoderSettings &other); + bool operator==(const QAudioEncoderSettings &other) const; + bool operator!=(const QAudioEncoderSettings &other) const; + + bool isNull() const; + + QtMultimediaKit::EncodingMode encodingMode() const; + void setEncodingMode(QtMultimediaKit::EncodingMode); + + QString codec() const; + void setCodec(const QString& codec); + + int bitRate() const; + void setBitRate(int bitrate); + + int channelCount() const; + void setChannelCount(int channels); + + int sampleRate() const; + void setSampleRate(int rate); + + QtMultimediaKit::EncodingQuality quality() const; + void setQuality(QtMultimediaKit::EncodingQuality quality); + +private: + QSharedDataPointer d; +}; + +class QVideoEncoderSettingsPrivate; +class Q_MULTIMEDIA_EXPORT QVideoEncoderSettings +{ +public: + QVideoEncoderSettings(); + QVideoEncoderSettings(const QVideoEncoderSettings& other); + + ~QVideoEncoderSettings(); + + QVideoEncoderSettings& operator=(const QVideoEncoderSettings &other); + bool operator==(const QVideoEncoderSettings &other) const; + bool operator!=(const QVideoEncoderSettings &other) const; + + bool isNull() const; + + QtMultimediaKit::EncodingMode encodingMode() const; + void setEncodingMode(QtMultimediaKit::EncodingMode); + + QString codec() const; + void setCodec(const QString &); + + QSize resolution() const; + void setResolution(const QSize &); + void setResolution(int width, int height); + + qreal frameRate() const; + void setFrameRate(qreal rate); + + int bitRate() const; + void setBitRate(int bitrate); + + QtMultimediaKit::EncodingQuality quality() const; + void setQuality(QtMultimediaKit::EncodingQuality quality); + +private: + QSharedDataPointer d; +}; + +class QImageEncoderSettingsPrivate; +class Q_MULTIMEDIA_EXPORT QImageEncoderSettings +{ +public: + QImageEncoderSettings(); + QImageEncoderSettings(const QImageEncoderSettings& other); + + ~QImageEncoderSettings(); + + QImageEncoderSettings& operator=(const QImageEncoderSettings &other); + bool operator==(const QImageEncoderSettings &other) const; + bool operator!=(const QImageEncoderSettings &other) const; + + bool isNull() const; + + QString codec() const; + void setCodec(const QString &); + + QSize resolution() const; + void setResolution(const QSize &); + void setResolution(int width, int height); + + QtMultimediaKit::EncodingQuality quality() const; + void setQuality(QtMultimediaKit::EncodingQuality quality); + +private: + QSharedDataPointer d; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/qmediaenumdebug.h b/src/multimediakit/qmediaenumdebug.h new file mode 100644 index 000000000..60530e3fd --- /dev/null +++ b/src/multimediakit/qmediaenumdebug.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAENUMDEBUG_H +#define QMEDIAENUMDEBUG_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#include +#include + +#ifndef QT_NO_DEBUG_STREAM + +#define Q_MEDIA_ENUM_DEBUG(Class,Enum) \ +inline QDebug operator<<(QDebug dbg, Class::Enum value) \ +{ \ + int index = Class::staticMetaObject.indexOfEnumerator(#Enum); \ + dbg.nospace() << #Class << "::" << Class::staticMetaObject.enumerator(index).valueToKey(value); \ + return dbg.space(); \ +} + +#else + +#define Q_MEDIA_ENUM_DEBUG(Class,Enum) + +#endif //QT_NO_DEBUG_STREAM + + +#endif + diff --git a/src/multimediakit/qmediaimageviewer.cpp b/src/multimediakit/qmediaimageviewer.cpp new file mode 100644 index 000000000..4baaf6bad --- /dev/null +++ b/src/multimediakit/qmediaimageviewer.cpp @@ -0,0 +1,599 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaimageviewer.h" + +#include "qmediaobject_p.h" +#include "qmediaimageviewerservice_p.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QMediaImageViewerPrivate : public QMediaObjectPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QMediaImageViewer) +public: + QMediaImageViewerPrivate(): + viewerControl(0), playlist(0), + state(QMediaImageViewer::StoppedState), timeout(3000), pauseTime(0) + { + } + + void _q_mediaStatusChanged(QMediaImageViewer::MediaStatus status); + void _q_playlistMediaChanged(const QMediaContent &content); + void _q_playlistDestroyed(); + + QMediaImageViewerControl *viewerControl; + QMediaPlaylist *playlist; + QPointer videoOutput; + QVideoSurfaceOutput surfaceOutput; + QMediaImageViewer::State state; + int timeout; + int pauseTime; + QTime time; + QBasicTimer timer; + QMediaContent media; +}; + +void QMediaImageViewerPrivate::_q_mediaStatusChanged(QMediaImageViewer::MediaStatus status) +{ + switch (status) { + case QMediaImageViewer::NoMedia: + case QMediaImageViewer::LoadingMedia: + emit q_func()->mediaStatusChanged(status); + break; + case QMediaImageViewer::LoadedMedia: + if (state == QMediaImageViewer::PlayingState) { + time.start(); + timer.start(qMax(0, timeout), q_func()); + q_func()->addPropertyWatch("elapsedTime"); + } + emit q_func()->mediaStatusChanged(status); + emit q_func()->elapsedTimeChanged(0); + break; + case QMediaImageViewer::InvalidMedia: + emit q_func()->mediaStatusChanged(status); + + if (state == QMediaImageViewer::PlayingState) { + playlist->next(); + if (playlist->currentIndex() < 0) + emit q_func()->stateChanged(state = QMediaImageViewer::StoppedState); + } + break; + } +} + +void QMediaImageViewerPrivate::_q_playlistMediaChanged(const QMediaContent &content) +{ + media = content; + pauseTime = 0; + + viewerControl->showMedia(media); + + emit q_func()->mediaChanged(media); +} + +void QMediaImageViewerPrivate::_q_playlistDestroyed() +{ + playlist = 0; + timer.stop(); + + if (state != QMediaImageViewer::StoppedState) + emit q_func()->stateChanged(state = QMediaImageViewer::StoppedState); + + q_func()->setMedia(QMediaContent()); +} + +/*! + \class QMediaImageViewer + \brief The QMediaImageViewer class provides a means of viewing image media. + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + + QMediaImageViewer is used together with a media display object such as + QVideoWidget to present an image. A display object is attached to the + image viewer by means of the bind function. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Binding + + QMediaImageViewer can be paired with a QMediaPlaylist to create a slide + show of images. Constructing a QMediaPlaylist with a pointer to an + instance of QMediaImageViewer will attach it to the image viewer; + changing the playlist's selection will then change the media displayed + by the image viewer. With a playlist attached QMediaImageViewer's + play(), pause(), and stop() slots can be control the progression of the + playlist. The \l timeout property determines how long an image is + displayed for before progressing to the next in the playlist, and the + \l elapsedTime property holds how the duration the current image has + been displayed for. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Playlist +*/ + +/*! + \enum QMediaImageViewer::State + + Enumerates the possible control states an image viewer may be in. The + control state of an image viewer determines whether the image viewer is + automatically progressing through images in an attached playlist. + + \value StoppedState The image viewer is stopped, and will not automatically move to the next + image. The \l elapsedTime is fixed at 0. + \value PlayingState The slide show is playing, and will move to the next image when the + \l elapsedTime reaches the \l timeout. The \l elapsedTime is being incremented. + \value PausedState The image viewer is paused, and will not automatically move the to next + image. The \l elapsedTime is fixed at the time the image viewer was paused. +*/ + +/*! + \enum QMediaImageViewer::MediaStatus + + Enumerates the status of an image viewer's current media. + + \value NoMedia There is no current media. + \value LoadingMedia The image viewer is loading the current media. + \value LoadedMedia The image viewer has loaded the current media. + \value InvalidMedia The current media cannot be loaded. +*/ + +/*! + Constructs a new image viewer with the given \a parent. +*/ +QMediaImageViewer::QMediaImageViewer(QObject *parent) + : QMediaObject(*new QMediaImageViewerPrivate, parent, new QMediaImageViewerService) +{ + Q_D(QMediaImageViewer); + + d->viewerControl = qobject_cast( + d->service->requestControl(QMediaImageViewerControl_iid)); + + connect(d->viewerControl, SIGNAL(mediaStatusChanged(QMediaImageViewer::MediaStatus)), + this, SLOT(_q_mediaStatusChanged(QMediaImageViewer::MediaStatus))); +} + +/*! + Destroys an image viewer. +*/ +QMediaImageViewer::~QMediaImageViewer() +{ + Q_D(QMediaImageViewer); + + delete d->service; +} + +/*! + \property QMediaImageViewer::state + \brief the playlist control state of a slide show. + \since 1.0 +*/ + +QMediaImageViewer::State QMediaImageViewer::state() const +{ + return d_func()->state; +} + +/*! + \fn QMediaImageViewer::stateChanged(QMediaImageViewer::State state) + + Signals that the playlist control \a state of an image viewer has changed. + \since 1.0 +*/ + +/*! + \property QMediaImageViewer::mediaStatus + \brief the status of the current media. + \since 1.0 +*/ + +QMediaImageViewer::MediaStatus QMediaImageViewer::mediaStatus() const +{ + return d_func()->viewerControl->mediaStatus(); +} + +/*! + \fn QMediaImageViewer::mediaStatusChanged(QMediaImageViewer::MediaStatus status) + + Signals the the \a status of the current media has changed. + \since 1.0 +*/ + +/*! + \property QMediaImageViewer::media + \brief the media an image viewer is presenting. + \since 1.0 +*/ + +QMediaContent QMediaImageViewer::media() const +{ + Q_D(const QMediaImageViewer); + + return d->media; +} + +void QMediaImageViewer::setMedia(const QMediaContent &media) +{ + Q_D(QMediaImageViewer); + + if (d->playlist && d->playlist->currentMedia() != media) { + disconnect(d->playlist, SIGNAL(currentMediaChanged(QMediaContent)), + this, SLOT(_q_playlistMediaChanged(QMediaContent))); + disconnect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed())); + + d->playlist = 0; + } + + d->media = media; + + if (d->timer.isActive()) { + d->pauseTime = 0; + d->timer.stop(); + removePropertyWatch("elapsedTime"); + emit elapsedTimeChanged(0); + } + + if (d->state != QMediaImageViewer::StoppedState) + emit stateChanged(d->state = QMediaImageViewer::StoppedState); + + d->viewerControl->showMedia(d->media); + + emit mediaChanged(d->media); +} + +/*! + Use \a playlist as the source of images to be displayed in the viewer. + \since 1.0 +*/ +void QMediaImageViewer::setPlaylist(QMediaPlaylist *playlist) +{ + Q_D(QMediaImageViewer); + + if (d->playlist) { + disconnect(d->playlist, SIGNAL(currentMediaChanged(QMediaContent)), + this, SLOT(_q_playlistMediaChanged(QMediaContent))); + disconnect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed())); + + QMediaObject::unbind(d->playlist); + } + + d->playlist = playlist; + + if (d->playlist) { + connect(d->playlist, SIGNAL(currentMediaChanged(QMediaContent)), + this, SLOT(_q_playlistMediaChanged(QMediaContent))); + connect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed())); + + QMediaObject::bind(d->playlist); + + setMedia(d->playlist->currentMedia()); + } else { + setMedia(QMediaContent()); + } +} + +/*! + Returns the current playlist, or 0 if none. + \since 1.0 +*/ +QMediaPlaylist *QMediaImageViewer::playlist() const +{ + return d_func()->playlist; +} + +/*! + \fn QMediaImageViewer::mediaChanged(const QMediaContent &media) + + Signals that the \a media an image viewer is presenting has changed. + \since 1.0 +*/ + +/*! + \property QMediaImageViewer::timeout + \brief the amount of time in milliseconds an image is displayed for before moving to the next + image. + + The timeout only applies if the image viewer has a playlist attached and is in the PlayingState. + \since 1.0 +*/ + +int QMediaImageViewer::timeout() const +{ + return d_func()->timeout; +} + +void QMediaImageViewer::setTimeout(int timeout) +{ + Q_D(QMediaImageViewer); + + d->timeout = qMax(0, timeout); + + if (d->timer.isActive()) + d->timer.start(qMax(0, d->timeout - d->pauseTime - d->time.elapsed()), this); +} + +/*! + \property QMediaImageViewer::elapsedTime + \brief the amount of time in milliseconds that has elapsed since the current image was loaded. + + The elapsed time only increases while the image viewer is in the PlayingState. If stopped the + elapsed time will be reset to 0. + \since 1.0 +*/ + +int QMediaImageViewer::elapsedTime() const +{ + Q_D(const QMediaImageViewer); + + int elapsedTime = d->pauseTime; + + if (d->timer.isActive()) + elapsedTime += d->time.elapsed(); + + return elapsedTime; +} + +/*! + \fn QMediaImageViewer::elapsedTimeChanged(int time) + + Signals that the amount of \a time in milliseconds since the current + image was loaded has changed. + + This signal is emitted at a regular interval when the image viewer is + in the PlayingState and an image is loaded. The notification interval + is controlled by the QMediaObject::notifyInterval property. + + \since 1.0 + \sa timeout, QMediaObject::notifyInterval +*/ + +/*! + Sets a video \a widget as the current video output. + + This will unbind any previous video output bound with setVideoOutput(). + \since 1.1 +*/ + +void QMediaImageViewer::setVideoOutput(QVideoWidget *widget) +{ + Q_D(QMediaImageViewer); + + if (d->videoOutput) + unbind(d->videoOutput); + + d->videoOutput = bind(widget) ? widget : 0; +} + +/*! + Sets a video \a item as the current video output. + + This will unbind any previous video output bound with setVideoOutput(). + \since 1.1 +*/ + +void QMediaImageViewer::setVideoOutput(QGraphicsVideoItem *item) +{ + Q_D(QMediaImageViewer); + + if (d->videoOutput) + unbind(d->videoOutput); + + d->videoOutput = bind(item) ? item : 0; +} + +/*! + Sets a video \a surface as the video output of a image viewer. + + If a video output has already been set on the image viewer the new surface + will replace it. + \since 1.2 +*/ + +void QMediaImageViewer::setVideoOutput(QAbstractVideoSurface *surface) +{ + Q_D(QMediaImageViewer); + + d->surfaceOutput.setVideoSurface(surface); + + if (d->videoOutput != &d->surfaceOutput) { + if (d->videoOutput) + unbind(d->videoOutput); + + d->videoOutput = bind(&d->surfaceOutput) ? &d->surfaceOutput : 0; + } +} + +/*! + \internal + \since 1.0 +*/ +bool QMediaImageViewer::bind(QObject *object) +{ + if (QMediaPlaylist *playlist = qobject_cast(object)) { + setPlaylist(playlist); + + return true; + } else { + return QMediaObject::bind(object); + } +} + +/*! + \internal + \since 1.0 + */ +void QMediaImageViewer::unbind(QObject *object) +{ + if (object == d_func()->playlist) + setPlaylist(0); + else + QMediaObject::unbind(object); +} + +/*! + Starts a slide show. + + If the playlist has no current media this will start at the beginning of the playlist, otherwise + it will resume from the current media. + + If no playlist is attached to an image viewer this will do nothing. + \since 1.0 +*/ +void QMediaImageViewer::play() +{ + Q_D(QMediaImageViewer); + + if (d->playlist && d->playlist->mediaCount() > 0 && d->state != PlayingState) { + d->state = PlayingState; + + switch (d->viewerControl->mediaStatus()) { + case NoMedia: + case InvalidMedia: + d->playlist->next(); + if (d->playlist->currentIndex() < 0) + d->state = StoppedState; + break; + case LoadingMedia: + break; + case LoadedMedia: + d->time.start(); + d->timer.start(qMax(0, d->timeout - d->pauseTime), this); + break; + } + + if (d->state == PlayingState) + emit stateChanged(d->state); + } +} + +/*! + Pauses a slide show. + + The current media and elapsed time are retained. If resumed, the current image will be + displayed for the remainder of the time out period before the next image is loaded. + \since 1.0 +*/ +void QMediaImageViewer::pause() +{ + Q_D(QMediaImageViewer); + + if (d->state == PlayingState) { + if (d->viewerControl->mediaStatus() == LoadedMedia) { + d->pauseTime += d->timeout - d->time.elapsed(); + d->timer.stop(); + removePropertyWatch("elapsedTime"); + } + + emit stateChanged(d->state = PausedState); + emit elapsedTimeChanged(d->pauseTime); + } +} + +/*! + Stops a slide show. + + The current media is retained, but the elapsed time is discarded. If resumed, the current + image will be displayed for the full time out period before the next image is loaded. + \since 1.0 +*/ +void QMediaImageViewer::stop() +{ + Q_D(QMediaImageViewer); + + switch (d->state) { + case PlayingState: + d->timer.stop(); + removePropertyWatch("elapsedTime"); + // fall through. + case PausedState: + d->pauseTime = 0; + d->state = QMediaImageViewer::StoppedState; + + emit stateChanged(d->state); + emit elapsedTimeChanged(0); + break; + case StoppedState: + break; + } +} + +/*! + \reimp + + \internal + \since 1.0 +*/ +void QMediaImageViewer::timerEvent(QTimerEvent *event) +{ + Q_D(QMediaImageViewer); + + if (event->timerId() == d->timer.timerId()) { + d->timer.stop(); + removePropertyWatch("elapsedTime"); + emit elapsedTimeChanged(d->pauseTime = d->timeout); + + d->playlist->next(); + + if (d->playlist->currentIndex() < 0) { + d->pauseTime = 0; + emit stateChanged(d->state = StoppedState); + emit elapsedTimeChanged(0); + } + } else { + QMediaObject::timerEvent(event); + } +} + +#include "moc_qmediaimageviewer.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediaimageviewer.h b/src/multimediakit/qmediaimageviewer.h new file mode 100644 index 000000000..f277f8520 --- /dev/null +++ b/src/multimediakit/qmediaimageviewer.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAIMAGEVIEWER_H +#define QMEDIAIMAGEVIEWER_H + +#include "qmediaobject.h" +#include "qmediacontent.h" +#include + +QT_BEGIN_NAMESPACE + +class QAbstractVideoSurface; +class QGraphicsVideoItem; +class QMediaPlaylist; +class QVideoWidget; + +class QMediaImageViewerPrivate; +class Q_MULTIMEDIA_EXPORT QMediaImageViewer : public QMediaObject +{ + Q_OBJECT + Q_PROPERTY(State state READ state NOTIFY stateChanged) + Q_PROPERTY(MediaStatus mediaStatus READ mediaStatus NOTIFY mediaStatusChanged) + Q_PROPERTY(QMediaContent media READ media WRITE setMedia NOTIFY mediaChanged) + Q_PROPERTY(int timeout READ timeout WRITE setTimeout) + Q_PROPERTY(int elapsedTime READ elapsedTime NOTIFY elapsedTimeChanged) + Q_ENUMS(State MediaStatus) + +public: + enum State + { + StoppedState, + PlayingState, + PausedState + }; + + enum MediaStatus + { + NoMedia, + LoadingMedia, + LoadedMedia, + InvalidMedia + }; + + explicit QMediaImageViewer(QObject *parent = 0); + ~QMediaImageViewer(); + + State state() const; + MediaStatus mediaStatus() const; + + QMediaContent media() const; + QMediaPlaylist *playlist() const; + + int timeout() const; + int elapsedTime() const; + + void setVideoOutput(QVideoWidget *widget); + void setVideoOutput(QGraphicsVideoItem *item); + void setVideoOutput(QAbstractVideoSurface *surface); + + bool bind(QObject *); + void unbind(QObject *); + +public Q_SLOTS: + void setMedia(const QMediaContent &media); + void setPlaylist(QMediaPlaylist *playlist); + + void play(); + void pause(); + void stop(); + + void setTimeout(int timeout); + +Q_SIGNALS: + void stateChanged(QMediaImageViewer::State state); + void mediaStatusChanged(QMediaImageViewer::MediaStatus status); + void mediaChanged(const QMediaContent &media); + void elapsedTimeChanged(int time); +protected: + void timerEvent(QTimerEvent *event); + +private: + Q_DECLARE_PRIVATE(QMediaImageViewer) + Q_PRIVATE_SLOT(d_func(), void _q_mediaStatusChanged(QMediaImageViewer::MediaStatus)) + Q_PRIVATE_SLOT(d_func(), void _q_playlistMediaChanged(const QMediaContent &)) + Q_PRIVATE_SLOT(d_func(), void _q_playlistDestroyed()) +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QMediaImageViewer::State) +Q_DECLARE_METATYPE(QMediaImageViewer::MediaStatus) + +Q_MEDIA_ENUM_DEBUG(QMediaImageViewer, State) +Q_MEDIA_ENUM_DEBUG(QMediaImageViewer, MediaStatus) + +#endif diff --git a/src/multimediakit/qmediaimageviewerservice.cpp b/src/multimediakit/qmediaimageviewerservice.cpp new file mode 100644 index 000000000..9d00fd0b9 --- /dev/null +++ b/src/multimediakit/qmediaimageviewerservice.cpp @@ -0,0 +1,465 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaimageviewerservice_p.h" + +#include "qmediacontrol_p.h" +#include "qmediaservice_p.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QMediaImageViewerServicePrivate : public QMediaServicePrivate +{ +public: + QMediaImageViewerServicePrivate() + : viewerControl(0) + , rendererControl(0) + , network(0) + , internalNetwork(0) + { + } + + bool load(QIODevice *device); + void clear(); + + QMediaImageViewerControl *viewerControl; + QMediaImageViewerRenderer *rendererControl; + QNetworkAccessManager *network; + QNetworkAccessManager *internalNetwork; + QImage m_image; +}; + + +QMediaImageViewerRenderer::QMediaImageViewerRenderer(QObject *parent) + : QVideoRendererControl(parent) + , m_surface(0) +{ +} + +QMediaImageViewerRenderer::~QMediaImageViewerRenderer() +{ + if (m_surface) + m_surface->stop(); +} + +QAbstractVideoSurface *QMediaImageViewerRenderer::surface() const +{ + return m_surface; +} + +void QMediaImageViewerRenderer::setSurface(QAbstractVideoSurface *surface) +{ + if (m_surface) + m_surface->stop(); + + m_surface = surface; + + if (m_surface && !m_image.isNull()) + showImage(m_image); +} + +void QMediaImageViewerRenderer::showImage(const QImage &image) +{ + m_image = image; + + if (m_surface) { + if (m_image.isNull()) { + m_surface->stop(); + } else { + QVideoSurfaceFormat format( + image.size(), QVideoFrame::pixelFormatFromImageFormat(image.format())); + + if (!m_surface->isFormatSupported(format)) { + foreach (QVideoFrame::PixelFormat pixelFormat, m_surface->supportedPixelFormats()) { + const QImage::Format imageFormat + = QVideoFrame::imageFormatFromPixelFormat(pixelFormat); + + if (imageFormat != QImage::Format_Invalid) { + format = QVideoSurfaceFormat(image.size(), pixelFormat); + + if (m_surface->isFormatSupported(format) && m_surface->start(format)) { + m_image = image.convertToFormat(imageFormat); + + m_surface->present(QVideoFrame(m_image)); + + return; + } + } + } + } else if (m_surface->start(format)) { + m_surface->present(QVideoFrame(image)); + } + } + } +} + +bool QMediaImageViewerServicePrivate::load(QIODevice *device) +{ + QImageReader reader(device); + + if (!reader.canRead()) { + m_image = QImage(); + } else { + m_image = reader.read(); + } + + if (rendererControl) + rendererControl->showImage(m_image); + + return !m_image.isNull(); +} + +void QMediaImageViewerServicePrivate::clear() +{ + m_image = QImage(); + + if (rendererControl) + rendererControl->showImage(m_image); +} + +/*! + \class QMediaImageViewerService + \since 1.0 + \internal +*/ + +/*! +*/ +QMediaImageViewerService::QMediaImageViewerService(QObject *parent) + : QMediaService(*new QMediaImageViewerServicePrivate, parent) +{ + Q_D(QMediaImageViewerService); + + d->viewerControl = new QMediaImageViewerControl(this); +} + +/*! +*/ +QMediaImageViewerService::~QMediaImageViewerService() +{ + Q_D(QMediaImageViewerService); + + delete d->rendererControl; + delete d->viewerControl; +} + +/*! +*/ +QMediaControl *QMediaImageViewerService::requestControl(const char *name) +{ + Q_D(QMediaImageViewerService); + + if (qstrcmp(name, QMediaImageViewerControl_iid) == 0) { + return d->viewerControl; + } else if (qstrcmp(name, QVideoRendererControl_iid) == 0) { + if (!d->rendererControl) { + d->rendererControl = new QMediaImageViewerRenderer; + d->rendererControl->showImage(d->m_image); + + return d->rendererControl; + } + } + return 0; +} + +void QMediaImageViewerService::releaseControl(QMediaControl *control) +{ + Q_D(QMediaImageViewerService); + + if (!control) { + qWarning("QMediaService::releaseControl():" + " Attempted release of null control"); + } else if (control == d->rendererControl) { + delete d->rendererControl; + + d->rendererControl = 0; + } +} + +/*! +*/ +QNetworkAccessManager *QMediaImageViewerService::networkManager() const +{ + Q_D(const QMediaImageViewerService); + + if (!d->network) { + QMediaImageViewerServicePrivate *_d = const_cast(d); + + if (!_d->internalNetwork) + _d->internalNetwork = new QNetworkAccessManager( + const_cast(this)); + + _d->network = d->internalNetwork; + } + + return d->network; +} + + +void QMediaImageViewerService::setNetworkManager(QNetworkAccessManager *manager) +{ + d_func()->network = manager; +} + +class QMediaImageViewerControlPrivate : public QMediaControlPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QMediaImageViewerControl) +public: + QMediaImageViewerControlPrivate() + : service(0) + , getReply(0) + , headReply(0) + , status(QMediaImageViewer::NoMedia) + { + foreach (const QByteArray &format, QImageReader::supportedImageFormats()) { + supportedExtensions.append( + QLatin1Char('.') + QString::fromLatin1(format.data(), format.size())); + } + } + + bool isImageType(const QUrl &url, const QString &mimeType) const; + + void loadImage(); + void cancelRequests(); + + void _q_getFinished(); + void _q_headFinished(); + + QMediaImageViewerService *service; + QNetworkReply *getReply; + QNetworkReply *headReply; + QMediaImageViewer::MediaStatus status; + QMediaContent media; + QMediaResource currentMedia; + QList possibleResources; + QStringList supportedExtensions; +}; + +bool QMediaImageViewerControlPrivate::isImageType(const QUrl &url, const QString &mimeType) const +{ + if (!mimeType.isEmpty()) { + return mimeType.startsWith(QLatin1String("image/")) + || mimeType == QLatin1String("application/xml+svg"); + } else if (url.scheme() == QLatin1String("file")) { + QString path = url.path(); + + foreach (const QString &extension, supportedExtensions) { + if (path.endsWith(extension, Qt::CaseInsensitive)) + return true; + } + } + return false; +} + +void QMediaImageViewerControlPrivate::loadImage() +{ + cancelRequests(); + + QMediaImageViewer::MediaStatus currentStatus = status; + status = QMediaImageViewer::InvalidMedia; + + QNetworkAccessManager *network = service->networkManager(); + + while (!possibleResources.isEmpty() && !headReply && !getReply) { + currentMedia = possibleResources.takeFirst(); + + QUrl url = currentMedia.url(); + QString mimeType = currentMedia.mimeType(); + + if (isImageType(url, mimeType)) { + getReply = network->get(QNetworkRequest(url)); + QObject::connect(getReply, SIGNAL(finished()), q_func(), SLOT(_q_getFinished())); + + status = QMediaImageViewer::LoadingMedia; + } else if (mimeType.isEmpty() && url.scheme() != QLatin1String("file")) { + headReply = network->head(QNetworkRequest(currentMedia.url())); + QObject::connect(headReply, SIGNAL(finished()), q_func(), SLOT(_q_headFinished())); + + status = QMediaImageViewer::LoadingMedia; + } + } + + if (status == QMediaImageViewer::InvalidMedia) + currentMedia = QMediaResource(); + + if (status != currentStatus) + emit q_func()->mediaStatusChanged(status); +} + +void QMediaImageViewerControlPrivate::cancelRequests() +{ + if (getReply) { + getReply->abort(); + getReply->deleteLater(); + getReply = 0; + } + + if (headReply) { + headReply->abort(); + headReply->deleteLater(); + headReply = 0; + } +} + +void QMediaImageViewerControlPrivate::_q_getFinished() +{ + if (getReply != q_func()->sender()) + return; + + QImage image; + + if (service->d_func()->load(getReply)) { + possibleResources.clear(); + + status = QMediaImageViewer::LoadedMedia; + + emit q_func()->mediaStatusChanged(status); + } else { + loadImage(); + } +} + +void QMediaImageViewerControlPrivate::_q_headFinished() +{ + if (headReply != q_func()->sender()) + return; + + QString mimeType = headReply->header(QNetworkRequest::ContentTypeHeader) + .toString().section(QLatin1Char(';'), 0, 0); + QUrl url = headReply->url(); + if (url.isEmpty()) + url = headReply->request().url(); + + headReply->deleteLater(); + headReply = 0; + + if (isImageType(url, mimeType) || mimeType.isEmpty()) { + QNetworkAccessManager *network = service->networkManager(); + + getReply = network->get(QNetworkRequest(url)); + + QObject::connect(getReply, SIGNAL(finished()), q_func(), SLOT(_q_getFinished())); + } else { + loadImage(); + } +} + +/*! + \class QMediaImageViewerControl + \internal + \since 1.1 +*/ +QMediaImageViewerControl::QMediaImageViewerControl(QMediaImageViewerService *parent) + : QMediaControl(*new QMediaImageViewerControlPrivate, parent) +{ + Q_D(QMediaImageViewerControl); + + d->service = parent; +} + +/*! +*/ +QMediaImageViewerControl::~QMediaImageViewerControl() +{ + Q_D(QMediaImageViewerControl); + + delete d->getReply; +} + +/*! + \since 1.1 +*/ +QMediaImageViewer::MediaStatus QMediaImageViewerControl::mediaStatus() const +{ + return d_func()->status; +} + +/*! + \fn QMediaImageViewerControl::mediaStatusChanged(QMediaImageViewer::MediaStatus status); + \since 1.1 +*/ + +/*! + \since 1.1 +*/ +void QMediaImageViewerControl::showMedia(const QMediaContent &media) +{ + Q_D(QMediaImageViewerControl); + + d->media = media; + d->currentMedia = QMediaResource(); + d->cancelRequests(); + + if (media.isNull()) { + d->service->d_func()->clear(); + if (d->status != QMediaImageViewer::NoMedia) { + d->status = QMediaImageViewer::NoMedia; + emit mediaStatusChanged(d->status); + } + } else { + d->possibleResources = media.resources(); + d->loadImage(); + } +} + + +#include "moc_qmediaimageviewerservice_p.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediaimageviewerservice_p.h b/src/multimediakit/qmediaimageviewerservice_p.h new file mode 100644 index 000000000..5d4811da9 --- /dev/null +++ b/src/multimediakit/qmediaimageviewerservice_p.h @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIASLIDESHOWSERVICE_P_H +#define QMEDIASLIDESHOWSERVICE_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 +#include +#include +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE +class QAbstractVideoSurface; +class QNetworkAccessManager; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class QMediaImageViewerServicePrivate; + +class Q_AUTOTEST_EXPORT QMediaImageViewerService : public QMediaService +{ + Q_OBJECT +public: + explicit QMediaImageViewerService(QObject *parent = 0); + ~QMediaImageViewerService(); + + QMediaControl *requestControl(const char *name); + void releaseControl(QMediaControl *); + + QNetworkAccessManager *networkManager() const; + void setNetworkManager(QNetworkAccessManager *manager); + +private: + Q_DECLARE_PRIVATE(QMediaImageViewerService) + friend class QMediaImageViewerControl; + friend class QMediaImageViewerControlPrivate; +}; + +class QMediaImageViewerControlPrivate; + +class QMediaImageViewerControl : public QMediaControl +{ + Q_OBJECT +public: + explicit QMediaImageViewerControl(QMediaImageViewerService *parent); + ~QMediaImageViewerControl(); + + QMediaImageViewer::MediaStatus mediaStatus() const; + + void showMedia(const QMediaContent &media); + +Q_SIGNALS: + void mediaStatusChanged(QMediaImageViewer::MediaStatus status); + +private: + Q_DECLARE_PRIVATE(QMediaImageViewerControl) + Q_PRIVATE_SLOT(d_func(), void _q_headFinished()) + Q_PRIVATE_SLOT(d_func(), void _q_getFinished()) +}; + +#define QMediaImageViewerControl_iid "com.nokia.Qt.QMediaImageViewerControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaImageViewerControl, QMediaImageViewerControl_iid) + +class QMediaImageViewerRenderer : public QVideoRendererControl +{ + Q_OBJECT +public: + QMediaImageViewerRenderer(QObject *parent = 0); + ~QMediaImageViewerRenderer(); + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + + void showImage(const QImage &image); + +Q_SIGNALS: + void surfaceChanged(QAbstractVideoSurface *surface); + +private: + QPointer m_surface; + QImage m_image; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/qmedianetworkaccesscontrol.cpp b/src/multimediakit/qmedianetworkaccesscontrol.cpp new file mode 100644 index 000000000..e5bdc840f --- /dev/null +++ b/src/multimediakit/qmedianetworkaccesscontrol.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmedianetworkaccesscontrol.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaNetworkAccessControl + \preliminary + \brief The QMediaNetworkAccessControl class allows the setting of the Network Access Point for media related activities. + \ingroup multimedia + \inmodule QtMultimediaKit + \since 1.2 + + The functionality provided by this control allows the + setting of a Network Access Point. + + This control can be used to set a network access for various + network related activities. the exact nature in dependant on the underlying + usage by the supported QMediaObject +*/ + +QMediaNetworkAccessControl::QMediaNetworkAccessControl(QObject *parent) : + QMediaControl(parent) +{ +} + +/*! + Destroys a network access control. +*/ +QMediaNetworkAccessControl::~QMediaNetworkAccessControl() +{ +} + +/*! + \fn void QMediaNetworkAccessControl::setConfigurations(const QList &configurations); + + \a configurations contains a list of network configurations to be used for network access. + + It is assumed the list is given in highest to lowest preference order. + By calling this function all previous configurations will be invalidated + and replaced with the new list. + \since 1.2 +*/ + +/* + \fn QNetworkConfiguration QMediaNetworkAccessControl::currentConfiguration() const + + Returns the current active configuration in use. + A default constructed QNetworkConfigration is returned if no user supplied configuration are in use. +*/ + + +/*! + \fn QMediaNetworkAccessControl::configurationChanged(const QNetworkConfiguration &configuration) + This signal is emitted when the current active network configuration changes + to \a configuration. + \since 1.2 +*/ + + + +#include "moc_qmedianetworkaccesscontrol.cpp" +QT_END_NAMESPACE diff --git a/src/multimediakit/qmedianetworkaccesscontrol.h b/src/multimediakit/qmedianetworkaccesscontrol.h new file mode 100644 index 000000000..65d693bb9 --- /dev/null +++ b/src/multimediakit/qmedianetworkaccesscontrol.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMEDIANETWORKACCESSCONTROL_H +#define QMEDIANETWORKACCESSCONTROL_H + +#include "qmediacontrol.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QMediaNetworkAccessControl : public QMediaControl +{ + Q_OBJECT +public: + + virtual ~QMediaNetworkAccessControl(); + + virtual void setConfigurations(const QList &configuration) = 0; + virtual QNetworkConfiguration currentConfiguration() const = 0; + +Q_SIGNALS: + void configurationChanged(const QNetworkConfiguration& configuration); + +protected: + QMediaNetworkAccessControl(QObject *parent = 0); +}; + +#define QMediaNetworkAccessControl_iid "com.nokia.Qt.QMediaNetworkAccessControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaNetworkAccessControl, QMediaNetworkAccessControl_iid) + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/qmediaobject.cpp b/src/multimediakit/qmediaobject.cpp new file mode 100644 index 000000000..a3c9007c5 --- /dev/null +++ b/src/multimediakit/qmediaobject.cpp @@ -0,0 +1,427 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "qmediaobject_p.h" + +#include +#include +#include + + +QT_BEGIN_NAMESPACE + +void QMediaObjectPrivate::_q_notify() +{ + Q_Q(QMediaObject); + + const QMetaObject* m = q->metaObject(); + + foreach (int pi, notifyProperties) { + QMetaProperty p = m->property(pi); + p.notifySignal().invoke( + q, QGenericArgument(QMetaType::typeName(p.userType()), p.read(q).data())); + } +} + + +/*! + \class QMediaObject + + \brief The QMediaObject class provides a common base for multimedia objects. + + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + XXX why do I care + + QMediaObject derived classes provide access to the functionality of a + QMediaService. Each media object hosts a QMediaService and uses the + QMediaControl interfaces implemented by the service to implement its + API. Most media objects when constructed will request a new + QMediaService instance from a QMediaServiceProvider, but some like + QMediaRecorder will share a service with another object. + + QMediaObject itself provides an API for accessing a media + service's \l {metaData()}{meta-data} and a means of connecting other media objects, + and peripheral classes like QVideoWidget and QMediaPlaylist. + + \sa QMediaService, QMediaControl +*/ + +/*! + Destroys this media object. +*/ + +QMediaObject::~QMediaObject() +{ + delete d_ptr; +} + +/*! + Returns the service availability error state. + \since 1.0 +*/ + +QtMultimediaKit::AvailabilityError QMediaObject::availabilityError() const +{ + return d_func()->service == 0 ? QtMultimediaKit::ServiceMissingError : QtMultimediaKit::NoError; +} + +/*! + Returns true if the service is available for use. + \since 1.0 +*/ + +bool QMediaObject::isAvailable() const +{ + return d_func()->service != 0; +} + +/*! + Returns the media service that provides the functionality of this multimedia object. + \since 1.0 +*/ + +QMediaService* QMediaObject::service() const +{ + return d_func()->service; +} + +int QMediaObject::notifyInterval() const +{ + return d_func()->notifyTimer->interval(); +} + +void QMediaObject::setNotifyInterval(int milliSeconds) +{ + Q_D(QMediaObject); + + if (d->notifyTimer->interval() != milliSeconds) { + d->notifyTimer->setInterval(milliSeconds); + + emit notifyIntervalChanged(milliSeconds); + } +} + +/*! + Bind \a object to this QMediaObject instance. + + This method establishes a relationship between this media object and a + helper object. The nature of the relationship depends on both parties. This + methods returns true if the helper was successfully bound, false otherwise. + + Most subclasses of QMediaObject provide more convenient functions + that wrap this functionality, so this function rarely needs to be + called directly. + + XXX for example + + The object passed must implement the QMediaBindableInterface interface. + + \since 1.0 + \sa QMediaBindableInterface +*/ +bool QMediaObject::bind(QObject *object) +{ + QMediaBindableInterface *helper = qobject_cast(object); + if (!helper) + return false; + + QMediaObject *currentObject = helper->mediaObject(); + + if (currentObject == this) + return true; + + if (currentObject) + currentObject->unbind(object); + + return helper->setMediaObject(this); +} + +/*! + Detach \a object from the QMediaObject instance. + + Unbind the helper object from this media object. A warning + will be generated if the object was not previously bound to this + object. + + \since 1.0 + \sa QMediaBindableInterface +*/ +void QMediaObject::unbind(QObject *object) +{ + QMediaBindableInterface *helper = qobject_cast(object); + + if (helper && helper->mediaObject() == this) + helper->setMediaObject(0); + else + qWarning() << "QMediaObject: Trying to unbind not connected helper object"; +} + +/*! + Constructs a media object which uses the functionality provided by a media \a service. + + The \a parent is passed to QObject. + + This class is meant as a base class for multimedia objects so this + constructor is protected. + \since 1.0 +*/ + +QMediaObject::QMediaObject(QObject *parent, QMediaService *service): + QObject(parent), + d_ptr(new QMediaObjectPrivate) + +{ + Q_D(QMediaObject); + + d->q_ptr = this; + + d->notifyTimer = new QTimer(this); + d->notifyTimer->setInterval(1000); + connect(d->notifyTimer, SIGNAL(timeout()), SLOT(_q_notify())); + + d->service = service; + + setupMetaData(); +} + +/*! + \internal +*/ + +QMediaObject::QMediaObject(QMediaObjectPrivate &dd, QObject *parent, + QMediaService *service): + QObject(parent), + d_ptr(&dd) +{ + Q_D(QMediaObject); + d->q_ptr = this; + + d->notifyTimer = new QTimer(this); + d->notifyTimer->setInterval(1000); + connect(d->notifyTimer, SIGNAL(timeout()), SLOT(_q_notify())); + + d->service = service; + + setupMetaData(); +} + +/*! + Watch the property \a name. The property's notify signal will be emitted + once every \code notifyInterval milliseconds. + + \since 1.0 + \sa notifyInterval +*/ + +void QMediaObject::addPropertyWatch(QByteArray const &name) +{ + Q_D(QMediaObject); + + const QMetaObject* m = metaObject(); + + int index = m->indexOfProperty(name.constData()); + + if (index != -1 && m->property(index).hasNotifySignal()) { + d->notifyProperties.insert(index); + + if (!d->notifyTimer->isActive()) + d->notifyTimer->start(); + } +} + +/*! + Remove property \a name from the list of properties whose changes are + regularly signaled. + + \since 1.0 + \sa notifyInterval +*/ + +void QMediaObject::removePropertyWatch(QByteArray const &name) +{ + Q_D(QMediaObject); + + int index = metaObject()->indexOfProperty(name.constData()); + + if (index != -1) { + d->notifyProperties.remove(index); + + if (d->notifyProperties.isEmpty()) + d->notifyTimer->stop(); + } +} + +/*! + \property QMediaObject::notifyInterval + + The interval at which notifiable properties will update. + + The interval is expressed in milliseconds, the default value is 1000. + + \since 1.0 + \sa addPropertyWatch(), removePropertyWatch() +*/ + +/*! + \fn void QMediaObject::notifyIntervalChanged(int milliseconds) + + Signal a change in the notify interval period to \a milliseconds. + \since 1.0 +*/ + +/*! + Returns true if there is meta-data associated with this media object, else false. + \since 1.0 +*/ + +bool QMediaObject::isMetaDataAvailable() const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->isMetaDataAvailable() + : false; +} + +/*! + \fn QMediaObject::metaDataAvailableChanged(bool available) + + Signals that the \a available state of a media object's meta-data has changed. + \since 1.0 +*/ + +/*! + Returns the value associated with a meta-data \a key. + \since 1.0 +*/ +QVariant QMediaObject::metaData(QtMultimediaKit::MetaData key) const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->metaData(key) + : QVariant(); +} + +/*! + Returns a list of keys there is meta-data available for. + \since 1.0 +*/ +QList QMediaObject::availableMetaData() const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->availableMetaData() + : QList(); +} + +/*! + \fn QMediaObject::metaDataChanged() + + Signals that this media object's meta-data has changed. + \since 1.0 +*/ + +/*! + Returns the value associated with a meta-data \a key. + + The naming and type of extended meta-data is not standardized, so the values and meaning + of keys may vary between backends. + \since 1.0 +*/ +QVariant QMediaObject::extendedMetaData(const QString &key) const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->extendedMetaData(key) + : QVariant(); +} + +/*! + Returns a list of keys there is extended meta-data available for. + \since 1.0 +*/ +QStringList QMediaObject::availableExtendedMetaData() const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->availableExtendedMetaData() + : QStringList(); +} + + +void QMediaObject::setupMetaData() +{ + Q_D(QMediaObject); + + if (d->service != 0) { + d->metaDataControl = qobject_cast( + d->service->requestControl(QMetaDataReaderControl_iid)); + + if (d->metaDataControl) { + connect(d->metaDataControl, SIGNAL(metaDataChanged()), SIGNAL(metaDataChanged())); + connect(d->metaDataControl, + SIGNAL(metaDataAvailableChanged(bool)), + SIGNAL(metaDataAvailableChanged(bool))); + } + } +} + +/*! + \fn QMediaObject::availabilityChanged(bool available) + + Signal emitted when the availability state has changed to \a available + \since 1.0 +*/ + + +#include "moc_qmediaobject.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediaobject.h b/src/multimediakit/qmediaobject.h new file mode 100644 index 000000000..604544b6b --- /dev/null +++ b/src/multimediakit/qmediaobject.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTMEDIAOBJECT_H +#define QABSTRACTMEDIAOBJECT_H + +#include +#include + +#include +#include "qtmedianamespace.h" + +QT_BEGIN_NAMESPACE + +class QMediaService; +class QMediaBindableInterface; + +class QMediaObjectPrivate; +class Q_MULTIMEDIA_EXPORT QMediaObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(int notifyInterval READ notifyInterval WRITE setNotifyInterval NOTIFY notifyIntervalChanged) +public: + ~QMediaObject(); + + virtual bool isAvailable() const; + virtual QtMultimediaKit::AvailabilityError availabilityError() const; + + virtual QMediaService* service() const; + + int notifyInterval() const; + void setNotifyInterval(int milliSeconds); + + virtual bool bind(QObject *); + virtual void unbind(QObject *); + + bool isMetaDataAvailable() const; + + QVariant metaData(QtMultimediaKit::MetaData key) const; + QList availableMetaData() const; + + QVariant extendedMetaData(const QString &key) const; + QStringList availableExtendedMetaData() const; + +Q_SIGNALS: + void notifyIntervalChanged(int milliSeconds); + + void metaDataAvailableChanged(bool available); + void metaDataChanged(); + + void availabilityChanged(bool available); + +protected: + QMediaObject(QObject *parent, QMediaService *service); + QMediaObject(QMediaObjectPrivate &dd, QObject *parent, QMediaService *service); + + void addPropertyWatch(QByteArray const &name); + void removePropertyWatch(QByteArray const &name); + + QMediaObjectPrivate *d_ptr; + +private: + void setupMetaData(); + + Q_DECLARE_PRIVATE(QMediaObject) + Q_PRIVATE_SLOT(d_func(), void _q_notify()) +}; + + +QT_END_NAMESPACE + +#endif // QABSTRACTMEDIAOBJECT_H diff --git a/src/multimediakit/qmediaobject_p.h b/src/multimediakit/qmediaobject_p.h new file mode 100644 index 000000000..a0d307227 --- /dev/null +++ b/src/multimediakit/qmediaobject_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTMEDIAOBJECT_P_H +#define QABSTRACTMEDIAOBJECT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +#include "qmediaobject.h" + +QT_BEGIN_NAMESPACE + +class QMetaDataReaderControl; + +#define Q_DECLARE_NON_CONST_PUBLIC(Class) \ + inline Class* q_func() { return static_cast(q_ptr); } \ + friend class Class; + + +class QMediaObjectPrivate +{ + Q_DECLARE_PUBLIC(QMediaObject) + +public: + QMediaObjectPrivate():metaDataControl(0), notifyTimer(0) {} + virtual ~QMediaObjectPrivate() {} + + void _q_notify(); + + QMediaService *service; + QMetaDataReaderControl *metaDataControl; + QTimer* notifyTimer; + QSet notifyProperties; + + QMediaObject *q_ptr; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/qmediaplayer.cpp b/src/multimediakit/qmediaplayer.cpp new file mode 100644 index 000000000..be3825861 --- /dev/null +++ b/src/multimediakit/qmediaplayer.cpp @@ -0,0 +1,1134 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + + +#include "qmediaplayer.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaPlayer + \brief The QMediaPlayer class allows the playing of a media source. + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + + + The QMediaPlayer class is a high level media playback class. It can be used + to playback such content as songs, movies and internet radio. The content + to playback is specified as a QMediaContent, which can be thought of as a + main or canonical URL with addition information attached. When provided + with a QMediaContent playback may be able to commence. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Player + + QVideoWidget can be used with QMediaPlayer for video rendering and QMediaPlaylist + for accessing playlist functionality. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Movie playlist + + \sa QMediaObject, QMediaService, QVideoWidget, QMediaPlaylist +*/ + +namespace +{ +class MediaPlayerRegisterMetaTypes +{ +public: + MediaPlayerRegisterMetaTypes() + { + qRegisterMetaType("QMediaPlayer::State"); + qRegisterMetaType("QMediaPlayer::MediaStatus"); + qRegisterMetaType("QMediaPlayer::Error"); + } +} _registerPlayerMetaTypes; +} + +class QMediaPlayerPrivate : public QMediaObjectPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QMediaPlayer) + +public: + QMediaPlayerPrivate() + : provider(0) + , control(0) + , playlistSourceControl(0) + , state(QMediaPlayer::StoppedState) + , error(QMediaPlayer::NoError) + , filterStates(false) + , playlist(0) + {} + + QMediaServiceProvider *provider; + QMediaPlayerControl* control; + QMediaPlaylistSourceControl* playlistSourceControl; + QMediaPlayer::State state; + QMediaPlayer::Error error; + QString errorString; + bool filterStates; + + QPointer videoOutput; + QMediaPlaylist *playlist; + QMediaNetworkAccessControl *networkAccessControl; + QVideoSurfaceOutput surfaceOutput; + + void _q_stateChanged(QMediaPlayer::State state); + void _q_mediaStatusChanged(QMediaPlayer::MediaStatus status); + void _q_error(int error, const QString &errorString); + void _q_updateMedia(const QMediaContent&); + void _q_playlistDestroyed(); +}; + +void QMediaPlayerPrivate::_q_stateChanged(QMediaPlayer::State ps) +{ + Q_Q(QMediaPlayer); + + if (filterStates) + return; + + if (playlist + && ps != state && ps == QMediaPlayer::StoppedState + && (control->mediaStatus() == QMediaPlayer::EndOfMedia || + control->mediaStatus() == QMediaPlayer::InvalidMedia)) { + playlist->next(); + ps = control->state(); + } + + if (ps != state) { + state = ps; + + if (ps == QMediaPlayer::PlayingState) + q->addPropertyWatch("position"); + else + q->removePropertyWatch("position"); + + emit q->stateChanged(ps); + } +} + +void QMediaPlayerPrivate::_q_mediaStatusChanged(QMediaPlayer::MediaStatus status) +{ + Q_Q(QMediaPlayer); + + switch (status) { + case QMediaPlayer::StalledMedia: + case QMediaPlayer::BufferingMedia: + q->addPropertyWatch("bufferStatus"); + emit q->mediaStatusChanged(status); + break; + default: + q->removePropertyWatch("bufferStatus"); + emit q->mediaStatusChanged(status); + break; + } + +} + +void QMediaPlayerPrivate::_q_error(int error, const QString &errorString) +{ + Q_Q(QMediaPlayer); + + this->error = QMediaPlayer::Error(error); + this->errorString = errorString; + + emit q->error(this->error); +} + +void QMediaPlayerPrivate::_q_updateMedia(const QMediaContent &media) +{ + Q_Q(QMediaPlayer); + + if (!control) + return; + + const QMediaPlayer::State currentState = state; + + filterStates = true; + control->setMedia(media, 0); + + if (!media.isNull()) { + switch (currentState) { + case QMediaPlayer::PlayingState: + control->play(); + break; + case QMediaPlayer::PausedState: + control->pause(); + break; + default: + break; + } + } + filterStates = false; + + state = control->state(); + + if (state != currentState) { + if (state == QMediaPlayer::PlayingState) + q->addPropertyWatch("position"); + else + q->removePropertyWatch("position"); + + emit q->stateChanged(state); + } +} + +void QMediaPlayerPrivate::_q_playlistDestroyed() +{ + playlist = 0; + + if (!control) + return; + + if (playlistSourceControl) + playlistSourceControl->setPlaylist(0); + + control->setMedia(QMediaContent(), 0); +} + +static QMediaService *playerService(QMediaPlayer::Flags flags, QMediaServiceProvider *provider) +{ + if (flags) { + QMediaServiceProviderHint::Features features = 0; + if (flags & QMediaPlayer::LowLatency) + features |= QMediaServiceProviderHint::LowLatencyPlayback; + + if (flags & QMediaPlayer::StreamPlayback) + features |= QMediaServiceProviderHint::StreamPlayback; + + if (flags & QMediaPlayer::VideoSurface) + features |= QMediaServiceProviderHint::VideoSurface; + + return provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER, + QMediaServiceProviderHint(features)); + } else + return provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER); +} + + +/*! + Construct a QMediaPlayer that uses the playback service from \a provider, + parented to \a parent and with \a flags. + + If a playback service is not specified the system default will be used. + \since 1.0 +*/ + +QMediaPlayer::QMediaPlayer(QObject *parent, QMediaPlayer::Flags flags, QMediaServiceProvider *provider): + QMediaObject(*new QMediaPlayerPrivate, + parent, + playerService(flags,provider)) +{ + Q_D(QMediaPlayer); + + d->provider = provider; + + if (d->service == 0) { + d->error = ServiceMissingError; + } else { + d->control = qobject_cast(d->service->requestControl(QMediaPlayerControl_iid)); + d->playlistSourceControl = qobject_cast(d->service->requestControl(QMediaPlaylistSourceControl_iid)); + d->networkAccessControl = qobject_cast(d->service->requestControl(QMediaNetworkAccessControl_iid)); + if (d->control != 0) { + connect(d->control, SIGNAL(mediaChanged(QMediaContent)), SIGNAL(mediaChanged(QMediaContent))); + connect(d->control, SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(_q_stateChanged(QMediaPlayer::State))); + connect(d->control, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + SLOT(_q_mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(d->control, SIGNAL(error(int,QString)), SLOT(_q_error(int,QString))); + + connect(d->control, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged(qint64))); + connect(d->control, SIGNAL(positionChanged(qint64)), SIGNAL(positionChanged(qint64))); + connect(d->control, SIGNAL(audioAvailableChanged(bool)), SIGNAL(audioAvailableChanged(bool))); + connect(d->control, SIGNAL(videoAvailableChanged(bool)), SIGNAL(videoAvailableChanged(bool))); + connect(d->control, SIGNAL(volumeChanged(int)), SIGNAL(volumeChanged(int))); + connect(d->control, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged(bool))); + connect(d->control, SIGNAL(seekableChanged(bool)), SIGNAL(seekableChanged(bool))); + connect(d->control, SIGNAL(playbackRateChanged(qreal)), SIGNAL(playbackRateChanged(qreal))); + connect(d->control, SIGNAL(bufferStatusChanged(int)), SIGNAL(bufferStatusChanged(int))); + + if (d->control->state() == PlayingState) + addPropertyWatch("position"); + + if (d->control->mediaStatus() == StalledMedia || d->control->mediaStatus() == BufferingMedia) + addPropertyWatch("bufferStatus"); + } + if (d->networkAccessControl != 0) { + connect(d->networkAccessControl, SIGNAL(configurationChanged(QNetworkConfiguration)), + this, SIGNAL(networkConfigurationChanged(QNetworkConfiguration))); + } + } +} + + +/*! + Destroys the player object. +*/ + +QMediaPlayer::~QMediaPlayer() +{ + Q_D(QMediaPlayer); + + if (d->service) { + if (d->control) + d->service->releaseControl(d->control); + } + + d->provider->releaseService(d->service); +} + +QMediaContent QMediaPlayer::media() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->media(); + + return QMediaContent(); +} + +/*! + Returns the stream source of media data. + + This is only valid if a stream was passed to setMedia(). + + \since 1.0 + \sa setMedia() +*/ + +const QIODevice *QMediaPlayer::mediaStream() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->mediaStream(); + + return 0; +} + +QMediaPlaylist *QMediaPlayer::playlist() const +{ + return d_func()->playlistSourceControl ? + d_func()->playlistSourceControl->playlist() : + d_func()->playlist; +} + +void QMediaPlayer::setPlaylist(QMediaPlaylist *playlist) +{ + Q_D(QMediaPlayer); + + if (d->playlistSourceControl) { + if (d->playlistSourceControl->playlist()) + disconnect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed())); + + d->playlistSourceControl->setPlaylist(playlist); + + if (playlist) + connect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed())); + } else { + if (d->playlist) { + disconnect(d->playlist, SIGNAL(currentMediaChanged(QMediaContent)), + this, SLOT(_q_updateMedia(QMediaContent))); + disconnect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed())); + } + + d->playlist = playlist; + + if (d->playlist) { + connect(d->playlist, SIGNAL(currentMediaChanged(QMediaContent)), + this, SLOT(_q_updateMedia(QMediaContent))); + connect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed())); + + if (d->control != 0) + d->control->setMedia(playlist->currentMedia(), 0); + } else { + setMedia(QMediaContent(), 0); + } + + } +} + +/*! + Sets the network access points for remote media playback. + \a configurations contains, in ascending preferential order, a list of + configuration that can be used for network access. + + This will invalidate the choice of previous configurations. + \since 1.2 +*/ +void QMediaPlayer::setNetworkConfigurations(const QList &configurations) +{ + Q_D(QMediaPlayer); + + if (d->networkAccessControl) + d->networkAccessControl->setConfigurations(configurations); +} + +QMediaPlayer::State QMediaPlayer::state() const +{ + return d_func()->state; +} + +QMediaPlayer::MediaStatus QMediaPlayer::mediaStatus() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->mediaStatus(); + + return QMediaPlayer::UnknownMediaStatus; +} + +qint64 QMediaPlayer::duration() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->duration(); + + return -1; +} + +qint64 QMediaPlayer::position() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->position(); + + return 0; +} + +int QMediaPlayer::volume() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->volume(); + + return 0; +} + +bool QMediaPlayer::isMuted() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->isMuted(); + + return false; +} + +int QMediaPlayer::bufferStatus() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->bufferStatus(); + + return 0; +} + +bool QMediaPlayer::isAudioAvailable() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->isAudioAvailable(); + + return false; +} + +bool QMediaPlayer::isVideoAvailable() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->isVideoAvailable(); + + return false; +} + +bool QMediaPlayer::isSeekable() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->isSeekable(); + + return false; +} + +qreal QMediaPlayer::playbackRate() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->playbackRate(); + + return 0.0; +} + +/*! + Returns the current error state. + \since 1.0 +*/ + +QMediaPlayer::Error QMediaPlayer::error() const +{ + return d_func()->error; +} + +QString QMediaPlayer::errorString() const +{ + return d_func()->errorString; +} + +/*! + Returns the current network access point in use. + If a default contructed QNetworkConfiguration is returned + this feature is not available or that none of the + current supplied configurations are in use. + \since 1.2 +*/ +QNetworkConfiguration QMediaPlayer::currentNetworkConfiguration() const +{ + Q_D(const QMediaPlayer); + + if (d->networkAccessControl) + return d_func()->networkAccessControl->currentConfiguration(); + + return QNetworkConfiguration(); +} + +//public Q_SLOTS: +/*! + Start or resume playing the current source. + \since 1.0 +*/ + +void QMediaPlayer::play() +{ + Q_D(QMediaPlayer); + + if (d->control == 0) { + QMetaObject::invokeMethod(this, "_q_error", Qt::QueuedConnection, + Q_ARG(int, QMediaPlayer::ServiceMissingError), + Q_ARG(QString, tr("The QMediaPlayer object does not have a valid service"))); + return; + } + + //if playlist control is available, the service should advance itself + if (d->playlist && d->playlist->currentIndex() == -1 && !d->playlist->isEmpty()) + d->playlist->setCurrentIndex(0); + + // Reset error conditions + d->error = NoError; + d->errorString = QString(); + + d->control->play(); +} + +/*! + Pause playing the current source. + \since 1.0 +*/ + +void QMediaPlayer::pause() +{ + Q_D(QMediaPlayer); + + if (d->control != 0) + d->control->pause(); +} + +/*! + Stop playing, and reset the play position to the beginning. + \since 1.0 +*/ + +void QMediaPlayer::stop() +{ + Q_D(QMediaPlayer); + + if (d->control != 0) + d->control->stop(); +} + +void QMediaPlayer::setPosition(qint64 position) +{ + Q_D(QMediaPlayer); + + if (d->control == 0 || !isSeekable()) + return; + + d->control->setPosition(qBound(qint64(0), position, duration())); +} + +void QMediaPlayer::setVolume(int v) +{ + Q_D(QMediaPlayer); + + if (d->control == 0) + return; + + int clamped = qBound(0, v, 100); + if (clamped == volume()) + return; + + d->control->setVolume(clamped); +} + +void QMediaPlayer::setMuted(bool muted) +{ + Q_D(QMediaPlayer); + + if (d->control == 0 || muted == isMuted()) + return; + + d->control->setMuted(muted); +} + +void QMediaPlayer::setPlaybackRate(qreal rate) +{ + Q_D(QMediaPlayer); + + if (d->control != 0) + d->control->setPlaybackRate(rate); +} + +/*! + Sets the current \a media source. + + If a \a stream is supplied; media data will be read from it instead of resolving the media + source. In this case the media source may still be used to resolve additional information + about the media such as mime type. + + Setting the media to a null QMediaContent will cause the player to discard all + information relating to the current media source and to cease all I/O operations related + to that media. + \since 1.0 +*/ + +void QMediaPlayer::setMedia(const QMediaContent &media, QIODevice *stream) +{ + Q_D(QMediaPlayer); + + if (playlist() && playlist()->currentMedia() != media) + setPlaylist(0); + + if (d->control != 0) + d_func()->control->setMedia(media, stream); +} + +/*! + \internal + \since 1.0 +*/ + +bool QMediaPlayer::bind(QObject *obj) +{ + return QMediaObject::bind(obj); +} + +/*! + \internal + \since 1.0 +*/ + +void QMediaPlayer::unbind(QObject *obj) +{ + QMediaObject::unbind(obj); +} + +/*! + Returns the level of support a media player has for a \a mimeType and a set of \a codecs. + + The \a flags argument allows additional requirements such as performance indicators to be + specified. + \since 1.0 +*/ +QtMultimediaKit::SupportEstimate QMediaPlayer::hasSupport(const QString &mimeType, + const QStringList& codecs, + Flags flags) +{ + return QMediaServiceProvider::defaultServiceProvider()->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), + mimeType, + codecs, + flags); +} + +/*! + \deprecated + Returns a list of MIME types supported by the media player. + + The \a flags argument causes the resultant list to be restricted to MIME types which can be supported + given additional requirements, such as performance indicators. + + This function may not return useful results on some platforms, and support for a specific file of a + given mime type is not guaranteed even if the mime type is in general supported. In addition, in some + cases this function will need to load all available media plugins and query them for their support, which + may take some time. + \since 1.0 +*/ +QStringList QMediaPlayer::supportedMimeTypes(Flags flags) +{ + return QMediaServiceProvider::defaultServiceProvider()->supportedMimeTypes(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), + flags); +} + +/*! + \fn void QMediaPlayer::setVideoOutput(QVideoWidget* output) + + Attach a QVideoWidget video \a output to the media player. + + If the media player has already video output attached, + it will be replaced with a new one. + \since 1.0 +*/ +void QMediaPlayer::setVideoOutput(QVideoWidget *output) +{ + Q_D(QMediaPlayer); + + if (d->videoOutput) + unbind(d->videoOutput); + + d->videoOutput = output && bind(output) ? output : 0; +} + +/*! + \fn void QMediaPlayer::setVideoOutput(QGraphicsVideoItem* output) + + Attach a QGraphicsVideoItem video \a output to the media player. + + If the media player has already video output attached, + it will be replaced with a new one. + \since 1.0 +*/ +void QMediaPlayer::setVideoOutput(QGraphicsVideoItem *output) +{ + Q_D(QMediaPlayer); + + if (d->videoOutput) + unbind(d->videoOutput); + + d->videoOutput = output && bind(output) ? output : 0; +} + +/*! + Sets a video \a surface as the video output of a media player. + + If a video output has already been set on the media player the new surface + will replace it. + \since 1.2 +*/ + +void QMediaPlayer::setVideoOutput(QAbstractVideoSurface *surface) +{ + Q_D(QMediaPlayer); + + d->surfaceOutput.setVideoSurface(surface); + + if (d->videoOutput != &d->surfaceOutput) { + if (d->videoOutput) + unbind(d->videoOutput); + + d->videoOutput = bind(&d->surfaceOutput) ? &d->surfaceOutput : 0; + } +} + +// Enums +/*! + \enum QMediaPlayer::State + + Defines the current state of a media player. + + \value PlayingState The media player is currently playing content. + \value PausedState The media player has paused playback, playback of the current track will + resume from the position the player was paused at. + \value StoppedState The media player is not playing content, playback will begin from the start + of the current track. +*/ + +/*! + \enum QMediaPlayer::MediaStatus + + Defines the status of a media player's current media. + + \value UnknownMediaStatus The status of the media cannot be determined. + \value NoMedia The is no current media. The player is in the StoppedState. + \value LoadingMedia The current media is being loaded. The player may be in any state. + \value LoadedMedia The current media has been loaded. The player is in the StoppedState. + \value StalledMedia Playback of the current media has stalled due to insufficient buffering or + some other temporary interruption. The player is in the PlayingState or PausedState. + \value BufferingMedia The player is buffering data but has enough data buffered for playback to + continue for the immediate future. The player is in the PlayingState or PausedState. + \value BufferedMedia The player has fully buffered the current media. The player is in the + PlayingState or PausedState. + \value EndOfMedia Playback has reached the end of the current media. The player is in the + StoppedState. + \value InvalidMedia The current media cannot be played. The player is in the StoppedState. +*/ + +/*! + \enum QMediaPlayer::Error + + Defines a media player error condition. + + \value NoError No error has occurred. + \value ResourceError A media resource couldn't be resolved. + \value FormatError The format of a media resource isn't (fully) supported. Playback may still + be possible, but without an audio or video component. + \value NetworkError A network error occurred. + \value AccessDeniedError There are not the appropriate permissions to play a media resource. + \value ServiceMissingError A valid playback service was not found, playback cannot proceed. +*/ + +// Signals +/*! + \fn QMediaPlayer::error(QMediaPlayer::Error error) + + Signals that an \a error condition has occurred. + + \since 1.0 + \sa errorString() +*/ + +/*! + \fn void QMediaPlayer::stateChanged(State state) + + \since 1.0 + Signal the \a state of the Player object has changed. +*/ + +/*! + \fn QMediaPlayer::mediaStatusChanged(QMediaPlayer::MediaStatus status) + + Signals that the \a status of the current media has changed. + + \since 1.0 + \sa mediaStatus() +*/ + +/*! + \fn void QMediaPlayer::mediaChanged(const QMediaContent &media); + + Signals that the current playing content will be obtained from \a media. + + \since 1.0 + \sa media() +*/ + +/*! + \fn void QMediaPlayer::playbackRateChanged(qreal rate); + + Signals the playbackRate has changed to \a rate. + \since 1.0 +*/ + +/*! + \fn void QMediaPlayer::seekableChanged(bool seekable); + + Signals the \a seekable status of the player object has changed. + \since 1.0 +*/ + +// Properties +/*! + \property QMediaPlayer::state + \brief the media player's playback state. + + By default this property is QMediaPlayer::Stopped + + \since 1.0 + \sa mediaStatus(), play(), pause(), stop() +*/ + +/*! + \property QMediaPlayer::error + \brief a string describing the last error condition. + + \since 1.0 + \sa error() +*/ + +/*! + \property QMediaPlayer::media + \brief the active media source being used by the player object. + + The player object will use the QMediaContent for selection of the content to + be played. + + By default this property has a null QMediaContent. + + Setting this property to a null QMediaContent will cause the player to discard all + information relating to the current media source and to cease all I/O operations related + to that media. + + \since 1.0 + \sa QMediaContent +*/ + +/*! + \property QMediaPlayer::playlist + \brief the media playlist being used by the player object. + + The player object will use the current playlist item for selection of the content to + be played. + + By default this property is set to null. + + If the media playlist is used as a source, QMediaPlayer::media is updated with + a current playlist item. The current source should be selected with + QMediaPlaylist::setCurrentIndex(int) instead of QMediaPlayer::setMedia(), + otherwise the current playlist will be discarded. + + \since 1.0 + \sa QMediaContent +*/ + + +/*! + \property QMediaPlayer::mediaStatus + \brief the status of the current media stream. + + The stream status describes how the playback of the current stream is + progressing. + + By default this property is QMediaPlayer::NoMedia + + \since 1.0 + \sa state +*/ + +/*! + \property QMediaPlayer::duration + \brief the duration of the current media. + + The value is the total playback time in milliseconds of the current media. + The value may change across the life time of the QMediaPlayer object and + may not be available when initial playback begins, connect to the + durationChanged() signal to receive status notifications. + \since 1.0 +*/ + +/*! + \property QMediaPlayer::position + \brief the playback position of the current media. + + The value is the current playback position, expressed in milliseconds since + the beginning of the media. Periodically changes in the position will be + indicated with the signal positionChanged(), the interval between updates + can be set with QMediaObject's method setNotifyInterval(). + \since 1.0 +*/ + +/*! + \property QMediaPlayer::volume + \brief the current playback volume. + + The playback volume is a linear in effect and the value can range from 0 - + 100, values outside this range will be clamped. + \since 1.0 +*/ + +/*! + \property QMediaPlayer::muted + \brief the muted state of the current media. + + The value will be true if the playback volume is muted; otherwise false. + \since 1.0 +*/ + +/*! + \property QMediaPlayer::bufferStatus + \brief the percentage of the temporary buffer filled before playback begins. + + When the player object is buffering; this property holds the percentage of + the temporary buffer that is filled. The buffer will need to reach 100% + filled before playback can resume, at which time the MediaStatus will be + BufferedMedia. + + \since 1.0 + \sa mediaStatus() +*/ + +/*! + \property QMediaPlayer::audioAvailable + \brief the audio availabilty status for the current media. + + As the life time of QMediaPlayer can be longer than the playback of one + QMediaContent, this property may change over time, the + audioAvailableChanged signal can be used to monitor it's status. + \since 1.0 +*/ + +/*! + \property QMediaPlayer::videoAvailable + \brief the video availability status for the current media. + + If available, the QVideoWidget class can be used to view the video. As the + life time of QMediaPlayer can be longer than the playback of one + QMediaContent, this property may change over time, the + videoAvailableChanged signal can be used to monitor it's status. + + \since 1.0 + \sa QVideoWidget, QMediaContent +*/ + +/*! + \property QMediaPlayer::seekable + \brief the seek-able status of the current media + + If seeking is supported this property will be true; false otherwise. The + status of this property may change across the life time of the QMediaPlayer + object, use the seekableChanged signal to monitor changes. + \since 1.0 +*/ + +/*! + \property QMediaPlayer::playbackRate + \brief the playback rate of the current media. + + This value is a multiplier applied to the media's standard play rate. By + default this value is 1.0, indicating that the media is playing at the + standard pace. Values higher than 1.0 will increase the rate of play. + Values less than zero can be set and indicate the media will rewind at the + multiplier of the standard pace. + + Not all playback services support change of the playback rate. It is + framework defined as to the status and quality of audio and video + while fast forwarding or rewinding. + \since 1.0 +*/ + +/*! + \fn void QMediaPlayer::durationChanged(qint64 duration) + + Signal the duration of the content has changed to \a duration, expressed in milliseconds. + \since 1.0 +*/ + +/*! + \fn void QMediaPlayer::positionChanged(qint64 position) + + Signal the position of the content has changed to \a position, expressed in + milliseconds. + \since 1.0 +*/ + +/*! + \fn void QMediaPlayer::volumeChanged(int volume) + + Signal the playback volume has changed to \a volume. + \since 1.0 +*/ + +/*! + \fn void QMediaPlayer::mutedChanged(bool muted) + + Signal the mute state has changed to \a muted. + \since 1.0 +*/ + +/*! + \fn void QMediaPlayer::videoAvailableChanged(bool videoAvailable) + + Signal the availability of visual content has changed to \a videoAvailable. + \since 1.0 +*/ + +/*! + \fn void QMediaPlayer::audioAvailableChanged(bool available) + + Signals the availability of audio content has changed to \a available. + \since 1.0 +*/ + +/*! + \fn void QMediaPlayer::bufferStatusChanged(int percentFilled) + + Signal the amount of the local buffer filled as a percentage by \a percentFilled. + \since 1.0 +*/ + +/*! + \fn void QMediaPlayer::networkConfigurationChanged(const QNetworkConfiguration &configuration) + + Signal that the active in use network access point has been changed to \a configuration and all subsequent network access will use this \a configuration. + \since 1.2 +*/ + +/*! + \enum QMediaPlayer::Flag + + \value LowLatency The player is expected to be used with simple audio formats, + but playback should start without significant delay. + Such playback service can be used for beeps, ringtones, etc. + + \value StreamPlayback The player is expected to play QIODevice based streams. + If passed to QMediaPlayer constructor, the service supporting + streams playback will be chosen. + + \value VideoSurface The player is expected to be able to render to a + QAbstractVideoSurface \l {setVideoOutput()}{output}. +*/ + +#include "moc_qmediaplayer.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediaplayer.h b/src/multimediakit/qmediaplayer.h new file mode 100644 index 000000000..444edb9ef --- /dev/null +++ b/src/multimediakit/qmediaplayer.h @@ -0,0 +1,224 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYER_H +#define QMEDIAPLAYER_H + + +#include "qmediaserviceprovider.h" +#include "qmediaobject.h" +#include "qmediacontent.h" +#include "qmediaenumdebug.h" + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QAbstractVideoSurface; +class QMediaPlaylist; +class QVideoWidget; +class QGraphicsVideoItem; + +class QMediaPlayerPrivate; +class Q_MULTIMEDIA_EXPORT QMediaPlayer : public QMediaObject +{ + Q_OBJECT + Q_PROPERTY(QMediaContent media READ media WRITE setMedia NOTIFY mediaChanged) + Q_PROPERTY(QMediaPlaylist * playlist READ playlist WRITE setPlaylist) + Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged) + Q_PROPERTY(qint64 position READ position WRITE setPosition NOTIFY positionChanged) + Q_PROPERTY(int volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) + Q_PROPERTY(int bufferStatus READ bufferStatus NOTIFY bufferStatusChanged) + Q_PROPERTY(bool audioAvailable READ isAudioAvailable NOTIFY audioAvailableChanged) + Q_PROPERTY(bool videoAvailable READ isVideoAvailable NOTIFY videoAvailableChanged) + Q_PROPERTY(bool seekable READ isSeekable NOTIFY seekableChanged) + 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(QString error READ errorString) + Q_ENUMS(State) + Q_ENUMS(MediaStatus) + Q_ENUMS(Error) + +public: + enum State + { + StoppedState, + PlayingState, + PausedState + }; + + enum MediaStatus + { + UnknownMediaStatus, + NoMedia, + LoadingMedia, + LoadedMedia, + StalledMedia, + BufferingMedia, + BufferedMedia, + EndOfMedia, + InvalidMedia + }; + + enum Flag + { + LowLatency = 0x01, + StreamPlayback = 0x02, + VideoSurface = 0x04 + }; + Q_DECLARE_FLAGS(Flags, Flag) + + enum Error + { + NoError, + ResourceError, + FormatError, + NetworkError, + AccessDeniedError, + ServiceMissingError + }; + + QMediaPlayer(QObject *parent = 0, Flags flags = 0, QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider()); + ~QMediaPlayer(); + + static QtMultimediaKit::SupportEstimate hasSupport(const QString &mimeType, + const QStringList& codecs = QStringList(), + Flags flags = 0); + static QStringList supportedMimeTypes(Flags flags = 0); + + void setVideoOutput(QVideoWidget *); + void setVideoOutput(QGraphicsVideoItem *); + void setVideoOutput(QAbstractVideoSurface *surface); + + QMediaContent media() const; + const QIODevice *mediaStream() const; + QMediaPlaylist *playlist() const; + + State state() const; + MediaStatus mediaStatus() const; + + qint64 duration() const; + qint64 position() const; + + int volume() const; + bool isMuted() const; + bool isAudioAvailable() const; + bool isVideoAvailable() const; + + int bufferStatus() const; + + bool isSeekable() const; + qreal playbackRate() const; + + Error error() const; + QString errorString() const; + + QNetworkConfiguration currentNetworkConfiguration() const; + +public Q_SLOTS: + void play(); + void pause(); + void stop(); + + void setPosition(qint64 position); + void setVolume(int volume); + void setMuted(bool muted); + + void setPlaybackRate(qreal rate); + + void setMedia(const QMediaContent &media, QIODevice *stream = 0); + void setPlaylist(QMediaPlaylist *playlist); + + void setNetworkConfigurations(const QList &configurations); + +Q_SIGNALS: + void mediaChanged(const QMediaContent &media); + + void stateChanged(QMediaPlayer::State newState); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + + void durationChanged(qint64 duration); + void positionChanged(qint64 position); + + void volumeChanged(int volume); + void mutedChanged(bool muted); + void audioAvailableChanged(bool available); + void videoAvailableChanged(bool videoAvailable); + + void bufferStatusChanged(int percentFilled); + + void seekableChanged(bool seekable); + void playbackRateChanged(qreal rate); + + void error(QMediaPlayer::Error error); + + void networkConfigurationChanged(const QNetworkConfiguration &configuration); +public: + virtual bool bind(QObject *); + virtual void unbind(QObject *); + +private: + Q_DISABLE_COPY(QMediaPlayer) + Q_DECLARE_PRIVATE(QMediaPlayer) + Q_PRIVATE_SLOT(d_func(), void _q_stateChanged(QMediaPlayer::State)) + Q_PRIVATE_SLOT(d_func(), void _q_mediaStatusChanged(QMediaPlayer::MediaStatus)) + Q_PRIVATE_SLOT(d_func(), void _q_error(int, const QString &)) + Q_PRIVATE_SLOT(d_func(), void _q_updateMedia(const QMediaContent&)) + Q_PRIVATE_SLOT(d_func(), void _q_playlistDestroyed()) +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QMediaPlayer::State) +Q_DECLARE_METATYPE(QMediaPlayer::MediaStatus) +Q_DECLARE_METATYPE(QMediaPlayer::Error) + +Q_MEDIA_ENUM_DEBUG(QMediaPlayer, State) +Q_MEDIA_ENUM_DEBUG(QMediaPlayer, MediaStatus) +Q_MEDIA_ENUM_DEBUG(QMediaPlayer, Error) + +QT_END_HEADER + +#endif // QMEDIAPLAYER_H diff --git a/src/multimediakit/qmediaplayercontrol.cpp b/src/multimediakit/qmediaplayercontrol.cpp new file mode 100644 index 000000000..255a63438 --- /dev/null +++ b/src/multimediakit/qmediaplayercontrol.cpp @@ -0,0 +1,414 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaplayercontrol.h" +#include "qmediacontrol_p.h" +#include "qmediaplayer.h" + +QT_BEGIN_NAMESPACE + + +/*! + \class QMediaPlayerControl + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + + \brief The QMediaPlayerControl class provides access to the media playing + functionality of a QMediaService. + + If a QMediaService can play media is will implement QMediaPlayerControl. + This control provides a means to set the \l {setMedia()}{media} to play, + \l {play()}{start}, \l {pause()} {pause} and \l {stop()}{stop} playback, + \l {setPosition()}{seek}, and control the \l {setVolume()}{volume}. + It also provides feedback on the \l {duration()}{duration} of the media, + the current \l {position()}{position}, and \l {bufferStatus()}{buffering} + progress. + + The functionality provided by this control is exposed to application + code through the QMediaPlayer class. + + The interface name of QMediaPlayerControl is \c com.nokia.Qt.QMediaPlayerControl/1.0 as + defined in QMediaPlayerControl_iid. + + \sa QMediaService::requestControl(), QMediaPlayer +*/ + +/*! + \macro QMediaPlayerControl_iid + + \c com.nokia.Qt.QMediaPlayerControl/1.0 + + Defines the interface name of the QMediaPlayerControl class. + + \relates QMediaPlayerControl +*/ + +/*! + Destroys a media player control. +*/ +QMediaPlayerControl::~QMediaPlayerControl() +{ +} + +/*! + Constructs a new media player control with the given \a parent. +*/ +QMediaPlayerControl::QMediaPlayerControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + \fn QMediaPlayerControl::state() const + + Returns the state of a player control. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::stateChanged(QMediaPlayer::State state) + + Signals that the \a state of a player control has changed. + + \since 1.0 + \sa state() +*/ + +/*! + \fn QMediaPlayerControl::mediaStatus() const + + Returns the status of the current media. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::mediaStatusChanged(QMediaPlayer::MediaStatus status) + + Signals that the \a status of the current media has changed. + + \since 1.0 + \sa mediaStatus() +*/ + + +/*! + \fn QMediaPlayerControl::duration() const + + Returns the duration of the current media in milliseconds. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::durationChanged(qint64 duration) + + Signals that the \a duration of the current media has changed. + + \since 1.0 + \sa duration() +*/ + +/*! + \fn QMediaPlayerControl::position() const + + Returns the current playback position in milliseconds. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::setPosition(qint64 position) + + Sets the playback \a position of the current media. This will initiate a seek and it may take + some time for playback to reach the position set. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::positionChanged(qint64 position) + + Signals the playback \a position has changed. + + This is only emitted in when there has been a discontinous change in the playback postion, such + as a seek or the position being reset. + + \since 1.0 + \sa position() +*/ + +/*! + \fn QMediaPlayerControl::volume() const + + Returns the audio volume of a player control. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::setVolume(int volume) + + Sets the audio \a volume of a player control. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::volumeChanged(int volume) + + Signals the audio \a volume of a player control has changed. + + \since 1.0 + \sa volume() +*/ + +/*! + \fn QMediaPlayerControl::isMuted() const + + Returns the mute state of a player control. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::setMuted(bool mute) + + Sets the \a mute state of a player control. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::mutedChanged(bool mute) + + Signals a change in the \a mute status of a player control. + + \since 1.0 + \sa isMuted() +*/ + +/*! + \fn QMediaPlayerControl::bufferStatus() const + + Returns the buffering progress of the current media. Progress is measured in the percentage + of the buffer filled. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::bufferStatusChanged(int progress) + + Signals that buffering \a progress has changed. + + \since 1.0 + \sa bufferStatus() +*/ + +/*! + \fn QMediaPlayerControl::isAudioAvailable() const + + Identifies if there is audio output available for the current media. + + Returns true if audio output is available and false otherwise. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::audioAvailableChanged(bool audio) + + Signals that there has been a change in the availability of \a audio output. + + \since 1.0 + \sa isAudioAvailable() +*/ + +/*! + \fn QMediaPlayerControl::isVideoAvailable() const + + Identifies if there is video output available for the current media. + + Returns true if video output is available and false otherwise. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::videoAvailableChanged(bool video) + + Signals that there has been a change in the availability of \a video output. + + \since 1.0 + \sa isVideoAvailable() +*/ + +/*! + \fn QMediaPlayerControl::isSeekable() const + + Identifies if the current media is seekable. + + Returns true if it possible to seek within the current media, and false otherwise. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::seekableChanged(bool seekable) + + Signals that the \a seekable state of a player control has changed. + + \since 1.0 + \sa isSeekable() +*/ + +/*! + \fn QMediaPlayerControl::availablePlaybackRanges() const + + Returns a range of times in milliseconds that can be played back. + + Usually for local files this is a continuous interval equal to [0..duration()] + or an empty time range if seeking is not supported, but for network sources + it refers to the buffered parts of the media. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::availablePlaybackRangesChanged(const QMediaTimeRange &ranges) + + Signals that the available media playback \a ranges have changed. + + \since 1.0 + \sa QMediaPlayerControl::availablePlaybackRanges() +*/ + +/*! + \fn qreal QMediaPlayerControl::playbackRate() const + + Returns the rate of playback. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::setPlaybackRate(qreal rate) + + Sets the \a rate of playback. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::media() const + + Returns the current media source. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::mediaStream() const + + Returns the current media stream. This is only a valid if a stream was passed to setMedia(). + + \since 1.0 + \sa setMedia() +*/ + +/*! + \fn QMediaPlayerControl::setMedia(const QMediaContent &media, QIODevice *stream) + + Sets the current \a media source. If a \a stream is supplied; data will be read from that + instead of attempting to resolve the media source. The media source may still be used to + supply media information such as mime type. + + Setting the media to a null QMediaContent will cause the control to discard all + information relating to the current media source and to cease all I/O operations related + to that media. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::mediaChanged(const QMediaContent& content) + + Signals that the current media \a content has changed. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::play() + + Starts playback of the current media. + + If successful the player control will immediately enter the \l {QMediaPlayer::PlayingState} + {playing} state. + + \since 1.0 + \sa state() +*/ + +/*! + \fn QMediaPlayerControl::pause() + + Pauses playback of the current media. + + If sucessful the player control will immediately enter the \l {QMediaPlayer::PausedState} + {paused} state. + + \since 1.0 + \sa state(), play(), stop() +*/ + +/*! + \fn QMediaPlayerControl::stop() + + Stops playback of the current media. + + If successful the player control will immediately enter the \l {QMediaPlayer::StoppedState} + {stopped} state. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::error(int error, const QString &errorString) + + Signals that an \a error has occurred. The \a errorString provides a more detailed explanation. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::playbackRateChanged(qreal rate) + + Signal emitted when playback rate changes to \a rate. + \since 1.0 +*/ + +#include "moc_qmediaplayercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediaplayercontrol.h b/src/multimediakit/qmediaplayercontrol.h new file mode 100644 index 000000000..842371c62 --- /dev/null +++ b/src/multimediakit/qmediaplayercontrol.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYERCONTROL_H +#define QMEDIAPLAYERCONTROL_H + +#include "qmediacontrol.h" +#include "qmediaplayer.h" +#include "qmediatimerange.h" + +#include + +QT_BEGIN_NAMESPACE + +class QMediaPlaylist; + +class Q_MULTIMEDIA_EXPORT QMediaPlayerControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QMediaPlayerControl(); + + virtual QMediaPlayer::State state() const = 0; + + virtual QMediaPlayer::MediaStatus mediaStatus() const = 0; + + virtual qint64 duration() const = 0; + + virtual qint64 position() const = 0; + virtual void setPosition(qint64 position) = 0; + + virtual int volume() const = 0; + virtual void setVolume(int volume) = 0; + + virtual bool isMuted() const = 0; + virtual void setMuted(bool muted) = 0; + + virtual int bufferStatus() const = 0; + + virtual bool isAudioAvailable() const = 0; + virtual bool isVideoAvailable() const = 0; + + virtual bool isSeekable() const = 0; + + virtual QMediaTimeRange availablePlaybackRanges() const = 0; + + virtual qreal playbackRate() const = 0; + virtual void setPlaybackRate(qreal rate) = 0; + + virtual QMediaContent media() const = 0; + virtual const QIODevice *mediaStream() const = 0; + virtual void setMedia(const QMediaContent &media, QIODevice *stream) = 0; + + virtual void play() = 0; + virtual void pause() = 0; + virtual void stop() = 0; + +Q_SIGNALS: + void mediaChanged(const QMediaContent& content); + void durationChanged(qint64 duration); + void positionChanged(qint64 position); + void stateChanged(QMediaPlayer::State newState); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void audioAvailableChanged(bool audioAvailable); + void videoAvailableChanged(bool videoAvailable); + void bufferStatusChanged(int percentFilled); + void seekableChanged(bool); + void availablePlaybackRangesChanged(const QMediaTimeRange&); + void playbackRateChanged(qreal rate); + void error(int error, const QString &errorString); + +protected: + QMediaPlayerControl(QObject* parent = 0); +}; + +#define QMediaPlayerControl_iid "com.nokia.Qt.QMediaPlayerControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaPlayerControl, QMediaPlayerControl_iid) + +QT_END_NAMESPACE + +#endif // QMEDIAPLAYERCONTROL_H + diff --git a/src/multimediakit/qmediaplaylist.cpp b/src/multimediakit/qmediaplaylist.cpp new file mode 100644 index 000000000..93a91847a --- /dev/null +++ b/src/multimediakit/qmediaplaylist.cpp @@ -0,0 +1,756 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaplaylist.h" +#include "qmediaplaylist_p.h" +#include "qmediaplaylistprovider.h" +#include "qlocalmediaplaylistprovider.h" +#include "qmediaplaylistioplugin.h" +#include "qmediaservice.h" +#include "qmediaplaylistcontrol.h" +#include "qmediaplayercontrol.h" + +#include +#include +#include +#include +#include + +#include "qmediapluginloader_p.h" + +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC_WITH_ARGS(QMediaPluginLoader, playlistIOLoader, + (QMediaPlaylistIOInterface_iid, QLatin1String("playlistformats"), Qt::CaseInsensitive)) + + +/*! + \class QMediaPlaylist + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + + \brief The QMediaPlaylist class provides a list of media content to play. + + QMediaPlaylist is intended to be used with other media objects, + like QMediaPlayer or QMediaImageViewer. + + QMediaPlaylist allows to access the service intrinsic playlist functionality + if available, otherwise it provides the the local memory playlist implementation. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Movie playlist + + Depending on playlist source implementation, most of the playlist mutating + operations can be asynchronous. + + \sa QMediaContent +*/ + + +/*! + \enum QMediaPlaylist::PlaybackMode + + The QMediaPlaylist::PlaybackMode describes the order items in playlist are played. + + \value CurrentItemOnce The current item is played only once. + + \value CurrentItemInLoop The current item is played repeatedly in a loop. + + \value Sequential Playback starts from the current and moves through each successive item until the last is reached and then stops. + The next item is a null item when the last one is currently playing. + + \value Loop Playback restarts at the first item after the last has finished playing. + + \value Random Play items in random order. +*/ + + + +/*! + Create a new playlist object for with the given \a parent. +*/ + +QMediaPlaylist::QMediaPlaylist(QObject *parent) + : QObject(parent) + , d_ptr(new QMediaPlaylistPrivate) +{ + Q_D(QMediaPlaylist); + + d->q_ptr = this; + d->localPlaylistControl = new QLocalMediaPlaylistControl(this); + + setMediaObject(0); +} + +/*! + Destroys the playlist. + */ + +QMediaPlaylist::~QMediaPlaylist() +{ + Q_D(QMediaPlaylist); + + if (d->mediaObject) + d->mediaObject->unbind(this); + + delete d_ptr; +} + +/*! + Returns the QMediaObject instance that this QMediaPlaylist is bound too, + or 0 otherwise. + \since 1.0 +*/ +QMediaObject *QMediaPlaylist::mediaObject() const +{ + return d_func()->mediaObject; +} + +/*! + \internal + If \a mediaObject is null or doesn't have an intrinsic playlist, + internal local memory playlist source will be created. + \since 1.0 +*/ +bool QMediaPlaylist::setMediaObject(QMediaObject *mediaObject) +{ + Q_D(QMediaPlaylist); + + if (mediaObject && mediaObject == d->mediaObject) + return true; + + QMediaService *service = mediaObject + ? mediaObject->service() : 0; + + QMediaPlaylistControl *newControl = 0; + + if (service) + newControl = qobject_cast(service->requestControl(QMediaPlaylistControl_iid)); + + if (!newControl) + newControl = d->localPlaylistControl; + + if (d->control != newControl) { + int oldSize = 0; + 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))); + + disconnect(playlist, SIGNAL(mediaChanged(int,int)), this, SIGNAL(mediaChanged(int,int))); + disconnect(playlist, SIGNAL(mediaAboutToBeInserted(int,int)), this, SIGNAL(mediaAboutToBeInserted(int,int))); + disconnect(playlist, SIGNAL(mediaInserted(int,int)), this, SIGNAL(mediaInserted(int,int))); + disconnect(playlist, SIGNAL(mediaAboutToBeRemoved(int,int)), this, SIGNAL(mediaAboutToBeRemoved(int,int))); + disconnect(playlist, SIGNAL(mediaRemoved(int,int)), this, SIGNAL(mediaRemoved(int,int))); + + disconnect(playlist, SIGNAL(loaded()), this, SIGNAL(loaded())); + + disconnect(d->control, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)), + this, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode))); + disconnect(d->control, SIGNAL(currentIndexChanged(int)), + this, SIGNAL(currentIndexChanged(int))); + disconnect(d->control, SIGNAL(currentMediaChanged(QMediaContent)), + this, SIGNAL(currentMediaChanged(QMediaContent))); + + if (d->mediaObject) + d->mediaObject->service()->releaseControl(d->control); + } + + d->control = newControl; + QMediaPlaylistProvider *playlist = d->control->playlistProvider(); + connect(playlist, SIGNAL(loadFailed(QMediaPlaylist::Error,QString)), + this, SLOT(_q_loadFailed(QMediaPlaylist::Error,QString))); + + connect(playlist, SIGNAL(mediaChanged(int,int)), this, SIGNAL(mediaChanged(int,int))); + connect(playlist, SIGNAL(mediaAboutToBeInserted(int,int)), this, SIGNAL(mediaAboutToBeInserted(int,int))); + connect(playlist, SIGNAL(mediaInserted(int,int)), this, SIGNAL(mediaInserted(int,int))); + connect(playlist, SIGNAL(mediaAboutToBeRemoved(int,int)), this, SIGNAL(mediaAboutToBeRemoved(int,int))); + connect(playlist, SIGNAL(mediaRemoved(int,int)), this, SIGNAL(mediaRemoved(int,int))); + + connect(playlist, SIGNAL(loaded()), this, SIGNAL(loaded())); + + connect(d->control, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)), + this, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode))); + connect(d->control, SIGNAL(currentIndexChanged(int)), + this, SIGNAL(currentIndexChanged(int))); + connect(d->control, SIGNAL(currentMediaChanged(QMediaContent)), + this, SIGNAL(currentMediaChanged(QMediaContent))); + + if (oldSize) + emit mediaRemoved(0, oldSize-1); + + if (playlist->mediaCount()) { + emit mediaAboutToBeInserted(0,playlist->mediaCount()-1); + emit mediaInserted(0,playlist->mediaCount()-1); + } + } + + d->mediaObject = mediaObject; + + return true; +} + +/*! + \property QMediaPlaylist::playbackMode + + This property defines the order, items in playlist are played. + + \since 1.0 + \sa QMediaPlaylist::PlaybackMode +*/ + +QMediaPlaylist::PlaybackMode QMediaPlaylist::playbackMode() const +{ + return d_func()->control->playbackMode(); +} + +void QMediaPlaylist::setPlaybackMode(QMediaPlaylist::PlaybackMode mode) +{ + Q_D(QMediaPlaylist); + d->control->setPlaybackMode(mode); +} + +/*! + Returns position of the current media content in the playlist. + \since 1.0 +*/ +int QMediaPlaylist::currentIndex() const +{ + return d_func()->control->currentIndex(); +} + +/*! + Returns the current media content. + \since 1.0 +*/ + +QMediaContent QMediaPlaylist::currentMedia() const +{ + return d_func()->playlist()->media(currentIndex()); +} + +/*! + Returns the index of the item, which would be current after calling next() + \a steps times. + + Returned value depends on the size of playlist, current position + and playback mode. + + \since 1.0 + \sa QMediaPlaylist::playbackMode +*/ +int QMediaPlaylist::nextIndex(int steps) const +{ + return d_func()->control->nextIndex(steps); +} + +/*! + Returns the index of the item, which would be current after calling previous() + \a steps times. + + \since 1.0 + \sa QMediaPlaylist::playbackMode +*/ + +int QMediaPlaylist::previousIndex(int steps) const +{ + return d_func()->control->previousIndex(steps); +} + + +/*! + Returns the number of items in the playlist. + + \since 1.0 + \sa isEmpty() + */ +int QMediaPlaylist::mediaCount() const +{ + return d_func()->playlist()->mediaCount(); +} + +/*! + Returns true if the playlist contains no items; otherwise returns false. + + \since 1.0 + \sa mediaCount() + */ +bool QMediaPlaylist::isEmpty() const +{ + return mediaCount() == 0; +} + +/*! + Returns true if the playlist can be modified; otherwise returns false. + + \since 1.0 + \sa mediaCount() + */ +bool QMediaPlaylist::isReadOnly() const +{ + return d_func()->playlist()->isReadOnly(); +} + +/*! + Returns the media content at \a index in the playlist. + \since 1.0 +*/ + +QMediaContent QMediaPlaylist::media(int index) const +{ + return d_func()->playlist()->media(index); +} + +/*! + Append the media \a content to the playlist. + + Returns true if the operation is successful, otherwise return false. + \since 1.0 + */ +bool QMediaPlaylist::addMedia(const QMediaContent &content) +{ + return d_func()->control->playlistProvider()->addMedia(content); +} + +/*! + Append multiple media content \a items to the playlist. + + Returns true if the operation is successful, otherwise return false. + \since 1.0 + */ +bool QMediaPlaylist::addMedia(const QList &items) +{ + return d_func()->control->playlistProvider()->addMedia(items); +} + +/*! + Insert the media \a content to the playlist at position \a pos. + + Returns true if the operation is successful, otherwise false. + \since 1.0 +*/ + +bool QMediaPlaylist::insertMedia(int pos, const QMediaContent &content) +{ + return d_func()->playlist()->insertMedia(pos, content); +} + +/*! + Insert multiple media content \a items to the playlist at position \a pos. + + Returns true if the operation is successful, otherwise false. + \since 1.0 +*/ + +bool QMediaPlaylist::insertMedia(int pos, const QList &items) +{ + return d_func()->playlist()->insertMedia(pos, items); +} + +/*! + Remove the item from the playlist at position \a pos. + + Returns true if the operation is successful, otherwise return false. + \since 1.0 + */ +bool QMediaPlaylist::removeMedia(int pos) +{ + Q_D(QMediaPlaylist); + return d->playlist()->removeMedia(pos); +} + +/*! + Remove items in the playlist from \a start to \a end inclusive. + + Returns true if the operation is successful, otherwise return false. + \since 1.0 + */ +bool QMediaPlaylist::removeMedia(int start, int end) +{ + Q_D(QMediaPlaylist); + return d->playlist()->removeMedia(start, end); +} + +/*! + Remove all the items from the playlist. + + Returns true if the operation is successful, otherwise return false. + \since 1.0 + */ +bool QMediaPlaylist::clear() +{ + Q_D(QMediaPlaylist); + return d->playlist()->clear(); +} + +bool QMediaPlaylistPrivate::readItems(QMediaPlaylistReader *reader) +{ + while (!reader->atEnd()) + playlist()->addMedia(reader->readItem()); + + return true; +} + +bool QMediaPlaylistPrivate::writeItems(QMediaPlaylistWriter *writer) +{ + for (int i=0; imediaCount(); i++) { + if (!writer->writeItem(playlist()->media(i))) + return false; + } + writer->close(); + return true; +} + +/*! + Load playlist from \a location. If \a format is specified, it is used, + otherwise format is guessed from location name and data. + + New items are appended to playlist. + + QMediaPlaylist::loaded() signal is emitted if playlist was loaded successfully, + otherwise the playlist emits loadFailed(). + \since 1.0 +*/ +void QMediaPlaylist::load(const QUrl &location, const char *format) +{ + Q_D(QMediaPlaylist); + + d->error = NoError; + d->errorString.clear(); + + if (d->playlist()->load(location,format)) + return; + + if (isReadOnly()) { + d->error = AccessDeniedError; + d->errorString = tr("Could not add items to read only playlist."); + emit loadFailed(); + return; + } + + foreach (QString const& key, playlistIOLoader()->keys()) { + QMediaPlaylistIOInterface* plugin = qobject_cast(playlistIOLoader()->instance(key)); + if (plugin && plugin->canRead(location,format)) { + QMediaPlaylistReader *reader = plugin->createReader(location,QByteArray(format)); + if (reader && d->readItems(reader)) { + delete reader; + emit loaded(); + return; + } + delete reader; + } + } + + d->error = FormatNotSupportedError; + d->errorString = tr("Playlist format is not supported"); + emit loadFailed(); + + return; +} + +/*! + Load playlist from QIODevice \a device. If \a format is specified, it is used, + otherwise format is guessed from device data. + + New items are appended to playlist. + + QMediaPlaylist::loaded() signal is emitted if playlist was loaded successfully, + otherwise the playlist emits loadFailed(). + \since 1.0 +*/ +void QMediaPlaylist::load(QIODevice * device, const char *format) +{ + Q_D(QMediaPlaylist); + + d->error = NoError; + d->errorString.clear(); + + if (d->playlist()->load(device,format)) + return; + + if (isReadOnly()) { + d->error = AccessDeniedError; + d->errorString = tr("Could not add items to read only playlist."); + emit loadFailed(); + return; + } + + foreach (QString const& key, playlistIOLoader()->keys()) { + QMediaPlaylistIOInterface* plugin = qobject_cast(playlistIOLoader()->instance(key)); + if (plugin && plugin->canRead(device,format)) { + QMediaPlaylistReader *reader = plugin->createReader(device,QByteArray(format)); + if (reader && d->readItems(reader)) { + delete reader; + emit loaded(); + return; + } + delete reader; + } + } + + d->error = FormatNotSupportedError; + d->errorString = tr("Playlist format is not supported"); + emit loadFailed(); + + return; +} + +/*! + Save playlist to \a location. If \a format is specified, it is used, + otherwise format is guessed from location name. + + Returns true if playlist was saved successfully, otherwise returns false. + \since 1.0 + */ +bool QMediaPlaylist::save(const QUrl &location, const char *format) +{ + Q_D(QMediaPlaylist); + + d->error = NoError; + d->errorString.clear(); + + if (d->playlist()->save(location,format)) + return true; + + QFile file(location.toLocalFile()); + + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + d->error = AccessDeniedError; + d->errorString = tr("The file could not be accessed."); + return false; + } + + return save(&file, format); +} + +/*! + Save playlist to QIODevice \a device using format \a format. + + Returns true if playlist was saved successfully, otherwise returns false. + \since 1.0 +*/ +bool QMediaPlaylist::save(QIODevice * device, const char *format) +{ + Q_D(QMediaPlaylist); + + d->error = NoError; + d->errorString.clear(); + + if (d->playlist()->save(device,format)) + return true; + + foreach (QString const& key, playlistIOLoader()->keys()) { + QMediaPlaylistIOInterface* plugin = qobject_cast(playlistIOLoader()->instance(key)); + if (plugin && plugin->canWrite(device,format)) { + QMediaPlaylistWriter *writer = plugin->createWriter(device,QByteArray(format)); + if (writer && d->writeItems(writer)) { + delete writer; + return true; + } + delete writer; + } + } + + d->error = FormatNotSupportedError; + d->errorString = tr("Playlist format is not supported."); + + return false; +} + +/*! + Returns the last error condition. + \since 1.0 +*/ +QMediaPlaylist::Error QMediaPlaylist::error() const +{ + return d_func()->error; +} + +/*! + Returns the string describing the last error condition. + \since 1.0 +*/ +QString QMediaPlaylist::errorString() const +{ + return d_func()->errorString; +} + +/*! + Shuffle items in the playlist. + \since 1.0 +*/ +void QMediaPlaylist::shuffle() +{ + d_func()->playlist()->shuffle(); +} + + +/*! + Advance to the next media content in playlist. + \since 1.0 +*/ +void QMediaPlaylist::next() +{ + d_func()->control->next(); +} + +/*! + Return to the previous media content in playlist. + \since 1.0 +*/ +void QMediaPlaylist::previous() +{ + d_func()->control->previous(); +} + +/*! + Activate media content from playlist at position \a playlistPosition. + \since 1.0 +*/ + +void QMediaPlaylist::setCurrentIndex(int playlistPosition) +{ + d_func()->control->setCurrentIndex(playlistPosition); +} + +/*! + \fn void QMediaPlaylist::mediaInserted(int start, int end) + + This signal is emitted after media has been inserted into the playlist. + The new items are those between \a start and \a end inclusive. + \since 1.0 + */ + +/*! + \fn void QMediaPlaylist::mediaRemoved(int start, int end) + + This signal is emitted after media has been removed from the playlist. + The removed items are those between \a start and \a end inclusive. + \since 1.0 + */ + +/*! + \fn void QMediaPlaylist::mediaChanged(int start, int end) + + This signal is emitted after media has been changed in the playlist + between \a start and \a end positions inclusive. + \since 1.0 + */ + +/*! + \fn void QMediaPlaylist::currentIndexChanged(int position) + + Signal emitted when playlist position changed to \a position. + \since 1.0 +*/ + +/*! + \fn void QMediaPlaylist::playbackModeChanged(QMediaPlaylist::PlaybackMode mode) + + Signal emitted when playback mode changed to \a mode. + \since 1.0 +*/ + +/*! + \fn void QMediaPlaylist::mediaAboutToBeInserted(int start, int end) + + Signal emitted when items are to be inserted at \a start and ending at \a end. + \since 1.0 +*/ + +/*! + \fn void QMediaPlaylist::mediaAboutToBeRemoved(int start, int end) + + Signal emitted when item are to be deleted at \a start and ending at \a end. + \since 1.0 +*/ + +/*! + \fn void QMediaPlaylist::currentMediaChanged(const QMediaContent &content) + + Signal emitted when current media changes to \a content. + \since 1.0 +*/ + +/*! + \property QMediaPlaylist::currentIndex + \brief Current position. + \since 1.0 +*/ + +/*! + \property QMediaPlaylist::currentMedia + \brief Current media content. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylist::loaded() + + Signal emitted when playlist finished loading. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylist::loadFailed() + + Signal emitted if failed to load playlist. + \since 1.0 +*/ + +/*! + \enum QMediaPlaylist::Error + + This enum describes the QMediaPlaylist error codes. + + \value NoError No errors. + \value FormatError Format error. + \value FormatNotSupportedError Format not supported. + \value NetworkError Network error. + \value AccessDeniedError Access denied error. +*/ + +#include "moc_qmediaplaylist.cpp" +#include "moc_qmediaplaylist_p.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediaplaylist.h b/src/multimediakit/qmediaplaylist.h new file mode 100644 index 000000000..4e82c5fae --- /dev/null +++ b/src/multimediakit/qmediaplaylist.h @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYLIST_H +#define QMEDIAPLAYLIST_H + +#include + +#include +#include +#include +#include + + +QT_BEGIN_NAMESPACE + +class QMediaPlaylistProvider; + +class QMediaPlaylistPrivate; +class Q_MULTIMEDIA_EXPORT QMediaPlaylist : public QObject, public QMediaBindableInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaBindableInterface) + Q_PROPERTY(QMediaPlaylist::PlaybackMode playbackMode READ playbackMode WRITE setPlaybackMode NOTIFY playbackModeChanged) + Q_PROPERTY(QMediaContent currentMedia READ currentMedia NOTIFY currentMediaChanged) + Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) + Q_ENUMS(PlaybackMode Error) + +public: + enum PlaybackMode { CurrentItemOnce, CurrentItemInLoop, Sequential, Loop, Random }; + enum Error { NoError, FormatError, FormatNotSupportedError, NetworkError, AccessDeniedError }; + + QMediaPlaylist(QObject *parent = 0); + virtual ~QMediaPlaylist(); + + QMediaObject *mediaObject() const; + + PlaybackMode playbackMode() const; + void setPlaybackMode(PlaybackMode mode); + + int currentIndex() const; + QMediaContent currentMedia() const; + + int nextIndex(int steps = 1) const; + int previousIndex(int steps = 1) const; + + QMediaContent media(int index) const; + + int mediaCount() const; + bool isEmpty() const; + bool isReadOnly() const; + + bool addMedia(const QMediaContent &content); + bool addMedia(const QList &items); + bool insertMedia(int index, const QMediaContent &content); + bool insertMedia(int index, const QList &items); + bool removeMedia(int pos); + bool removeMedia(int start, int end); + bool clear(); + + void load(const QUrl &location, const char *format = 0); + void load(QIODevice * device, const char *format = 0); + + bool save(const QUrl &location, const char *format = 0); + bool save(QIODevice * device, const char *format); + + Error error() const; + QString errorString() const; + +public Q_SLOTS: + void shuffle(); + + void next(); + void previous(); + + void setCurrentIndex(int index); + +Q_SIGNALS: + void currentIndexChanged(int index); + void playbackModeChanged(QMediaPlaylist::PlaybackMode mode); + void currentMediaChanged(const QMediaContent&); + + void mediaAboutToBeInserted(int start, int end); + void mediaInserted(int start, int end); + void mediaAboutToBeRemoved(int start, int end); + void mediaRemoved(int start, int end); + void mediaChanged(int start, int end); + + void loaded(); + void loadFailed(); + +protected: + bool setMediaObject(QMediaObject *object); + QMediaPlaylistPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QMediaPlaylist) + Q_PRIVATE_SLOT(d_func(), void _q_loadFailed(QMediaPlaylist::Error, const QString &)) +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QMediaPlaylist::PlaybackMode) +Q_DECLARE_METATYPE(QMediaPlaylist::Error) + +Q_MEDIA_ENUM_DEBUG(QMediaPlaylist, PlaybackMode) +Q_MEDIA_ENUM_DEBUG(QMediaPlaylist, Error) + +#endif // QMEDIAPLAYLIST_H diff --git a/src/multimediakit/qmediaplaylist_p.h b/src/multimediakit/qmediaplaylist_p.h new file mode 100644 index 000000000..d029a68d4 --- /dev/null +++ b/src/multimediakit/qmediaplaylist_p.h @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYLIST_P_H +#define QMEDIAPLAYLIST_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmediaplaylist.h" +#include "qmediaplaylistcontrol.h" +#include "qmediaplayer.h" +#include "qmediaplayercontrol.h" +#include "qlocalmediaplaylistprovider.h" +#include "qmediaobject_p.h" + +#include + +#ifdef Q_MOC_RUN +# pragma Q_MOC_EXPAND_MACROS +#endif + +QT_BEGIN_NAMESPACE + +class QMediaPlaylistControl; +class QMediaPlaylistProvider; +class QMediaPlaylistReader; +class QMediaPlaylistWriter; +class QMediaPlayerControl; + +class QMediaPlaylistPrivate +{ + Q_DECLARE_PUBLIC(QMediaPlaylist) +public: + QMediaPlaylistPrivate() + :mediaObject(0), + control(0), + localPlaylistControl(0), + error(QMediaPlaylist::NoError) + { + } + + virtual ~QMediaPlaylistPrivate() {} + + void _q_loadFailed(QMediaPlaylist::Error error, const QString &errorString) + { + this->error = error; + this->errorString = errorString; + + emit q_ptr->loadFailed(); + } + + void _q_mediaObjectDeleted() + { + Q_Q(QMediaPlaylist); + mediaObject = 0; + if (control != localPlaylistControl) + control = 0; + q->setMediaObject(0); + } + + QMediaObject *mediaObject; + + QMediaPlaylistControl *control; + QMediaPlaylistProvider *playlist() const { return control->playlistProvider(); } + + QMediaPlaylistControl *localPlaylistControl; + + bool readItems(QMediaPlaylistReader *reader); + bool writeItems(QMediaPlaylistWriter *writer); + + QMediaPlaylist::Error error; + QString errorString; + + QMediaPlaylist *q_ptr; +}; + + +class QLocalMediaPlaylistControl : public QMediaPlaylistControl +{ + Q_OBJECT +public: + QLocalMediaPlaylistControl(QObject *parent) + :QMediaPlaylistControl(parent) + { + QMediaPlaylistProvider *playlist = new QLocalMediaPlaylistProvider(this); + m_navigator = new QMediaPlaylistNavigator(playlist,this); + m_navigator->setPlaybackMode(QMediaPlaylist::Sequential); + + connect(m_navigator, SIGNAL(currentIndexChanged(int)), SIGNAL(currentIndexChanged(int))); + connect(m_navigator, SIGNAL(activated(QMediaContent)), SIGNAL(currentMediaChanged(QMediaContent))); + connect(m_navigator, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)), SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode))); + } + + virtual ~QLocalMediaPlaylistControl() {}; + + QMediaPlaylistProvider* playlistProvider() const { return m_navigator->playlist(); } + bool setPlaylistProvider(QMediaPlaylistProvider *mediaPlaylist) + { + m_navigator->setPlaylist(mediaPlaylist); + emit playlistProviderChanged(); + return true; + } + + int currentIndex() const { return m_navigator->currentIndex(); } + void setCurrentIndex(int position) { m_navigator->jump(position); } + int nextIndex(int steps) const { return m_navigator->nextIndex(steps); } + int previousIndex(int steps) const { return m_navigator->previousIndex(steps); } + + void next() { m_navigator->next(); } + void previous() { m_navigator->previous(); } + + QMediaPlaylist::PlaybackMode playbackMode() const { return m_navigator->playbackMode(); } + void setPlaybackMode(QMediaPlaylist::PlaybackMode mode) { m_navigator->setPlaybackMode(mode); } + +private: + QMediaPlaylistNavigator *m_navigator; +}; + + +QT_END_NAMESPACE + +#endif // QMEDIAPLAYLIST_P_H diff --git a/src/multimediakit/qmediaplaylistcontrol.cpp b/src/multimediakit/qmediaplaylistcontrol.cpp new file mode 100644 index 000000000..47b4b5794 --- /dev/null +++ b/src/multimediakit/qmediaplaylistcontrol.cpp @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qmediaplaylistcontrol.h" +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaPlaylistControl + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + + \brief The QMediaPlaylistControl class provides access to the playlist + functionality of a QMediaService. + + If a QMediaService contains an internal playlist it will implement + QMediaPlaylistControl. This control provides access to the contents of the + \l {playlistProvider()}{playlist}, as well as the \l + {currentIndex()}{position} of the current media, and a means of navigating + to the \l {next()}{next} and \l {previous()}{previous} media. + + The functionality provided by the control is exposed to application code + through the QMediaPlaylist class. + + The interface name of QMediaPlaylistControl is \c com.nokia.Qt.QMediaPlaylistControl/1.0 as + defined in QMediaPlaylistControl_iid. + + \sa QMediaService::requestControl(), QMediaPlayer +*/ + +/*! + \macro QMediaPlaylistControl_iid + + \c com.nokia.Qt.QMediaPlaylistControl/1.0 + + Defines the interface name of the QMediaPlaylistControl class. + + \relates QMediaPlaylistControl +*/ + +/*! + Create a new playlist control object with the given \a parent. +*/ +QMediaPlaylistControl::QMediaPlaylistControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroys the playlist control. +*/ +QMediaPlaylistControl::~QMediaPlaylistControl() +{ +} + + +/*! + \fn QMediaPlaylistControl::playlistProvider() const + + Returns the playlist used by this media player. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistControl::setPlaylistProvider(QMediaPlaylistProvider *playlist) + + Set the playlist of this media player to \a playlist. + + In many cases it is possible just to use the playlist + constructed by player, but sometimes replacing the whole + playlist allows to avoid copyting of all the items bettween playlists. + + Returns true if player can use this passed playlist; otherwise returns false. + + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistControl::currentIndex() const + + Returns position of the current media source in the playlist. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistControl::setCurrentIndex(int position) + + Jump to the item at the given \a position. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistControl::nextIndex(int step) const + + Returns the index of item, which were current after calling next() + \a step times. + + Returned value depends on the size of playlist, current position + and playback mode. + + \since 1.0 + \sa QMediaPlaylist::playbackMode +*/ + +/*! + \fn QMediaPlaylistControl::previousIndex(int step) const + + Returns the index of item, which were current after calling previous() + \a step times. + + \since 1.0 + \sa QMediaPlaylist::playbackMode +*/ + +/*! + \fn QMediaPlaylistControl::next() + + Moves to the next item in playlist. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistControl::previous() + + Returns to the previous item in playlist. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistControl::playbackMode() const + + Returns the playlist navigation mode. + + \since 1.0 + \sa QMediaPlaylist::PlaybackMode +*/ + +/*! + \fn QMediaPlaylistControl::setPlaybackMode(QMediaPlaylist::PlaybackMode mode) + + Sets the playback \a mode. + + \since 1.0 + \sa QMediaPlaylist::PlaybackMode +*/ + +/*! + \fn QMediaPlaylistControl::playlistProviderChanged() + + Signal emitted when the playlist provider has changed. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistControl::currentIndexChanged(int position) + + Signal emitted when the playlist \a position is changed. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistControl::playbackModeChanged(QMediaPlaylist::PlaybackMode mode) + + Signal emitted when the playback \a mode is changed. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistControl::currentMediaChanged(const QMediaContent& content) + + Signal emitted when current media changes to \a content. + \since 1.0 +*/ + +#include "moc_qmediaplaylistcontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediaplaylistcontrol.h b/src/multimediakit/qmediaplaylistcontrol.h new file mode 100644 index 000000000..ff113135a --- /dev/null +++ b/src/multimediakit/qmediaplaylistcontrol.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMEDIAPLAYLISTCONTROL_H +#define QMEDIAPLAYLISTCONTROL_H + +#include "qmediacontrol.h" +#include "qmediaplaylistnavigator.h" + + +QT_BEGIN_NAMESPACE + +class QMediaPlaylistProvider; + +class Q_MULTIMEDIA_EXPORT QMediaPlaylistControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QMediaPlaylistControl(); + + virtual QMediaPlaylistProvider* playlistProvider() const = 0; + virtual bool setPlaylistProvider(QMediaPlaylistProvider *playlist) = 0; + + virtual int currentIndex() const = 0; + virtual void setCurrentIndex(int position) = 0; + virtual int nextIndex(int steps) const = 0; + virtual int previousIndex(int steps) const = 0; + + virtual void next() = 0; + virtual void previous() = 0; + + virtual QMediaPlaylist::PlaybackMode playbackMode() const = 0; + virtual void setPlaybackMode(QMediaPlaylist::PlaybackMode mode) = 0; + +Q_SIGNALS: + void playlistProviderChanged(); + void currentIndexChanged(int position); + void currentMediaChanged(const QMediaContent&); + void playbackModeChanged(QMediaPlaylist::PlaybackMode mode); + +protected: + QMediaPlaylistControl(QObject* parent = 0); +}; + +#define QMediaPlaylistControl_iid "com.nokia.Qt.QMediaPlaylistControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaPlaylistControl, QMediaPlaylistControl_iid) + +QT_END_NAMESPACE + +#endif // QMEDIAPLAYLISTCONTROL_H diff --git a/src/multimediakit/qmediaplaylistioplugin.cpp b/src/multimediakit/qmediaplaylistioplugin.cpp new file mode 100644 index 000000000..f0b5196f4 --- /dev/null +++ b/src/multimediakit/qmediaplaylistioplugin.cpp @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaplaylistioplugin.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaPlaylistReader + + \brief The QMediaPlaylistReader class provides an interface for reading a playlist file. + \inmodule QtMultimediaKit + \since 1.0 + + \sa QMediaPlaylistIOPlugin +*/ + +/*! + Destroys a media playlist reader. +*/ +QMediaPlaylistReader::~QMediaPlaylistReader() +{ +} + +/*! + \fn QMediaPlaylistReader::atEnd() const + + Identifies if a playlist reader has reached the end of its input. + + Returns true if the reader has reached the end; and false otherwise. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistReader::readItem() + + Reads an item of media from a playlist file. + + Returns the read media, or a null QMediaContent if no more media is available. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistReader::close() + + Closes a playlist reader's input device. + \since 1.0 +*/ + +/*! + \class QMediaPlaylistWriter + + \brief The QMediaPlaylistWriter class provides an interface for writing a playlist file. + + \since 1.0 + \sa QMediaPlaylistIOPlugin +*/ + +/*! + Destroys a media playlist writer. +*/ +QMediaPlaylistWriter::~QMediaPlaylistWriter() +{ +} + +/*! + \fn QMediaPlaylistWriter::writeItem(const QMediaContent &media) + + Writes an item of \a media to a playlist file. + + Returns true if the media was written successfully; and false otherwise. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistWriter::close() + + Finalizes the writing of a playlist and closes the output device. + \since 1.0 +*/ + +/*! + \class QMediaPlaylistIOPlugin + \brief The QMediaPlaylistIOPlugin class provides an interface for media playlist I/O plug-ins. + \since 1.0 +*/ + +/*! + Constructs a media playlist I/O plug-in with the given \a parent. +*/ +QMediaPlaylistIOPlugin::QMediaPlaylistIOPlugin(QObject *parent) + :QObject(parent) +{ +} + +/*! + Destroys a media playlist I/O plug-in. +*/ +QMediaPlaylistIOPlugin::~QMediaPlaylistIOPlugin() +{ +} + +/*! + \fn QMediaPlaylistIOPlugin::canRead(QIODevice *device, const QByteArray &format) const + + Identifies if plug-in can read \a format data from an I/O \a device. + + Returns true if the data can be read; and false otherwise. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistIOPlugin::canRead(const QUrl& location, const QByteArray &format) const + + Identifies if a plug-in can read \a format data from a URL \a location. + + Returns true if the data can be read; and false otherwise. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistIOPlugin::canWrite(QIODevice *device, const QByteArray &format) const + + Identifies if a plug-in can write \a format data to an I/O \a device. + + Returns true if the data can be written; and false otherwise. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistIOPlugin::keys() const + + Returns a list of format keys supported by a plug-in. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistIOPlugin::createReader(QIODevice *device, const QByteArray &format) + + Returns a new QMediaPlaylistReader which reads \a format data from an I/O \a device. + + If the device is invalid or the format is unsupported this will return a null pointer. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistIOPlugin::createReader(const QUrl& location, const QByteArray &format) + + Returns a new QMediaPlaylistReader which reads \a format data from a URL \a location. + + If the location or the format is unsupported this will return a null pointer. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistIOPlugin::createWriter(QIODevice *device, const QByteArray &format) + + Returns a new QMediaPlaylistWriter which writes \a format data to an I/O \a device. + + If the device is invalid or the format is unsupported this will return a null pointer. + \since 1.0 +*/ + +#include "moc_qmediaplaylistioplugin.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediaplaylistioplugin.h b/src/multimediakit/qmediaplaylistioplugin.h new file mode 100644 index 000000000..aa5f4fd95 --- /dev/null +++ b/src/multimediakit/qmediaplaylistioplugin.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYLISTIOPLUGIN_H +#define QMEDIAPLAYLISTIOPLUGIN_H + +#include +#include +#include + +#include + +#include "qmediacontent.h" + +QT_BEGIN_NAMESPACE +class QString; +class QUrl; +class QByteArray; +class QIODevice; +class QStringList; + +class Q_MULTIMEDIA_EXPORT QMediaPlaylistReader +{ +public: + virtual ~QMediaPlaylistReader(); + + virtual bool atEnd() const = 0; + virtual QMediaContent readItem() = 0; + virtual void close() = 0; +}; + +class Q_MULTIMEDIA_EXPORT QMediaPlaylistWriter +{ +public: + virtual ~QMediaPlaylistWriter(); + + virtual bool writeItem(const QMediaContent &content) = 0; + virtual void close() = 0; +}; + +struct Q_MULTIMEDIA_EXPORT QMediaPlaylistIOInterface : public QFactoryInterface +{ + virtual bool canRead(QIODevice *device, const QByteArray &format = QByteArray() ) const = 0; + virtual bool canRead(const QUrl& location, const QByteArray &format = QByteArray()) const = 0; + + virtual bool canWrite(QIODevice *device, const QByteArray &format) const = 0; + + virtual QMediaPlaylistReader *createReader(QIODevice *device, const QByteArray &format = QByteArray()) = 0; + virtual QMediaPlaylistReader *createReader(const QUrl& location, const QByteArray &format = QByteArray()) = 0; + + virtual QMediaPlaylistWriter *createWriter(QIODevice *device, const QByteArray &format) = 0; +}; + +#define QMediaPlaylistIOInterface_iid "com.nokia.Qt.QMediaPlaylistIOInterface" +Q_DECLARE_INTERFACE(QMediaPlaylistIOInterface, QMediaPlaylistIOInterface_iid); + +class Q_MULTIMEDIA_EXPORT QMediaPlaylistIOPlugin : public QObject, public QMediaPlaylistIOInterface +{ +Q_OBJECT +Q_INTERFACES(QMediaPlaylistIOInterface:QFactoryInterface) +public: + explicit QMediaPlaylistIOPlugin(QObject *parent = 0); + virtual ~QMediaPlaylistIOPlugin(); + + virtual bool canRead(QIODevice *device, const QByteArray &format = QByteArray() ) const = 0; + virtual bool canRead(const QUrl& location, const QByteArray &format = QByteArray()) const = 0; + + virtual bool canWrite(QIODevice *device, const QByteArray &format) const = 0; + + virtual QStringList keys() const = 0; + + virtual QMediaPlaylistReader *createReader(QIODevice *device, const QByteArray &format = QByteArray()) = 0; + virtual QMediaPlaylistReader *createReader(const QUrl& location, const QByteArray &format = QByteArray()) = 0; + + virtual QMediaPlaylistWriter *createWriter(QIODevice *device, const QByteArray &format) = 0; +}; + +QT_END_NAMESPACE + +#endif // QMEDIAPLAYLISTIOPLUGIN_H diff --git a/src/multimediakit/qmediaplaylistnavigator.cpp b/src/multimediakit/qmediaplaylistnavigator.cpp new file mode 100644 index 000000000..c3e358716 --- /dev/null +++ b/src/multimediakit/qmediaplaylistnavigator.cpp @@ -0,0 +1,568 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaplaylistnavigator.h" +#include "qmediaplaylistprovider.h" +#include "qmediaplaylist.h" +#include "qmediaobject_p.h" + +#include + +QT_BEGIN_NAMESPACE + +class QMediaPlaylistNullProvider : public QMediaPlaylistProvider +{ +public: + QMediaPlaylistNullProvider() :QMediaPlaylistProvider() {} + virtual ~QMediaPlaylistNullProvider() {} + virtual int mediaCount() const {return 0;} + virtual QMediaContent media(int) const { return QMediaContent(); } +}; + +Q_GLOBAL_STATIC(QMediaPlaylistNullProvider, _q_nullMediaPlaylist) + +class QMediaPlaylistNavigatorPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QMediaPlaylistNavigator) +public: + QMediaPlaylistNavigatorPrivate() + :playlist(0), + currentPos(-1), + lastValidPos(-1), + playbackMode(QMediaPlaylist::Sequential), + randomPositionsOffset(-1) + { + } + + QMediaPlaylistProvider *playlist; + int currentPos; + int lastValidPos; //to be used with CurrentItemOnce playback mode + QMediaPlaylist::PlaybackMode playbackMode; + QMediaContent currentItem; + + mutable QList randomModePositions; + mutable int randomPositionsOffset; + + int nextItemPos(int steps = 1) const; + int previousItemPos(int steps = 1) const; + + void _q_mediaInserted(int start, int end); + void _q_mediaRemoved(int start, int end); + void _q_mediaChanged(int start, int end); + + QMediaPlaylistNavigator *q_ptr; +}; + + +int QMediaPlaylistNavigatorPrivate::nextItemPos(int steps) const +{ + if (playlist->mediaCount() == 0) + return -1; + + if (steps == 0) + return currentPos; + + switch (playbackMode) { + case QMediaPlaylist::CurrentItemOnce: + return /*currentPos == -1 ? lastValidPos :*/ -1; + case QMediaPlaylist::CurrentItemInLoop: + return currentPos; + case QMediaPlaylist::Sequential: + { + int nextPos = currentPos+steps; + return nextPos < playlist->mediaCount() ? nextPos : -1; + } + case QMediaPlaylist::Loop: + return (currentPos+steps) % playlist->mediaCount(); + case QMediaPlaylist::Random: + { + //TODO: limit the history size + + if (randomPositionsOffset == -1) { + randomModePositions.clear(); + randomModePositions.append(currentPos); + randomPositionsOffset = 0; + } + + while (randomModePositions.size() < randomPositionsOffset+steps+1) + randomModePositions.append(-1); + int res = randomModePositions[randomPositionsOffset+steps]; + if (res<0 || res >= playlist->mediaCount()) { + res = qrand() % playlist->mediaCount(); + randomModePositions[randomPositionsOffset+steps] = res; + } + + return res; + } + } + + return -1; +} + +int QMediaPlaylistNavigatorPrivate::previousItemPos(int steps) const +{ + if (playlist->mediaCount() == 0) + return -1; + + if (steps == 0) + return currentPos; + + switch (playbackMode) { + case QMediaPlaylist::CurrentItemOnce: + return /*currentPos == -1 ? lastValidPos :*/ -1; + case QMediaPlaylist::CurrentItemInLoop: + return currentPos; + case QMediaPlaylist::Sequential: + { + int prevPos = currentPos == -1 ? playlist->mediaCount() - steps : currentPos - steps; + return prevPos>=0 ? prevPos : -1; + } + case QMediaPlaylist::Loop: + { + int prevPos = currentPos - steps; + while (prevPos<0) + prevPos += playlist->mediaCount(); + return prevPos; + } + case QMediaPlaylist::Random: + { + //TODO: limit the history size + + if (randomPositionsOffset == -1) { + randomModePositions.clear(); + randomModePositions.append(currentPos); + randomPositionsOffset = 0; + } + + while (randomPositionsOffset-steps < 0) { + randomModePositions.prepend(-1); + randomPositionsOffset++; + } + + int res = randomModePositions[randomPositionsOffset-steps]; + if (res<0 || res >= playlist->mediaCount()) { + res = qrand() % playlist->mediaCount(); + randomModePositions[randomPositionsOffset-steps] = res; + } + + return res; + } + } + + return -1; +} + +/*! + \class QMediaPlaylistNavigator + + \brief The QMediaPlaylistNavigator class provides navigation for a media playlist. + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + \sa QMediaPlaylist, QMediaPlaylistProvider +*/ + + +/*! + Constructs a media playlist navigator for a \a playlist. + + The \a parent is passed to QObject. + \since 1.0 + */ +QMediaPlaylistNavigator::QMediaPlaylistNavigator(QMediaPlaylistProvider *playlist, QObject *parent) + : QObject(parent) + , d_ptr(new QMediaPlaylistNavigatorPrivate) +{ + d_ptr->q_ptr = this; + + setPlaylist(playlist ? playlist : _q_nullMediaPlaylist()); +} + +/*! + Destroys a media playlist navigator. + */ + +QMediaPlaylistNavigator::~QMediaPlaylistNavigator() +{ + delete d_ptr; +} + + +/*! \property QMediaPlaylistNavigator::playbackMode + Contains the playback mode. + \since 1.0 + */ +QMediaPlaylist::PlaybackMode QMediaPlaylistNavigator::playbackMode() const +{ + return d_func()->playbackMode; +} + +/*! + Sets the playback \a mode. + \since 1.0 + */ +void QMediaPlaylistNavigator::setPlaybackMode(QMediaPlaylist::PlaybackMode mode) +{ + Q_D(QMediaPlaylistNavigator); + if (d->playbackMode == mode) + return; + + if (mode == QMediaPlaylist::Random) { + d->randomPositionsOffset = 0; + d->randomModePositions.append(d->currentPos); + } else if (d->playbackMode == QMediaPlaylist::Random) { + d->randomPositionsOffset = -1; + d->randomModePositions.clear(); + } + + d->playbackMode = mode; + + emit playbackModeChanged(mode); + emit surroundingItemsChanged(); +} + +/*! + Returns the playlist being navigated. + \since 1.0 +*/ + +QMediaPlaylistProvider *QMediaPlaylistNavigator::playlist() const +{ + return d_func()->playlist; +} + +/*! + Sets the \a playlist to navigate. + \since 1.0 +*/ +void QMediaPlaylistNavigator::setPlaylist(QMediaPlaylistProvider *playlist) +{ + Q_D(QMediaPlaylistNavigator); + + if (d->playlist == playlist) + return; + + if (d->playlist) { + d->playlist->disconnect(this); + } + + if (playlist) { + d->playlist = playlist; + } else { + //assign to shared readonly null playlist + d->playlist = _q_nullMediaPlaylist(); + } + + connect(d->playlist, SIGNAL(mediaInserted(int,int)), SLOT(_q_mediaInserted(int,int))); + connect(d->playlist, SIGNAL(mediaRemoved(int,int)), SLOT(_q_mediaRemoved(int,int))); + connect(d->playlist, SIGNAL(mediaChanged(int,int)), SLOT(_q_mediaChanged(int,int))); + + d->randomPositionsOffset = -1; + d->randomModePositions.clear(); + + if (d->currentPos != -1) { + d->currentPos = -1; + emit currentIndexChanged(-1); + } + + if (!d->currentItem.isNull()) { + d->currentItem = QMediaContent(); + emit activated(d->currentItem); //stop playback + } +} + +/*! \property QMediaPlaylistNavigator::currentItem + + Contains the media at the current position in the playlist. + + \since 1.0 + \sa currentIndex() +*/ + +QMediaContent QMediaPlaylistNavigator::currentItem() const +{ + return itemAt(d_func()->currentPos); +} + +/*! \fn QMediaContent QMediaPlaylistNavigator::nextItem(int steps) const + + Returns the media that is \a steps positions ahead of the current + position in the playlist. + + \since 1.0 + \sa nextIndex() +*/ +QMediaContent QMediaPlaylistNavigator::nextItem(int steps) const +{ + return itemAt(nextIndex(steps)); +} + +/*! + Returns the media that is \a steps positions behind the current + position in the playlist. + + \since 1.0 + \sa previousIndex() + */ +QMediaContent QMediaPlaylistNavigator::previousItem(int steps) const +{ + return itemAt(previousIndex(steps)); +} + +/*! + Returns the media at a \a position in the playlist. + \since 1.0 + */ +QMediaContent QMediaPlaylistNavigator::itemAt(int position) const +{ + return d_func()->playlist->media(position); +} + +/*! \property QMediaPlaylistNavigator::currentIndex + + Contains the position of the current media. + + If no media is current, the property contains -1. + + \since 1.0 + \sa nextIndex(), previousIndex() +*/ + +int QMediaPlaylistNavigator::currentIndex() const +{ + return d_func()->currentPos; +} + +/*! + Returns a position \a steps ahead of the current position + accounting for the playbackMode(). + + If the position is beyond the end of the playlist, this value + returned is -1. + + \since 1.0 + \sa currentIndex(), previousIndex(), playbackMode() +*/ + +int QMediaPlaylistNavigator::nextIndex(int steps) const +{ + return d_func()->nextItemPos(steps); +} + +/*! + + Returns a position \a steps behind the current position accounting + for the playbackMode(). + + If the position is prior to the beginning of the playlist this will + return -1. + + \since 1.0 + \sa currentIndex(), nextIndex(), playbackMode() +*/ +int QMediaPlaylistNavigator::previousIndex(int steps) const +{ + return d_func()->previousItemPos(steps); +} + +/*! + Advances to the next item in the playlist. + + \since 1.0 + \sa previous(), jump(), playbackMode() + */ +void QMediaPlaylistNavigator::next() +{ + Q_D(QMediaPlaylistNavigator); + + int nextPos = d->nextItemPos(); + + if ( playbackMode() == QMediaPlaylist::Random ) + d->randomPositionsOffset++; + + jump(nextPos); +} + +/*! + Returns to the previous item in the playlist, + + \since 1.0 + \sa next(), jump(), playbackMode() + */ +void QMediaPlaylistNavigator::previous() +{ + Q_D(QMediaPlaylistNavigator); + + int prevPos = d->previousItemPos(); + if ( playbackMode() == QMediaPlaylist::Random ) + d->randomPositionsOffset--; + + jump(prevPos); +} + +/*! + Jumps to a new \a position in the playlist. + \since 1.0 + */ +void QMediaPlaylistNavigator::jump(int position) +{ + Q_D(QMediaPlaylistNavigator); + + if (position<-1 || position>=d->playlist->mediaCount()) { + qWarning() << "QMediaPlaylistNavigator: Jump outside playlist range"; + position = -1; + } + + if (position != -1) + d->lastValidPos = position; + + if (playbackMode() == QMediaPlaylist::Random) { + if (d->randomModePositions[d->randomPositionsOffset] != position) { + d->randomModePositions.clear(); + d->randomModePositions.append(position); + d->randomPositionsOffset = 0; + } + } + + if (position != -1) + d->currentItem = d->playlist->media(position); + else + d->currentItem = QMediaContent(); + + if (position != d->currentPos) { + d->currentPos = position; + emit currentIndexChanged(d->currentPos); + emit surroundingItemsChanged(); + } + + emit activated(d->currentItem); +} + +/*! + \internal + \since 1.0 +*/ +void QMediaPlaylistNavigatorPrivate::_q_mediaInserted(int start, int end) +{ + Q_Q(QMediaPlaylistNavigator); + + if (currentPos >= start) { + currentPos = end-start+1; + q->jump(currentPos); + } + + //TODO: check if they really changed + emit q->surroundingItemsChanged(); +} + +/*! + \internal + \since 1.0 +*/ +void QMediaPlaylistNavigatorPrivate::_q_mediaRemoved(int start, int end) +{ + Q_Q(QMediaPlaylistNavigator); + + if (currentPos > end) { + currentPos = currentPos - end-start+1; + q->jump(currentPos); + } else if (currentPos >= start) { + //current item was removed + currentPos = qMin(start, playlist->mediaCount()-1); + q->jump(currentPos); + } + + //TODO: check if they really changed + emit q->surroundingItemsChanged(); +} + +/*! + \internal + \since 1.0 +*/ +void QMediaPlaylistNavigatorPrivate::_q_mediaChanged(int start, int end) +{ + Q_Q(QMediaPlaylistNavigator); + + if (currentPos >= start && currentPos<=end) { + QMediaContent src = playlist->media(currentPos); + if (src != currentItem) { + currentItem = src; + emit q->activated(src); + } + } + + //TODO: check if they really changed + emit q->surroundingItemsChanged(); +} + +/*! + \fn QMediaPlaylistNavigator::activated(const QMediaContent &media) + + Signals that the current \a media has changed. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistNavigator::currentIndexChanged(int position) + + Signals the \a position of the current media has changed. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistNavigator::playbackModeChanged(QMediaPlaylist::PlaybackMode mode) + + Signals that the playback \a mode has changed. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistNavigator::surroundingItemsChanged() + + Signals that media immediately surrounding the current position has changed. + \since 1.0 +*/ + +#include "moc_qmediaplaylistnavigator.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediaplaylistnavigator.h b/src/multimediakit/qmediaplaylistnavigator.h new file mode 100644 index 000000000..e19686a7a --- /dev/null +++ b/src/multimediakit/qmediaplaylistnavigator.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYLISTNAVIGATOR_H +#define QMEDIAPLAYLISTNAVIGATOR_H + +#include "qmediaplaylistprovider.h" +#include "qmediaplaylist.h" +#include + +QT_BEGIN_NAMESPACE + +class QMediaPlaylistNavigatorPrivate; +class Q_MULTIMEDIA_EXPORT QMediaPlaylistNavigator : public QObject +{ + Q_OBJECT + Q_PROPERTY(QMediaPlaylist::PlaybackMode playbackMode READ playbackMode WRITE setPlaybackMode NOTIFY playbackModeChanged) + Q_PROPERTY(int currentIndex READ currentIndex WRITE jump NOTIFY currentIndexChanged) + Q_PROPERTY(QMediaContent currentItem READ currentItem) + +public: + QMediaPlaylistNavigator(QMediaPlaylistProvider *playlist, QObject *parent = 0); + virtual ~QMediaPlaylistNavigator(); + + QMediaPlaylistProvider *playlist() const; + void setPlaylist(QMediaPlaylistProvider *playlist); + + QMediaPlaylist::PlaybackMode playbackMode() const; + + QMediaContent currentItem() const; + QMediaContent nextItem(int steps = 1) const; + QMediaContent previousItem(int steps = 1) const; + + QMediaContent itemAt(int position) const; + + int currentIndex() const; + int nextIndex(int steps = 1) const; + int previousIndex(int steps = 1) const; + +public Q_SLOTS: + void next(); + void previous(); + + void jump(int); + + void setPlaybackMode(QMediaPlaylist::PlaybackMode mode); + +Q_SIGNALS: + void activated(const QMediaContent &content); + void currentIndexChanged(int); + void playbackModeChanged(QMediaPlaylist::PlaybackMode mode); + + void surroundingItemsChanged(); + +protected: + QMediaPlaylistNavigatorPrivate *d_ptr; + +private: + Q_DISABLE_COPY(QMediaPlaylistNavigator) + Q_DECLARE_PRIVATE(QMediaPlaylistNavigator) + + Q_PRIVATE_SLOT(d_func(), void _q_mediaInserted(int start, int end)) + Q_PRIVATE_SLOT(d_func(), void _q_mediaRemoved(int start, int end)) + Q_PRIVATE_SLOT(d_func(), void _q_mediaChanged(int start, int end)) +}; + +QT_END_NAMESPACE + +#endif // QMEDIAPLAYLISTNAVIGATOR_H diff --git a/src/multimediakit/qmediaplaylistprovider.cpp b/src/multimediakit/qmediaplaylistprovider.cpp new file mode 100644 index 000000000..5c892b79e --- /dev/null +++ b/src/multimediakit/qmediaplaylistprovider.cpp @@ -0,0 +1,329 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaplaylistprovider.h" +#include "qmediaplaylistprovider_p.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaPlaylistProvider + + \brief The QMediaPlaylistProvider class provides an abstract list of media. + \inmodule QtMultimediaKit + \since 1.0 + + \sa QMediaPlaylist +*/ + +/*! + Constructs a playlist provider with the given \a parent. +*/ +QMediaPlaylistProvider::QMediaPlaylistProvider(QObject *parent) + :QObject(parent), d_ptr(new QMediaPlaylistProviderPrivate) +{ +} + +/*! + \internal +*/ +QMediaPlaylistProvider::QMediaPlaylistProvider(QMediaPlaylistProviderPrivate &dd, QObject *parent) + :QObject(parent), d_ptr(&dd) +{ +} + +/*! + Destroys a playlist provider. +*/ +QMediaPlaylistProvider::~QMediaPlaylistProvider() +{ + delete d_ptr; +} + +/*! + \fn QMediaPlaylistProvider::mediaCount() const; + + Returns the size of playlist. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistProvider::media(int index) const; + + Returns the media at \a index in the playlist. + + If the index is invalid this will return a null media content. + \since 1.0 +*/ + + +/*! + Loads a playlist from from a URL \a location. If no playlist \a format is specified the loader + will inspect the URL or probe the headers to guess the format. + + New items are appended to playlist. + + Returns true if the provider supports the format and loading from the locations URL protocol, + otherwise this will return false. + \since 1.0 +*/ +bool QMediaPlaylistProvider::load(const QUrl &location, const char *format) +{ + Q_UNUSED(location); + Q_UNUSED(format); + return false; +} + +/*! + Loads a playlist from from an I/O \a device. If no playlist \a format is specified the loader + will probe the headers to guess the format. + + New items are appended to playlist. + + Returns true if the provider supports the format and loading from an I/O device, otherwise this + will return false. + \since 1.0 +*/ +bool QMediaPlaylistProvider::load(QIODevice * device, const char *format) +{ + Q_UNUSED(device); + Q_UNUSED(format); + return false; +} + +/*! + Saves the contents of a playlist to a URL \a location. If no playlist \a format is specified + the writer will inspect the URL to guess the format. + + Returns true if the playlist was saved successfully; and false otherwise. + \since 1.0 + */ +bool QMediaPlaylistProvider::save(const QUrl &location, const char *format) +{ + Q_UNUSED(location); + Q_UNUSED(format); + return false; +} + +/*! + Saves the contents of a playlist to an I/O \a device in the specified \a format. + + Returns true if the playlist was saved successfully; and false otherwise. + \since 1.0 +*/ +bool QMediaPlaylistProvider::save(QIODevice * device, const char *format) +{ + Q_UNUSED(device); + Q_UNUSED(format); + return false; +} + +/*! + Returns true if a playlist is read-only; otherwise returns false. + \since 1.0 +*/ +bool QMediaPlaylistProvider::isReadOnly() const +{ + return true; +} + +/*! + Append \a media to a playlist. + + Returns true if the media was appended; and false otherwise. + \since 1.0 +*/ +bool QMediaPlaylistProvider::addMedia(const QMediaContent &media) +{ + Q_UNUSED(media); + return false; +} + +/*! + Append multiple media \a items to a playlist. + + Returns true if the media items were appended; and false otherwise. + \since 1.0 +*/ +bool QMediaPlaylistProvider::addMedia(const QList &items) +{ + foreach(const QMediaContent &item, items) { + if (!addMedia(item)) + return false; + } + + return true; +} + +/*! + Inserts \a media into a playlist at \a position. + + Returns true if the media was inserted; and false otherwise. + \since 1.0 +*/ +bool QMediaPlaylistProvider::insertMedia(int position, const QMediaContent &media) +{ + Q_UNUSED(position); + Q_UNUSED(media); + return false; +} + +/*! + Inserts multiple media \a items into a playlist at \a position. + + Returns true if the media \a items were inserted; and false otherwise. + \since 1.0 +*/ +bool QMediaPlaylistProvider::insertMedia(int position, const QList &items) +{ + for (int i=0; i + +#include "qmediacontent.h" +#include "qmediaplaylist.h" + +QT_BEGIN_NAMESPACE +class QString; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class QMediaPlaylistProviderPrivate; +class Q_MULTIMEDIA_EXPORT QMediaPlaylistProvider : public QObject +{ +Q_OBJECT +public: + QMediaPlaylistProvider(QObject *parent=0); + virtual ~QMediaPlaylistProvider(); + + virtual bool load(const QUrl &location, const char *format = 0); + virtual bool load(QIODevice * device, const char *format = 0); + virtual bool save(const QUrl &location, const char *format = 0); + virtual bool save(QIODevice * device, const char *format); + + virtual int mediaCount() const = 0; + virtual QMediaContent media(int index) const = 0; + + virtual bool isReadOnly() const; + + virtual bool addMedia(const QMediaContent &content); + virtual bool addMedia(const QList &contentList); + virtual bool insertMedia(int index, const QMediaContent &content); + virtual bool insertMedia(int index, const QList &content); + virtual bool removeMedia(int pos); + virtual bool removeMedia(int start, int end); + virtual bool clear(); + +public Q_SLOTS: + virtual void shuffle(); + +Q_SIGNALS: + void mediaAboutToBeInserted(int start, int end); + void mediaInserted(int start, int end); + + void mediaAboutToBeRemoved(int start, int end); + void mediaRemoved(int start, int end); + + void mediaChanged(int start, int end); + + void loaded(); + void loadFailed(QMediaPlaylist::Error, const QString& errorMessage); + +protected: + QMediaPlaylistProviderPrivate *d_ptr; + QMediaPlaylistProvider(QMediaPlaylistProviderPrivate &dd, QObject *parent); + +private: + Q_DECLARE_PRIVATE(QMediaPlaylistProvider) +}; + +QT_END_NAMESPACE + +#endif // QMEDIAPLAYLISTPROVIDER_H diff --git a/src/multimediakit/qmediaplaylistprovider_p.h b/src/multimediakit/qmediaplaylistprovider_p.h new file mode 100644 index 000000000..ded31a7b2 --- /dev/null +++ b/src/multimediakit/qmediaplaylistprovider_p.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYLISTPROVIDER_P_H +#define QMEDIAPLAYLISTPROVIDER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmediaplaylist.h" + +QT_BEGIN_NAMESPACE + +class QMediaPlaylistProviderPrivate +{ +public: + QMediaPlaylistProviderPrivate() + {} + virtual ~QMediaPlaylistProviderPrivate() + {} +}; + +QT_END_NAMESPACE + + +#endif // QMEDIAPLAYLISTSOURCE_P_H diff --git a/src/multimediakit/qmediaplaylistsourcecontrol.cpp b/src/multimediakit/qmediaplaylistsourcecontrol.cpp new file mode 100644 index 000000000..e8feaf07b --- /dev/null +++ b/src/multimediakit/qmediaplaylistsourcecontrol.cpp @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaPlaylistSourceControl + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + + \brief The QMediaPlaylistSourceControl class provides access to the playlist playback + functionality of a QMediaService. + + This control allows QMediaPlaylist to be passed directly to the service + instead of playing media sources one by one. This control should be + implemented if backend benefits from knowing the next media source to be + played, for example for preloading, cross fading or gap-less playback. + + If QMediaPlaylistSourceControl is provided, the backend must listen for + current playlist item changes to load corresponding media source and + advance the playlist with QMediaPlaylist::next() when playback of the + current media is finished. + + The interface name of QMediaPlaylistSourceControl is \c com.nokia.Qt.QMediaPlaylistSourceControl/1.0 as + defined in QMediaPlaylistSourceControl_iid. + + \sa QMediaService::requestControl(), QMediaPlayer +*/ + +/*! + \macro QMediaPlaylistSourceControl_iid + + \c com.nokia.Qt.QMediaPlaylistSourceControl/1.0 + + Defines the interface name of the QMediaPlaylistSourceControl class. + + \relates QMediaPlaylistSourceControl +*/ + +/*! + Create a new playlist source control object with the given \a parent. +*/ +QMediaPlaylistSourceControl::QMediaPlaylistSourceControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroys the playlist control. +*/ +QMediaPlaylistSourceControl::~QMediaPlaylistSourceControl() +{ +} + + +/*! + \fn QMediaPlaylistSourceControl::playlist() const + + Returns the current playlist. + Should return a null pointer if no playlist is assigned. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistSourceControl::setPlaylist(QMediaPlaylist *playlist) + + Set the playlist of this media player to \a playlist. + If a null pointer is passed, the playlist source should be disabled. + + The current media should be replaced with the current item of the media playlist. + \since 1.0 +*/ + + +/*! + \fn QMediaPlaylistSourceControl::playlistChanged(QMediaPlaylist* playlist) + + Signal emitted when the playlist has changed to \a playlist. + \since 1.0 +*/ + +#include "moc_qmediaplaylistsourcecontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediaplaylistsourcecontrol.h b/src/multimediakit/qmediaplaylistsourcecontrol.h new file mode 100644 index 000000000..d9b40392e --- /dev/null +++ b/src/multimediakit/qmediaplaylistsourcecontrol.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMEDIAPLAYLISTSOURCECONTROL_H +#define QMEDIAPLAYLISTSOURCECONTROL_H + +#include + +QT_BEGIN_NAMESPACE + +class QMediaPlaylist; + +class Q_MULTIMEDIA_EXPORT QMediaPlaylistSourceControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QMediaPlaylistSourceControl(); + + virtual QMediaPlaylist *playlist() const = 0; + virtual void setPlaylist(QMediaPlaylist *) = 0; + +Q_SIGNALS: + void playlistChanged(QMediaPlaylist* playlist); + +protected: + QMediaPlaylistSourceControl(QObject* parent = 0); +}; + +#define QMediaPlaylistSourceControl_iid "com.nokia.Qt.QMediaPlaylistSourceControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaPlaylistSourceControl, QMediaPlaylistSourceControl_iid) + +QT_END_NAMESPACE + +#endif // QMEDIAPLAYLISTCONTROL_H diff --git a/src/multimediakit/qmediapluginloader.cpp b/src/multimediakit/qmediapluginloader.cpp new file mode 100644 index 000000000..5fa52ab10 --- /dev/null +++ b/src/multimediakit/qmediapluginloader.cpp @@ -0,0 +1,271 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediapluginloader_p.h" +#include +#include +#include +#include + +#include "qmediaserviceproviderplugin.h" + +#if defined(Q_OS_SYMBIAN) +# include +#endif + +#if defined(Q_OS_MAC) +# include +#endif + +QT_BEGIN_NAMESPACE + +typedef QMap ObjectListMap; +Q_GLOBAL_STATIC(ObjectListMap, staticMediaPlugins); + + +#if defined(Q_OS_SYMBIAN) +// XXX: Copied over from Mobility, hopefully to be removed at some point +class DirChecker +{ +public: + DirChecker(); + ~DirChecker(); + bool checkDir(const QDir& dir); + +private: + RFs rfs; +}; + +DirChecker::DirChecker() +{ + qt_symbian_throwIfError(rfs.Connect()); +} + +bool DirChecker::checkDir(const QDir& dir) +{ + bool pathFound = false; + // In Symbian, going cdUp() in a c:/private// will result in *platsec* error at fileserver (requires AllFiles capability) + // Also, trying to cd() to a nonexistent directory causes *platsec* error. This does not cause functional harm, but should + // nevertheless be changed to use native Symbian methods to avoid unnecessary platsec warnings (as per qpluginloader.cpp). + // Use native Symbian code to check for directory existence, because checking + // for files from under non-existent protected dir like E:/private/ using + // QDir::exists causes platform security violations on most apps. + QString nativePath = QDir::toNativeSeparators(dir.absolutePath()); + TPtrC ptr = TPtrC16(static_cast(nativePath.utf16()), nativePath.length()); + TUint attributes; + TInt err = rfs.Att(ptr, attributes); + if (err == KErrNone) { + // yes, the directory exists. + pathFound = true; + } + return pathFound; +} + +DirChecker::~DirChecker() +{ + rfs.Close(); +} +#endif + + +QMediaPluginLoader::QMediaPluginLoader(const char *iid, const QString &location, Qt::CaseSensitivity): + m_iid(iid) +{ + m_location = QString::fromLatin1("/%1").arg(location); + load(); +} + +QStringList QMediaPluginLoader::keys() const +{ + return m_instances.keys(); +} + +QObject* QMediaPluginLoader::instance(QString const &key) +{ + return m_instances.value(key).value(0); +} + +QList QMediaPluginLoader::instances(QString const &key) +{ + return m_instances.value(key); +} + +//to be used for testing purposes only +void QMediaPluginLoader::setStaticPlugins(const QString &location, const QObjectList& objects) +{ + staticMediaPlugins()->insert(QString::fromLatin1("/%1").arg(location), objects); +} + +QStringList QMediaPluginLoader::availablePlugins() const +{ + QStringList paths; + QStringList plugins; + +#if defined(Q_OS_SYMBIAN) + DirChecker dirChecker; +#endif + +#if defined(Q_OS_MAC) + QString imageSuffix(qgetenv("DYLD_IMAGE_SUFFIX")); + + // Bundle plugin directory + CFBundleRef mainBundle = CFBundleGetMainBundle(); + if (mainBundle != 0) { + CFURLRef baseUrl = CFBundleCopyBundleURL(mainBundle); + CFURLRef pluginUrlPart = CFBundleCopyBuiltInPlugInsURL(mainBundle); + CFStringRef pluginPathPart = CFURLCopyFileSystemPath(pluginUrlPart, kCFURLPOSIXPathStyle); + CFURLRef pluginUrl = CFURLCreateCopyAppendingPathComponent(0, baseUrl, pluginPathPart, true); + CFStringRef pluginPath = CFURLCopyFileSystemPath(pluginUrl, kCFURLPOSIXPathStyle); + + CFIndex length = CFStringGetLength(pluginPath); + UniChar buffer[length]; + CFStringGetCharacters(pluginPath, CFRangeMake(0, length), buffer); + + paths << QString(reinterpret_cast(buffer), length); + + CFRelease(pluginPath); + CFRelease(pluginUrl); + CFRelease(pluginPathPart); + CFRelease(pluginUrlPart); + CFRelease(baseUrl); + } +#endif + + // Qt paths + paths << QCoreApplication::libraryPaths(); + + foreach (const QString &path, paths) { + QDir typeDir(path + m_location); +#if defined(Q_OS_SYMBIAN) + if (dirChecker.checkDir(typeDir)) +#endif + { + foreach (const QString &file, typeDir.entryList(QDir::Files)) { +#if defined(Q_OS_MAC) + if (!imageSuffix.isEmpty()) { // Only add appropriate images + if (file.lastIndexOf(imageSuffix, -6) == -1) + continue; + } else { // Ignore any images with common suffixes + if (file.endsWith(QLatin1String("_debug.dylib")) || + file.endsWith(QLatin1String("_profile.dylib"))) + continue; + } +#elif defined(Q_OS_UNIX) + // Ignore separate debug files + if (file.endsWith(QLatin1String(".debug"))) + continue; +#elif defined(Q_OS_WIN) + // Ignore non-dlls + if (!file.endsWith(QLatin1String(".dll"), Qt::CaseInsensitive)) + continue; +#endif + plugins << typeDir.absoluteFilePath(file); + } + } + } + + return plugins; +} + +void QMediaPluginLoader::load() +{ + if (!m_instances.isEmpty()) + return; + +#if !defined QT_NO_DEBUG + const bool showDebug = qgetenv("QT_DEBUG_PLUGINS").toInt() > 0; +#endif + + if (staticMediaPlugins() && staticMediaPlugins()->contains(m_location)) { + foreach(QObject *o, staticMediaPlugins()->value(m_location)) { + if (o != 0 && o->qt_metacast(m_iid) != 0) { + QFactoryInterface* p = qobject_cast(o); + if (p != 0) { + foreach (QString const &key, p->keys()) + m_instances[key].append(o); + } + } + } + } else { + QSet loadedPlugins; + + foreach (const QString &plugin, availablePlugins()) { + QString fileName = QFileInfo(plugin).fileName(); + //don't try to load plugin with the same name if it's already loaded + if (loadedPlugins.contains(fileName)) { +#if !defined QT_NO_DEBUG + if (showDebug) + qDebug() << "Skip loading plugin" << plugin; +#endif + continue; + } + + QPluginLoader loader(plugin); + + QObject *o = loader.instance(); + if (o != 0 && o->qt_metacast(m_iid) != 0) { + QFactoryInterface* p = qobject_cast(o); + if (p != 0) { + foreach (const QString &key, p->keys()) + m_instances[key].append(o); + + loadedPlugins.insert(fileName); +#if !defined QT_NO_DEBUG + if (showDebug) + qDebug() << "Loaded plugin" << plugin << "services:" << p->keys(); +#endif + } + + continue; + } else { +#if !defined QT_NO_DEBUG + if (showDebug) + qWarning() << "QMediaPluginLoader: Failed to load plugin: " << plugin << loader.errorString(); +#endif + } + + delete o; + } + } +} + +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediapluginloader_p.h b/src/multimediakit/qmediapluginloader_p.h new file mode 100644 index 000000000..eef395a33 --- /dev/null +++ b/src/multimediakit/qmediapluginloader_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLUGINLOADER_H +#define QMEDIAPLUGINLOADER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include + + +QT_BEGIN_NAMESPACE + +class QMediaServiceProviderPlugin; + +class Q_AUTOTEST_EXPORT QMediaPluginLoader +{ +public: + QMediaPluginLoader(const char *iid, + const QString &suffix = QString(), + Qt::CaseSensitivity = Qt::CaseSensitive); + + QStringList keys() const; + QObject* instance(QString const &key); + QList instances(QString const &key); + + static void setStaticPlugins(const QString &location, const QObjectList& objects); + +private: + void load(); + QStringList availablePlugins() const; + + QByteArray m_iid; + QString m_location; + QMap > m_instances; +}; + +QT_END_NAMESPACE + +#endif // QMEDIAPLUGINLOADER_H diff --git a/src/multimediakit/qmediarecorder.cpp b/src/multimediakit/qmediarecorder.cpp new file mode 100644 index 000000000..1b5601249 --- /dev/null +++ b/src/multimediakit/qmediarecorder.cpp @@ -0,0 +1,899 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediarecorder.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaRecorder + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + + \brief The QMediaRecorder class is used for the recording of media content. + + The QMediaRecorder class is a high level media recording class. It's not + intended to be used alone but for accessing the media recording functions + of other media objects, like QRadioTuner, or QAudioCaptureSource. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Media recorder + + \sa QAudioCaptureSource +*/ + +namespace +{ +class MediaRecorderRegisterMetaTypes +{ +public: + MediaRecorderRegisterMetaTypes() + { + qRegisterMetaType("QMediaRecorder::State"); + qRegisterMetaType("QMediaRecorder::Error"); + } +} _registerRecorderMetaTypes; +} + + +class QMediaRecorderPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QMediaRecorder) + +public: + QMediaRecorderPrivate(); + + QMediaObject *mediaObject; + + QMediaRecorderControl *control; + QMediaContainerControl *formatControl; + QAudioEncoderControl *audioControl; + QVideoEncoderControl *videoControl; + QMetaDataWriterControl *metaDataControl; + + QTimer* notifyTimer; + + QMediaRecorder::State state; + QMediaRecorder::Error error; + QString errorString; + + void _q_stateChanged(QMediaRecorder::State state); + void _q_error(int error, const QString &errorString); + void _q_serviceDestroyed(); + void _q_notify(); + void _q_updateNotifyInterval(int ms); + + QMediaRecorder *q_ptr; +}; + +QMediaRecorderPrivate::QMediaRecorderPrivate(): + mediaObject(0), + control(0), + formatControl(0), + audioControl(0), + videoControl(0), + metaDataControl(0), + notifyTimer(0), + state(QMediaRecorder::StoppedState), + error(QMediaRecorder::NoError) +{ +} + +#define ENUM_NAME(c,e,v) (c::staticMetaObject.enumerator(c::staticMetaObject.indexOfEnumerator(e)).valueToKey((v))) + +void QMediaRecorderPrivate::_q_stateChanged(QMediaRecorder::State ps) +{ + Q_Q(QMediaRecorder); + + if (ps == QMediaRecorder::RecordingState) + notifyTimer->start(); + else + notifyTimer->stop(); + +// qDebug() << "Recorder state changed:" << ENUM_NAME(QMediaRecorder,"State",ps); + if (state != ps) { + emit q->stateChanged(ps); + } + + state = ps; +} + + +void QMediaRecorderPrivate::_q_error(int error, const QString &errorString) +{ + Q_Q(QMediaRecorder); + + this->error = QMediaRecorder::Error(error); + this->errorString = errorString; + + emit q->error(this->error); +} + +void QMediaRecorderPrivate::_q_serviceDestroyed() +{ + q_func()->setMediaObject(0); +} + +void QMediaRecorderPrivate::_q_notify() +{ + emit q_func()->durationChanged(q_func()->duration()); +} + +void QMediaRecorderPrivate::_q_updateNotifyInterval(int ms) +{ + notifyTimer->setInterval(ms); +} + + +/*! + Constructs a media recorder which records the media produced by \a mediaObject. + + The \a parent is passed to QMediaObject. + \since 1.0 +*/ + +QMediaRecorder::QMediaRecorder(QMediaObject *mediaObject, QObject *parent): + QObject(parent), + d_ptr(new QMediaRecorderPrivate) +{ + Q_D(QMediaRecorder); + d->q_ptr = this; + setMediaObject(mediaObject); + + d->notifyTimer = new QTimer(this); + d->notifyTimer->setInterval(mediaObject->notifyInterval()); + connect(d->notifyTimer, SIGNAL(timeout()), SLOT(_q_notify())); + connect(mediaObject, SIGNAL(notifyIntervalChanged(int)), SLOT(_q_updateNotifyInterval(int))); +} + +/*! + Destroys a media recorder object. +*/ + +QMediaRecorder::~QMediaRecorder() +{ +} + +/*! + Returns the QMediaObject instance that this QMediaRecorder is bound too, + or 0 otherwise. + \since 1.0 +*/ +QMediaObject *QMediaRecorder::mediaObject() const +{ + return d_func()->mediaObject; +} + +/*! + \internal + \since 1.0 +*/ +bool QMediaRecorder::setMediaObject(QMediaObject *object) +{ + Q_D(QMediaRecorder); + + if (object == d->mediaObject) + return true; + + if (d->mediaObject) { + if (d->control) { + disconnect(d->control, SIGNAL(stateChanged(QMediaRecorder::State)), + this, SLOT(_q_stateChanged(QMediaRecorder::State))); + + disconnect(d->control, SIGNAL(mutedChanged(bool)), + this, SIGNAL(mutedChanged(bool))); + + disconnect(d->control, SIGNAL(durationChanged(qint64)), + this, SIGNAL(durationChanged(qint64))); + + disconnect(d->control, SIGNAL(error(int,QString)), + this, SLOT(_q_error(int,QString))); + } + + QMediaService *service = d->mediaObject->service(); + + if (service) { + disconnect(service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed())); + + if (d->control) + service->releaseControl(d->control); + if (d->formatControl) + service->releaseControl(d->formatControl); + if (d->audioControl) + service->releaseControl(d->audioControl); + if (d->videoControl) + service->releaseControl(d->videoControl); + if (d->metaDataControl) { + disconnect(d->metaDataControl, SIGNAL(metaDataChanged()), + this, SIGNAL(metaDataChanged())); + disconnect(d->metaDataControl, SIGNAL(metaDataAvailableChanged(bool)), + this, SIGNAL(metaDataAvailableChanged(bool))); + disconnect(d->metaDataControl, SIGNAL(writableChanged(bool)), + this, SIGNAL(metaDataWritableChanged(bool))); + + service->releaseControl(d->metaDataControl); + } + } + } + + d->control = 0; + d->formatControl = 0; + d->audioControl = 0; + d->videoControl = 0; + d->metaDataControl = 0; + + d->mediaObject = object; + + if (d->mediaObject) { + QMediaService *service = d->mediaObject->service(); + + if (service) { + d->control = qobject_cast(service->requestControl(QMediaRecorderControl_iid)); + + if (d->control) { + d->formatControl = qobject_cast(service->requestControl(QMediaContainerControl_iid)); + d->audioControl = qobject_cast(service->requestControl(QAudioEncoderControl_iid)); + d->videoControl = qobject_cast(service->requestControl(QVideoEncoderControl_iid)); + + QMediaControl *control = service->requestControl(QMetaDataWriterControl_iid); + if (control) { + d->metaDataControl = qobject_cast(control); + if (!d->metaDataControl) { + service->releaseControl(control); + } else { + connect(d->metaDataControl, + SIGNAL(metaDataChanged()), + SIGNAL(metaDataChanged())); + connect(d->metaDataControl, + SIGNAL(metaDataAvailableChanged(bool)), + SIGNAL(metaDataAvailableChanged(bool))); + connect(d->metaDataControl, + SIGNAL(writableChanged(bool)), + SIGNAL(metaDataWritableChanged(bool))); + } + } + + connect(d->control, SIGNAL(stateChanged(QMediaRecorder::State)), + this, SLOT(_q_stateChanged(QMediaRecorder::State))); + + connect(d->control, SIGNAL(mutedChanged(bool)), + this, SIGNAL(mutedChanged(bool))); + + connect(d->control, SIGNAL(durationChanged(qint64)), + this, SIGNAL(durationChanged(qint64))); + + connect(d->control, SIGNAL(error(int,QString)), + this, SLOT(_q_error(int,QString))); + + connect(service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed())); + + + return true; + } + } + + d->mediaObject = 0; + return false; + } + + return true; +} + +/*! + \property QMediaRecorder::outputLocation + \brief the destination location of media content. + + Setting the location can fail, for example when the service supports only + local file system locations but a network URL was passed. If the service + does not support media recording this setting the output location will + always fail. + + The \a location can be relative or empty; + in this case the recorder uses the system specific place and file naming scheme. + After recording has stated, QMediaRecorder::outputLocation() returns the actual output location. + \since 1.0 +*/ + +/*! + Returns true if media recorder service ready to use. + \since 1.0 +*/ +bool QMediaRecorder::isAvailable() const +{ + if (d_func()->control != NULL) + return true; + else + return false; +} + +/*! + Returns the availability error code. + \since 1.0 +*/ +QtMultimediaKit::AvailabilityError QMediaRecorder::availabilityError() const +{ + if (d_func()->control != NULL) + return QtMultimediaKit::NoError; + else + return QtMultimediaKit::ServiceMissingError; +} + +QUrl QMediaRecorder::outputLocation() const +{ + return d_func()->control ? d_func()->control->outputLocation() : QUrl(); +} + +bool QMediaRecorder::setOutputLocation(const QUrl &location) +{ + Q_D(QMediaRecorder); + return d->control ? d->control->setOutputLocation(location) : false; +} + +/*! + Returns the current media recorder state. + + \since 1.0 + \sa QMediaRecorder::State +*/ + +QMediaRecorder::State QMediaRecorder::state() const +{ + return d_func()->control ? QMediaRecorder::State(d_func()->control->state()) : StoppedState; +} + +/*! + Returns the current error state. + + \since 1.0 + \sa errorString() +*/ + +QMediaRecorder::Error QMediaRecorder::error() const +{ + return d_func()->error; +} + +/*! + Returns a string describing the current error state. + + \since 1.0 + \sa error() +*/ + +QString QMediaRecorder::errorString() const +{ + return d_func()->errorString; +} + +/*! + \property QMediaRecorder::duration + + \brief the recorded media duration in milliseconds. + \since 1.0 +*/ + +qint64 QMediaRecorder::duration() const +{ + return d_func()->control ? d_func()->control->duration() : 0; +} + +/*! + \property QMediaRecorder::muted + + \brief whether a recording audio stream is muted. + \since 1.0 +*/ + +bool QMediaRecorder::isMuted() const +{ + return d_func()->control ? d_func()->control->isMuted() : 0; +} + +void QMediaRecorder::setMuted(bool muted) +{ + Q_D(QMediaRecorder); + + if (d->control) + d->control->setMuted(muted); +} + +/*! + Returns a list of MIME types of supported container formats. + \since 1.0 +*/ +QStringList QMediaRecorder::supportedContainers() const +{ + return d_func()->formatControl ? + d_func()->formatControl->supportedContainers() : QStringList(); +} + +/*! + Returns a description of a container format \a mimeType. + \since 1.0 +*/ +QString QMediaRecorder::containerDescription(const QString &mimeType) const +{ + return d_func()->formatControl ? + d_func()->formatControl->containerDescription(mimeType) : QString(); +} + +/*! + Returns the MIME type of the selected container format. + \since 1.0 +*/ + +QString QMediaRecorder::containerMimeType() const +{ + return d_func()->formatControl ? + d_func()->formatControl->containerMimeType() : QString(); +} + +/*! + Returns a list of supported audio codecs. + \since 1.0 +*/ +QStringList QMediaRecorder::supportedAudioCodecs() const +{ + return d_func()->audioControl ? + d_func()->audioControl->supportedAudioCodecs() : QStringList(); +} + +/*! + Returns a description of an audio \a codec. + \since 1.0 +*/ +QString QMediaRecorder::audioCodecDescription(const QString &codec) const +{ + return d_func()->audioControl ? + d_func()->audioControl->codecDescription(codec) : QString(); +} + +/*! + Returns a list of supported audio sample rates. + + If non null audio \a settings parameter is passed, the returned list is + reduced to sample rates supported with partial settings applied. + + This can be used to query the list of sample rates, supported by specific + audio codec. + + If the encoder supports arbitrary sample rates within the supported rates + range, *\a continuous is set to true, otherwise *\a continuous is set to + false. + \since 1.0 +*/ + +QList QMediaRecorder::supportedAudioSampleRates(const QAudioEncoderSettings &settings, bool *continuous) const +{ + if (continuous) + *continuous = false; + + return d_func()->audioControl ? + d_func()->audioControl->supportedSampleRates(settings, continuous) : QList(); +} + +/*! + Returns a list of resolutions video can be encoded at. + + If non null video \a settings parameter is passed, the returned list is + reduced to resolution supported with partial settings like video codec or + framerate applied. + + If the encoder supports arbitrary resolutions within the supported range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + + \since 1.0 + \sa QVideoEncoderSettings::resolution() +*/ +QList QMediaRecorder::supportedResolutions(const QVideoEncoderSettings &settings, bool *continuous) const +{ + if (continuous) + *continuous = false; + + return d_func()->videoControl ? + d_func()->videoControl->supportedResolutions(settings, continuous) : QList(); +} + +/*! + Returns a list of frame rates video can be encoded at. + + If non null video \a settings parameter is passed, the returned list is + reduced to frame rates supported with partial settings like video codec or + resolution applied. + + If the encoder supports arbitrary frame rates within the supported range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + + \since 1.0 + \sa QVideoEncoderSettings::frameRate() +*/ +QList QMediaRecorder::supportedFrameRates(const QVideoEncoderSettings &settings, bool *continuous) const +{ + if (continuous) + *continuous = false; + + return d_func()->videoControl ? + d_func()->videoControl->supportedFrameRates(settings, continuous) : QList(); +} + +/*! + Returns a list of supported video codecs. + \since 1.0 +*/ +QStringList QMediaRecorder::supportedVideoCodecs() const +{ + return d_func()->videoControl ? + d_func()->videoControl->supportedVideoCodecs() : QStringList(); +} + +/*! + Returns a description of a video \a codec. + + \since 1.0 + \sa setEncodingSettings() +*/ +QString QMediaRecorder::videoCodecDescription(const QString &codec) const +{ + return d_func()->videoControl ? + d_func()->videoControl->videoCodecDescription(codec) : QString(); +} + +/*! + Returns the audio encoder settings being used. + + \since 1.0 + \sa setEncodingSettings() +*/ + +QAudioEncoderSettings QMediaRecorder::audioSettings() const +{ + return d_func()->audioControl ? + d_func()->audioControl->audioSettings() : QAudioEncoderSettings(); +} + +/*! + Returns the video encoder settings being used. + + \since 1.0 + \sa setEncodingSettings() +*/ + +QVideoEncoderSettings QMediaRecorder::videoSettings() const +{ + return d_func()->videoControl ? + d_func()->videoControl->videoSettings() : QVideoEncoderSettings(); +} + +/*! + Sets the \a audio and \a video encoder settings and \a container format MIME type. + + If some parameters are not specified, or null settings are passed, the + encoder will choose default encoding parameters, depending on media + source properties. + While setEncodingSettings is optional, the backend can preload + encoding pipeline to improve recording startup time. + + It's only possible to change settings when the encoder is in the + QMediaEncoder::StoppedState state. + + \since 1.0 + \sa audioSettings(), videoSettings(), containerMimeType() +*/ + +void QMediaRecorder::setEncodingSettings(const QAudioEncoderSettings &audio, + const QVideoEncoderSettings &video, + const QString &container) +{ + Q_D(QMediaRecorder); + + QCamera *camera = qobject_cast(d->mediaObject); + if (camera && camera->captureMode() == QCamera::CaptureVideo) { + QMetaObject::invokeMethod(camera, + "_q_preparePropertyChange", + Qt::DirectConnection, + Q_ARG(int, QCameraControl::VideoEncodingSettings)); + } + + if (d->audioControl) + d->audioControl->setAudioSettings(audio); + + if (d->videoControl) + d->videoControl->setVideoSettings(video); + + if (d->formatControl) + d->formatControl->setContainerMimeType(container); + + if (d->control) + d->control->applySettings(); +} + + +/*! + Start recording. + + This is an asynchronous call, with signal + stateCahnged(QMediaRecorder::RecordingState) being emitted when recording + started, otherwise the error() signal is emitted. + \since 1.0 +*/ + +void QMediaRecorder::record() +{ + Q_D(QMediaRecorder); + + // reset error + d->error = NoError; + d->errorString = QString(); + + if (d->control) + d->control->record(); +} + +/*! + Pause recording. + \since 1.0 +*/ + +void QMediaRecorder::pause() +{ + Q_D(QMediaRecorder); + if (d->control) + d->control->pause(); +} + +/*! + Stop recording. + \since 1.0 +*/ + +void QMediaRecorder::stop() +{ + Q_D(QMediaRecorder); + if (d->control) + d->control->stop(); +} + +/*! + \enum QMediaRecorder::State + + \value StoppedState The recorder is not active. + \value RecordingState The recorder is currently active and producing data. + \value PausedState The recorder is paused. +*/ + +/*! + \enum QMediaRecorder::Error + + \value NoError No Errors. + \value ResourceError Device is not ready or not available. + \value FormatError Current format is not supported. +*/ + +/*! + \fn QMediaRecorder::stateChanged(State state) + + Signals that a media recorder's \a state has changed. + \since 1.0 +*/ + +/*! + \fn QMediaRecorder::durationChanged(qint64 duration) + + Signals that the \a duration of the recorded media has changed. + \since 1.0 +*/ + +/*! + \fn QMediaRecorder::error(QMediaRecorder::Error error) + + Signals that an \a error has occurred. + \since 1.0 +*/ + +/*! + \fn QMediaRecorder::mutedChanged(bool muted) + + Signals that the \a muted state has changed. If true the recording is being muted. + \since 1.0 +*/ + +/*! + \property QMediaRecorder::metaDataAvailable + \brief whether access to a media object's meta-data is available. + + If this is true there is meta-data available, otherwise there is no meta-data available. + \since 1.0 +*/ + +bool QMediaRecorder::isMetaDataAvailable() const +{ + Q_D(const QMediaRecorder); + + return d->metaDataControl + ? d->metaDataControl->isMetaDataAvailable() + : false; +} + +/*! + \fn QMediaRecorder::metaDataAvailableChanged(bool available) + + Signals that the \a available state of a media object's meta-data has changed. + \since 1.0 +*/ + +/*! + \property QMediaRecorder::metaDataWritable + \brief whether a media object's meta-data is writable. + + If this is true the meta-data is writable, otherwise the meta-data is read-only. + \since 1.0 +*/ + +bool QMediaRecorder::isMetaDataWritable() const +{ + Q_D(const QMediaRecorder); + + return d->metaDataControl + ? d->metaDataControl->isWritable() + : false; +} + +/*! + \fn QMediaRecorder::metaDataWritableChanged(bool writable) + + Signals that the \a writable state of a media object's meta-data has changed. + \since 1.0 +*/ + +/*! + Returns the value associated with a meta-data \a key. + \since 1.0 +*/ +QVariant QMediaRecorder::metaData(QtMultimediaKit::MetaData key) const +{ + Q_D(const QMediaRecorder); + + return d->metaDataControl + ? d->metaDataControl->metaData(key) + : QVariant(); +} + +/*! + Sets a \a value for a meta-data \a key. + + \note To ensure that meta data is set corretly, it should be set before starting the recording. + Once the recording is stopped, any meta data set will be attached to the next recording. + \since 1.0 +*/ +void QMediaRecorder::setMetaData(QtMultimediaKit::MetaData key, const QVariant &value) +{ + Q_D(QMediaRecorder); + + if (d->metaDataControl) + d->metaDataControl->setMetaData(key, value); +} + +/*! + Returns a list of keys there is meta-data available for. + \since 1.0 +*/ +QList QMediaRecorder::availableMetaData() const +{ + Q_D(const QMediaRecorder); + + return d->metaDataControl + ? d->metaDataControl->availableMetaData() + : QList(); +} + +/*! + \fn QMediaRecorder::metaDataChanged() + + Signals that a media object's meta-data has changed. + \since 1.0 +*/ + +/*! + Returns the value associated with a meta-data \a key. + + The naming and type of extended meta-data is not standardized, so the values and meaning + of keys may vary between backends. + \since 1.0 +*/ +QVariant QMediaRecorder::extendedMetaData(const QString &key) const +{ + Q_D(const QMediaRecorder); + + return d->metaDataControl + ? d->metaDataControl->extendedMetaData(key) + : QVariant(); +} + +/*! + Sets a \a value for a meta-data \a key. + + The naming and type of extended meta-data is not standardized, so the values and meaning + of keys may vary between backends. + \since 1.0 +*/ +void QMediaRecorder::setExtendedMetaData(const QString &key, const QVariant &value) +{ + Q_D(QMediaRecorder); + + if (d->metaDataControl) + d->metaDataControl->setExtendedMetaData(key, value); +} + +/*! + Returns a list of keys there is extended meta-data available for. + \since 1.0 +*/ +QStringList QMediaRecorder::availableExtendedMetaData() const +{ + Q_D(const QMediaRecorder); + + return d->metaDataControl + ? d->metaDataControl->availableExtendedMetaData() + : QStringList(); +} + +#include "moc_qmediarecorder.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediarecorder.h b/src/multimediakit/qmediarecorder.h new file mode 100644 index 000000000..4f5d6fd69 --- /dev/null +++ b/src/multimediakit/qmediarecorder.h @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIARECORDER_H +#define QMEDIARECORDER_H + +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE +class QUrl; +class QSize; +class QAudioFormat; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class QMediaRecorderService; +class QAudioEncoderSettings; +class QVideoEncoderSettings; + +class QMediaRecorderPrivate; +class Q_MULTIMEDIA_EXPORT QMediaRecorder : public QObject, public QMediaBindableInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaBindableInterface) + Q_ENUMS(State) + Q_ENUMS(Error) + Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged) + Q_PROPERTY(QUrl outputLocation READ outputLocation WRITE setOutputLocation) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) + Q_PROPERTY(bool metaDataAvailable READ isMetaDataAvailable NOTIFY metaDataAvailableChanged) + Q_PROPERTY(bool metaDataWritable READ isMetaDataWritable NOTIFY metaDataWritableChanged) +public: + + enum State + { + StoppedState, + RecordingState, + PausedState + }; + + enum Error + { + NoError, + ResourceError, + FormatError + }; + + QMediaRecorder(QMediaObject *mediaObject, QObject *parent = 0); + ~QMediaRecorder(); + + QMediaObject *mediaObject() const; + + bool isAvailable() const; + QtMultimediaKit::AvailabilityError availabilityError() const; + + QUrl outputLocation() const; + bool setOutputLocation(const QUrl &location); + + State state() const; + + Error error() const; + QString errorString() const; + + qint64 duration() const; + + bool isMuted() const; + + QStringList supportedContainers() const; + QString containerDescription(const QString &containerMimeType) const; + + QStringList supportedAudioCodecs() const; + QString audioCodecDescription(const QString &codecName) const; + + QList supportedAudioSampleRates(const QAudioEncoderSettings &settings = QAudioEncoderSettings(), + bool *continuous = 0) const; + + QStringList supportedVideoCodecs() const; + QString videoCodecDescription(const QString &codecName) const; + + QList supportedResolutions(const QVideoEncoderSettings &settings = QVideoEncoderSettings(), + bool *continuous = 0) const; + + QList supportedFrameRates(const QVideoEncoderSettings &settings = QVideoEncoderSettings(), + bool *continuous = 0) const; + + QAudioEncoderSettings audioSettings() const; + QVideoEncoderSettings videoSettings() const; + QString containerMimeType() const; + + void setEncodingSettings(const QAudioEncoderSettings &audioSettings, + const QVideoEncoderSettings &videoSettings = QVideoEncoderSettings(), + const QString &containerMimeType = QString()); + + + bool isMetaDataAvailable() const; + bool isMetaDataWritable() const; + + QVariant metaData(QtMultimediaKit::MetaData key) const; + void setMetaData(QtMultimediaKit::MetaData key, const QVariant &value); + QList availableMetaData() const; + + QVariant extendedMetaData(const QString &key) const; + void setExtendedMetaData(const QString &key, const QVariant &value); + QStringList availableExtendedMetaData() const; + +public Q_SLOTS: + void record(); + void pause(); + void stop(); + void setMuted(bool muted); + +Q_SIGNALS: + void stateChanged(QMediaRecorder::State state); + void durationChanged(qint64 duration); + void mutedChanged(bool muted); + + void error(QMediaRecorder::Error error); + + void metaDataAvailableChanged(bool available); + void metaDataWritableChanged(bool writable); + void metaDataChanged(); + +protected: + bool setMediaObject(QMediaObject *object); + +private: + QMediaRecorderPrivate *d_ptr; + Q_DISABLE_COPY(QMediaRecorder) + Q_DECLARE_PRIVATE(QMediaRecorder) + Q_PRIVATE_SLOT(d_func(), void _q_stateChanged(QMediaRecorder::State)) + Q_PRIVATE_SLOT(d_func(), void _q_error(int, const QString &)) + Q_PRIVATE_SLOT(d_func(), void _q_serviceDestroyed()) + Q_PRIVATE_SLOT(d_func(), void _q_notify()) + Q_PRIVATE_SLOT(d_func(), void _q_updateNotifyInterval(int)) +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QMediaRecorder::State) +Q_DECLARE_METATYPE(QMediaRecorder::Error) + +Q_MEDIA_ENUM_DEBUG(QMediaRecorder, State) +Q_MEDIA_ENUM_DEBUG(QMediaRecorder, Error) + +#endif // QMEDIARECORDER_H diff --git a/src/multimediakit/qmediarecordercontrol.cpp b/src/multimediakit/qmediarecordercontrol.cpp new file mode 100644 index 000000000..2b88ee9ef --- /dev/null +++ b/src/multimediakit/qmediarecordercontrol.cpp @@ -0,0 +1,209 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediarecordercontrol.h" + +QT_BEGIN_NAMESPACE + + +/*! + \class QMediaRecorderControl + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + + \brief The QMediaRecorderControl class provides access to the recording + functionality of a QMediaService. + + If a QMediaService can record media it will implement QMediaRecorderControl. + This control provides a means to set the \l {outputLocation()}{output location}, + and \l {record()}{start}, \l {pause()}{pause} and \l {stop()}{stop} + recording. It also provides feedback on the \l {duration()}{duration} + of the recording. + + The functionality provided by this control is exposed to application + code through the QMediaRecorder class. + + The interface name of QMediaRecorderControl is \c com.nokia.Qt.QMediaRecorderControl/1.0 as + defined in QMediaRecorderControl_iid. + + \sa QMediaService::requestControl(), QMediaRecorder + +*/ + +/*! + \macro QMediaRecorderControl_iid + + \c com.nokia.Qt.QMediaRecorderControl/1.0 + + Defines the interface name of the QMediaRecorderControl class. + + \relates QMediaRecorderControl +*/ + +/*! + Constructs a media recorder control with the given \a parent. +*/ + +QMediaRecorderControl::QMediaRecorderControl(QObject* parent) + : QMediaControl(parent) +{ +} + +/*! + Destroys a media recorder control. +*/ + +QMediaRecorderControl::~QMediaRecorderControl() +{ +} + +/*! + \fn QUrl QMediaRecorderControl::outputLocation() const + + Returns the current output location being used. + \since 1.0 +*/ + +/*! + \fn bool QMediaRecorderControl::setOutputLocation(const QUrl &location) + + Sets the output \a location and returns if this operation is successful. + If file at the output location already exists, it should be overwritten. + + The \a location can be relative or empty; + in this case the service should use the system specific place and file naming scheme. + After recording has stated, QMediaRecorderControl::outputLocation() should return the actual output location. + \since 1.0 +*/ + +/*! + \fn int QMediaRecorderControl::state() const + + Return the current recording state. + \since 1.0 +*/ + +/*! + \fn qint64 QMediaRecorderControl::duration() const + + Return the current duration in milliseconds. + \since 1.0 +*/ + +/*! + \fn void QMediaRecorderControl::record() + + Start recording. + \since 1.0 +*/ + +/*! + \fn void QMediaRecorderControl::pause() + + Pause recording. + \since 1.0 +*/ + +/*! + \fn void QMediaRecorderControl::stop() + + Stop recording. + \since 1.0 +*/ + +/*! + \fn void QMediaRecorderControl::applySettings() + + Commits the encoder settings and performs pre-initialization to reduce delays when recording + is started. + \since 1.0 +*/ + +/*! + \fn bool QMediaRecorderControl::isMuted() const + + Returns true if the recorder is muted, and false if it is not. + \since 1.0 +*/ + +/*! + \fn void QMediaRecorderControl::setMuted(bool muted) + + Sets the \a muted state of a media recorder. + \since 1.0 +*/ + + +/*! + \fn void QMediaRecorderControl::stateChanged(QMediaRecorder::State state) + + Signals that the \a state of a media recorder has changed. + \since 1.0 +*/ + +/*! + \fn void QMediaRecorderControl::durationChanged(qint64 duration) + + Signals that the \a duration of the recorded media has changed. + + This only emitted when there is a discontinuous change in the duration such as being reset to 0. + \since 1.0 +*/ + +/*! + \fn void QMediaRecorderControl::mutedChanged(bool muted) + + Signals that the \a muted state of a media recorder has changed. + \since 1.0 +*/ + +/*! + \fn void QMediaRecorderControl::error(int error, const QString &errorString) + + Signals that an \a error has occurred. The \a errorString describes the error. + \since 1.0 +*/ + +#include "moc_qmediarecordercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediarecordercontrol.h b/src/multimediakit/qmediarecordercontrol.h new file mode 100644 index 000000000..bc5bf71be --- /dev/null +++ b/src/multimediakit/qmediarecordercontrol.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIARECORDERCONTROL_H +#define QMEDIARECORDERCONTROL_H + +#include "qmediacontrol.h" +#include "qmediarecorder.h" + +QT_BEGIN_NAMESPACE +class QUrl; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QMediaRecorderControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QMediaRecorderControl(); + + virtual QUrl outputLocation() const = 0; + virtual bool setOutputLocation(const QUrl &location) = 0; + + virtual QMediaRecorder::State state() const = 0; + + virtual qint64 duration() const = 0; + + virtual bool isMuted() const = 0; + + virtual void applySettings() = 0; + +Q_SIGNALS: + void stateChanged(QMediaRecorder::State state); + void durationChanged(qint64 position); + void mutedChanged(bool muted); + void error(int error, const QString &errorString); + +public Q_SLOTS: + virtual void record() = 0; + virtual void pause() = 0; + virtual void stop() = 0; + virtual void setMuted(bool muted) = 0; + +protected: + QMediaRecorderControl(QObject* parent = 0); +}; + +#define QMediaRecorderControl_iid "com.nokia.Qt.QMediaRecorderControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaRecorderControl, QMediaRecorderControl_iid) + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/qmediaresource.cpp b/src/multimediakit/qmediaresource.cpp new file mode 100644 index 000000000..a0dddb103 --- /dev/null +++ b/src/multimediakit/qmediaresource.cpp @@ -0,0 +1,440 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaresource.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaResource + + \brief The QMediaResource class provides a description of a media resource. + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + A media resource is composed of a \l {url()}{URL} containing the + location of the resource and a set of properties that describe the + format of the resource. The properties provide a means to assess a + resource without first attempting to load it, and in situations where + media be represented by multiple alternative representations provide a + means to select the appropriate resource. + + Media made available by a remote services can often be available in + multiple encodings or quality levels, this allows a client to select + an appropriate resource based on considerations such as codecs supported, + network bandwidth, and display constraints. QMediaResource includes + information such as the \l {mimeType()}{MIME type}, \l {audioCodec()}{audio} + and \l {videoCodec()}{video} codecs, \l {audioBitRate()}{audio} and + \l {videoBitRate()}{video} bit rates, and \l {resolution()}{resolution} + so these constraints and others can be evaluated. + + The only mandatory property of a QMediaResource is the url(). + + \sa QMediaContent +*/ + +/*! + \typedef QMediaResourceList + + Synonym for \c QList +*/ + +/*! + Constructs a null media resource. +*/ +QMediaResource::QMediaResource() +{ +} + +/*! + Constructs a media resource with the given \a mimeType from a \a url. + \since 1.0 +*/ +QMediaResource::QMediaResource(const QUrl &url, const QString &mimeType) +{ + values.insert(Url, url); + values.insert(MimeType, mimeType); +} + +/*! + Constructs a media resource with the given \a mimeType from a network \a request. + \since 1.0 +*/ +QMediaResource::QMediaResource(const QNetworkRequest &request, const QString &mimeType) +{ + values.insert(Request, QVariant::fromValue(request)); + values.insert(Url, request.url()); + values.insert(MimeType, mimeType); +} + +/*! + Constructs a copy of a media resource \a other. + \since 1.0 +*/ +QMediaResource::QMediaResource(const QMediaResource &other) + : values(other.values) +{ +} + +/*! + Assigns the value of \a other to a media resource. + \since 1.0 +*/ +QMediaResource &QMediaResource::operator =(const QMediaResource &other) +{ + values = other.values; + + return *this; +} + +/*! + Destroys a media resource. +*/ +QMediaResource::~QMediaResource() +{ +} + + +/*! + Compares a media resource to \a other. + + Returns true if the resources are identical, and false otherwise. + \since 1.0 +*/ +bool QMediaResource::operator ==(const QMediaResource &other) const +{ + // Compare requests directly as QNetworkRequests are "custom types". + foreach (int key, values.keys()) { + switch (key) { + case Request: + if (request() != other.request()) + return false; + break; + default: + if (values.value(key) != other.values.value(key)) + return false; + } + } + return true; +} + +/*! + Compares a media resource to \a other. + + Returns true if they are different, and false otherwise. + \since 1.0 +*/ +bool QMediaResource::operator !=(const QMediaResource &other) const +{ + return !(*this == other); +} + +/*! + Identifies if a media resource is null. + + Returns true if the resource is null, and false otherwise. + \since 1.0 +*/ +bool QMediaResource::isNull() const +{ + return values.isEmpty(); +} + +/*! + Returns the URL of a media resource. + \since 1.0 +*/ +QUrl QMediaResource::url() const +{ + return qvariant_cast(values.value(Url)); +} + +/*! + Returns the network request associated with this media resource. + \since 1.0 +*/ +QNetworkRequest QMediaResource::request() const +{ + if(values.contains(Request)) + return qvariant_cast(values.value(Request)); + + return QNetworkRequest(url()); +} + +/*! + Returns the MIME type of a media resource. + + This may be null if the MIME type is unknown. + \since 1.0 +*/ +QString QMediaResource::mimeType() const +{ + return qvariant_cast(values.value(MimeType)); +} + +/*! + Returns the language of a media resource as an ISO 639-2 code. + + This may be null if the language is unknown. + \since 1.0 +*/ +QString QMediaResource::language() const +{ + return qvariant_cast(values.value(Language)); +} + +/*! + Sets the \a language of a media resource. + \since 1.0 +*/ +void QMediaResource::setLanguage(const QString &language) +{ + if (!language.isNull()) + values.insert(Language, language); + else + values.remove(Language); +} + +/*! + Returns the audio codec of a media resource. + + This may be null if the media resource does not contain an audio stream, or the codec is + unknown. + \since 1.0 +*/ +QString QMediaResource::audioCodec() const +{ + return qvariant_cast(values.value(AudioCodec)); +} + +/*! + Sets the audio \a codec of a media resource. + \since 1.0 +*/ +void QMediaResource::setAudioCodec(const QString &codec) +{ + if (!codec.isNull()) + values.insert(AudioCodec, codec); + else + values.remove(AudioCodec); +} + +/*! + Returns the video codec of a media resource. + + This may be null if the media resource does not contain a video stream, or the codec is + unknonwn. + \since 1.0 +*/ +QString QMediaResource::videoCodec() const +{ + return qvariant_cast(values.value(VideoCodec)); +} + +/*! + Sets the video \a codec of media resource. + \since 1.0 +*/ +void QMediaResource::setVideoCodec(const QString &codec) +{ + if (!codec.isNull()) + values.insert(VideoCodec, codec); + else + values.remove(VideoCodec); +} + +/*! + Returns the size in bytes of a media resource. + + This may be zero if the size is unknown. + \since 1.0 +*/ +qint64 QMediaResource::dataSize() const +{ + return qvariant_cast(values.value(DataSize)); +} + +/*! + Sets the \a size in bytes of a media resource. + \since 1.0 +*/ +void QMediaResource::setDataSize(const qint64 size) +{ + if (size != 0) + values.insert(DataSize, size); + else + values.remove(DataSize); +} + +/*! + Returns the bit rate in bits per second of a media resource's audio stream. + + This may be zero if the bit rate is unknown, or the resource contains no audio stream. + \since 1.0 +*/ +int QMediaResource::audioBitRate() const +{ + return values.value(AudioBitRate).toInt(); +} + +/*! + Sets the bit \a rate in bits per second of a media resource's video stream. + \since 1.0 +*/ +void QMediaResource::setAudioBitRate(int rate) +{ + if (rate != 0) + values.insert(AudioBitRate, rate); + else + values.remove(AudioBitRate); +} + +/*! + Returns the audio sample rate of a media resource. + + This may be zero if the sample size is unknown, or the resource contains no audio stream. + \since 1.0 +*/ +int QMediaResource::sampleRate() const +{ + return qvariant_cast(values.value(SampleRate)); +} + +/*! + Sets the audio \a sampleRate of a media resource. + \since 1.0 +*/ +void QMediaResource::setSampleRate(int sampleRate) +{ + if (sampleRate != 0) + values.insert(SampleRate, sampleRate); + else + values.remove(SampleRate); +} + +/*! + Returns the number of audio channels in a media resource. + + This may be zero if the sample size is unknown, or the resource contains no audio stream. + \since 1.0 +*/ +int QMediaResource::channelCount() const +{ + return qvariant_cast(values.value(ChannelCount)); +} + +/*! + Sets the number of audio \a channels in a media resource. + \since 1.0 +*/ +void QMediaResource::setChannelCount(int channels) +{ + if (channels != 0) + values.insert(ChannelCount, channels); + else + values.remove(ChannelCount); +} + +/*! + Returns the bit rate in bits per second of a media resource's video stream. + + This may be zero if the bit rate is unknown, or the resource contains no video stream. + \since 1.0 +*/ +int QMediaResource::videoBitRate() const +{ + return values.value(VideoBitRate).toInt(); +} + +/*! + Sets the bit \a rate in bits per second of a media resource's video stream. + \since 1.0 +*/ +void QMediaResource::setVideoBitRate(int rate) +{ + if (rate != 0) + values.insert(VideoBitRate, rate); + else + values.remove(VideoBitRate); +} + +/*! + Returns the resolution in pixels of a media resource. + + This may be null is the resolution is unknown, or the resource contains no pixel data (i.e. the + resource is an audio stream. + \since 1.0 +*/ +QSize QMediaResource::resolution() const +{ + return qvariant_cast(values.value(Resolution)); +} + +/*! + Sets the \a resolution in pixels of a media resource. + \since 1.0 +*/ +void QMediaResource::setResolution(const QSize &resolution) +{ + if (resolution.width() != -1 || resolution.height() != -1) + values.insert(Resolution, resolution); + else + values.remove(Resolution); +} + +/*! + Sets the \a width and \a height in pixels of a media resource. + \since 1.0 +*/ +void QMediaResource::setResolution(int width, int height) +{ + if (width != -1 || height != -1) + values.insert(Resolution, QSize(width, height)); + else + values.remove(Resolution); +} +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediaresource.h b/src/multimediakit/qmediaresource.h new file mode 100644 index 000000000..0dd930cc2 --- /dev/null +++ b/src/multimediakit/qmediaresource.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIARESOURCE_H +#define QMEDIARESOURCE_H + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QMediaResource +{ +public: + QMediaResource(); + QMediaResource(const QUrl &url, const QString &mimeType = QString()); + QMediaResource(const QNetworkRequest &request, const QString &mimeType = QString()); + QMediaResource(const QMediaResource &other); + QMediaResource &operator =(const QMediaResource &other); + ~QMediaResource(); + + bool isNull() const; + + bool operator ==(const QMediaResource &other) const; + bool operator !=(const QMediaResource &other) const; + + QUrl url() const; + QNetworkRequest request() const; + QString mimeType() const; + + QString language() const; + void setLanguage(const QString &language); + + QString audioCodec() const; + void setAudioCodec(const QString &codec); + + QString videoCodec() const; + void setVideoCodec(const QString &codec); + + qint64 dataSize() const; + void setDataSize(const qint64 size); + + int audioBitRate() const; + void setAudioBitRate(int rate); + + int sampleRate() const; + void setSampleRate(int frequency); + + int channelCount() const; + void setChannelCount(int channels); + + int videoBitRate() const; + void setVideoBitRate(int rate); + + QSize resolution() const; + void setResolution(const QSize &resolution); + void setResolution(int width, int height); + + +private: + enum Property + { + Url, + Request, + MimeType, + Language, + AudioCodec, + VideoCodec, + DataSize, + AudioBitRate, + VideoBitRate, + SampleRate, + ChannelCount, + Resolution + }; + QMap values; +}; + +typedef QList QMediaResourceList; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QMediaResource) +Q_DECLARE_METATYPE(QMediaResourceList) + + +#endif diff --git a/src/multimediakit/qmediaservice.cpp b/src/multimediakit/qmediaservice.cpp new file mode 100644 index 000000000..6ea6fa20c --- /dev/null +++ b/src/multimediakit/qmediaservice.cpp @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaservice.h" +#include "qmediaservice_p.h" + +#include + + + +QT_BEGIN_NAMESPACE + + +/*! + \class QMediaService + \brief The QMediaService class provides a common base class for media + service implementations. + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + + Media services provide implementations of the functionality promised + by media objects, and allow multiple providers to implement a QMediaObject. + + To provide the functionality of a QMediaObject media services implement + QMediaControl interfaces. Services typically implement one core media + control which provides the core feature of a media object, and some + number of additional controls which provide either optional features of + the media object, or features of a secondary media object or peripheral + object. + + A pointer to media service's QMediaControl implementation can be obtained + by passing the control's interface name to the requestControl() function. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Request control + + Media objects can use services loaded dynamically from plug-ins or + implemented statically within an applications. Plug-in based services + should also implement the QMediaServiceProviderPlugin interface. Static + services should implement the QMediaServiceProvider interface. + + \sa QMediaObject, QMediaControl, QMediaServiceProvider, QMediaServiceProviderPlugin +*/ + +/*! + Construct a media service with the given \a parent. This class is meant as a + base class for Multimedia services so this constructor is protected. +*/ + +QMediaService::QMediaService(QObject *parent) + : QObject(parent) + , d_ptr(new QMediaServicePrivate) +{ + d_ptr->q_ptr = this; +} + +/*! + \internal +*/ +QMediaService::QMediaService(QMediaServicePrivate &dd, QObject *parent) + : QObject(parent) + , d_ptr(&dd) +{ + d_ptr->q_ptr = this; +} + +/*! + Destroys a media service. +*/ + +QMediaService::~QMediaService() +{ + delete d_ptr; +} + +/*! + \fn QMediaControl* QMediaService::requestControl(const char *interface) + + Returns a pointer to the media control implementing \a interface. + + If the service does not implement the control, or if it is unavailable a + null pointer is returned instead. + + Controls must be returned to the service when no longer needed using the + releaseControl() function. + \since 1.0 +*/ + +/*! + \fn T QMediaService::requestControl() + + Returns a pointer to the media control of type T implemented by a media service. + + If the service does not implement the control, or if it is unavailable a + null pointer is returned instead. + + Controls must be returned to the service when no longer needed using the + releaseControl() function. + \since 1.0 +*/ + +/*! + \fn void QMediaService::releaseControl(QMediaControl *control); + + Releases a \a control back to the service. + \since 1.0 +*/ + +#include "moc_qmediaservice.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediaservice.h b/src/multimediakit/qmediaservice.h new file mode 100644 index 000000000..57ae3bba3 --- /dev/null +++ b/src/multimediakit/qmediaservice.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTMEDIASERVICE_H +#define QABSTRACTMEDIASERVICE_H + +#include +#include +#include + +#include "qmediacontrol.h" + +QT_BEGIN_NAMESPACE + +class QMediaServicePrivate; +class Q_MULTIMEDIA_EXPORT QMediaService : public QObject +{ + Q_OBJECT + +public: + ~QMediaService(); + + virtual QMediaControl* requestControl(const char *name) = 0; + +#ifndef QT_NO_MEMBER_TEMPLATES + template inline T requestControl() { + if (QMediaControl *control = requestControl(qmediacontrol_iid())) { + if (T typedControl = qobject_cast(control)) + return typedControl; + releaseControl(control); + } + return 0; + } +#endif + + virtual void releaseControl(QMediaControl *control) = 0; + +protected: + QMediaService(QObject* parent); + QMediaService(QMediaServicePrivate &dd, QObject *parent); + + QMediaServicePrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QMediaService) +}; + +QT_END_NAMESPACE + +#endif // QABSTRACTMEDIASERVICE_H + diff --git a/src/multimediakit/qmediaservice_p.h b/src/multimediakit/qmediaservice_p.h new file mode 100644 index 000000000..37eac75ca --- /dev/null +++ b/src/multimediakit/qmediaservice_p.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTMEDIASERVICE_P_H +#define QABSTRACTMEDIASERVICE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +class QAudioDeviceControl; + +class QMediaServicePrivate +{ +public: + QMediaServicePrivate(): q_ptr(0) {} + virtual ~QMediaServicePrivate() {} + + QMediaService *q_ptr; +}; + +QT_END_NAMESPACE + + +#endif diff --git a/src/multimediakit/qmediaserviceprovider.cpp b/src/multimediakit/qmediaserviceprovider.cpp new file mode 100644 index 000000000..74db5a2e0 --- /dev/null +++ b/src/multimediakit/qmediaserviceprovider.cpp @@ -0,0 +1,780 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "qmediaservice.h" +#include "qmediaserviceprovider.h" +#include "qmediaserviceproviderplugin.h" +#include "qmediapluginloader_p.h" +#include "qmediaplayer.h" + +QT_BEGIN_NAMESPACE + +class QMediaServiceProviderHintPrivate : public QSharedData +{ +public: + QMediaServiceProviderHintPrivate(QMediaServiceProviderHint::Type type) + :type(type), features(0) + { + } + + QMediaServiceProviderHintPrivate(const QMediaServiceProviderHintPrivate &other) + :QSharedData(other), + type(other.type), + device(other.device), + mimeType(other.mimeType), + codecs(other.codecs), + features(other.features) + { + } + + ~QMediaServiceProviderHintPrivate() + { + } + + QMediaServiceProviderHint::Type type; + QByteArray device; + QString mimeType; + QStringList codecs; + QMediaServiceProviderHint::Features features; +}; + +/*! + \class QMediaServiceProviderHint + + \brief The QMediaServiceProviderHint class describes what is required of a QMediaService. + + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + The QMediaServiceProvider class uses hints to select an appropriate media service. +*/ + +/*! + \enum QMediaServiceProviderHint::Feature + + Enumerates features a media service may provide. + + \value LowLatencyPlayback + The service is expected to play simple audio formats, + but playback should start without significant delay. + Such playback service can be used for beeps, ringtones, etc. + + \value RecordingSupport + The service provides audio or video recording functions. + + \value StreamPlayback + The service is capable of playing QIODevice based streams. + + \value VideoSurface + The service is capable of renderering to a QAbstractVideoSurface + output. +*/ + +/*! + \enum QMediaServiceProviderHint::Type + + Enumerates the possible types of media service provider hint. + + \value Null En empty hint, use the default service. + \value ContentType Select media service most suitable for certain content type. + \value Device Select media service which supports certain device. + \value SupportedFeatures Select media service supporting the set of optional features. +*/ + + +/*! + Constructs an empty media service provider hint. +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint() + :d(new QMediaServiceProviderHintPrivate(Null)) +{ +} + +/*! + Constructs a ContentType media service provider hint. + + This type of hint describes a service that is able to play content of a specific MIME \a type + encoded with one or more of the listed \a codecs. + \since 1.0 +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint(const QString &type, const QStringList& codecs) + :d(new QMediaServiceProviderHintPrivate(ContentType)) +{ + d->mimeType = type; + d->codecs = codecs; +} + +/*! + Constructs a Device media service provider hint. + + This type of hint describes a media service that utilizes a specific \a device. + \since 1.0 +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint(const QByteArray &device) + :d(new QMediaServiceProviderHintPrivate(Device)) +{ + d->device = device; +} + +/*! + Constructs a SupportedFeatures media service provider hint. + + This type of hint describes a service which supports a specific set of \a features. + \since 1.0 +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint(QMediaServiceProviderHint::Features features) + :d(new QMediaServiceProviderHintPrivate(SupportedFeatures)) +{ + d->features = features; +} + +/*! + Constructs a copy of the media service provider hint \a other. + \since 1.0 +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint(const QMediaServiceProviderHint &other) + :d(other.d) +{ +} + +/*! + Destroys a media service provider hint. +*/ +QMediaServiceProviderHint::~QMediaServiceProviderHint() +{ +} + +/*! + Assigns the value \a other to a media service provider hint. + \since 1.0 +*/ +QMediaServiceProviderHint& QMediaServiceProviderHint::operator=(const QMediaServiceProviderHint &other) +{ + d = other.d; + return *this; +} + +/*! + Identifies if \a other is of equal value to a media service provider hint. + + Returns true if the hints are equal, and false if they are not. + \since 1.0 +*/ +bool QMediaServiceProviderHint::operator == (const QMediaServiceProviderHint &other) const +{ + return (d == other.d) || + (d->type == other.d->type && + d->device == other.d->device && + d->mimeType == other.d->mimeType && + d->codecs == other.d->codecs && + d->features == other.d->features); +} + +/*! + Identifies if \a other is not of equal value to a media service provider hint. + + Returns true if the hints are not equal, and false if they are. + \since 1.0 +*/ +bool QMediaServiceProviderHint::operator != (const QMediaServiceProviderHint &other) const +{ + return !(*this == other); +} + +/*! + Returns true if a media service provider is null. + \since 1.0 +*/ +bool QMediaServiceProviderHint::isNull() const +{ + return d->type == Null; +} + +/*! + Returns the type of a media service provider hint. + \since 1.0 +*/ +QMediaServiceProviderHint::Type QMediaServiceProviderHint::type() const +{ + return d->type; +} + +/*! + Returns the mime type of the media a service is expected to be able play. + \since 1.0 +*/ +QString QMediaServiceProviderHint::mimeType() const +{ + return d->mimeType; +} + +/*! + Returns a list of codes a media service is expected to be able to decode. + \since 1.0 +*/ +QStringList QMediaServiceProviderHint::codecs() const +{ + return d->codecs; +} + +/*! + Returns the name of a device a media service is expected to utilize. + \since 1.0 +*/ +QByteArray QMediaServiceProviderHint::device() const +{ + return d->device; +} + +/*! + Returns a set of features a media service is expected to provide. + \since 1.0 +*/ +QMediaServiceProviderHint::Features QMediaServiceProviderHint::features() const +{ + return d->features; +} + + +Q_GLOBAL_STATIC_WITH_ARGS(QMediaPluginLoader, loader, + (QMediaServiceProviderFactoryInterface_iid, QLatin1String("mediaservice"), Qt::CaseInsensitive)) + + +class QPluginServiceProvider : public QMediaServiceProvider +{ + QMap pluginMap; + +public: + QMediaService* requestService(const QByteArray &type, const QMediaServiceProviderHint &hint) + { + QString key(type); + + QListplugins; + foreach (QObject *obj, loader()->instances(key)) { + QMediaServiceProviderPlugin *plugin = + qobject_cast(obj); + if (plugin) + plugins << plugin; + } + + if (!plugins.isEmpty()) { + QMediaServiceProviderPlugin *plugin = 0; + + switch (hint.type()) { + case QMediaServiceProviderHint::Null: + plugin = plugins[0]; + //special case for media player, if low latency was not asked, + //prefer services not offering it, since they are likely to support + //more formats + if (type == QByteArray(Q_MEDIASERVICE_MEDIAPLAYER)) { + foreach (QMediaServiceProviderPlugin *currentPlugin, plugins) { + QMediaServiceFeaturesInterface *iface = + qobject_cast(currentPlugin); + + if (!iface || !(iface->supportedFeatures(type) & + QMediaServiceProviderHint::LowLatencyPlayback)) { + plugin = currentPlugin; + break; + } + + } + } + break; + case QMediaServiceProviderHint::SupportedFeatures: + plugin = plugins[0]; + foreach (QMediaServiceProviderPlugin *currentPlugin, plugins) { + QMediaServiceFeaturesInterface *iface = + qobject_cast(currentPlugin); + + if (iface) { + if ((iface->supportedFeatures(type) & hint.features()) == hint.features()) { + plugin = currentPlugin; + break; + } + } + } + break; + case QMediaServiceProviderHint::Device: { + foreach (QMediaServiceProviderPlugin *currentPlugin, plugins) { + QMediaServiceSupportedDevicesInterface *iface = + qobject_cast(currentPlugin); + + if (!iface) { + // the plugin may support the device, + // but this choice still can be overridden + plugin = currentPlugin; + } else { + if (iface->devices(type).contains(hint.device())) { + plugin = currentPlugin; + break; + } + } + } + } + break; + case QMediaServiceProviderHint::ContentType: { + QtMultimediaKit::SupportEstimate estimate = QtMultimediaKit::NotSupported; + foreach (QMediaServiceProviderPlugin *currentPlugin, plugins) { + QtMultimediaKit::SupportEstimate currentEstimate = QtMultimediaKit::MaybeSupported; + QMediaServiceSupportedFormatsInterface *iface = + qobject_cast(currentPlugin); + + if (iface) + currentEstimate = iface->hasSupport(hint.mimeType(), hint.codecs()); + + if (currentEstimate > estimate) { + estimate = currentEstimate; + plugin = currentPlugin; + + if (currentEstimate == QtMultimediaKit::PreferredService) + break; + } + } + } + break; + } + + if (plugin != 0) { + QMediaService *service = plugin->create(key); + if (service != 0) + pluginMap.insert(service, plugin); + + return service; + } + } + + qWarning() << "defaultServiceProvider::requestService(): no service found for -" << key; + return 0; + } + + void releaseService(QMediaService *service) + { + if (service != 0) { + QMediaServiceProviderPlugin *plugin = pluginMap.take(service); + + if (plugin != 0) + plugin->release(service); + } + } + + QtMultimediaKit::SupportEstimate hasSupport(const QByteArray &serviceType, + const QString &mimeType, + const QStringList& codecs, + int flags) const + { + QList instances = loader()->instances(serviceType); + + if (instances.isEmpty()) + return QtMultimediaKit::NotSupported; + + bool allServicesProvideInterface = true; + QtMultimediaKit::SupportEstimate supportEstimate = QtMultimediaKit::NotSupported; + + foreach(QObject *obj, instances) { + QMediaServiceSupportedFormatsInterface *iface = + qobject_cast(obj); + + + if (flags) { + QMediaServiceFeaturesInterface *iface = + qobject_cast(obj); + + if (iface) { + QMediaServiceProviderHint::Features features = iface->supportedFeatures(serviceType); + + //if low latency playback was asked, skip services known + //not to provide low latency playback + if ((flags & QMediaPlayer::LowLatency) && + !(features & QMediaServiceProviderHint::LowLatencyPlayback)) + continue; + + //the same for QIODevice based streams support + if ((flags & QMediaPlayer::StreamPlayback) && + !(features & QMediaServiceProviderHint::StreamPlayback)) + continue; + } + } + + if (iface) + supportEstimate = qMax(supportEstimate, iface->hasSupport(mimeType, codecs)); + else + allServicesProvideInterface = false; + } + + //don't return PreferredService + supportEstimate = qMin(supportEstimate, QtMultimediaKit::ProbablySupported); + + //Return NotSupported only if no services are available of serviceType + //or all the services returned NotSupported, otherwise return at least MaybeSupported + if (!allServicesProvideInterface) + supportEstimate = qMax(QtMultimediaKit::MaybeSupported, supportEstimate); + + return supportEstimate; + } + + QStringList supportedMimeTypes(const QByteArray &serviceType, int flags) const + { + QList instances = loader()->instances(serviceType); + + QStringList supportedTypes; + + foreach(QObject *obj, instances) { + QMediaServiceSupportedFormatsInterface *iface = + qobject_cast(obj); + + + if (flags) { + QMediaServiceFeaturesInterface *iface = + qobject_cast(obj); + + if (iface) { + QMediaServiceProviderHint::Features features = iface->supportedFeatures(serviceType); + + // If low latency playback was asked for, skip MIME types from services known + // not to provide low latency playback + if ((flags & QMediaPlayer::LowLatency) && + !(features & QMediaServiceProviderHint::LowLatencyPlayback)) + continue; + + //the same for QIODevice based streams support + if ((flags & QMediaPlayer::StreamPlayback) && + !(features & QMediaServiceProviderHint::StreamPlayback)) + continue; + + //the same for QAbstractVideoSurface support + if ((flags & QMediaPlayer::VideoSurface) && + !(features & QMediaServiceProviderHint::VideoSurface)) + continue; + } + } + + if (iface) { + supportedTypes << iface->supportedMimeTypes(); + } + } + + // Multiple services may support the same MIME type + supportedTypes.removeDuplicates(); + + return supportedTypes; + } + + QList devices(const QByteArray &serviceType) const + { + QList res; + + foreach(QObject *obj, loader()->instances(serviceType)) { + QMediaServiceSupportedDevicesInterface *iface = + qobject_cast(obj); + + if (iface) { + res.append(iface->devices(serviceType)); + } + } + + return res; + } + + QString deviceDescription(const QByteArray &serviceType, const QByteArray &device) + { + foreach(QObject *obj, loader()->instances(serviceType)) { + QMediaServiceSupportedDevicesInterface *iface = + qobject_cast(obj); + + if (iface) { + if (iface->devices(serviceType).contains(device)) + return iface->deviceDescription(serviceType, device); + } + } + + return QString(); + } +}; + +Q_GLOBAL_STATIC(QPluginServiceProvider, pluginProvider); + +/*! + \class QMediaServiceProvider + + \brief The QMediaServiceProvider class provides an abstract allocator for media services. + \since 1.0 +*/ + +/*! + \fn QMediaServiceProvider::requestService(const QByteArray &type, const QMediaServiceProviderHint &hint) + + Requests an instance of a \a type service which best matches the given \a + hint. + + Returns a pointer to the requested service, or a null pointer if there is + no suitable service. + + The returned service must be released with releaseService when it is + finished with. + \since 1.0 +*/ + +/*! + \fn QMediaServiceProvider::releaseService(QMediaService *service) + + Releases a media \a service requested with requestService(). + \since 1.0 +*/ + +/*! + \fn QtMultimediaKit::SupportEstimate QMediaServiceProvider::hasSupport(const QByteArray &serviceType, const QString &mimeType, const QStringList& codecs, int flags) const + + Returns how confident a media service provider is that is can provide a \a + serviceType service that is able to play media of a specific \a mimeType + that is encoded using the listed \a codecs while adhering to constraints + identified in \a flags. + \since 1.0 +*/ +QtMultimediaKit::SupportEstimate QMediaServiceProvider::hasSupport(const QByteArray &serviceType, + const QString &mimeType, + const QStringList& codecs, + int flags) const +{ + Q_UNUSED(serviceType); + Q_UNUSED(mimeType); + Q_UNUSED(codecs); + Q_UNUSED(flags); + + return QtMultimediaKit::MaybeSupported; +} + +/*! + \fn QStringList QMediaServiceProvider::supportedMimeTypes(const QByteArray &serviceType, int flags) const + + Returns a list of MIME types supported by the service provider for the + specified \a serviceType. + + The resultant list is restricted to MIME types which can be supported given + the constraints in \a flags. + \since 1.0 +*/ +QStringList QMediaServiceProvider::supportedMimeTypes(const QByteArray &serviceType, int flags) const +{ + Q_UNUSED(serviceType); + Q_UNUSED(flags); + + return QStringList(); +} + +/*! + Returns the list of devices related to \a service type. + \since 1.0 +*/ +QList QMediaServiceProvider::devices(const QByteArray &service) const +{ + Q_UNUSED(service); + return QList(); +} + +/*! + Returns the description of \a device related to \a serviceType, suitable for use by + an application for display. + \since 1.0 +*/ +QString QMediaServiceProvider::deviceDescription(const QByteArray &serviceType, const QByteArray &device) +{ + Q_UNUSED(serviceType); + Q_UNUSED(device); + return QString(); +} + + +#ifdef QT_BUILD_INTERNAL + +static QMediaServiceProvider *qt_defaultMediaServiceProvider = 0; + +/*! + Sets a media service \a provider as the default. + + \internal + \since 1.0 +*/ +void QMediaServiceProvider::setDefaultServiceProvider(QMediaServiceProvider *provider) +{ + qt_defaultMediaServiceProvider = provider; +} + +#endif + +/*! + Returns a default provider of media services. +*/ +QMediaServiceProvider *QMediaServiceProvider::defaultServiceProvider() +{ +#ifdef QT_BUILD_INTERNAL + return qt_defaultMediaServiceProvider != 0 + ? qt_defaultMediaServiceProvider + : static_cast(pluginProvider()); +#else + return pluginProvider(); +#endif +} + +/*! + \class QMediaServiceProviderPlugin + + \brief The QMediaServiceProviderPlugin class interface provides an interface for QMediaService + plug-ins. + \since 1.0 + + A media service provider plug-in may implement one or more of + QMediaServiceSupportedFormatsInterface, + QMediaServiceSupportedDevicesInterface, and QMediaServiceFeaturesInterface + to identify the features it supports. +*/ + +/*! + \fn QMediaServiceProviderPlugin::keys() const + + Returns a list of keys for media services a plug-in can create. + \since 1.0 +*/ + +/*! + \fn QMediaServiceProviderPlugin::create(const QString &key) + + Constructs a new instance of the QMediaService identified by \a key. + + The QMediaService returned must be destroyed with release(). + \since 1.0 +*/ + +/*! + \fn QMediaServiceProviderPlugin::release(QMediaService *service) + + Destroys a media \a service constructed with create(). + \since 1.0 +*/ + + +/*! + \class QMediaServiceSupportedFormatsInterface + \brief The QMediaServiceSupportedFormatsInterface class interface + identifies if a media service plug-in supports a media format. + \since 1.0 + + A QMediaServiceProviderPlugin may implement this interface. +*/ + +/*! + \fn QMediaServiceSupportedFormatsInterface::~QMediaServiceSupportedFormatsInterface() + + Destroys a media service supported formats interface. +*/ + +/*! + \fn QMediaServiceSupportedFormatsInterface::hasSupport(const QString &mimeType, const QStringList& codecs) const + + Returns the level of support a media service plug-in has for a \a mimeType + and set of \a codecs. + \since 1.0 +*/ + +/*! + \fn QMediaServiceSupportedFormatsInterface::supportedMimeTypes() const + + Returns a list of MIME types supported by the media service plug-in. + \since 1.0 +*/ + +/*! + \class QMediaServiceSupportedDevicesInterface + \brief The QMediaServiceSupportedDevicesInterface class interface + identifies the devices supported by a media service plug-in. + \since 1.0 + + A QMediaServiceProviderPlugin may implement this interface. +*/ + +/*! + \fn QMediaServiceSupportedDevicesInterface::~QMediaServiceSupportedDevicesInterface() + + Destroys a media service supported devices interface. +*/ + +/*! + \fn QMediaServiceSupportedDevicesInterface::devices(const QByteArray &service) const + + Returns a list of devices supported by a plug-in \a service. + \since 1.0 +*/ + +/*! + \fn QMediaServiceSupportedDevicesInterface::deviceDescription(const QByteArray &service, const QByteArray &device) + + Returns a description of a \a device supported by a plug-in \a service. + \since 1.0 +*/ + +/*! + \class QMediaServiceFeaturesInterface + \brief The QMediaServiceFeaturesInterface class interface identifies + features supported by a media service plug-in. + \since 1.0 + + A QMediaServiceProviderPlugin may implement this interface. +*/ + +/*! + \fn QMediaServiceFeaturesInterface::~QMediaServiceFeaturesInterface() + + Destroys a media service features interface. +*/ +/*! + \fn QMediaServiceFeaturesInterface::supportedFeatures(const QByteArray &service) const + + Returns a set of features supported by a plug-in \a service. + \since 1.0 +*/ + +#include "moc_qmediaserviceprovider.cpp" +#include "moc_qmediaserviceproviderplugin.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediaserviceprovider.h b/src/multimediakit/qmediaserviceprovider.h new file mode 100644 index 000000000..997f371f5 --- /dev/null +++ b/src/multimediakit/qmediaserviceprovider.h @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIASERVICEPROVIDER_H +#define QMEDIASERVICEPROVIDER_H + +#include +#include +#include +#include "qtmedianamespace.h" + +QT_BEGIN_NAMESPACE + +class QMediaService; + +class QMediaServiceProviderHintPrivate; +class Q_MULTIMEDIA_EXPORT QMediaServiceProviderHint +{ +public: + enum Type { Null, ContentType, Device, SupportedFeatures }; + + enum Feature { + LowLatencyPlayback = 0x01, + RecordingSupport = 0x02, + StreamPlayback = 0x04, + VideoSurface = 0x08 + }; + Q_DECLARE_FLAGS(Features, Feature) + + QMediaServiceProviderHint(); + QMediaServiceProviderHint(const QString &mimeType, const QStringList& codecs); + QMediaServiceProviderHint(const QByteArray &device); + QMediaServiceProviderHint(Features features); + QMediaServiceProviderHint(const QMediaServiceProviderHint &other); + ~QMediaServiceProviderHint(); + + QMediaServiceProviderHint& operator=(const QMediaServiceProviderHint &other); + + bool operator == (const QMediaServiceProviderHint &other) const; + bool operator != (const QMediaServiceProviderHint &other) const; + + bool isNull() const; + + Type type() const; + + QString mimeType() const; + QStringList codecs() const; + + QByteArray device() const; + + Features features() const; + + //to be extended, if necessary + +private: + QSharedDataPointer d; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QMediaServiceProviderHint::Features) + +class Q_MULTIMEDIA_EXPORT QMediaServiceProvider : public QObject +{ + Q_OBJECT + +public: + virtual QMediaService* requestService(const QByteArray &type, const QMediaServiceProviderHint &hint = QMediaServiceProviderHint()) = 0; + virtual void releaseService(QMediaService *service) = 0; + + virtual QtMultimediaKit::SupportEstimate hasSupport(const QByteArray &serviceType, + const QString &mimeType, + const QStringList& codecs, + int flags = 0) const; + virtual QStringList supportedMimeTypes(const QByteArray &serviceType, int flags = 0) const; + + virtual QList devices(const QByteArray &serviceType) const; + virtual QString deviceDescription(const QByteArray &serviceType, const QByteArray &device); + + static QMediaServiceProvider* defaultServiceProvider(); + +#ifdef QT_BUILD_INTERNAL + static void setDefaultServiceProvider(QMediaServiceProvider *provider); +#endif +}; + +/*! + Service with support for media playback + Required Controls: QMediaPlayerControl + Optional Controls: QMediaPlaylistControl, QAudioDeviceControl + Video Output Controls (used by QWideoWidget and QGraphicsVideoItem): + Required: QVideoOutputControl + Optional: QVideoWindowControl, QVideoRendererControl, QVideoWidgetControl +*/ +#define Q_MEDIASERVICE_MEDIAPLAYER "com.nokia.qt.mediaplayer" + +/*! + Service with support for recording from audio sources + Required Controls: QAudioDeviceControl + Recording Controls (QMediaRecorder): + Required: QMediaRecorderControl + Recommended: QAudioEncoderControl + Optional: QMediaContainerControl +*/ +#define Q_MEDIASERVICE_AUDIOSOURCE "com.nokia.qt.audiosource" + +/*! + Service with support for camera use. + Required Controls: QCameraControl + Optional Controls: QCameraExposureControl, QCameraFocusControl, QCameraImageProcessingControl + Still Capture Controls: QCameraImageCaptureControl + Video Capture Controls (QMediaRecorder): + Required: QMediaRecorderControl + Recommended: QAudioEncoderControl, QVideoEncoderControl, QMediaContainerControl + Viewfinder Video Output Controls (used by QCameraViewfinder and QGraphicsVideoItem): + Required: QVideoOutputControl + Optional: QVideoWindowControl, QVideoRendererControl, QVideoWidgetControl +*/ +#define Q_MEDIASERVICE_CAMERA "com.nokia.qt.camera" + +/*! + Service with support for radio tuning. + Required Controls: QRadioTunerControl + Recording Controls (Optional, used by QMediaRecorder): + Required: QMediaRecorderControl + Recommended: QAudioEncoderControl + Optional: QMediaContainerControl +*/ +#define Q_MEDIASERVICE_RADIO "com.nokia.qt.radio" + + +QT_END_NAMESPACE + +#endif // QMEDIASERVICEPROVIDER_H diff --git a/src/multimediakit/qmediaserviceproviderplugin.h b/src/multimediakit/qmediaserviceproviderplugin.h new file mode 100644 index 000000000..767dd4949 --- /dev/null +++ b/src/multimediakit/qmediaserviceproviderplugin.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIASERVICEPROVIDERPLUGIN_H +#define QMEDIASERVICEPROVIDERPLUGIN_H + +#include +#include +#include +#include +#include "qmediaserviceprovider.h" + +#ifdef Q_MOC_RUN +# pragma Q_MOC_EXPAND_MACROS +#endif + +QT_BEGIN_NAMESPACE + +class QMediaService; + +struct Q_MULTIMEDIA_EXPORT QMediaServiceProviderFactoryInterface : public QFactoryInterface +{ + virtual QStringList keys() const = 0; + virtual QMediaService* create(QString const& key) = 0; + virtual void release(QMediaService *service) = 0; +}; + +#define QMediaServiceProviderFactoryInterface_iid \ + "com.nokia.Qt.QMediaServiceProviderFactoryInterface/1.0" +Q_DECLARE_INTERFACE(QMediaServiceProviderFactoryInterface, QMediaServiceProviderFactoryInterface_iid) + + +struct Q_MULTIMEDIA_EXPORT QMediaServiceSupportedFormatsInterface +{ + virtual ~QMediaServiceSupportedFormatsInterface() {} + virtual QtMultimediaKit::SupportEstimate hasSupport(const QString &mimeType, const QStringList& codecs) const = 0; + virtual QStringList supportedMimeTypes() const = 0; +}; + +#define QMediaServiceSupportedFormatsInterface_iid \ + "com.nokia.Qt.QMediaServiceSupportedFormatsInterface/1.0" +Q_DECLARE_INTERFACE(QMediaServiceSupportedFormatsInterface, QMediaServiceSupportedFormatsInterface_iid) + + +struct Q_MULTIMEDIA_EXPORT QMediaServiceSupportedDevicesInterface +{ + virtual ~QMediaServiceSupportedDevicesInterface() {} + virtual QList devices(const QByteArray &service) const = 0; + virtual QString deviceDescription(const QByteArray &service, const QByteArray &device) = 0; +}; + +#define QMediaServiceSupportedDevicesInterface_iid \ + "com.nokia.Qt.QMediaServiceSupportedDevicesInterface/1.0" +Q_DECLARE_INTERFACE(QMediaServiceSupportedDevicesInterface, QMediaServiceSupportedDevicesInterface_iid) + + + +struct Q_MULTIMEDIA_EXPORT QMediaServiceFeaturesInterface +{ + virtual ~QMediaServiceFeaturesInterface() {} + virtual QMediaServiceProviderHint::Features supportedFeatures(const QByteArray &service) const = 0; +}; + +#define QMediaServiceFeaturesInterface_iid \ + "com.nokia.Qt.QMediaServiceFeaturesInterface/1.0" +Q_DECLARE_INTERFACE(QMediaServiceFeaturesInterface, QMediaServiceFeaturesInterface_iid) + + +class Q_MULTIMEDIA_EXPORT QMediaServiceProviderPlugin : public QObject, public QMediaServiceProviderFactoryInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceProviderFactoryInterface:QFactoryInterface) + +public: + virtual QStringList keys() const = 0; + virtual QMediaService* create(const QString& key) = 0; + virtual void release(QMediaService *service) = 0; +}; + +QT_END_NAMESPACE + + +#endif // QMEDIASERVICEPROVIDERPLUGIN_H diff --git a/src/multimediakit/qmediastreamscontrol.cpp b/src/multimediakit/qmediastreamscontrol.cpp new file mode 100644 index 000000000..3b4e668b3 --- /dev/null +++ b/src/multimediakit/qmediastreamscontrol.cpp @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediastreamscontrol.h" +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaStreamsControl + \preliminary + + \inmodule QtMultimediaKit + \ingroup multimedia + \brief The QMediaStreamsControl class provides a media stream selection control. + + \ingroup multimedia + \since 1.0 + + The QMediaStreamsControl class provides descriptions of the available media streams + and allows individual streams to be activated and deactivated. + + The interface name of QMediaStreamsControl is \c com.nokia.Qt.MediaStreamsControl as + defined in QMediaStreamsControl_iid. + + \sa QMediaService::requestControl() +*/ + +/*! + \macro QMediaStreamsControl_iid + + \c com.nokia.Qt.MediaStreamsControl + + Defines the interface name of the QMediaStreamsControl class. + + \relates QMediaStreamsControl + \since 1.0 +*/ + +/*! + Constructs a new media streams control with the given \a parent. +*/ +QMediaStreamsControl::QMediaStreamsControl(QObject *parent) + :QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroys a media streams control. +*/ +QMediaStreamsControl::~QMediaStreamsControl() +{ +} + +/*! + \enum QMediaStreamsControl::StreamType + + Media stream type. + + \value AudioStream Audio stream. + \value VideoStream Video stream. + \value SubPictureStream Subpicture or teletext stream. + \value UnknownStream The stream type is unknown. + \value DataStream +*/ + +/*! + \fn QMediaStreamsControl::streamCount() + + Returns the number of media streams. + \since 1.0 +*/ + +/*! + \fn QMediaStreamsControl::streamType(int stream) + + Return the type of a media \a stream. + \since 1.0 +*/ + +/*! + \fn QMediaStreamsControl::metaData(int stream, QtMultimediaKit::MetaData key) + + Returns the meta-data value of \a key for a given \a stream. + + Useful metadata keya are QtMultimediaKit::Title, QtMultimediaKit::Description and QtMultimediaKit::Language. + \since 1.0 +*/ + +/*! + \fn QMediaStreamsControl::isActive(int stream) + + Returns true if the media \a stream is active. + \since 1.0 +*/ + +/*! + \fn QMediaStreamsControl::setActive(int stream, bool state) + + Sets the active \a state of a media \a stream. + + Setting the active state of a media stream to true will activate it. If any other stream + of the same type was previously active it will be deactivated. Setting the active state fo a + media stream to false will deactivate it. + \since 1.0 +*/ + +/*! + \fn QMediaStreamsControl::streamsChanged() + + The signal is emitted when the available streams list is changed. + \since 1.0 +*/ + +/*! + \fn QMediaStreamsControl::activeStreamsChanged() + + The signal is emitted when the active streams list is changed. + \since 1.0 +*/ + +#include "moc_qmediastreamscontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediastreamscontrol.h b/src/multimediakit/qmediastreamscontrol.h new file mode 100644 index 000000000..a5ee71e3e --- /dev/null +++ b/src/multimediakit/qmediastreamscontrol.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMEDIASTREAMSCONTROL_H +#define QMEDIASTREAMSCONTROL_H + +#include "qmediacontrol.h" +#include "qtmedianamespace.h" +#include "qmobilityglobal.h" +#include + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QMediaStreamsControl : public QMediaControl +{ + Q_OBJECT + Q_ENUMS(SteamType) +public: + enum StreamType { UnknownStream, VideoStream, AudioStream, SubPictureStream, DataStream }; + + virtual ~QMediaStreamsControl(); + + virtual int streamCount() = 0; + virtual StreamType streamType(int streamNumber) = 0; + + virtual QVariant metaData(int streamNumber, QtMultimediaKit::MetaData key) = 0; + + virtual bool isActive(int streamNumber) = 0; + virtual void setActive(int streamNumber, bool state) = 0; + +Q_SIGNALS: + void streamsChanged(); + void activeStreamsChanged(); + +protected: + QMediaStreamsControl(QObject *parent = 0); +}; + +#define QMediaStreamsControl_iid "com.nokia.Qt.QMediaStreamsControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaStreamsControl, QMediaStreamsControl_iid) + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QMediaStreamsControl::StreamType) + +Q_MEDIA_ENUM_DEBUG(QMediaStreamsControl, StreamType) + +#endif // QMEDIASTREAMSCONTROL_H + diff --git a/src/multimediakit/qmediatimerange.cpp b/src/multimediakit/qmediatimerange.cpp new file mode 100644 index 000000000..9183f0ae1 --- /dev/null +++ b/src/multimediakit/qmediatimerange.cpp @@ -0,0 +1,759 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "qmediatimerange.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaTimeInterval + \brief The QMediaTimeInterval class represents a time interval with integer precision. + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + An interval is specified by an inclusive start() and end() time. These + must be set in the constructor, as this is an immutable class. The + specific units of time represented by the class have not been defined - it + is suitable for any times which can be represented by a signed 64 bit + integer. + + The isNormal() method determines if a time interval is normal (a normal + time interval has start() <= end()). An abnormal interval can be converted + in to a normal interval by calling the normalized() method. + + The contains() method determines if a specified time lies within the time + interval. + + The translated() method returns a time interval which has been translated + forwards or backwards through time by a specified offset. + + \sa QMediaTimeRange +*/ + +/*! + \fn QMediaTimeInterval::QMediaTimeInterval() + + Constructs an empty interval. +*/ +QMediaTimeInterval::QMediaTimeInterval() + : s(0) + , e(0) +{ + +} + +/*! + \fn QMediaTimeInterval::QMediaTimeInterval(qint64 start, qint64 end) + + Constructs an interval with the specified \a start and \a end times. + \since 1.0 +*/ +QMediaTimeInterval::QMediaTimeInterval(qint64 start, qint64 end) + : s(start) + , e(end) +{ + +} + +/*! + \fn QMediaTimeInterval::QMediaTimeInterval(const QMediaTimeInterval &other) + + Constructs an interval by taking a copy of \a other. + \since 1.0 +*/ +QMediaTimeInterval::QMediaTimeInterval(const QMediaTimeInterval &other) + : s(other.s) + , e(other.e) +{ + +} + +/*! + \fn QMediaTimeInterval::start() const + + Returns the start time of the interval. + + \since 1.0 + \sa end() +*/ +qint64 QMediaTimeInterval::start() const +{ + return s; +} + +/*! + \fn QMediaTimeInterval::end() const + + Returns the end time of the interval. + + \since 1.0 + \sa start() +*/ +qint64 QMediaTimeInterval::end() const +{ + return e; +} + +/*! + \fn QMediaTimeInterval::contains(qint64 time) const + + Returns true if the time interval contains the specified \a time. + That is, start() <= time <= end(). + \since 1.0 +*/ +bool QMediaTimeInterval::contains(qint64 time) const +{ + return isNormal() ? (s <= time && time <= e) + : (e <= time && time <= s); +} + +/*! + \fn QMediaTimeInterval::isNormal() const + + Returns true if this time interval is normal. + A normal time interval has start() <= end(). + + \since 1.0 + \sa normalized() +*/ +bool QMediaTimeInterval::isNormal() const +{ + return s <= e; +} + +/*! + \fn QMediaTimeInterval::normalized() const + + Returns a normalized version of this interval. + + If the start() time of the interval is greater than the end() time, + then the returned interval has the start and end times swapped. + \since 1.0 +*/ +QMediaTimeInterval QMediaTimeInterval::normalized() const +{ + if(s > e) + return QMediaTimeInterval(e, s); + + return *this; +} + +/*! + \fn QMediaTimeInterval::translated(qint64 offset) const + + Returns a copy of this time interval, translated by a value of \a offset. + An interval can be moved forward through time with a positive offset, or backward + through time with a negative offset. + \since 1.0 +*/ +QMediaTimeInterval QMediaTimeInterval::translated(qint64 offset) const +{ + return QMediaTimeInterval(s + offset, e + offset); +} + +/*! + \fn operator==(const QMediaTimeInterval &a, const QMediaTimeInterval &b) + \relates QMediaTimeRange + + Returns true if \a a is exactly equal to \a b. + \since 1.0 +*/ +bool operator==(const QMediaTimeInterval &a, const QMediaTimeInterval &b) +{ + return a.start() == b.start() && a.end() == b.end(); +} + +/*! + \fn operator!=(const QMediaTimeInterval &a, const QMediaTimeInterval &b) + \relates QMediaTimeRange + + Returns true if \a a is not exactly equal to \a b. + \since 1.0 +*/ +bool operator!=(const QMediaTimeInterval &a, const QMediaTimeInterval &b) +{ + return a.start() != b.start() || a.end() != b.end(); +} + +class QMediaTimeRangePrivate : public QSharedData +{ +public: + + QMediaTimeRangePrivate(); + QMediaTimeRangePrivate(const QMediaTimeRangePrivate &other); + QMediaTimeRangePrivate(const QMediaTimeInterval &interval); + + QList intervals; + + void addInterval(const QMediaTimeInterval &interval); + void removeInterval(const QMediaTimeInterval &interval); +}; + +QMediaTimeRangePrivate::QMediaTimeRangePrivate() + : QSharedData() +{ + +} + +QMediaTimeRangePrivate::QMediaTimeRangePrivate(const QMediaTimeRangePrivate &other) + : QSharedData() + , intervals(other.intervals) +{ + +} + +QMediaTimeRangePrivate::QMediaTimeRangePrivate(const QMediaTimeInterval &interval) + : QSharedData() +{ + if(interval.isNormal()) + intervals << interval; +} + +void QMediaTimeRangePrivate::addInterval(const QMediaTimeInterval &interval) +{ + // Handle normalized intervals only + if(!interval.isNormal()) + return; + + // Find a place to insert the interval + int i; + for (i = 0; i < intervals.count(); i++) { + // Insert before this element + if(interval.s < intervals[i].s) { + intervals.insert(i, interval); + break; + } + } + + // Interval needs to be added to the end of the list + if (i == intervals.count()) + intervals.append(interval); + + // Do we need to correct the element before us? + if(i > 0 && intervals[i - 1].e >= interval.s - 1) + i--; + + // Merge trailing ranges + while (i < intervals.count() - 1 + && intervals[i].e >= intervals[i + 1].s - 1) { + intervals[i].e = qMax(intervals[i].e, intervals[i + 1].e); + intervals.removeAt(i + 1); + } +} + +void QMediaTimeRangePrivate::removeInterval(const QMediaTimeInterval &interval) +{ + // Handle normalized intervals only + if(!interval.isNormal()) + return; + + for (int i = 0; i < intervals.count(); i++) { + QMediaTimeInterval r = intervals[i]; + + if (r.e < interval.s) { + // Before the removal interval + continue; + } else if (interval.e < r.s) { + // After the removal interval - stop here + break; + } else if (r.s < interval.s && interval.e < r.e) { + // Split case - a single range has a chunk removed + intervals[i].e = interval.s -1; + addInterval(QMediaTimeInterval(interval.e + 1, r.e)); + break; + } else if (r.s < interval.s) { + // Trimming Tail Case + intervals[i].e = interval.s - 1; + } else if (interval.e < r.e) { + // Trimming Head Case - we can stop after this + intervals[i].s = interval.e + 1; + break; + } else { + // Complete coverage case + intervals.removeAt(i); + --i; + } + } +} + +/*! + \class QMediaTimeRange + \brief The QMediaTimeRange class represents a set of zero or more disjoint + time intervals. + \ingroup multimedia + \since 1.0 + + \reentrant + + The earliestTime(), latestTime(), intervals() and isEmpty() + methods are used to get information about the current time range. + + The addInterval(), removeInterval() and clear() methods are used to modify + the current time range. + + When adding or removing intervals from the time range, existing intervals + within the range may be expanded, trimmed, deleted, merged or split to ensure + that all intervals within the time range remain distinct and disjoint. As a + consequence, all intervals added or removed from a time range must be + \l{QMediaTimeInterval::isNormal()}{normal}. + + \sa QMediaTimeInterval +*/ + +/*! + \fn QMediaTimeRange::QMediaTimeRange() + + Constructs an empty time range. +*/ +QMediaTimeRange::QMediaTimeRange() + : d(new QMediaTimeRangePrivate) +{ + +} + +/*! + \fn QMediaTimeRange::QMediaTimeRange(qint64 start, qint64 end) + + Constructs a time range that contains an initial interval from + \a start to \a end inclusive. + + If the interval is not \l{QMediaTimeInterval::isNormal()}{normal}, + the resulting time range will be empty. + + \since 1.0 + \sa addInterval() +*/ +QMediaTimeRange::QMediaTimeRange(qint64 start, qint64 end) + : d(new QMediaTimeRangePrivate(QMediaTimeInterval(start, end))) +{ + +} + +/*! + \fn QMediaTimeRange::QMediaTimeRange(const QMediaTimeInterval &interval) + + Constructs a time range that contains an intitial interval, \a interval. + + If \a interval is not \l{QMediaTimeInterval::isNormal()}{normal}, + the resulting time range will be empty. + + \since 1.0 + \sa addInterval() +*/ +QMediaTimeRange::QMediaTimeRange(const QMediaTimeInterval &interval) + : d(new QMediaTimeRangePrivate(interval)) +{ + +} + +/*! + \fn QMediaTimeRange::QMediaTimeRange(const QMediaTimeRange &range) + + Constructs a time range by copying another time \a range. + \since 1.0 +*/ +QMediaTimeRange::QMediaTimeRange(const QMediaTimeRange &range) + : d(range.d) +{ + +} + +/*! + \fn QMediaTimeRange::~QMediaTimeRange() + + Destructor. +*/ +QMediaTimeRange::~QMediaTimeRange() +{ + +} + +/*! + \fn QMediaTimeRange::operator=(const QMediaTimeRange &other) + + Takes a copy of the \a other time range and returns itself. + \since 1.0 +*/ +QMediaTimeRange &QMediaTimeRange::operator=(const QMediaTimeRange &other) +{ + d = other.d; + return *this; +} + +/*! + \fn QMediaTimeRange::operator=(const QMediaTimeInterval &interval) + + Sets the time range to a single continuous interval, \a interval. + \since 1.0 +*/ +QMediaTimeRange &QMediaTimeRange::operator=(const QMediaTimeInterval &interval) +{ + d = new QMediaTimeRangePrivate(interval); + return *this; +} + +/*! + \fn QMediaTimeRange::earliestTime() const + + Returns the earliest time within the time range. + + For empty time ranges, this value is equal to zero. + + \since 1.0 + \sa latestTime() +*/ +qint64 QMediaTimeRange::earliestTime() const +{ + if (!d->intervals.isEmpty()) + return d->intervals[0].s; + + return 0; +} + +/*! + \fn QMediaTimeRange::latestTime() const + + Returns the latest time within the time range. + + For empty time ranges, this value is equal to zero. + + \since 1.0 + \sa earliestTime() +*/ +qint64 QMediaTimeRange::latestTime() const +{ + if (!d->intervals.isEmpty()) + return d->intervals[d->intervals.count() - 1].e; + + return 0; +} + +/*! + \fn QMediaTimeRange::addInterval(qint64 start, qint64 end) + \overload + + Adds the interval specified by \a start and \a end + to the time range. + + \since 1.0 + \sa addInterval() +*/ +void QMediaTimeRange::addInterval(qint64 start, qint64 end) +{ + d->addInterval(QMediaTimeInterval(start, end)); +} + +/*! + \fn QMediaTimeRange::addInterval(const QMediaTimeInterval &interval) + + Adds the specified \a interval to the time range. + + Adding intervals which are not \l{QMediaTimeInterval::isNormal()}{normal} + is invalid, and will be ignored. + + If the specified interval is adjacent to, or overlaps existing + intervals within the time range, these intervals will be merged. + + This operation takes \l{linear time} + + \since 1.0 + \sa removeInterval() +*/ +void QMediaTimeRange::addInterval(const QMediaTimeInterval &interval) +{ + d->addInterval(interval); +} + +/*! + \fn QMediaTimeRange::addTimeRange(const QMediaTimeRange &range) + + Adds each of the intervals in \a range to this time range. + + Equivalent to calling addInterval() for each interval in \a range. + \since 1.0 +*/ +void QMediaTimeRange::addTimeRange(const QMediaTimeRange &range) +{ + foreach(const QMediaTimeInterval &i, range.intervals()) { + d->addInterval(i); + } +} + +/*! + \fn QMediaTimeRange::removeInterval(qint64 start, qint64 end) + \overload + + Removes the interval specified by \a start and \a end + from the time range. + + \since 1.0 + \sa removeInterval() +*/ +void QMediaTimeRange::removeInterval(qint64 start, qint64 end) +{ + d->removeInterval(QMediaTimeInterval(start, end)); +} + +/*! + \fn QMediaTimeRange::removeInterval(const QMediaTimeInterval &interval) + + Removes the specified \a interval from the time range. + + Removing intervals which are not \l{QMediaTimeInterval::isNormal()}{normal} + is invalid, and will be ignored. + + Intervals within the time range will be trimmed, split or deleted + such that no intervals within the time range include any part of the + target interval. + + This operation takes \l{linear time} + + \since 1.0 + \sa addInterval() +*/ +void QMediaTimeRange::removeInterval(const QMediaTimeInterval &interval) +{ + d->removeInterval(interval); +} + +/*! + \fn QMediaTimeRange::removeTimeRange(const QMediaTimeRange &range) + + Removes each of the intervals in \a range from this time range. + + Equivalent to calling removeInterval() for each interval in \a range. + \since 1.0 +*/ +void QMediaTimeRange::removeTimeRange(const QMediaTimeRange &range) +{ + foreach(const QMediaTimeInterval &i, range.intervals()) { + d->removeInterval(i); + } +} + +/*! + \fn QMediaTimeRange::operator+=(const QMediaTimeRange &other) + + Adds each interval in \a other to the time range and returns the result. + \since 1.0 +*/ +QMediaTimeRange& QMediaTimeRange::operator+=(const QMediaTimeRange &other) +{ + addTimeRange(other); + return *this; +} + +/*! + \fn QMediaTimeRange::operator+=(const QMediaTimeInterval &interval) + + Adds the specified \a interval to the time range and returns the result. + \since 1.0 +*/ +QMediaTimeRange& QMediaTimeRange::operator+=(const QMediaTimeInterval &interval) +{ + addInterval(interval); + return *this; +} + +/*! + \fn QMediaTimeRange::operator-=(const QMediaTimeRange &other) + + Removes each interval in \a other from the time range and returns the result. + \since 1.0 +*/ +QMediaTimeRange& QMediaTimeRange::operator-=(const QMediaTimeRange &other) +{ + removeTimeRange(other); + return *this; +} + +/*! + \fn QMediaTimeRange::operator-=(const QMediaTimeInterval &interval) + + Removes the specified \a interval from the time range and returns the result. + \since 1.0 +*/ +QMediaTimeRange& QMediaTimeRange::operator-=(const QMediaTimeInterval &interval) +{ + removeInterval(interval); + return *this; +} + +/*! + \fn QMediaTimeRange::clear() + + Removes all intervals from the time range. + + \since 1.0 + \sa removeInterval() +*/ +void QMediaTimeRange::clear() +{ + d->intervals.clear(); +} + +/*! + \fn QMediaTimeRange::intervals() const + + Returns the list of intervals covered by this time range. + \since 1.0 +*/ +QList QMediaTimeRange::intervals() const +{ + return d->intervals; +} + +/*! + \fn QMediaTimeRange::isEmpty() const + + Returns true if there are no intervals within the time range. + + \since 1.0 + \sa intervals() +*/ +bool QMediaTimeRange::isEmpty() const +{ + return d->intervals.isEmpty(); +} + +/*! + \fn QMediaTimeRange::isContinuous() const + + Returns true if the time range consists of a continuous interval. + That is, there is one or fewer disjoint intervals within the time range. + \since 1.0 +*/ +bool QMediaTimeRange::isContinuous() const +{ + return (d->intervals.count() <= 1); +} + +/*! + \fn QMediaTimeRange::contains(qint64 time) const + + Returns true if the specified \a time lies within the time range. + \since 1.0 +*/ +bool QMediaTimeRange::contains(qint64 time) const +{ + for (int i = 0; i < d->intervals.count(); i++) { + if (d->intervals[i].contains(time)) + return true; + + if (time < d->intervals[i].s) + break; + } + + return false; +} + +/*! + \fn operator==(const QMediaTimeRange &a, const QMediaTimeRange &b) + \relates QMediaTimeRange + + Returns true if all intervals in \a a are present in \a b. + \since 1.0 +*/ +bool operator==(const QMediaTimeRange &a, const QMediaTimeRange &b) +{ + if (a.intervals().count() != b.intervals().count()) + return false; + + for (int i = 0; i < a.intervals().count(); i++) + { + if(a.intervals()[i] != b.intervals()[i]) + return false; + } + + return true; +} + +/*! + \fn operator!=(const QMediaTimeRange &a, const QMediaTimeRange &b) + \relates QMediaTimeRange + + Returns true if one or more intervals in \a a are not present in \a b. + \since 1.0 +*/ +bool operator!=(const QMediaTimeRange &a, const QMediaTimeRange &b) +{ + return !(a == b); +} + +/*! + \fn operator+(const QMediaTimeRange &r1, const QMediaTimeRange &r2) + + Returns a time range containing the union between \a r1 and \a r2. + \since 1.0 + */ +QMediaTimeRange operator+(const QMediaTimeRange &r1, const QMediaTimeRange &r2) +{ + return (QMediaTimeRange(r1) += r2); +} + +/*! + \fn operator-(const QMediaTimeRange &r1, const QMediaTimeRange &r2) + + Returns a time range containing \a r2 subtracted from \a r1. + \since 1.0 + */ +QMediaTimeRange operator-(const QMediaTimeRange &r1, const QMediaTimeRange &r2) +{ + return (QMediaTimeRange(r1) -= r2); +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const QMediaTimeRange &range) +{ + dbg.nospace() << "QMediaTimeRange( "; + foreach (const QMediaTimeInterval &interval, range.intervals()) { + dbg.nospace() << "(" << interval.start() << ", " << interval.end() << ") "; + } + dbg.space() << ")"; + return dbg; +} +#endif + +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmediatimerange.h b/src/multimediakit/qmediatimerange.h new file mode 100644 index 000000000..cb236c688 --- /dev/null +++ b/src/multimediakit/qmediatimerange.h @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIATIMERANGE_H +#define QMEDIATIMERANGE_H + +#include +#include "qtmedianamespace.h" +#include + +QT_BEGIN_NAMESPACE + +class QMediaTimeRangePrivate; + +class Q_MULTIMEDIA_EXPORT QMediaTimeInterval +{ +public: + QMediaTimeInterval(); + QMediaTimeInterval(qint64 start, qint64 end); + QMediaTimeInterval(const QMediaTimeInterval&); + + qint64 start() const; + qint64 end() const; + + bool contains(qint64 time) const; + + bool isNormal() const; + QMediaTimeInterval normalized() const; + QMediaTimeInterval translated(qint64 offset) const; + +private: + friend class QMediaTimeRangePrivate; + friend class QMediaTimeRange; + + qint64 s; + qint64 e; +}; + +Q_MULTIMEDIA_EXPORT bool operator==(const QMediaTimeInterval&, const QMediaTimeInterval&); +Q_MULTIMEDIA_EXPORT bool operator!=(const QMediaTimeInterval&, const QMediaTimeInterval&); + +class Q_MULTIMEDIA_EXPORT QMediaTimeRange +{ +public: + + QMediaTimeRange(); + QMediaTimeRange(qint64 start, qint64 end); + QMediaTimeRange(const QMediaTimeInterval&); + QMediaTimeRange(const QMediaTimeRange &range); + ~QMediaTimeRange(); + + QMediaTimeRange &operator=(const QMediaTimeRange&); + QMediaTimeRange &operator=(const QMediaTimeInterval&); + + qint64 earliestTime() const; + qint64 latestTime() const; + + QList intervals() const; + bool isEmpty() const; + bool isContinuous() const; + + bool contains(qint64 time) const; + + void addInterval(qint64 start, qint64 end); + void addInterval(const QMediaTimeInterval &interval); + void addTimeRange(const QMediaTimeRange&); + + void removeInterval(qint64 start, qint64 end); + void removeInterval(const QMediaTimeInterval &interval); + void removeTimeRange(const QMediaTimeRange&); + + QMediaTimeRange& operator+=(const QMediaTimeRange&); + QMediaTimeRange& operator+=(const QMediaTimeInterval&); + QMediaTimeRange& operator-=(const QMediaTimeRange&); + QMediaTimeRange& operator-=(const QMediaTimeInterval&); + + void clear(); + +private: + QSharedDataPointer d; +}; + +Q_MULTIMEDIA_EXPORT bool operator==(const QMediaTimeRange&, const QMediaTimeRange&); +Q_MULTIMEDIA_EXPORT bool operator!=(const QMediaTimeRange&, const QMediaTimeRange&); +Q_MULTIMEDIA_EXPORT QMediaTimeRange operator+(const QMediaTimeRange&, const QMediaTimeRange&); +Q_MULTIMEDIA_EXPORT QMediaTimeRange operator-(const QMediaTimeRange&, const QMediaTimeRange&); + +#ifndef QT_NO_DEBUG_STREAM +Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, const QMediaTimeRange &); +#endif + +QT_END_NAMESPACE + +#endif // QMEDIATIMERANGE_H diff --git a/src/multimediakit/qmetadatareadercontrol.cpp b/src/multimediakit/qmetadatareadercontrol.cpp new file mode 100644 index 000000000..8f9b86acb --- /dev/null +++ b/src/multimediakit/qmetadatareadercontrol.cpp @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +QT_BEGIN_NAMESPACE + + +/*! + \class QMetaDataReaderControl + \inmodule QtMultimediaKit + \ingroup multimedia-serv + \since 1.0 + + + \brief The QMetaDataReaderControl class provides read access to the + meta-data of a QMediaService's media. + + If a QMediaService can provide read or write access to the meta-data of + its current media it will implement QMetaDataReaderControl. This control + provides functions for both retrieving and setting meta-data values. + Meta-data may be addressed by the well defined keys in the + QtMultimediaKit::MetaData enumeration using the metaData() functions, or by + string keys using the extendedMetaData() functions. + + The functionality provided by this control is exposed to application + code by the meta-data members of QMediaObject, and so meta-data access + is potentially available in any of the media object classes. Any media + service may implement QMetaDataReaderControl. + + The interface name of QMetaDataReaderControl is + \c com.nokia.Qt.QMetaDataReaderControl/1.0 as defined in + QMetaDataReaderControl_iid. + + \sa QMediaService::requestControl(), QMediaObject +*/ + +/*! + \macro QMetaDataReaderControl_iid + + \c com.nokia.Qt.QMetaDataReaderControl/1.0 + + Defines the interface name of the QMetaDataReaderControl class. + + \relates QMetaDataReaderControl +*/ + +/*! + Construct a QMetaDataReaderControl with \a parent. This class is meant as a base class + for service specific meta data providers so this constructor is protected. +*/ + +QMetaDataReaderControl::QMetaDataReaderControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroy the meta-data object. +*/ + +QMetaDataReaderControl::~QMetaDataReaderControl() +{ +} + +/*! + \fn bool QMetaDataReaderControl::isMetaDataAvailable() const + + Identifies if meta-data is available from a media service. + + Returns true if the meta-data is available and false otherwise. + \since 1.0 +*/ + +/*! + \fn QVariant QMetaDataReaderControl::metaData(QtMultimediaKit::MetaData key) const + + Returns the meta-data for the given \a key. + \since 1.0 +*/ + +/*! + \fn QMetaDataReaderControl::availableMetaData() const + + Returns a list of keys there is meta-data available for. + \since 1.0 +*/ + +/*! + \fn QMetaDataReaderControl::extendedMetaData(const QString &key) const + + Returns the metaData for an abitrary string \a key. + + The valid selection of keys for extended meta-data is determined by the provider and the meaning + and type may differ between providers. + \since 1.0 +*/ + +/*! + \fn QMetaDataReaderControl::availableExtendedMetaData() const + + Returns a list of keys there is extended meta-data available for. + \since 1.0 +*/ + + +/*! + \fn void QMetaDataReaderControl::metaDataChanged() + + Signal the changes of meta-data. + \since 1.0 +*/ + +/*! + \fn void QMetaDataReaderControl::metaDataAvailableChanged(bool available) + + Signal the availability of meta-data has changed, \a available will + be true if the multimedia object has meta-data. + \since 1.0 +*/ + +#include "moc_qmetadatareadercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmetadatareadercontrol.h b/src/multimediakit/qmetadatareadercontrol.h new file mode 100644 index 000000000..a2c7d8184 --- /dev/null +++ b/src/multimediakit/qmetadatareadercontrol.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMETADATAREADERCONTROL_H +#define QMETADATAREADERCONTROL_H + +#include +#include + +#include + +#include +#include "qtmedianamespace.h" + +QT_BEGIN_NAMESPACE + + +class Q_MULTIMEDIA_EXPORT QMetaDataReaderControl : public QMediaControl +{ + Q_OBJECT +public: + ~QMetaDataReaderControl(); + + virtual bool isMetaDataAvailable() const = 0; + + virtual QVariant metaData(QtMultimediaKit::MetaData key) const = 0; + virtual QList availableMetaData() const = 0; + + virtual QVariant extendedMetaData(const QString &key) const = 0; + virtual QStringList availableExtendedMetaData() const = 0; + +Q_SIGNALS: + void metaDataChanged(); + + void metaDataAvailableChanged(bool available); + +protected: + QMetaDataReaderControl(QObject *parent = 0); +}; + +#define QMetaDataReaderControl_iid "com.nokia.Qt.QMetaDataReaderControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMetaDataReaderControl, QMetaDataReaderControl_iid) + +QT_END_NAMESPACE + +#endif // QMETADATAPROVIDER_H diff --git a/src/multimediakit/qmetadatawritercontrol.cpp b/src/multimediakit/qmetadatawritercontrol.cpp new file mode 100644 index 000000000..45b81541c --- /dev/null +++ b/src/multimediakit/qmetadatawritercontrol.cpp @@ -0,0 +1,195 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +QT_BEGIN_NAMESPACE + + +/*! + \class QMetaDataWriterControl + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + + \brief The QMetaDataWriterControl class provides write access to the + meta-data of a QMediaService's media. + + If a QMediaService can provide write access to the meta-data of its + current media it will implement QMetaDataWriterControl. This control + provides functions for both retrieving and setting meta-data values. + Meta-data may be addressed by the well defined keys in the + QtMultimediaKit::MetaData enumeration using the metaData() functions, or + by string keys using the extendedMetaData() functions. + + The functionality provided by this control is exposed to application code + by the meta-data members of QMediaObject, and so meta-data access is + potentially available in any of the media object classes. Any media + service may implement QMetaDataControl. + + The interface name of QMetaDataWriterControl is \c com.nokia.Qt.QMetaDataWriterControl/1.0 as + defined in QMetaDataWriterControl_iid. + + \sa QMediaService::requestControl(), QMediaObject +*/ + +/*! + \macro QMetaDataWriterControl_iid + + \c com.nokia.Qt.QMetaDataWriterControl/1.0 + + Defines the interface name of the QMetaDataWriterControl class. + + \relates QMetaDataWriterControl +*/ + +/*! + Construct a QMetaDataWriterControl with \a parent. This class is meant as a base class + for service specific meta data providers so this constructor is protected. +*/ + +QMetaDataWriterControl::QMetaDataWriterControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroy the meta-data writer control. +*/ + +QMetaDataWriterControl::~QMetaDataWriterControl() +{ +} + +/*! + \fn bool QMetaDataWriterControl::isMetaDataAvailable() const + + Identifies if meta-data is available from a media service. + + Returns true if the meta-data is available and false otherwise. + \since 1.0 +*/ + +/*! + \fn bool QMetaDataWriterControl::isWritable() const + + Identifies if a media service's meta-data can be edited. + + Returns true if the meta-data is writable and false otherwise. + \since 1.0 +*/ + +/*! + \fn QVariant QMetaDataWriterControl::metaData(QtMultimediaKit::MetaData key) const + + Returns the meta-data for the given \a key. + \since 1.0 +*/ + +/*! + \fn void QMetaDataWriterControl::setMetaData(QtMultimediaKit::MetaData key, const QVariant &value) + + Sets the \a value of the meta-data element with the given \a key. + \since 1.0 +*/ + +/*! + \fn QMetaDataWriterControl::availableMetaData() const + + Returns a list of keys there is meta-data available for. +*/ + +/*! + \fn QMetaDataWriterControl::extendedMetaData(const QString &key) const + + Returns the meta-data for an abitrary string \a key. + + The valid selection of keys for extended meta-data is determined by the provider and the meaning + and type may differ between providers. + \since 1.0 +*/ + +/*! + \fn QMetaDataWriterControl::setExtendedMetaData(const QString &key, const QVariant &value) + + Change the value of the meta-data element with an abitrary string \a key to \a value. + + The valid selection of keys for extended meta-data is determined by the provider and the meaning + and type may differ between providers. + \since 1.0 +*/ + +/*! + \fn QMetaDataWriterControl::availableExtendedMetaData() const + + Returns a list of keys there is extended meta-data available for. + \since 1.0 +*/ + + +/*! + \fn void QMetaDataWriterControl::metaDataChanged() + + Signal the changes of meta-data. + \since 1.0 +*/ + +/*! + \fn void QMetaDataWriterControl::metaDataAvailableChanged(bool available) + + Signal the availability of meta-data has changed, \a available will + be true if the multimedia object has meta-data. + \since 1.0 +*/ + +/*! + \fn void QMetaDataWriterControl::writableChanged(bool writable) + + Signal a change in the writable status of meta-data, \a writable will be + true if meta-data elements can be added or adjusted. + \since 1.0 +*/ + +#include "moc_qmetadatawritercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qmetadatawritercontrol.h b/src/multimediakit/qmetadatawritercontrol.h new file mode 100644 index 000000000..1e3388426 --- /dev/null +++ b/src/multimediakit/qmetadatawritercontrol.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMETADATAWRITERCONTROL_H +#define QMETADATAWRITERCONTROL_H + +#include "qmediacontrol.h" +#include "qmediaobject.h" + +#include "qmediaresource.h" + +#include +#include "qtmedianamespace.h" + +QT_BEGIN_NAMESPACE + + +class Q_MULTIMEDIA_EXPORT QMetaDataWriterControl : public QMediaControl +{ + Q_OBJECT +public: + ~QMetaDataWriterControl(); + + virtual bool isWritable() const = 0; + virtual bool isMetaDataAvailable() const = 0; + + virtual QVariant metaData(QtMultimediaKit::MetaData key) const = 0; + virtual void setMetaData(QtMultimediaKit::MetaData key, const QVariant &value) = 0; + virtual QList availableMetaData() const = 0; + + virtual QVariant extendedMetaData(const QString &key) const = 0; + virtual void setExtendedMetaData(const QString &key, const QVariant &value) = 0; + virtual QStringList availableExtendedMetaData() const = 0; + + +Q_SIGNALS: + void metaDataChanged(); + + void writableChanged(bool writable); + void metaDataAvailableChanged(bool available); + +protected: + QMetaDataWriterControl(QObject *parent = 0); +}; + +#define QMetaDataWriterControl_iid "com.nokia.Qt.QMetaDataWriterControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMetaDataWriterControl, QMetaDataWriterControl_iid) + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/qmobilityglobal.h b/src/multimediakit/qmobilityglobal.h new file mode 100644 index 000000000..b32b243ce --- /dev/null +++ b/src/multimediakit/qmobilityglobal.h @@ -0,0 +1,245 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMOBILITYGLOBAL_H +#define QMOBILITYGLOBAL_H + +#define QTM_VERSION_STR "1.2.0" +/* + QTM_VERSION is (major << 16) + (minor << 8) + patch. +*/ +#define QTM_VERSION 0x010200 +/* + can be used like #if (QTM_VERSION >= QTM_VERSION_CHECK(1, 2, 0)) +*/ +#define QTM_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch)) + +#define QTM_PACKAGEDATE_STR "YYYY-MM-DD" + +#define QTM_PACKAGE_TAG "" + +#include +#if defined(QTM_BUILD_UNITTESTS) && (defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)) && defined(QT_MAKEDLL) +# define QM_AUTOTEST_EXPORT Q_DECL_EXPORT +#elif defined(QTM_BUILD_UNITTESTS) && (defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)) && defined(QT_DLL) +# define QM_AUTOTEST_EXPORT Q_DECL_IMPORT +#elif defined(QTM_BUILD_UNITTESTS) && !(defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)) && defined(QT_SHARED) +# define QM_AUTOTEST_EXPORT Q_DECL_EXPORT +#else +# define QM_AUTOTEST_EXPORT +#endif + + +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) +# if defined(QT_NODLL) +# undef QT_MAKEDLL +# undef QT_DLL +# elif defined(QT_MAKEDLL) +# if defined(QT_DLL) +# undef QT_DLL +# endif +# if defined(QT_BUILD_BEARER_LIB) +# define Q_BEARER_EXPORT Q_DECL_EXPORT +# else +# define Q_BEARER_EXPORT Q_DECL_IMPORT +# endif +# if defined(QT_BUILD_CFW_LIB) +# define Q_PUBLISHSUBSCRIBE_EXPORT Q_DECL_EXPORT +# else +# define Q_PUBLISHSUBSCRIBE_EXPORT Q_DECL_IMPORT +# endif +# if defined(QT_BUILD_CONTACTS_LIB) +# define Q_CONTACTS_EXPORT Q_DECL_EXPORT +# else +# define Q_CONTACTS_EXPORT Q_DECL_IMPORT +# endif +# if defined(QT_BUILD_VERSIT_LIB) +# define Q_VERSIT_EXPORT Q_DECL_EXPORT +# else +# define Q_VERSIT_EXPORT Q_DECL_IMPORT +# endif +# if defined(QT_BUILD_VERSIT_ORGANIZER_LIB) +# define Q_VERSIT_ORGANIZER_EXPORT Q_DECL_EXPORT +# else +# define Q_VERSIT_ORGANIZER_EXPORT Q_DECL_IMPORT +# endif +# if defined(QT_BUILD_LOCATION_LIB) +# define Q_LOCATION_EXPORT Q_DECL_EXPORT +# else +# define Q_LOCATION_EXPORT Q_DECL_IMPORT +# endif +# if defined(QT_BUILD_MESSAGING_LIB) +# define Q_MESSAGING_EXPORT Q_DECL_EXPORT +# else +# define Q_MESSAGING_EXPORT Q_DECL_IMPORT +# endif +# if defined(QT_BUILD_MULTIMEDIA_LIB) +# define Q_MULTIMEDIA_EXPORT Q_DECL_EXPORT +# else +# define Q_MULTIMEDIA_EXPORT Q_DECL_IMPORT +# endif +# if defined(QT_BUILD_SFW_LIB) +# define Q_SERVICEFW_EXPORT Q_DECL_EXPORT +# else +# define Q_SERVICEFW_EXPORT Q_DECL_IMPORT +# endif +# if defined(QT_BUILD_SYSINFO_LIB) +# define Q_SYSINFO_EXPORT Q_DECL_EXPORT +# else +# define Q_SYSINFO_EXPORT Q_DECL_IMPORT +# endif +# if defined(QT_BUILD_SENSORS_LIB) +# define Q_SENSORS_EXPORT Q_DECL_EXPORT +# else +# define Q_SENSORS_EXPORT Q_DECL_IMPORT +# endif +# if defined(QT_BUILD_FEEDBACK_LIB) +# define Q_FEEDBACK_EXPORT Q_DECL_EXPORT +# else +# define Q_FEEDBACK_EXPORT Q_DECL_IMPORT +# endif +# if defined(QT_BUILD_GALLERY_LIB) +# define Q_GALLERY_EXPORT Q_DECL_EXPORT +# else +# define Q_GALLERY_EXPORT Q_DECL_IMPORT +# endif +# if defined(QT_BUILD_ORGANIZER_LIB) +# define Q_ORGANIZER_EXPORT Q_DECL_EXPORT +# else +# define Q_ORGANIZER_EXPORT Q_DECL_IMPORT +# endif +# if defined(QT_BUILD_CONNECTIVITY_LIB) +# define Q_CONNECTIVITY_EXPORT Q_DECL_EXPORT +# else +# define Q_CONNECTIVITY_EXPORT Q_DECL_IMPORT +# endif +# elif defined(QT_DLL) /* use a Qt DLL library */ +# define Q_BEARER_EXPORT Q_DECL_IMPORT +# define Q_PUBLISHSUBSCRIBE_EXPORT Q_DECL_IMPORT +# define Q_CONTACTS_EXPORT Q_DECL_IMPORT +# define Q_VERSIT_EXPORT Q_DECL_IMPORT +# define Q_VERSIT_ORGANIZER_EXPORT Q_DECL_IMPORT +# define Q_LOCATION_EXPORT Q_DECL_IMPORT +# define Q_MULTIMEDIA_EXPORT Q_DECL_IMPORT +# define Q_MESSAGING_EXPORT Q_DECL_IMPORT +# if QTM_SERVICEFW_SYMBIAN_DATABASEMANAGER_SERVER +# define Q_SERVICEFW_EXPORT +# else +# define Q_SERVICEFW_EXPORT Q_DECL_IMPORT +# endif +# define Q_SYSINFO_EXPORT Q_DECL_IMPORT +# define Q_SENSORS_EXPORT Q_DECL_IMPORT +# define Q_FEEDBACK_EXPORT Q_DECL_IMPORT +# define Q_GALLERY_EXPORT Q_DECL_IMPORT +# define Q_ORGANIZER_EXPORT Q_DECL_IMPORT +# define Q_CONNECTIVITY_EXPORT Q_DECL_IMPORT +# endif +#endif + +#if !defined(Q_SERVICEFW_EXPORT) +# if defined(QT_SHARED) +# define Q_BEARER_EXPORT Q_DECL_EXPORT +# define Q_PUBLISHSUBSCRIBE_EXPORT Q_DECL_EXPORT +# define Q_CONTACTS_EXPORT Q_DECL_EXPORT +# define Q_VERSIT_EXPORT Q_DECL_EXPORT +# define Q_VERSIT_ORGANIZER_EXPORT Q_DECL_EXPORT +# define Q_LOCATION_EXPORT Q_DECL_EXPORT +# define Q_MULTIMEDIA_EXPORT Q_DECL_EXPORT +# define Q_MESSAGING_EXPORT Q_DECL_EXPORT +# define Q_SERVICEFW_EXPORT Q_DECL_EXPORT +# define Q_SYSINFO_EXPORT Q_DECL_EXPORT +# define Q_SENSORS_EXPORT Q_DECL_EXPORT +# define Q_FEEDBACK_EXPORT Q_DECL_EXPORT +# define Q_GALLERY_EXPORT Q_DECL_EXPORT +# define Q_ORGANIZER_EXPORT Q_DECL_EXPORT +# define Q_CONNECTIVITY_EXPORT Q_DECL_EXPORT +# else +# define Q_BEARER_EXPORT +# define Q_PUBLISHSUBSCRIBE_EXPORT +# define Q_CONTACTS_EXPORT +# define Q_VERSIT_EXPORT +# define Q_VERSIT_ORGANIZER_EXPORT +# define Q_LOCATION_EXPORT +# define Q_MULTIMEDIA_EXPORT +# define Q_MESSAGING_EXPORT +# define Q_SERVICEFW_EXPORT +# define Q_SYSINFO_EXPORT +# define Q_SENSORS_EXPORT +# define Q_FEEDBACK_EXPORT +# define Q_GALLERY_EXPORT +# define Q_ORGANIZER_EXPORT +# define Q_CONNECTIVITY_EXPORT +# endif +#endif + + +#ifdef QTM_SERVICEFW_SYMBIAN_DATABASEMANAGER_SERVER +# ifdef Q_SERVICEFW_EXPORT +# undef Q_SERVICEFW_EXPORT +# endif +# define Q_SERVICEFW_EXPORT +# ifdef QM_AUTOTEST_EXPORT +# undef QM_AUTOTEST_EXPORT +# endif +# define QM_AUTOTEST_EXPORT +#endif + +// The namespace is hardcoded as moc has issues resolving +// macros which would be a prerequisite for a dynmamic namespace +#define QTM_NAMESPACE QtMobility + +#ifdef QTM_NAMESPACE +# define QTM_PREPEND_NAMESPACE(name) ::QTM_NAMESPACE::name +# define QTM_BEGIN_NAMESPACE namespace QTM_NAMESPACE { +# define QTM_END_NAMESPACE } +# define QTM_USE_NAMESPACE using namespace QTM_NAMESPACE; +#else +# define QTM_PREPEND_NAMESPACE(name) ::name +# define QTM_BEGIN_NAMESPACE +# define QTM_END_NAMESPACE +# define QTM_USE_NAMESPACE +#endif + +//in case Qt is in namespace +QT_USE_NAMESPACE + +#endif // QMOBILITYGLOBAL_H + diff --git a/src/multimediakit/qpaintervideosurface.cpp b/src/multimediakit/qpaintervideosurface.cpp new file mode 100644 index 000000000..49148e870 --- /dev/null +++ b/src/multimediakit/qpaintervideosurface.cpp @@ -0,0 +1,1728 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include + +#include +#include +#include + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) +#include +#ifndef GL_CLAMP_TO_EDGE +#define GL_CLAMP_TO_EDGE 0x812F +#endif +#endif + +#include +QT_BEGIN_NAMESPACE + +QVideoSurfacePainter::~QVideoSurfacePainter() +{ +} + +class QVideoSurfaceGenericPainter : public QVideoSurfacePainter +{ +public: + QVideoSurfaceGenericPainter(); + + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const; + + bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const; + + QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); + void stop(); + + QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame); + + QAbstractVideoSurface::Error paint( + const QRectF &target, QPainter *painter, const QRectF &source); + + void updateColors(int brightness, int contrast, int hue, int saturation); + +private: + QList m_imagePixelFormats; + QVideoFrame m_frame; + QSize m_imageSize; + QImage::Format m_imageFormat; + QVideoSurfaceFormat::Direction m_scanLineDirection; +}; + +QVideoSurfaceGenericPainter::QVideoSurfaceGenericPainter() + : m_imageFormat(QImage::Format_Invalid) + , m_scanLineDirection(QVideoSurfaceFormat::TopToBottom) +{ + m_imagePixelFormats + << QVideoFrame::Format_RGB32 +#ifndef QT_OPENGL_ES // The raster formats should be a subset of the GL formats. + << QVideoFrame::Format_RGB24 +#endif + << QVideoFrame::Format_ARGB32 + << QVideoFrame::Format_RGB565; +} + +QList QVideoSurfaceGenericPainter::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + switch (handleType) { + case QAbstractVideoBuffer::QPixmapHandle: + case QAbstractVideoBuffer::NoHandle: + return m_imagePixelFormats; + default: + ; + } + return QList(); +} + +bool QVideoSurfaceGenericPainter::isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *) const +{ + switch (format.handleType()) { + case QAbstractVideoBuffer::QPixmapHandle: + return true; + case QAbstractVideoBuffer::NoHandle: + return m_imagePixelFormats.contains(format.pixelFormat()) + && !format.frameSize().isEmpty(); + default: + ; + } + return false; +} + +QAbstractVideoSurface::Error QVideoSurfaceGenericPainter::start(const QVideoSurfaceFormat &format) +{ + m_frame = QVideoFrame(); + m_imageFormat = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat()); + m_imageSize = format.frameSize(); + m_scanLineDirection = format.scanLineDirection(); + + const QAbstractVideoBuffer::HandleType t = format.handleType(); + if (t == QAbstractVideoBuffer::NoHandle) { + if (m_imageFormat != QImage::Format_Invalid +#ifdef QT_OPENGL_ES + && format.pixelFormat() != QVideoFrame::Format_RGB24 +#endif + && !m_imageSize.isEmpty()) { + return QAbstractVideoSurface::NoError; + } + } else if (t == QAbstractVideoBuffer::QPixmapHandle) { + return QAbstractVideoSurface::NoError; + } + return QAbstractVideoSurface::UnsupportedFormatError; +} + +void QVideoSurfaceGenericPainter::stop() +{ + m_frame = QVideoFrame(); +} + +QAbstractVideoSurface::Error QVideoSurfaceGenericPainter::setCurrentFrame(const QVideoFrame &frame) +{ + m_frame = frame; + + return QAbstractVideoSurface::NoError; +} + +QAbstractVideoSurface::Error QVideoSurfaceGenericPainter::paint( + const QRectF &target, QPainter *painter, const QRectF &source) +{ + if (!m_frame.isValid()) { + painter->fillRect(target, Qt::black); + return QAbstractVideoSurface::NoError; + } + + if (m_frame.handleType() == QAbstractVideoBuffer::QPixmapHandle) { + painter->drawPixmap(target, m_frame.handle().value(), source); + } else if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) { + QImage image( + m_frame.bits(), + m_imageSize.width(), + m_imageSize.height(), + m_frame.bytesPerLine(), + m_imageFormat); + + if (m_scanLineDirection == QVideoSurfaceFormat::BottomToTop) { + const QTransform oldTransform = painter->transform(); + + painter->scale(1, -1); + painter->translate(0, -target.bottom()); + painter->drawImage( + QRectF(target.x(), 0, target.width(), target.height()), image, source); + painter->setTransform(oldTransform); + } else { + painter->drawImage(target, image, source); + } + + m_frame.unmap(); + } else if (m_frame.isValid()) { + return QAbstractVideoSurface::IncorrectFormatError; + } else { + painter->fillRect(target, Qt::black); + } + return QAbstractVideoSurface::NoError; +} + +void QVideoSurfaceGenericPainter::updateColors(int, int, int, int) +{ +} + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + +#ifndef Q_WS_MAC +# ifndef APIENTRYP +# ifdef APIENTRY +# define APIENTRYP APIENTRY * +# else +# define APIENTRY +# define APIENTRYP * +# endif +# endif +#else +# define APIENTRY +# define APIENTRYP * +#endif + +#ifndef GL_TEXTURE0 +# define GL_TEXTURE0 0x84C0 +# define GL_TEXTURE1 0x84C1 +# define GL_TEXTURE2 0x84C2 +#endif +#ifndef GL_PROGRAM_ERROR_STRING_ARB +# define GL_PROGRAM_ERROR_STRING_ARB 0x8874 +#endif + +#ifndef GL_UNSIGNED_SHORT_5_6_5 +# define GL_UNSIGNED_SHORT_5_6_5 33635 +#endif + +class QVideoSurfaceGLPainter : public QVideoSurfacePainter +{ +public: + QVideoSurfaceGLPainter(QGLContext *context); + ~QVideoSurfaceGLPainter(); + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const; + + bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const; + + QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame); + + QAbstractVideoSurface::Error paint( + const QRectF &target, QPainter *painter, const QRectF &source); + + void updateColors(int brightness, int contrast, int hue, int saturation); + void viewportDestroyed(); + +protected: + void initRgbTextureInfo(GLenum internalFormat, GLuint format, GLenum type, const QSize &size); + void initYuv420PTextureInfo(const QSize &size); + void initYv12TextureInfo(const QSize &size); + +#ifndef QT_OPENGL_ES + typedef void (APIENTRY *_glActiveTexture) (GLenum); + _glActiveTexture glActiveTexture; +#endif + + QList m_imagePixelFormats; + QList m_glPixelFormats; + QMatrix4x4 m_colorMatrix; + QVideoFrame m_frame; + + QGLContext *m_context; + QAbstractVideoBuffer::HandleType m_handleType; + QVideoSurfaceFormat::Direction m_scanLineDirection; + QVideoSurfaceFormat::YCbCrColorSpace m_colorSpace; + GLenum m_textureFormat; + GLuint m_textureInternalFormat; + GLenum m_textureType; + int m_textureCount; + GLuint m_textureIds[3]; + int m_textureWidths[3]; + int m_textureHeights[3]; + int m_textureOffsets[3]; + bool m_yuv; +}; + +QVideoSurfaceGLPainter::QVideoSurfaceGLPainter(QGLContext *context) + : m_context(context) + , m_handleType(QAbstractVideoBuffer::NoHandle) + , m_scanLineDirection(QVideoSurfaceFormat::TopToBottom) + , m_colorSpace(QVideoSurfaceFormat::YCbCr_BT601) + , m_textureFormat(0) + , m_textureInternalFormat(0) + , m_textureType(0) + , m_textureCount(0) + , m_yuv(false) +{ +#ifndef QT_OPENGL_ES + glActiveTexture = (_glActiveTexture)m_context->getProcAddress(QLatin1String("glActiveTexture")); +#endif +} + +QVideoSurfaceGLPainter::~QVideoSurfaceGLPainter() +{ +} + +void QVideoSurfaceGLPainter::viewportDestroyed() +{ + m_context = 0; +} + +QList QVideoSurfaceGLPainter::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + switch (handleType) { + case QAbstractVideoBuffer::NoHandle: + return m_imagePixelFormats; + case QAbstractVideoBuffer::QPixmapHandle: + case QAbstractVideoBuffer::GLTextureHandle: + return m_glPixelFormats; + default: + ; + } + return QList(); +} + +bool QVideoSurfaceGLPainter::isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *) const +{ + if (format.frameSize().isEmpty()) { + return false; + } else { + switch (format.handleType()) { + case QAbstractVideoBuffer::NoHandle: + return m_imagePixelFormats.contains(format.pixelFormat()); + case QAbstractVideoBuffer::QPixmapHandle: + case QAbstractVideoBuffer::GLTextureHandle: + return m_glPixelFormats.contains(format.pixelFormat()); + default: + ; + } + } + return false; +} + +QAbstractVideoSurface::Error QVideoSurfaceGLPainter::setCurrentFrame(const QVideoFrame &frame) +{ + m_frame = frame; + + if (m_handleType == QAbstractVideoBuffer::GLTextureHandle) { + m_textureIds[0] = frame.handle().toInt(); + } else if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) { + m_context->makeCurrent(); + + for (int i = 0; i < m_textureCount; ++i) { + glBindTexture(GL_TEXTURE_2D, m_textureIds[i]); + glTexImage2D( + GL_TEXTURE_2D, + 0, + m_textureInternalFormat, + m_textureWidths[i], + m_textureHeights[i], + 0, + m_textureFormat, + m_textureType, + m_frame.bits() + m_textureOffsets[i]); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + m_frame.unmap(); + } else if (m_handleType != QAbstractVideoBuffer::QPixmapHandle && m_frame.isValid()) { + return QAbstractVideoSurface::IncorrectFormatError; + } + + return QAbstractVideoSurface::NoError; +} + +QAbstractVideoSurface::Error QVideoSurfaceGLPainter::paint( + const QRectF &target, QPainter *painter, const QRectF &source) +{ + if (!m_frame.isValid()) { + painter->fillRect(target, Qt::black); + return QAbstractVideoSurface::NoError; + } + + if (m_frame.handleType() == QAbstractVideoBuffer::QPixmapHandle) { + painter->drawPixmap(target, m_frame.handle().value(), source); + } else if (m_frame.isValid()) { + return QAbstractVideoSurface::IncorrectFormatError; + } else { + painter->fillRect(target, Qt::black); + } + return QAbstractVideoSurface::NoError; +} + +void QVideoSurfaceGLPainter::updateColors(int brightness, int contrast, int hue, int saturation) +{ + const qreal b = brightness / 200.0; + const qreal c = contrast / 100.0 + 1.0; + const qreal h = hue / 100.0; + const qreal s = saturation / 100.0 + 1.0; + + const qreal cosH = qCos(M_PI * h); + const qreal sinH = qSin(M_PI * h); + + const qreal h11 = 0.787 * cosH - 0.213 * sinH + 0.213; + const qreal h21 = -0.213 * cosH + 0.143 * sinH + 0.213; + const qreal h31 = -0.213 * cosH - 0.787 * sinH + 0.213; + + const qreal h12 = -0.715 * cosH - 0.715 * sinH + 0.715; + const qreal h22 = 0.285 * cosH + 0.140 * sinH + 0.715; + const qreal h32 = -0.715 * cosH + 0.715 * sinH + 0.715; + + const qreal h13 = -0.072 * cosH + 0.928 * sinH + 0.072; + const qreal h23 = -0.072 * cosH - 0.283 * sinH + 0.072; + const qreal h33 = 0.928 * cosH + 0.072 * sinH + 0.072; + + const qreal sr = (1.0 - s) * 0.3086; + const qreal sg = (1.0 - s) * 0.6094; + const qreal sb = (1.0 - s) * 0.0820; + + const qreal sr_s = sr + s; + const qreal sg_s = sg + s; + const qreal sb_s = sr + s; + + const float m4 = (s + sr + sg + sb) * (0.5 - 0.5 * c + b); + + m_colorMatrix(0, 0) = c * (sr_s * h11 + sg * h21 + sb * h31); + m_colorMatrix(0, 1) = c * (sr_s * h12 + sg * h22 + sb * h32); + m_colorMatrix(0, 2) = c * (sr_s * h13 + sg * h23 + sb * h33); + m_colorMatrix(0, 3) = m4; + + m_colorMatrix(1, 0) = c * (sr * h11 + sg_s * h21 + sb * h31); + m_colorMatrix(1, 1) = c * (sr * h12 + sg_s * h22 + sb * h32); + m_colorMatrix(1, 2) = c * (sr * h13 + sg_s * h23 + sb * h33); + m_colorMatrix(1, 3) = m4; + + m_colorMatrix(2, 0) = c * (sr * h11 + sg * h21 + sb_s * h31); + m_colorMatrix(2, 1) = c * (sr * h12 + sg * h22 + sb_s * h32); + m_colorMatrix(2, 2) = c * (sr * h13 + sg * h23 + sb_s * h33); + m_colorMatrix(2, 3) = m4; + + m_colorMatrix(3, 0) = 0.0; + m_colorMatrix(3, 1) = 0.0; + m_colorMatrix(3, 2) = 0.0; + m_colorMatrix(3, 3) = 1.0; + + if (m_yuv) { + QMatrix4x4 colorSpaceMatrix; + + switch (m_colorSpace) { + case QVideoSurfaceFormat::YCbCr_JPEG: + colorSpaceMatrix = QMatrix4x4( + 1.0, 0.000, 1.402, -0.701, + 1.0, -0.344, -0.714, 0.529, + 1.0, 1.772, 0.000, -0.886, + 0.0, 0.000, 0.000, 1.0000); + break; + case QVideoSurfaceFormat::YCbCr_BT709: + case QVideoSurfaceFormat::YCbCr_xvYCC709: + colorSpaceMatrix = QMatrix4x4( + 1.164, 0.000, 1.793, -0.5727, + 1.164, -0.534, -0.213, 0.3007, + 1.164, 2.115, 0.000, -1.1302, + 0.0, 0.000, 0.000, 1.0000); + break; + default: //BT 601: + colorSpaceMatrix = QMatrix4x4( + 1.164, 0.000, 1.596, -0.8708, + 1.164, -0.392, -0.813, 0.5296, + 1.164, 2.017, 0.000, -1.081, + 0.0, 0.000, 0.000, 1.0000); + } + + m_colorMatrix = m_colorMatrix * colorSpaceMatrix; + } +} + +void QVideoSurfaceGLPainter::initRgbTextureInfo( + GLenum internalFormat, GLuint format, GLenum type, const QSize &size) +{ + m_yuv = false; + m_textureInternalFormat = internalFormat; + m_textureFormat = format; + m_textureType = type; + m_textureCount = 1; + m_textureWidths[0] = size.width(); + m_textureHeights[0] = size.height(); + m_textureOffsets[0] = 0; +} + +void QVideoSurfaceGLPainter::initYuv420PTextureInfo(const QSize &size) +{ + int bytesPerLine = (size.width() + 3) & ~3; + int bytesPerLine2 = (size.width() / 2 + 3) & ~3; + + m_yuv = true; + m_textureInternalFormat = GL_LUMINANCE; + m_textureFormat = GL_LUMINANCE; + m_textureType = GL_UNSIGNED_BYTE; + m_textureCount = 3; + m_textureWidths[0] = bytesPerLine; + m_textureHeights[0] = size.height(); + m_textureOffsets[0] = 0; + m_textureWidths[1] = bytesPerLine2; + m_textureHeights[1] = size.height() / 2; + m_textureOffsets[1] = bytesPerLine * size.height(); + m_textureWidths[2] = bytesPerLine2; + m_textureHeights[2] = size.height() / 2; + m_textureOffsets[2] = bytesPerLine * size.height() + bytesPerLine2 * size.height()/2; +} + +void QVideoSurfaceGLPainter::initYv12TextureInfo(const QSize &size) +{ + int bytesPerLine = (size.width() + 3) & ~3; + int bytesPerLine2 = (size.width() / 2 + 3) & ~3; + + m_yuv = true; + m_textureInternalFormat = GL_LUMINANCE; + m_textureFormat = GL_LUMINANCE; + m_textureType = GL_UNSIGNED_BYTE; + m_textureCount = 3; + m_textureWidths[0] = bytesPerLine; + m_textureHeights[0] = size.height(); + m_textureOffsets[0] = 0; + m_textureWidths[1] = bytesPerLine2; + m_textureHeights[1] = size.height() / 2; + m_textureOffsets[1] = bytesPerLine * size.height() + bytesPerLine2 * size.height()/2; + m_textureWidths[2] = bytesPerLine2; + m_textureHeights[2] = size.height() / 2; + m_textureOffsets[2] = bytesPerLine * size.height(); +} + +#ifndef QT_OPENGL_ES + +# ifndef GL_FRAGMENT_PROGRAM_ARB +# define GL_FRAGMENT_PROGRAM_ARB 0x8804 +# define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 +# endif + +// Paints an RGB32 frame +static const char *qt_arbfp_xrgbShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP xrgb;\n" + "TEX xrgb.xyz, fragment.texcoord[0], texture[0], 2D;\n" + "MOV xrgb.w, matrix[3].w;\n" + "DP4 result.color.x, xrgb.zyxw, matrix[0];\n" + "DP4 result.color.y, xrgb.zyxw, matrix[1];\n" + "DP4 result.color.z, xrgb.zyxw, matrix[2];\n" + "END"; + +// Paints an ARGB frame. +static const char *qt_arbfp_argbShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP argb;\n" + "TEX argb, fragment.texcoord[0], texture[0], 2D;\n" + "MOV argb.w, matrix[3].w;\n" + "DP4 result.color.x, argb.zyxw, matrix[0];\n" + "DP4 result.color.y, argb.zyxw, matrix[1];\n" + "DP4 result.color.z, argb.zyxw, matrix[2];\n" + "TEX result.color.w, fragment.texcoord[0], texture, 2D;\n" + "END"; + +// Paints an RGB(A) frame. +static const char *qt_arbfp_rgbShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP rgb;\n" + "TEX rgb, fragment.texcoord[0], texture[0], 2D;\n" + "MOV rgb.w, matrix[3].w;\n" + "DP4 result.color.x, rgb, matrix[0];\n" + "DP4 result.color.y, rgb, matrix[1];\n" + "DP4 result.color.z, rgb, matrix[2];\n" + "TEX result.color.w, fragment.texcoord[0], texture, 2D;\n" + "END"; + +// Paints a YUV420P or YV12 frame. +static const char *qt_arbfp_yuvPlanarShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP yuv;\n" + "TEX yuv.x, fragment.texcoord[0], texture[0], 2D;\n" + "TEX yuv.y, fragment.texcoord[0], texture[1], 2D;\n" + "TEX yuv.z, fragment.texcoord[0], texture[2], 2D;\n" + "MOV yuv.w, matrix[3].w;\n" + "DP4 result.color.x, yuv, matrix[0];\n" + "DP4 result.color.y, yuv, matrix[1];\n" + "DP4 result.color.z, yuv, matrix[2];\n" + "END"; + +// Paints a YUV444 frame. +static const char *qt_arbfp_xyuvShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP ayuv;\n" + "TEX ayuv, fragment.texcoord[0], texture[0], 2D;\n" + "MOV ayuv.x, matrix[3].w;\n" + "DP4 result.color.x, ayuv.yzwx, matrix[0];\n" + "DP4 result.color.y, ayuv.yzwx, matrix[1];\n" + "DP4 result.color.z, ayuv.yzwx, matrix[2];\n" + "END"; + +// Paints a AYUV444 frame. +static const char *qt_arbfp_ayuvShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP ayuv;\n" + "TEX ayuv, fragment.texcoord[0], texture[0], 2D;\n" + "MOV ayuv.x, matrix[3].w;\n" + "DP4 result.color.x, ayuv.yzwx, matrix[0];\n" + "DP4 result.color.y, ayuv.yzwx, matrix[1];\n" + "DP4 result.color.z, ayuv.yzwx, matrix[2];\n" + "TEX result.color.w, fragment.texcoord[0], texture, 2D;\n" + "END"; + +class QVideoSurfaceArbFpPainter : public QVideoSurfaceGLPainter +{ +public: + QVideoSurfaceArbFpPainter(QGLContext *context); + + QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); + void stop(); + + QAbstractVideoSurface::Error paint( + const QRectF &target, QPainter *painter, const QRectF &source); + +private: + typedef void (APIENTRY *_glProgramStringARB) (GLenum, GLenum, GLsizei, const GLvoid *); + typedef void (APIENTRY *_glBindProgramARB) (GLenum, GLuint); + typedef void (APIENTRY *_glDeleteProgramsARB) (GLsizei, const GLuint *); + typedef void (APIENTRY *_glGenProgramsARB) (GLsizei, GLuint *); + typedef void (APIENTRY *_glProgramLocalParameter4fARB) ( + GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat); + typedef void (APIENTRY *_glActiveTexture) (GLenum); + + _glProgramStringARB glProgramStringARB; + _glBindProgramARB glBindProgramARB; + _glDeleteProgramsARB glDeleteProgramsARB; + _glGenProgramsARB glGenProgramsARB; + _glProgramLocalParameter4fARB glProgramLocalParameter4fARB; + + GLuint m_programId; + QSize m_frameSize; +}; + +QVideoSurfaceArbFpPainter::QVideoSurfaceArbFpPainter(QGLContext *context) + : QVideoSurfaceGLPainter(context) + , m_programId(0) +{ + glProgramStringARB = (_glProgramStringARB) m_context->getProcAddress( + QLatin1String("glProgramStringARB")); + glBindProgramARB = (_glBindProgramARB) m_context->getProcAddress( + QLatin1String("glBindProgramARB")); + glDeleteProgramsARB = (_glDeleteProgramsARB) m_context->getProcAddress( + QLatin1String("glDeleteProgramsARB")); + glGenProgramsARB = (_glGenProgramsARB) m_context->getProcAddress( + QLatin1String("glGenProgramsARB")); + glProgramLocalParameter4fARB = (_glProgramLocalParameter4fARB) m_context->getProcAddress( + QLatin1String("glProgramLocalParameter4fARB")); + + m_imagePixelFormats + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_BGR32 + << QVideoFrame::Format_ARGB32 + << QVideoFrame::Format_RGB24 + << QVideoFrame::Format_BGR24 + << QVideoFrame::Format_RGB565 + << QVideoFrame::Format_AYUV444 + << QVideoFrame::Format_YUV444 + << QVideoFrame::Format_YV12 + << QVideoFrame::Format_YUV420P; + m_glPixelFormats + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_ARGB32; +} + +QAbstractVideoSurface::Error QVideoSurfaceArbFpPainter::start(const QVideoSurfaceFormat &format) +{ + Q_ASSERT(m_textureCount == 0); + + QAbstractVideoSurface::Error error = QAbstractVideoSurface::NoError; + + m_context->makeCurrent(); + + const char *program = 0; + + if (format.handleType() == QAbstractVideoBuffer::NoHandle) { + switch (format.pixelFormat()) { + case QVideoFrame::Format_RGB32: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_xrgbShaderProgram; + break; + case QVideoFrame::Format_BGR32: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_rgbShaderProgram; + break; + case QVideoFrame::Format_ARGB32: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_argbShaderProgram; + break; + case QVideoFrame::Format_RGB24: + initRgbTextureInfo(GL_RGB8, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_rgbShaderProgram; + break; + case QVideoFrame::Format_BGR24: + initRgbTextureInfo(GL_RGB8, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_xrgbShaderProgram; + break; + case QVideoFrame::Format_RGB565: + initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, format.frameSize()); + program = qt_arbfp_rgbShaderProgram; + break; + case QVideoFrame::Format_YUV444: + initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_xyuvShaderProgram; + m_yuv = true; + break; + case QVideoFrame::Format_AYUV444: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_ayuvShaderProgram; + m_yuv = true; + break; + case QVideoFrame::Format_YV12: + initYv12TextureInfo(format.frameSize()); + program = qt_arbfp_yuvPlanarShaderProgram; + break; + case QVideoFrame::Format_YUV420P: + initYuv420PTextureInfo(format.frameSize()); + program = qt_arbfp_yuvPlanarShaderProgram; + break; + default: + break; + } + } else if (format.handleType() == QAbstractVideoBuffer::GLTextureHandle) { + switch (format.pixelFormat()) { + case QVideoFrame::Format_RGB32: + case QVideoFrame::Format_ARGB32: + m_yuv = false; + m_textureCount = 1; + program = qt_arbfp_rgbShaderProgram; + break; + default: + break; + } + } else if (format.handleType() == QAbstractVideoBuffer::QPixmapHandle) { + m_handleType = QAbstractVideoBuffer::QPixmapHandle; + return QAbstractVideoSurface::NoError; + } + + if (!program) { + error = QAbstractVideoSurface::UnsupportedFormatError; + } else { + glGenProgramsARB(1, &m_programId); + + GLenum glError = glGetError(); + if (glError != GL_NO_ERROR) { + qWarning("QPainterVideoSurface: ARBfb Shader allocation error %x", int(glError)); + m_textureCount = 0; + m_programId = 0; + + error = QAbstractVideoSurface::ResourceError; + } else { + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_programId); + glProgramStringARB( + GL_FRAGMENT_PROGRAM_ARB, + GL_PROGRAM_FORMAT_ASCII_ARB, + qstrlen(program), + reinterpret_cast(program)); + + if ((glError = glGetError()) != GL_NO_ERROR) { + const GLubyte* errorString = glGetString(GL_PROGRAM_ERROR_STRING_ARB); + + qWarning("QPainterVideoSurface: ARBfp Shader compile error %x, %s", + int(glError), + reinterpret_cast(errorString)); + glDeleteProgramsARB(1, &m_programId); + + m_textureCount = 0; + m_programId = 0; + + error = QAbstractVideoSurface::ResourceError; + } else { + m_handleType = format.handleType(); + m_scanLineDirection = format.scanLineDirection(); + m_frameSize = format.frameSize(); + m_colorSpace = format.yCbCrColorSpace(); + + if (m_handleType == QAbstractVideoBuffer::NoHandle) + glGenTextures(m_textureCount, m_textureIds); + } + } + } + + return error; +} + +void QVideoSurfaceArbFpPainter::stop() +{ + if (m_context) { + m_context->makeCurrent(); + + if (m_handleType != QAbstractVideoBuffer::GLTextureHandle) + glDeleteTextures(m_textureCount, m_textureIds); + glDeleteProgramsARB(1, &m_programId); + } + + m_textureCount = 0; + m_programId = 0; + m_handleType = QAbstractVideoBuffer::NoHandle; +} + +QAbstractVideoSurface::Error QVideoSurfaceArbFpPainter::paint( + const QRectF &target, QPainter *painter, const QRectF &source) +{ + if (!m_frame.isValid()) { + painter->fillRect(target, Qt::black); + return QAbstractVideoSurface::NoError; + } + + const QAbstractVideoBuffer::HandleType h = m_frame.handleType(); + if (h == QAbstractVideoBuffer::NoHandle || h == QAbstractVideoBuffer::GLTextureHandle) { + bool stencilTestEnabled = glIsEnabled(GL_STENCIL_TEST); + bool scissorTestEnabled = glIsEnabled(GL_SCISSOR_TEST); + + painter->beginNativePainting(); + + if (stencilTestEnabled) + glEnable(GL_STENCIL_TEST); + if (scissorTestEnabled) + glEnable(GL_SCISSOR_TEST); + + const float txLeft = source.left() / m_frameSize.width(); + const float txRight = source.right() / m_frameSize.width(); + const float txTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.top() / m_frameSize.height() + : source.bottom() / m_frameSize.height(); + const float txBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.bottom() / m_frameSize.height() + : source.top() / m_frameSize.height(); + + const float tx_array[] = + { + txLeft , txBottom, + txRight, txBottom, + txLeft , txTop, + txRight, txTop + }; + + const GLfloat vTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? target.top() + : target.bottom() + 1; + const GLfloat vBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? target.bottom() + 1 + : target.top(); + + const GLfloat v_array[] = + { + GLfloat(target.left()) , GLfloat(vBottom), + GLfloat(target.right() + 1), GLfloat(vBottom), + GLfloat(target.left()) , GLfloat(vTop), + GLfloat(target.right() + 1), GLfloat(vTop) + }; + + glEnable(GL_FRAGMENT_PROGRAM_ARB); + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_programId); + + glProgramLocalParameter4fARB( + GL_FRAGMENT_PROGRAM_ARB, + 0, + m_colorMatrix(0, 0), + m_colorMatrix(0, 1), + m_colorMatrix(0, 2), + m_colorMatrix(0, 3)); + glProgramLocalParameter4fARB( + GL_FRAGMENT_PROGRAM_ARB, + 1, + m_colorMatrix(1, 0), + m_colorMatrix(1, 1), + m_colorMatrix(1, 2), + m_colorMatrix(1, 3)); + glProgramLocalParameter4fARB( + GL_FRAGMENT_PROGRAM_ARB, + 2, + m_colorMatrix(2, 0), + m_colorMatrix(2, 1), + m_colorMatrix(2, 2), + m_colorMatrix(2, 3)); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_textureIds[0]); + + if (m_textureCount == 3) { + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m_textureIds[1]); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, m_textureIds[2]); + glActiveTexture(GL_TEXTURE0); + } + + glVertexPointer(2, GL_FLOAT, 0, v_array); + glTexCoordPointer(2, GL_FLOAT, 0, tx_array); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + glDisable(GL_FRAGMENT_PROGRAM_ARB); + + painter->endNativePainting(); + + return QAbstractVideoSurface::NoError; + } + + return QVideoSurfaceGLPainter::paint(target, painter, source); +} + +#endif + +static const char *qt_glsl_vertexShaderProgram = + "attribute highp vec4 vertexCoordArray;\n" + "attribute highp vec2 textureCoordArray;\n" + "uniform highp mat4 positionMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " gl_Position = positionMatrix * vertexCoordArray;\n" + " textureCoord = textureCoordArray;\n" + "}\n"; + +// Paints an RGB32 frame +static const char *qt_glsl_xrgbShaderProgram = + "uniform sampler2D texRgb;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).bgr, 1.0);\n" + " gl_FragColor = colorMatrix * color;\n" + "}\n"; + +// Paints an ARGB frame. +static const char *qt_glsl_argbShaderProgram = + "uniform sampler2D texRgb;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).bgr, 1.0);\n" + " color = colorMatrix * color;\n" + " gl_FragColor = vec4(color.rgb, texture2D(texRgb, textureCoord.st).a);\n" + "}\n"; + +// Paints an RGB(A) frame. +static const char *qt_glsl_rgbShaderProgram = + "uniform sampler2D texRgb;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).rgb, 1.0);\n" + " color = colorMatrix * color;\n" + " gl_FragColor = vec4(color.rgb, texture2D(texRgb, textureCoord.st).a);\n" + "}\n"; + +// Paints a YUV420P or YV12 frame. +static const char *qt_glsl_yuvPlanarShaderProgram = + "uniform sampler2D texY;\n" + "uniform sampler2D texU;\n" + "uniform sampler2D texV;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(\n" + " texture2D(texY, textureCoord.st).r,\n" + " texture2D(texU, textureCoord.st).r,\n" + " texture2D(texV, textureCoord.st).r,\n" + " 1.0);\n" + " gl_FragColor = colorMatrix * color;\n" + "}\n"; + +// Paints a YUV444 frame. +static const char *qt_glsl_xyuvShaderProgram = + "uniform sampler2D texRgb;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).gba, 1.0);\n" + " gl_FragColor = colorMatrix * color;\n" + "}\n"; + +// Paints a AYUV444 frame. +static const char *qt_glsl_ayuvShaderProgram = + "uniform sampler2D texRgb;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).gba, 1.0);\n" + " color = colorMatrix * color;\n" + " gl_FragColor = vec4(color.rgb, texture2D(texRgb, textureCoord.st).r);\n" + "}\n"; + +class QVideoSurfaceGlslPainter : public QVideoSurfaceGLPainter +{ +public: + QVideoSurfaceGlslPainter(QGLContext *context); + + QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); + void stop(); + + QAbstractVideoSurface::Error paint( + const QRectF &target, QPainter *painter, const QRectF &source); + +private: + QGLShaderProgram m_program; + QSize m_frameSize; +}; + +QVideoSurfaceGlslPainter::QVideoSurfaceGlslPainter(QGLContext *context) + : QVideoSurfaceGLPainter(context) + , m_program(context) +{ + m_imagePixelFormats + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_BGR32 + << QVideoFrame::Format_ARGB32 +#ifndef QT_OPENGL_ES + << QVideoFrame::Format_RGB24 + << QVideoFrame::Format_BGR24 +#endif + << QVideoFrame::Format_RGB565 + << QVideoFrame::Format_YUV444 + << QVideoFrame::Format_AYUV444 + << QVideoFrame::Format_YV12 + << QVideoFrame::Format_YUV420P; + m_glPixelFormats + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_ARGB32; +} + +QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::start(const QVideoSurfaceFormat &format) +{ + Q_ASSERT(m_textureCount == 0); + + QAbstractVideoSurface::Error error = QAbstractVideoSurface::NoError; + + m_context->makeCurrent(); + + const char *fragmentProgram = 0; + + if (format.handleType() == QAbstractVideoBuffer::NoHandle) { + switch (format.pixelFormat()) { + case QVideoFrame::Format_RGB32: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_xrgbShaderProgram; + break; + case QVideoFrame::Format_BGR32: + initRgbTextureInfo(GL_RGB, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_rgbShaderProgram; + break; + case QVideoFrame::Format_ARGB32: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_argbShaderProgram; + break; +#ifndef QT_OPENGL_ES + case QVideoFrame::Format_RGB24: + initRgbTextureInfo(GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_rgbShaderProgram; + break; + case QVideoFrame::Format_BGR24: + initRgbTextureInfo(GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_argbShaderProgram; + break; +#endif + case QVideoFrame::Format_RGB565: + initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, format.frameSize()); + fragmentProgram = qt_glsl_rgbShaderProgram; + break; + case QVideoFrame::Format_YUV444: + initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_xyuvShaderProgram; + m_yuv = true; + break; + case QVideoFrame::Format_AYUV444: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_ayuvShaderProgram; + m_yuv = true; + break; + case QVideoFrame::Format_YV12: + initYv12TextureInfo(format.frameSize()); + fragmentProgram = qt_glsl_yuvPlanarShaderProgram; + break; + case QVideoFrame::Format_YUV420P: + initYuv420PTextureInfo(format.frameSize()); + fragmentProgram = qt_glsl_yuvPlanarShaderProgram; + break; + default: + break; + } + } else if (format.handleType() == QAbstractVideoBuffer::GLTextureHandle) { + switch (format.pixelFormat()) { + case QVideoFrame::Format_RGB32: + case QVideoFrame::Format_ARGB32: + m_yuv = false; + m_textureCount = 1; + fragmentProgram = qt_glsl_rgbShaderProgram; + break; + default: + break; + } + } else if (format.handleType() == QAbstractVideoBuffer::QPixmapHandle) { + m_handleType = QAbstractVideoBuffer::QPixmapHandle; + return QAbstractVideoSurface::NoError; + } + + if (!fragmentProgram) { + error = QAbstractVideoSurface::UnsupportedFormatError; + } else if (!m_program.addShaderFromSourceCode(QGLShader::Vertex, qt_glsl_vertexShaderProgram)) { + qWarning("QPainterVideoSurface: Vertex shader compile error %s", + qPrintable(m_program.log())); + error = QAbstractVideoSurface::ResourceError; + } else if (!m_program.addShaderFromSourceCode(QGLShader::Fragment, fragmentProgram)) { + qWarning("QPainterVideoSurface: Shader compile error %s", qPrintable(m_program.log())); + error = QAbstractVideoSurface::ResourceError; + m_program.removeAllShaders(); + } else if(!m_program.link()) { + qWarning("QPainterVideoSurface: Shader link error %s", qPrintable(m_program.log())); + m_program.removeAllShaders(); + error = QAbstractVideoSurface::ResourceError; + } else { + m_handleType = format.handleType(); + m_scanLineDirection = format.scanLineDirection(); + m_frameSize = format.frameSize(); + m_colorSpace = format.yCbCrColorSpace(); + + if (m_handleType == QAbstractVideoBuffer::NoHandle) + glGenTextures(m_textureCount, m_textureIds); + } + + return error; +} + +void QVideoSurfaceGlslPainter::stop() +{ + if (m_context) { + m_context->makeCurrent(); + + if (m_handleType != QAbstractVideoBuffer::GLTextureHandle) + glDeleteTextures(m_textureCount, m_textureIds); + } + + m_program.removeAllShaders(); + + m_textureCount = 0; + m_handleType = QAbstractVideoBuffer::NoHandle; +} + +QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::paint( + const QRectF &target, QPainter *painter, const QRectF &source) +{ + if (!m_frame.isValid()) { + painter->fillRect(target, Qt::black); + return QAbstractVideoSurface::NoError; + } + + const QAbstractVideoBuffer::HandleType h = m_frame.handleType(); + if (h == QAbstractVideoBuffer::NoHandle || h == QAbstractVideoBuffer::GLTextureHandle) { + bool stencilTestEnabled = glIsEnabled(GL_STENCIL_TEST); + bool scissorTestEnabled = glIsEnabled(GL_SCISSOR_TEST); + + painter->beginNativePainting(); + + if (stencilTestEnabled) + glEnable(GL_STENCIL_TEST); + if (scissorTestEnabled) + glEnable(GL_SCISSOR_TEST); + + const int width = QGLContext::currentContext()->device()->width(); + const int height = QGLContext::currentContext()->device()->height(); + + const QTransform transform = painter->deviceTransform(); + + const GLfloat wfactor = 2.0 / width; + const GLfloat hfactor = -2.0 / height; + + const GLfloat positionMatrix[4][4] = + { + { + /*(0,0)*/ GLfloat(wfactor * transform.m11() - transform.m13()), + /*(0,1)*/ GLfloat(hfactor * transform.m12() + transform.m13()), + /*(0,2)*/ 0.0, + /*(0,3)*/ GLfloat(transform.m13()) + }, { + /*(1,0)*/ GLfloat(wfactor * transform.m21() - transform.m23()), + /*(1,1)*/ GLfloat(hfactor * transform.m22() + transform.m23()), + /*(1,2)*/ 0.0, + /*(1,3)*/ GLfloat(transform.m23()) + }, { + /*(2,0)*/ 0.0, + /*(2,1)*/ 0.0, + /*(2,2)*/ -1.0, + /*(2,3)*/ 0.0 + }, { + /*(3,0)*/ GLfloat(wfactor * transform.dx() - transform.m33()), + /*(3,1)*/ GLfloat(hfactor * transform.dy() + transform.m33()), + /*(3,2)*/ 0.0, + /*(3,3)*/ GLfloat(transform.m33()) + } + }; + + const GLfloat vTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? target.top() + : target.bottom() + 1; + const GLfloat vBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? target.bottom() + 1 + : target.top(); + + + const GLfloat vertexCoordArray[] = + { + GLfloat(target.left()) , GLfloat(vBottom), + GLfloat(target.right() + 1), GLfloat(vBottom), + GLfloat(target.left()) , GLfloat(vTop), + GLfloat(target.right() + 1), GLfloat(vTop) + }; + + const GLfloat txLeft = source.left() / m_frameSize.width(); + const GLfloat txRight = source.right() / m_frameSize.width(); + const GLfloat txTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.top() / m_frameSize.height() + : source.bottom() / m_frameSize.height(); + const GLfloat txBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.bottom() / m_frameSize.height() + : source.top() / m_frameSize.height(); + + const GLfloat textureCoordArray[] = + { + txLeft , txBottom, + txRight, txBottom, + txLeft , txTop, + txRight, txTop + }; + + m_program.bind(); + + m_program.enableAttributeArray("vertexCoordArray"); + m_program.enableAttributeArray("textureCoordArray"); + m_program.setAttributeArray("vertexCoordArray", vertexCoordArray, 2); + m_program.setAttributeArray("textureCoordArray", textureCoordArray, 2); + m_program.setUniformValue("positionMatrix", positionMatrix); + + if (m_textureCount == 3) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_textureIds[0]); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m_textureIds[1]); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, m_textureIds[2]); + glActiveTexture(GL_TEXTURE0); + + m_program.setUniformValue("texY", 0); + m_program.setUniformValue("texU", 1); + m_program.setUniformValue("texV", 2); + } else { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_textureIds[0]); + + m_program.setUniformValue("texRgb", 0); + } + m_program.setUniformValue("colorMatrix", m_colorMatrix); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + m_program.release(); + + painter->endNativePainting(); + + return QAbstractVideoSurface::NoError; + } + + return QVideoSurfaceGLPainter::paint(target, painter, source); +} + +#endif + +/*! + \class QPainterVideoSurface + \since 1.0 + \internal +*/ + +/*! +*/ +QPainterVideoSurface::QPainterVideoSurface(QObject *parent) + : QAbstractVideoSurface(parent) + , m_painter(0) +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + , m_glContext(0) + , m_shaderTypes(NoShaders) + , m_shaderType(NoShaders) +#endif + , m_brightness(0) + , m_contrast(0) + , m_hue(0) + , m_saturation(0) + , m_pixelFormat(QVideoFrame::Format_Invalid) + , m_colorsDirty(true) + , m_ready(false) +{ +} + +/*! +*/ +QPainterVideoSurface::~QPainterVideoSurface() +{ + if (isActive()) + m_painter->stop(); + + delete m_painter; +} + +/*! + \since 1.0 +*/ +QList QPainterVideoSurface::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + if (!m_painter) + const_cast(this)->createPainter(); + + return m_painter->supportedPixelFormats(handleType); +} + +/*! + \since 1.0 +*/ +bool QPainterVideoSurface::isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const +{ + if (!m_painter) + const_cast(this)->createPainter(); + + return m_painter->isFormatSupported(format, similar); +} + +/*! + \since 1.0 +*/ +bool QPainterVideoSurface::start(const QVideoSurfaceFormat &format) +{ + if (isActive()) + m_painter->stop(); + + if (!m_painter) + createPainter(); + + if (format.frameSize().isEmpty()) { + setError(UnsupportedFormatError); + } else { + QAbstractVideoSurface::Error error = m_painter->start(format); + + if (error != QAbstractVideoSurface::NoError) { + setError(error); + } else { + m_pixelFormat = format.pixelFormat(); + m_frameSize = format.frameSize(); + m_sourceRect = format.viewport(); + m_colorsDirty = true; + m_ready = true; + + return QAbstractVideoSurface::start(format); + } + } + + QAbstractVideoSurface::stop(); + + return false; +} + +/*! + \since 1.0 +*/ +void QPainterVideoSurface::stop() +{ + if (isActive()) { + m_painter->stop(); + m_ready = false; + + QAbstractVideoSurface::stop(); + } +} + +/*! + \since 1.0 +*/ +bool QPainterVideoSurface::present(const QVideoFrame &frame) +{ + if (!m_ready) { + if (!isActive()) + setError(StoppedError); + } else if (frame.isValid() + && (frame.pixelFormat() != m_pixelFormat || frame.size() != m_frameSize)) { + setError(IncorrectFormatError); + + stop(); + } else { + QAbstractVideoSurface::Error error = m_painter->setCurrentFrame(frame); + + if (error != QAbstractVideoSurface::NoError) { + setError(error); + + stop(); + } else { + m_ready = false; + + emit frameChanged(); + + return true; + } + } + return false; +} + +/*! + \since 1.0 +*/ +int QPainterVideoSurface::brightness() const +{ + return m_brightness; +} + +/*! + \since 1.0 +*/ +void QPainterVideoSurface::setBrightness(int brightness) +{ + m_brightness = brightness; + + m_colorsDirty = true; +} + +/*! + \since 1.0 +*/ +int QPainterVideoSurface::contrast() const +{ + return m_contrast; +} + +/*! + \since 1.0 +*/ +void QPainterVideoSurface::setContrast(int contrast) +{ + m_contrast = contrast; + + m_colorsDirty = true; +} + +/*! + \since 1.0 +*/ +int QPainterVideoSurface::hue() const +{ + return m_hue; +} + +/*! + \since 1.0 +*/ +void QPainterVideoSurface::setHue(int hue) +{ + m_hue = hue; + + m_colorsDirty = true; +} + +/*! + \since 1.0 +*/ +int QPainterVideoSurface::saturation() const +{ + return m_saturation; +} + +/*! + \since 1.0 +*/ +void QPainterVideoSurface::setSaturation(int saturation) +{ + m_saturation = saturation; + + m_colorsDirty = true; +} + +/*! + \since 1.0 +*/ +bool QPainterVideoSurface::isReady() const +{ + return m_ready; +} + +/*! + \since 1.0 +*/ +void QPainterVideoSurface::setReady(bool ready) +{ + m_ready = ready; +} + +/*! + \since 1.0 +*/ +void QPainterVideoSurface::paint(QPainter *painter, const QRectF &target, const QRectF &source) +{ + if (!isActive()) { + painter->fillRect(target, QBrush(Qt::black)); + } else { + if (m_colorsDirty) { + m_painter->updateColors(m_brightness, m_contrast, m_hue, m_saturation); + m_colorsDirty = false; + } + + const QRectF sourceRect( + m_sourceRect.x() + m_sourceRect.width() * source.x(), + m_sourceRect.y() + m_sourceRect.height() * source.y(), + m_sourceRect.width() * source.width(), + m_sourceRect.height() * source.height()); + + QAbstractVideoSurface::Error error = m_painter->paint(target, painter, sourceRect); + + if (error != QAbstractVideoSurface::NoError) { + setError(error); + + stop(); + } + } +} + +/*! + \fn QPainterVideoSurface::frameChanged() + \since 1.0 +*/ + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + +/*! +*/ +const QGLContext *QPainterVideoSurface::glContext() const +{ + return m_glContext; +} + +/*! +*/ +void QPainterVideoSurface::setGLContext(QGLContext *context) +{ + if (m_glContext == context) + return; + + m_glContext = context; + + m_shaderTypes = NoShaders; + + if (m_glContext) { + m_glContext->makeCurrent(); + + const QByteArray extensions(reinterpret_cast(glGetString(GL_EXTENSIONS))); +#ifndef QT_OPENGL_ES + + if (extensions.contains("ARB_fragment_program")) + m_shaderTypes |= FragmentProgramShader; +#endif + if (QGLShaderProgram::hasOpenGLShaderPrograms(m_glContext) +#ifndef QT_OPENGL_ES_2 + && extensions.contains("ARB_shader_objects") +#endif + ) + m_shaderTypes |= GlslShader; + } + + ShaderType type = (m_shaderType & m_shaderTypes) + ? m_shaderType + : NoShaders; + + if (type != m_shaderType || type != NoShaders) { + m_shaderType = type; + + if (isActive()) { + m_painter->stop(); + delete m_painter; + m_painter = 0; + m_ready = false; + + setError(ResourceError); + QAbstractVideoSurface::stop(); + } + emit supportedFormatsChanged(); + } +} + +/*! + \enum QPainterVideoSurface::ShaderType + + \value NoShaders + \value FragmentProgramShader + \value HlslShader +*/ + +/*! + \typedef QPainterVideoSurface::ShaderTypes +*/ + +/*! + \since 1.0 +*/ +QPainterVideoSurface::ShaderTypes QPainterVideoSurface::supportedShaderTypes() const +{ + return m_shaderTypes; +} + +/*! + \since 1.0 +*/ +QPainterVideoSurface::ShaderType QPainterVideoSurface::shaderType() const +{ + return m_shaderType; +} + +/*! + \since 1.0 +*/ +void QPainterVideoSurface::setShaderType(ShaderType type) +{ + if (!(type & m_shaderTypes)) + type = NoShaders; + + if (type != m_shaderType) { + m_shaderType = type; + + if (isActive()) { + m_painter->stop(); + delete m_painter; + m_painter = 0; + m_ready = false; + + setError(ResourceError); + QAbstractVideoSurface::stop(); + } else { + delete m_painter; + m_painter = 0; + } + emit supportedFormatsChanged(); + } +} + +#endif + +void QPainterVideoSurface::viewportDestroyed() +{ + if (m_painter) { + m_painter->viewportDestroyed(); + + setError(ResourceError); + stop(); + delete m_painter; + m_painter = 0; + } +} + +void QPainterVideoSurface::createPainter() +{ + Q_ASSERT(!m_painter); + +#ifdef Q_WS_MAC + if (m_glContext) + m_glContext->makeCurrent(); + + m_painter = new QVideoSurfaceCoreGraphicsPainter(m_glContext != 0); + return; +#endif + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + switch (m_shaderType) { +#ifndef QT_OPENGL_ES + case FragmentProgramShader: + Q_ASSERT(m_glContext); + m_glContext->makeCurrent(); + m_painter = new QVideoSurfaceArbFpPainter(m_glContext); + break; +#endif + case GlslShader: + Q_ASSERT(m_glContext); + m_glContext->makeCurrent(); + m_painter = new QVideoSurfaceGlslPainter(m_glContext); + break; + default: + m_painter = new QVideoSurfaceGenericPainter; + break; + } +#else + m_painter = new QVideoSurfaceGenericPainter; +#endif +} + +#include "moc_qpaintervideosurface_p.cpp" +QT_END_NAMESPACE + + diff --git a/src/multimediakit/qpaintervideosurface_mac.mm b/src/multimediakit/qpaintervideosurface_mac.mm new file mode 100644 index 000000000..51aae04bb --- /dev/null +++ b/src/multimediakit/qpaintervideosurface_mac.mm @@ -0,0 +1,284 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpaintervideosurface_mac_p.h" + +#include + +#include + +#include +#include +#include + +#include + +#include +#include + + +QT_BEGIN_NAMESPACE + +extern CGContextRef qt_mac_cg_context(const QPaintDevice *pdev); //qpaintdevice_mac.cpp + +QVideoSurfaceCoreGraphicsPainter::QVideoSurfaceCoreGraphicsPainter(bool glSupported) + : ciContext(0) + , m_imageFormat(QImage::Format_Invalid) + , m_scanLineDirection(QVideoSurfaceFormat::TopToBottom) +{ + //qDebug() << "QVideoSurfaceCoreGraphicsPainter, GL supported:" << glSupported; + ciContext = 0; + m_imagePixelFormats + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_ARGB32 + << QVideoFrame::Format_ARGB32_Premultiplied + << QVideoFrame::Format_RGB24 + << QVideoFrame::Format_RGB565 + << QVideoFrame::Format_RGB555 + << QVideoFrame::Format_ARGB8565_Premultiplied; + + m_supportedHandles + << QAbstractVideoBuffer::NoHandle + << QAbstractVideoBuffer::CoreImageHandle; + + if (glSupported) + m_supportedHandles << QAbstractVideoBuffer::GLTextureHandle; +} + +QVideoSurfaceCoreGraphicsPainter::~QVideoSurfaceCoreGraphicsPainter() +{ + [(CIContext*)ciContext release]; +} + +QList QVideoSurfaceCoreGraphicsPainter::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + return m_supportedHandles.contains(handleType) + ? m_imagePixelFormats + : QList(); +} + +bool QVideoSurfaceCoreGraphicsPainter::isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *) const +{ + return m_supportedHandles.contains(format.handleType()) + && m_imagePixelFormats.contains(format.pixelFormat()) + && !format.frameSize().isEmpty(); +} + +QAbstractVideoSurface::Error QVideoSurfaceCoreGraphicsPainter::start(const QVideoSurfaceFormat &format) +{ + m_frame = QVideoFrame(); + m_imageFormat = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat()); + m_imageSize = format.frameSize(); + m_scanLineDirection = format.scanLineDirection(); + + return m_supportedHandles.contains(format.handleType()) + && m_imageFormat != QImage::Format_Invalid + && !m_imageSize.isEmpty() + ? QAbstractVideoSurface::NoError + : QAbstractVideoSurface::UnsupportedFormatError; +} + +void QVideoSurfaceCoreGraphicsPainter::stop() +{ + m_frame = QVideoFrame(); +} + +QAbstractVideoSurface::Error QVideoSurfaceCoreGraphicsPainter::setCurrentFrame(const QVideoFrame &frame) +{ + m_frame = frame; + + return QAbstractVideoSurface::NoError; +} + +QAbstractVideoSurface::Error QVideoSurfaceCoreGraphicsPainter::paint( + const QRectF &target, QPainter *painter, const QRectF &source) +{ + if (m_frame.handleType() == QAbstractVideoBuffer::CoreImageHandle) { + if (painter->paintEngine()->type() == QPaintEngine::CoreGraphics ) { + + CIImage *img = (CIImage*)(m_frame.handle().value()); + + if (img) { + CGContextRef cgContext = qt_mac_cg_context(painter->device()); + + if (cgContext) { + painter->beginNativePainting(); + + CGRect sRect = CGRectMake(source.x(), source.y(), source.width(), source.height()); + CGRect dRect = CGRectMake(target.x(), target.y(), target.width(), target.height()); + + NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCIImage:img]; + + if (m_scanLineDirection == QVideoSurfaceFormat::TopToBottom) { + CGContextSaveGState( cgContext ); + CGContextTranslateCTM(cgContext, 0, dRect.origin.y + CGRectGetMaxY(dRect)); + CGContextScaleCTM(cgContext, 1, -1); + + CGContextDrawImage(cgContext, dRect, [bitmap CGImage]); + + CGContextRestoreGState(cgContext); + } else { + CGContextDrawImage(cgContext, dRect, [bitmap CGImage]); + } + + [bitmap release]; + + painter->endNativePainting(); + + return QAbstractVideoSurface::NoError; + } + } + } else if (painter->paintEngine()->type() == QPaintEngine::OpenGL2 || + painter->paintEngine()->type() == QPaintEngine::OpenGL) { + CIImage *img = (CIImage*)(m_frame.handle().value()); + + if (img) { + CGLContextObj cglContext = CGLGetCurrentContext(); + + if (cglContext) { + + if (!ciContext) { + CGLContextObj cglContext = CGLGetCurrentContext(); + NSOpenGLPixelFormat *nsglPixelFormat = [NSOpenGLView defaultPixelFormat]; + CGLPixelFormatObj cglPixelFormat = static_cast([nsglPixelFormat CGLPixelFormatObj]); + + ciContext = [CIContext contextWithCGLContext:cglContext + pixelFormat:cglPixelFormat + options:nil]; + + [(CIContext*)ciContext retain]; + } + + CGRect sRect = CGRectMake(source.x(), source.y(), source.width(), source.height()); + CGRect dRect = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom ? + CGRectMake(target.x(), target.y()+target.height(), target.width(), -target.height()) : + CGRectMake(target.x(), target.y(), target.width(), target.height()); + + + painter->beginNativePainting(); + + [(CIContext*)ciContext drawImage:img inRect:dRect fromRect:sRect]; + + painter->endNativePainting(); + + return QAbstractVideoSurface::NoError; + } + } + } + } + + if (m_frame.handleType() == QAbstractVideoBuffer::GLTextureHandle && + (painter->paintEngine()->type() == QPaintEngine::OpenGL2 || + painter->paintEngine()->type() == QPaintEngine::OpenGL)) { + + painter->beginNativePainting(); + GLuint texture = m_frame.handle().toUInt(); + + glDisable(GL_CULL_FACE); + glEnable(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + const float txLeft = source.left() / m_frame.width(); + const float txRight = source.right() / m_frame.width(); + const float txTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.top() / m_frame.height() + : source.bottom() / m_frame.height(); + const float txBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.bottom() / m_frame.height() + : source.top() / m_frame.height(); + + glBegin(GL_QUADS); + QRectF rect = target; + glTexCoord2f(txLeft, txBottom); + glVertex2f(rect.topLeft().x(), rect.topLeft().y()); + glTexCoord2f(txRight, txBottom); + glVertex2f(rect.topRight().x() + 1, rect.topRight().y()); + glTexCoord2f(txRight, txTop); + glVertex2f(rect.bottomRight().x() + 1, rect.bottomRight().y() + 1); + glTexCoord2f(txLeft, txTop); + glVertex2f(rect.bottomLeft().x(), rect.bottomLeft().y() + 1); + glEnd(); + painter->endNativePainting(); + + return QAbstractVideoSurface::NoError; + } + + //fallback case, software rendering + if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) { + QImage image( + m_frame.bits(), + m_imageSize.width(), + m_imageSize.height(), + m_frame.bytesPerLine(), + m_imageFormat); + + if (m_scanLineDirection == QVideoSurfaceFormat::BottomToTop) { + const QTransform oldTransform = painter->transform(); + + painter->scale(1, -1); + painter->translate(0, -target.bottom()); + painter->drawImage( + QRectF(target.x(), 0, target.width(), target.height()), image, source); + painter->setTransform(oldTransform); + } else { + painter->drawImage(target, image, source); + } + + m_frame.unmap(); + } else if (m_frame.isValid()) { + return QAbstractVideoSurface::IncorrectFormatError; + } else { + painter->fillRect(target, Qt::black); + } + + return QAbstractVideoSurface::NoError; +} + +void QVideoSurfaceCoreGraphicsPainter::updateColors(int, int, int, int) +{ +} + +QT_END_NAMESPACE diff --git a/src/multimediakit/qpaintervideosurface_mac_p.h b/src/multimediakit/qpaintervideosurface_mac_p.h new file mode 100644 index 000000000..9ec801218 --- /dev/null +++ b/src/multimediakit/qpaintervideosurface_mac_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPAINTERVIDEOSURFACE_MAC_P_H +#define QPAINTERVIDEOSURFACE_MAC_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 "qpaintervideosurface_p.h" +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QVideoSurfaceCoreGraphicsPainter : public QVideoSurfacePainter +{ +public: + QVideoSurfaceCoreGraphicsPainter(bool glSupported); + ~QVideoSurfaceCoreGraphicsPainter(); + + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const; + + bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const; + + QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); + void stop(); + + QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame); + + QAbstractVideoSurface::Error paint( + const QRectF &target, QPainter *painter, const QRectF &source); + + void updateColors(int brightness, int contrast, int hue, int saturation); + +private: + void* ciContext; + QList m_imagePixelFormats; + QVideoFrame m_frame; + QSize m_imageSize; + QImage::Format m_imageFormat; + QVector m_supportedHandles; + QVideoSurfaceFormat::Direction m_scanLineDirection; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimediakit/qpaintervideosurface_p.h b/src/multimediakit/qpaintervideosurface_p.h new file mode 100644 index 000000000..b48759479 --- /dev/null +++ b/src/multimediakit/qpaintervideosurface_p.h @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPAINTERVIDEOSURFACE_P_H +#define QPAINTERVIDEOSURFACE_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 +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QGLContext; +QT_END_NAMESPACE + +QT_USE_NAMESPACE + +QT_BEGIN_NAMESPACE + +class QVideoSurfacePainter +{ +public: + virtual ~QVideoSurfacePainter(); + + virtual QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const = 0; + + virtual bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const = 0; + + virtual QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format) = 0; + virtual void stop() = 0; + + virtual QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame) = 0; + + virtual QAbstractVideoSurface::Error paint( + const QRectF &target, QPainter *painter, const QRectF &source) = 0; + + virtual void updateColors(int brightness, int contrast, int hue, int saturation) = 0; + virtual void viewportDestroyed() {} +}; + + +class Q_AUTOTEST_EXPORT QPainterVideoSurface : public QAbstractVideoSurface +{ + Q_OBJECT +public: + explicit QPainterVideoSurface(QObject *parent = 0); + ~QPainterVideoSurface(); + + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const; + + bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar = 0) const; + + bool start(const QVideoSurfaceFormat &format); + void stop(); + + bool present(const QVideoFrame &frame); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + bool isReady() const; + void setReady(bool ready); + + void paint(QPainter *painter, const QRectF &target, const QRectF &source = QRectF(0, 0, 1, 1)); + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + const QGLContext *glContext() const; + void setGLContext(QGLContext *context); + + enum ShaderType + { + NoShaders = 0x00, + FragmentProgramShader = 0x01, + GlslShader = 0x02 + }; + + Q_DECLARE_FLAGS(ShaderTypes, ShaderType) + + ShaderTypes supportedShaderTypes() const; + + ShaderType shaderType() const; + void setShaderType(ShaderType type); +#endif + +public Q_SLOTS: + void viewportDestroyed(); + +Q_SIGNALS: + void frameChanged(); + +private: + void createPainter(); + + QVideoSurfacePainter *m_painter; +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + QGLContext *m_glContext; + ShaderTypes m_shaderTypes; + ShaderType m_shaderType; +#endif + int m_brightness; + int m_contrast; + int m_hue; + int m_saturation; + + QVideoFrame::PixelFormat m_pixelFormat; + QSize m_frameSize; + QRect m_sourceRect; + bool m_colorsDirty; + bool m_ready; +}; + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) +Q_DECLARE_OPERATORS_FOR_FLAGS(QPainterVideoSurface::ShaderTypes) +#endif + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/qradiotuner.cpp b/src/multimediakit/qradiotuner.cpp new file mode 100644 index 000000000..21a2b1c33 --- /dev/null +++ b/src/multimediakit/qradiotuner.cpp @@ -0,0 +1,614 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qradiotuner.h" +#include "qmediaservice.h" +#include "qmediaobject_p.h" +#include "qradiotunercontrol.h" + +#include + + +QT_BEGIN_NAMESPACE + +/*! + \class QRadioTuner + \brief The QRadioTuner class provides an interface to the systems analog radio device. + + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + You can control the systems analog radio device using this interface, for example: + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Radio tuner + + The radio object will emit signals for any changes in state such as: + bandChanged(), frequencyChanged(), stereoStatusChanged(), searchingChanged(), + signalStrengthChanged(), volumeChanged(), mutedChanged(). + + You can change between the frequency bands using setBand() however it is recommended + that you check to make sure the band is available first using isBandSupported(). + +*/ + + +class QRadioTunerPrivate : public QMediaObjectPrivate +{ +public: + QRadioTunerPrivate():provider(0), control(0) {} + QMediaServiceProvider *provider; + QRadioTunerControl* control; +}; + + + +/*! + Constructs a radio tuner based on a media service allocated by a media service \a provider. + + The \a parent is passed to QMediaObject. + \since 1.0 +*/ + +QRadioTuner::QRadioTuner(QObject *parent, QMediaServiceProvider* provider): + QMediaObject(*new QRadioTunerPrivate, parent, provider->requestService(Q_MEDIASERVICE_RADIO)) +{ + Q_D(QRadioTuner); + + d->provider = provider; + + if (d->service != 0) { + d->control = qobject_cast(d->service->requestControl(QRadioTunerControl_iid)); + if (d->control != 0) { + connect(d->control, SIGNAL(stateChanged(QRadioTuner::State)), SIGNAL(stateChanged(QRadioTuner::State))); + connect(d->control, SIGNAL(bandChanged(QRadioTuner::Band)), SIGNAL(bandChanged(QRadioTuner::Band))); + connect(d->control, SIGNAL(frequencyChanged(int)), SIGNAL(frequencyChanged(int))); + connect(d->control, SIGNAL(stereoStatusChanged(bool)), SIGNAL(stereoStatusChanged(bool))); + connect(d->control, SIGNAL(searchingChanged(bool)), SIGNAL(searchingChanged(bool))); + connect(d->control, SIGNAL(signalStrengthChanged(int)), SIGNAL(signalStrengthChanged(int))); + connect(d->control, SIGNAL(volumeChanged(int)), SIGNAL(volumeChanged(int))); + connect(d->control, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged(bool))); + connect(d->control, SIGNAL(error(QRadioTuner::Error)), SIGNAL(error(QRadioTuner::Error))); + } + } +} + +/*! + Destroys a radio tuner. +*/ + +QRadioTuner::~QRadioTuner() +{ + Q_D(QRadioTuner); + + if (d->service && d->control) + d->service->releaseControl(d->control); + + d->provider->releaseService(d->service); +} + +/*! + Returns true if the radio tuner service is ready to use. + \since 1.0 +*/ +bool QRadioTuner::isAvailable() const +{ + if (d_func()->control != NULL) + return d_func()->control->isAvailable(); + else + return false; +} + +/*! + Returns the availability error state. + \since 1.0 +*/ +QtMultimediaKit::AvailabilityError QRadioTuner::availabilityError() const +{ + if (d_func()->control != NULL) + return d_func()->control->availabilityError(); + else + return QtMultimediaKit::ServiceMissingError; +} + +/*! + \property QRadioTuner::state + Return the current radio tuner state. + + \since 1.0 + \sa QRadioTuner::State +*/ + +QRadioTuner::State QRadioTuner::state() const +{ + return d_func()->control ? + d_func()->control->state() : QRadioTuner::StoppedState; +} + +/*! + \property QRadioTuner::band + \brief the frequency band a radio tuner is tuned to. + + \since 1.0 + \sa QRadioTuner::Band +*/ + +QRadioTuner::Band QRadioTuner::band() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->band(); + + return QRadioTuner::FM; +} + +/*! + \property QRadioTuner::frequency + \brief the frequency in Hertz a radio tuner is tuned to. + \since 1.0 +*/ + +int QRadioTuner::frequency() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->frequency(); + + return 0; +} + +/*! + Returns the number of Hertz to increment the frequency by when stepping through frequencies + within a given \a band. + \since 1.0 +*/ + +int QRadioTuner::frequencyStep(QRadioTuner::Band band) const +{ + Q_D(const QRadioTuner); + + if(d->control != 0) + return d->control->frequencyStep(band); + + return 0; +} + +/*! + Returns a frequency \a band's minimum and maximum frequency. + \since 1.0 +*/ + +QPair QRadioTuner::frequencyRange(QRadioTuner::Band band) const +{ + Q_D(const QRadioTuner); + + if(d->control != 0) + return d->control->frequencyRange(band); + + return qMakePair(0,0); +} + +/*! + \property QRadioTuner::stereo + \brief whether a radio tuner is receiving a stereo signal. + \since 1.0 +*/ + +bool QRadioTuner::isStereo() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->isStereo(); + + return false; +} + + +/*! + \property QRadioTuner::stereoMode + \brief the stereo mode of a radio tuner. + \since 1.0 +*/ + +QRadioTuner::StereoMode QRadioTuner::stereoMode() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->stereoMode(); + + return QRadioTuner::Auto; +} + +void QRadioTuner::setStereoMode(QRadioTuner::StereoMode mode) +{ + Q_D(QRadioTuner); + + if (d->control != 0) + return d->control->setStereoMode(mode); +} + +/*! + Identifies if a frequency \a band is supported by a radio tuner. + + Returns true if the band is supported, and false if it is not. + \since 1.0 +*/ + +bool QRadioTuner::isBandSupported(QRadioTuner::Band band) const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->isBandSupported(band); + + return false; +} + +/*! + Activate the radio device. + \since 1.0 +*/ + +void QRadioTuner::start() +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + d->control->start(); +} + +/*! + Deactivate the radio device. + \since 1.0 +*/ + +void QRadioTuner::stop() +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + d->control->stop(); +} + +/*! + \property QRadioTuner::signalStrength + \brief the strength of the current radio signal as a percentage. + \since 1.0 +*/ + +int QRadioTuner::signalStrength() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->signalStrength(); + + return 0; +} + +/*! + \property QRadioTuner::volume + \brief the volume of a radio tuner's audio output as a percentage. + \since 1.0 +*/ + + +int QRadioTuner::volume() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->volume(); + + return 0; +} + +/*! + \property QRadioTuner::muted + \brief whether a radio tuner's audio output is muted. + \since 1.0 +*/ + +bool QRadioTuner::isMuted() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->isMuted(); + + return false; +} + +/*! + Sets a radio tuner's frequency \a band. + + Changing the band will reset the \l frequency to the new band's minimum frequency. + \since 1.0 +*/ + +void QRadioTuner::setBand(QRadioTuner::Band band) +{ + Q_D(QRadioTuner); + + if (d->control != 0) + d->control->setBand(band); +} + +/*! + Sets a radio tuner's \a frequency. + + If the tuner is set to a frequency outside the current \l band, the band will be changed to + one occupied by the new frequency. + \since 1.0 +*/ + +void QRadioTuner::setFrequency(int frequency) +{ + Q_D(QRadioTuner); + + if (d->control != 0) + d->control->setFrequency(frequency); +} + +void QRadioTuner::setVolume(int volume) +{ + Q_D(QRadioTuner); + + if (d->control != 0) + d->control->setVolume(volume); +} + +void QRadioTuner::setMuted(bool muted) +{ + Q_D(QRadioTuner); + + if (d->control != 0) + d->control->setMuted(muted); +} + +/*! + \property QRadioTuner::searching + \brief whether a radio tuner is currently scanning for a signal. + + \sa searchForward(), searchBackward(), cancelSearch() + \since 1.0 +*/ + +bool QRadioTuner::isSearching() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->isSearching(); + + return false; +} + +/*! + Starts a forward scan for a signal, starting from the current \l frequency. + + \since 1.0 + \sa searchBackward(), cancelSearch(), searching +*/ + +void QRadioTuner::searchForward() +{ + Q_D(QRadioTuner); + + if (d->control != 0) + d->control->searchForward(); +} + +/*! + Starts a backwards scan for a signal, starting from the current \l frequency. + + \since 1.0 + \sa searchForward(), cancelSearch(), searching +*/ + +void QRadioTuner::searchBackward() +{ + Q_D(QRadioTuner); + + if (d->control != 0) + d->control->searchBackward(); +} + +/*! + Stops scanning for a signal. + + \since 1.0 + \sa searchForward(), searchBackward(), searching +*/ + +void QRadioTuner::cancelSearch() +{ + Q_D(QRadioTuner); + + if (d->control != 0) + d->control->cancelSearch(); +} + +/*! + Returns the error state of a radio tuner. + + \since 1.0 + \sa errorString() +*/ + +QRadioTuner::Error QRadioTuner::error() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->error(); + + return QRadioTuner::ResourceError; +} + +/*! + Returns a description of a radio tuner's error state. + + \since 1.0 + \sa error() +*/ + +QString QRadioTuner::errorString() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->errorString(); + + return QString(); +} + +/*! + \fn void QRadioTuner::bandChanged(QRadioTuner::Band band) + + Signals a radio tuner's \a band has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTuner::frequencyChanged(int frequency) + + Signals that the \a frequency a radio tuner is tuned to has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTuner::mutedChanged(bool muted) + + Signals that the \a muted state of a radio tuner's audio output has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTuner::volumeChanged(int volume) + + Signals that the \a volume of a radio tuner's audio output has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTuner::searchingChanged(bool searching) + + Signals that the \a searching state of a radio tuner has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTuner::stereoStatusChanged(bool stereo) + + Signals that the \a stereo state of a radio tuner has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTuner::signalStrengthChanged(int strength) + + Signals that the \a strength of the signal received by a radio tuner has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTuner::error(QRadioTuner::Error error) + + Signals that an \a error occurred. + \since 1.0 +*/ + +/*! + \enum QRadioTuner::State + + Enumerates radio tuner states. + + \value ActiveState The tuner is started and active. + \value StoppedState The tuner device is stopped. +*/ + + +/*! + \enum QRadioTuner::Band + + Enumerates radio frequency bands. + + \value AM 520 to 1610 kHz, 9 or 10kHz channel spacing, extended 1610 to 1710 kHz + \value FM 87.5 to 108.0 MHz, except Japan 76-90 MHz + \value SW 1.711 to 30.0 MHz, divided into 15 bands. 5kHz channel spacing + \value LW 148.5 to 283.5 kHz, 9kHz channel spacing (Europe, Africa, Asia) + \value FM2 range not defined, used when area supports more than one FM range. +*/ + +/*! + \enum QRadioTuner::Error + + Enumerates radio tuner error conditions. + + \value NoError No errors have occurred. + \value ResourceError There is no radio service available. + \value OpenError Unable to open radio device. + \value OutOfRangeError An attempt to set a frequency or band that is not supported by radio device. +*/ + +/*! + \enum QRadioTuner::StereoMode + + Enumerates radio tuner policy for receiving stereo signals. + + \value Auto Uses the stereo mode matching the station. + \value ForceStereo Provide stereo mode, converting if required. + \value ForceMono Provide mono mode, converting if required. +*/ + +/*! \fn void QRadioTuner::stateChanged(QRadioTuner::State state) + This signal is emitted when the state changes to \a state. + \since 1.0 + */ + +#include "moc_qradiotuner.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qradiotuner.h b/src/multimediakit/qradiotuner.h new file mode 100644 index 000000000..31510cf0c --- /dev/null +++ b/src/multimediakit/qradiotuner.h @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRADIOTUNER_H +#define QRADIOTUNER_H + +#include + +#include "qmediaobject.h" +#include "qmediaserviceprovider.h" +#include + +#include + +QT_BEGIN_NAMESPACE + +class QRadioTunerPrivate; +class Q_MULTIMEDIA_EXPORT QRadioTuner : public QMediaObject +{ + Q_OBJECT + Q_PROPERTY(State state READ state NOTIFY stateChanged) + Q_PROPERTY(Band band READ band WRITE setBand NOTIFY bandChanged) + Q_PROPERTY(int frequency READ frequency WRITE setFrequency NOTIFY frequencyChanged) + Q_PROPERTY(bool stereo READ isStereo NOTIFY stereoStatusChanged) + Q_PROPERTY(StereoMode stereoMode READ stereoMode WRITE setStereoMode) + Q_PROPERTY(int signalStrength READ signalStrength NOTIFY signalStrengthChanged) + Q_PROPERTY(int volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) + Q_PROPERTY(bool searching READ isSearching NOTIFY searchingChanged) + Q_ENUMS(State) + Q_ENUMS(Band) + Q_ENUMS(Error) + Q_ENUMS(StereoMode) + +public: + enum State { ActiveState, StoppedState }; + enum Band { AM, FM, SW, LW, FM2 }; + enum Error { NoError, ResourceError, OpenError, OutOfRangeError }; + enum StereoMode { ForceStereo, ForceMono, Auto }; + + QRadioTuner(QObject *parent = 0, QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider()); + ~QRadioTuner(); + + bool isAvailable() const; + QtMultimediaKit::AvailabilityError availabilityError() const; + + State state() const; + + Band band() const; + + bool isBandSupported(Band b) const; + + int frequency() const; + int frequencyStep(Band band) const; + QPair frequencyRange(Band band) const; + + bool isStereo() const; + void setStereoMode(QRadioTuner::StereoMode mode); + StereoMode stereoMode() const; + + int signalStrength() const; + + int volume() const; + bool isMuted() const; + + bool isSearching() const; + + Error error() const; + QString errorString() const; + +public Q_SLOTS: + void searchForward(); + void searchBackward(); + void cancelSearch(); + + void setBand(Band band); + void setFrequency(int frequency); + + void setVolume(int volume); + void setMuted(bool muted); + + void start(); + void stop(); + +Q_SIGNALS: + void stateChanged(QRadioTuner::State state); + void bandChanged(QRadioTuner::Band band); + void frequencyChanged(int frequency); + void stereoStatusChanged(bool stereo); + void searchingChanged(bool searching); + void signalStrengthChanged(int signalStrength); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void error(QRadioTuner::Error error); + +private: + Q_DISABLE_COPY(QRadioTuner) + Q_DECLARE_PRIVATE(QRadioTuner) +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QRadioTuner::State) +Q_DECLARE_METATYPE(QRadioTuner::Band) +Q_DECLARE_METATYPE(QRadioTuner::Error) +Q_DECLARE_METATYPE(QRadioTuner::StereoMode) + +Q_MEDIA_ENUM_DEBUG(QRadioTuner, State) +Q_MEDIA_ENUM_DEBUG(QRadioTuner, Band) +Q_MEDIA_ENUM_DEBUG(QRadioTuner, Error) +Q_MEDIA_ENUM_DEBUG(QRadioTuner, StereoMode) + +#endif // QRADIOPLAYER_H diff --git a/src/multimediakit/qradiotunercontrol.cpp b/src/multimediakit/qradiotunercontrol.cpp new file mode 100644 index 000000000..39c39b4b3 --- /dev/null +++ b/src/multimediakit/qradiotunercontrol.cpp @@ -0,0 +1,364 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "qradiotunercontrol.h" +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + + +/*! + \class QRadioTunerControl + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + + \brief The QRadioTunerControl class provides access to the radio tuning + functionality of a QMediaService. + + If a QMediaService can tune an analog radio device it will implement + QRadioTunerControl. This control provides a means to tune a radio device + to a specific \l {setFrequency()}{frequency} as well as search \l + {searchForward()}{forwards} and \l {searchBackward()}{backwards} for a + signal. + + The functionality provided by this control is exposed to application code + through the QRadioTuner class. + + The interface name of QRadioTunerControl is \c com.nokia.Qt.QRadioTunerControl/1.0 as + defined in QRadioTunerControl_iid. + + \sa QMediaService::requestControl(), QRadioTuner +*/ + +/*! + \macro QRadioTunerControl_iid + + \c com.nokia.Qt.QRadioTunerControl/1.0 + + Defines the interface name of the QRadioTunerControl class. + + \relates QRadioTunerControl +*/ + +/*! + Constructs a radio tuner control with the given \a parent. +*/ + +QRadioTunerControl::QRadioTunerControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroys a radio tuner control. +*/ + +QRadioTunerControl::~QRadioTunerControl() +{ +} + +/*! + \fn bool QRadioTunerControl::isAvailable() const + + Returns true if the radio service is ready to use. + \since 1.0 +*/ + +/*! + \fn QtMultimediaKit::AvailabilityError QRadioTunerControl::availabilityError() const + + Returns the error state of the radio service. + \since 1.0 +*/ + +/*! + \fn QRadioTuner::State QRadioTunerControl::state() const + + Returns the current radio tuner state. + \since 1.0 +*/ + +/*! + \fn QRadioTuner::Band QRadioTunerControl::band() const + + Returns the frequency band a radio tuner is tuned to. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::bandChanged(QRadioTuner::Band band) + + Signals that the frequency \a band a radio tuner is tuned to has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::setBand(QRadioTuner::Band band) + + Sets the frequecy \a band a radio tuner is tuned to. + + Changing the frequency band will reset the frequency to the minimum frequency of the new band. + \since 1.0 +*/ + +/*! + \fn bool QRadioTunerControl::isBandSupported(QRadioTuner::Band band) const + + Identifies if a frequency \a band is supported. + + Returns true if the band is supported, and false if it is not. + \since 1.0 +*/ + +/*! + \fn int QRadioTunerControl::frequency() const + + Returns the frequency a radio tuner is tuned to. + \since 1.0 +*/ + +/*! + \fn int QRadioTunerControl::frequencyStep(QRadioTuner::Band band) const + + Returns the number of Hertz to increment the frequency by when stepping through frequencies + within a given \a band. + \since 1.0 +*/ + +/*! + \fn QPair QRadioTunerControl::frequencyRange(QRadioTuner::Band band) const + + Returns a frequency \a band's minimum and maximum frequency. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::setFrequency(int frequency) + + Sets the \a frequency a radio tuner is tuned to. + \since 1.0 +*/ + +/*! + \fn bool QRadioTunerControl::isStereo() const + + Identifies if a radio tuner is receiving a stereo signal. + + Returns true if the tuner is receiving a stereo signal, and false if it is not. + \since 1.0 +*/ + +/*! + \fn QRadioTuner::StereoMode QRadioTunerControl::stereoMode() const + + Returns a radio tuner's stereo mode. + + \since 1.0 + \sa QRadioTuner::StereoMode +*/ + +/*! + \fn void QRadioTunerControl::setStereoMode(QRadioTuner::StereoMode mode) + + Sets a radio tuner's stereo \a mode. + + \since 1.0 + \sa QRadioTuner::StereoMode +*/ + +/*! + \fn int QRadioTunerControl::signalStrength() const + + Return a radio tuner's current signal strength as a percentage. + \since 1.0 +*/ + +/*! + \fn int QRadioTunerControl::volume() const + + Returns the volume of a radio tuner's audio output as a percentage. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::setVolume(int volume) + + Sets the percentage \a volume of a radio tuner's audio output. + \since 1.0 +*/ + +/*! + \fn bool QRadioTunerControl::isMuted() const + + Identifies if a radio tuner's audio output is muted. + + Returns true if the audio is muted, and false if it is not. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::setMuted(bool muted) + + Sets the \a muted state of a radio tuner's audio output. + \since 1.0 +*/ + +/*! + \fn bool QRadioTunerControl::isSearching() const + + Identifies if a radio tuner is currently scanning for signal. + + Returns true if the tuner is scanning, and false if it is not. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::searchForward() + + Starts a forward scan for a signal, starting from the current \l frequency(). + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::searchBackward() + + Starts a backwards scan for a signal, starting from the current \l frequency(). + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::cancelSearch() + + Stops scanning for a signal. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::start() + + Activate the radio device. + \since 1.0 +*/ + +/*! + \fn QRadioTunerControl::stop() + + Deactivate the radio device. + \since 1.0 +*/ + +/*! + \fn QRadioTuner::Error QRadioTunerControl::error() const + + Returns the error state of a radio tuner. + \since 1.0 +*/ + +/*! + \fn QString QRadioTunerControl::errorString() const + + Returns a string describing a radio tuner's error state. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::stateChanged(QRadioTuner::State state) + + Signals that the \a state of a radio tuner has changed. + \since 1.0 +*/ + + +/*! + \fn void QRadioTunerControl::frequencyChanged(int frequency) + + Signals that the \a frequency a radio tuner is tuned to has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::stereoStatusChanged(bool stereo) + + Signals that the \a stereo state of a radio tuner has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::searchingChanged(bool searching) + + Signals that the \a searching state of a radio tuner has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::signalStrengthChanged(int strength) + + Signals that the percentage \a strength of the signal received by a radio tuner has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::volumeChanged(int volume) + + Signals that the percentage \a volume of radio tuner's audio output has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::mutedChanged(bool muted) + + Signals that the \a muted state of a radio tuner's audio output has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::error(QRadioTuner::Error error) + + Signals that an \a error has occurred. + \since 1.0 +*/ + +#include "moc_qradiotunercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qradiotunercontrol.h b/src/multimediakit/qradiotunercontrol.h new file mode 100644 index 000000000..d21946a98 --- /dev/null +++ b/src/multimediakit/qradiotunercontrol.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRADIOTUNERCONTROL_H +#define QRADIOTUNERCONTROL_H + +#include "qmediacontrol.h" +#include "qradiotuner.h" + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QRadioTunerControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QRadioTunerControl(); + + virtual bool isAvailable() const = 0; + virtual QtMultimediaKit::AvailabilityError availabilityError() const = 0; + + virtual QRadioTuner::State state() const = 0; + + virtual QRadioTuner::Band band() const = 0; + virtual void setBand(QRadioTuner::Band b) = 0; + virtual bool isBandSupported(QRadioTuner::Band b) const = 0; + + virtual int frequency() const = 0; + virtual int frequencyStep(QRadioTuner::Band b) const = 0; + virtual QPair frequencyRange(QRadioTuner::Band b) const = 0; + virtual void setFrequency(int frequency) = 0; + + virtual bool isStereo() const = 0; + virtual QRadioTuner::StereoMode stereoMode() const = 0; + virtual void setStereoMode(QRadioTuner::StereoMode mode) = 0; + + virtual int signalStrength() const = 0; + + virtual int volume() const = 0; + virtual void setVolume(int volume) = 0; + + virtual bool isMuted() const = 0; + virtual void setMuted(bool muted) = 0; + + virtual bool isSearching() const = 0; + + virtual void searchForward() = 0; + virtual void searchBackward() = 0; + virtual void cancelSearch() = 0; + + virtual void start() = 0; + virtual void stop() = 0; + + virtual QRadioTuner::Error error() const = 0; + virtual QString errorString() const = 0; + +Q_SIGNALS: + void stateChanged(QRadioTuner::State state); + void bandChanged(QRadioTuner::Band band); + void frequencyChanged(int frequency); + void stereoStatusChanged(bool stereo); + void searchingChanged(bool stereo); + void signalStrengthChanged(int signalStrength); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void error(QRadioTuner::Error err); + +protected: + QRadioTunerControl(QObject *parent = 0); +}; + +#define QRadioTunerControl_iid "com.nokia.Qt.QRadioTunerControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QRadioTunerControl, QRadioTunerControl_iid) + +QT_END_NAMESPACE + +#endif // QRADIOTUNERCONTROL_H diff --git a/src/multimediakit/qtmedianamespace.h b/src/multimediakit/qtmedianamespace.h new file mode 100644 index 000000000..1f2b800ca --- /dev/null +++ b/src/multimediakit/qtmedianamespace.h @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTMEDIANAMESPACE_H +#define QTMEDIANAMESPACE_H + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace QtMultimediaKit +{ + enum MetaData + { + // Common + Title, + SubTitle, + Author, + Comment, + Description, + Category, + Genre, + Year, + Date, + UserRating, + Keywords, + Language, + Publisher, + Copyright, + ParentalRating, + RatingOrganisation, + + // Media + Size, + MediaType, + Duration, + + // Audio + AudioBitRate, + AudioCodec, + AverageLevel, + ChannelCount, + PeakValue, + SampleRate, + + // Music + AlbumTitle, + AlbumArtist, + ContributingArtist, + Composer, + Conductor, + Lyrics, + Mood, + TrackNumber, + TrackCount, + + CoverArtUrlSmall, + CoverArtUrlLarge, + + // Image/Video + Resolution, + PixelAspectRatio, + + // Video + VideoFrameRate, + VideoBitRate, + VideoCodec, + + PosterUrl, + + // Movie + ChapterNumber, + Director, + LeadPerformer, + Writer, + + // Photos + CameraManufacturer, + CameraModel, + Event, + Subject, + Orientation, + ExposureTime, + FNumber, + ExposureProgram, + ISOSpeedRatings, + ExposureBiasValue, + DateTimeOriginal, + DateTimeDigitized, + SubjectDistance, + MeteringMode, + LightSource, + Flash, + FocalLength, + ExposureMode, + WhiteBalance, + DigitalZoomRatio, + FocalLengthIn35mmFilm, + SceneCaptureType, + GainControl, + Contrast, + Saturation, + Sharpness, + DeviceSettingDescription, + + PosterImage, + CoverArtImage, + ThumbnailImage + + }; + + enum SupportEstimate + { + NotSupported, + MaybeSupported, + ProbablySupported, + PreferredService + }; + + enum EncodingQuality + { + VeryLowQuality, + LowQuality, + NormalQuality, + HighQuality, + VeryHighQuality + }; + + enum EncodingMode + { + ConstantQualityEncoding, + ConstantBitRateEncoding, + AverageBitRateEncoding, + TwoPassEncoding + }; + + enum AvailabilityError + { + NoError, + ServiceMissingError, + BusyError, + ResourceError + }; + +} + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/qtmedianamespace.qdoc b/src/multimediakit/qtmedianamespace.qdoc new file mode 100644 index 000000000..a5a642ff0 --- /dev/null +++ b/src/multimediakit/qtmedianamespace.qdoc @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \namespace QtMultimediaKit + \ingroup multimedia + \inmodule QtMultimediaKit + + \brief The QtMultimediaKit namespace contains miscellaneous identifiers used throughout the Qt Media services library. + + QtMultimediaKit is a module containing the low level, low latency, + Multimedia APIs which were introduced in Qt 4.6 and also includes the + high level QtMultimedia APIs which were introduced in QtMobility 1.0. + +*/ + +/*! + \enum QtMultimediaKit::MetaData + + This enum provides identifiers for meta-data attributes. + + \note Not all identifiers are supported on all platforms. Please consult vendor documentation for specific support + on different platforms. + + Common attributes + \value Title The title of the media. QString. + \value SubTitle The sub-title of the media. QString. + \value Author The authors of the media. QStringList. + \value Comment A user comment about the media. QString. + \value Description A description of the media. QString + \value Category The category of the media. QStringList. + \value Genre The genre of the media. QStringList. + \value Year The year of release of the media. int. + \value Date The date of the media. QDate. + \value UserRating A user rating of the media. int [0..100]. + \value Keywords A list of keywords describing the media. QStringList. + \value Language The language of media, as an ISO 639-2 code. + + \value Publisher The publisher of the media. QString. + \value Copyright The media's copyright notice. QString. + \value ParentalRating The parental rating of the media. QString. + \value RatingOrganisation The organisation responsible for the parental rating of the media. + QString. + + Media attributes + \value Size The size in bytes of the media. qint64 + \value MediaType The type of the media (audio, video, etc). QString. + \value Duration The duration in millseconds of the media. qint64. + + Audio attributes + \value AudioBitRate The bit rate of the media's audio stream in bits per second. int. + \value AudioCodec The codec of the media's audio stream. QString. + \value AverageLevel The average volume level of the media. int. + \value ChannelCount The number of channels in the media's audio stream. int. + \value PeakValue The peak volume of the media's audio stream. int + \value SampleRate The sample rate of the media's audio stream in hertz. int + + Music attributes + \value AlbumTitle The title of the album the media belongs to. QString. + \value AlbumArtist The principal artist of the album the media belongs to. QString. + \value ContributingArtist The artists contributing to the media. QStringList. + \value Composer The composer of the media. QStringList. + \value Conductor The conductor of the media. QString. + \value Lyrics The lyrics to the media. QString. + \value Mood The mood of the media. QString. + \value TrackNumber The track number of the media. int. + \value TrackCount The number of tracks on the album containing the media. int. + + \value CoverArtUrlSmall The URL of a small cover art image. QUrl. + \value CoverArtUrlLarge The URL of a large cover art image. QUrl. + \value CoverArtImage An embedded cover art image. QImage. + + Image and video attributes + \value Resolution The dimensions of an image or video. QSize. + \value PixelAspectRatio The pixel aspect ratio of an image or video. QSize. + + Video attributes + \value VideoFrameRate The frame rate of the media's video stream. qreal. + \value VideoBitRate The bit rate of the media's video stream in bits per second. int. + \value VideoCodec The codec of the media's video stream. QString. + + \value PosterUrl The URL of a poster image. QUrl. + \value PosterImage An embedded poster image. QImage. + + Movie attributes + \value ChapterNumber The chapter number of the media. int. + \value Director The director of the media. QString. + \value LeadPerformer The lead performer in the media. QStringList. + \value Writer The writer of the media. QStringList. + + Photo attributes. + \value CameraManufacturer The manufacturer of the camera used to capture the media. QString. + \value CameraModel The model of the camera used to capture the media. QString. + \value Event The event during which the media was captured. QString. + \value Subject The subject of the media. QString. + \value Orientation Orientation of image. + \value ExposureTime Exposure time, given in seconds. + \value FNumber The F Number. + \value ExposureProgram + The class of the program used by the camera to set exposure when the picture is taken. + \value ISOSpeedRatings + Indicates the ISO Speed and ISO Latitude of the camera or input device as specified in ISO 12232. + \value ExposureBiasValue + The exposure bias. + The unit is the APEX (Additive System of Photographic Exposure) setting. + \value DateTimeOriginal The date and time when the original image data was generated. + \value DateTimeDigitized The date and time when the image was stored as digital data. + \value SubjectDistance The distance to the subject, given in meters. + \value MeteringMode The metering mode. + \value LightSource + The kind of light source. + \value Flash + Status of flash when the image was shot. + \value FocalLength + The actual focal length of the lens, in mm. + \value ExposureMode + Indicates the exposure mode set when the image was shot. + \value WhiteBalance + Indicates the white balance mode set when the image was shot. + \value DigitalZoomRatio + Indicates the digital zoom ratio when the image was shot. + \value FocalLengthIn35mmFilm + Indicates the equivalent focal length assuming a 35mm film camera, in mm. + \value SceneCaptureType + Indicates the type of scene that was shot. + It can also be used to record the mode in which the image was shot. + \value GainControl + Indicates the degree of overall image gain adjustment. + \value Contrast + Indicates the direction of contrast processing applied by the camera when the image was shot. + \value Saturation + Indicates the direction of saturation processing applied by the camera when the image was shot. + \value Sharpness + Indicates the direction of sharpness processing applied by the camera when the image was shot. + \value DeviceSettingDescription + Exif tag, indicates information on the picture-taking conditions of a particular camera model. QString + + \value ThumbnailImage An embedded thumbnail image. QImage. +*/ + +/*! + \enum QtMultimediaKit::SupportEstimate + + Enumerates the levels of support a media service provider may have for a feature. + + \value NotSupported The feature is not supported. + \value MaybeSupported The feature may be supported. + \value ProbablySupported The feature is probably supported. + \value PreferredService The service is the preferred provider of a service. +*/ + +/*! + \enum QtMultimediaKit::EncodingQuality + + Enumerates quality encoding levels. + + \value VeryLowQuality + \value LowQuality + \value NormalQuality + \value HighQuality + \value VeryHighQuality +*/ + +/*! + \enum QtMultimediaKit::EncodingMode + + Enumerates encoding modes. + + \value ConstantQualityEncoding + \value ConstantBitRateEncoding + \value AverageBitRateEncoding + \value TwoPassEncoding +*/ + +/*! + \enum QtMultimediaKit::AvailabilityError + + Enumerates Service status errors. + + \value NoError The service is operating correctly. + \value ServiceMissingError There is no service available to provide the requested functionality. + \value ResourceError The service could not allocate resources required to function correctly. + \value BusyError The service must wait for access to necessary resources. +*/ diff --git a/src/multimediakit/qvideodevicecontrol.cpp b/src/multimediakit/qvideodevicecontrol.cpp new file mode 100644 index 000000000..27fe122f9 --- /dev/null +++ b/src/multimediakit/qvideodevicecontrol.cpp @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideodevicecontrol.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoDeviceControl + + \brief The QVideoDeviceControl class provides an video device selector media control. + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + The QVideoDeviceControl class provides descriptions of the video devices + available on a system and allows one to be selected as the endpoint of a + media service. + + The interface name of QVideoDeviceControl is \c com.nokia.Qt.VideoDeviceControl as + defined in QVideoDeviceControl_iid. +*/ + +/*! + \macro QVideoDeviceControl_iid + + \c com.nokia.Qt.VideoDeviceControl + + Defines the interface name of the QVideoDeviceControl class. + + \relates QVideoDeviceControl +*/ + +/*! + Constructs a video device control with the given \a parent. +*/ +QVideoDeviceControl::QVideoDeviceControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys a video device control. +*/ +QVideoDeviceControl::~QVideoDeviceControl() +{ +} + +/*! + \fn QVideoDeviceControl::deviceCount() const + + Returns the number of available video devices; + \since 1.0 +*/ + +/*! + \fn QVideoDeviceControl::deviceName(int index) const + + Returns the name of the video device at \a index. + \since 1.0 +*/ + +/*! + \fn QVideoDeviceControl::deviceDescription(int index) const + + Returns a description of the video device at \a index. + \since 1.0 +*/ + +/*! + \fn QVideoDeviceControl::deviceIcon(int index) const + + Returns an icon for the video device at \a index. + \since 1.0 +*/ + +/*! + \fn QVideoDeviceControl::defaultDevice() const + + Returns the index of the default video device. + \since 1.0 +*/ + +/*! + \fn QVideoDeviceControl::selectedDevice() const + + Returns the index of the selected video device. + \since 1.0 +*/ + +/*! + \fn QVideoDeviceControl::setSelectedDevice(int index) + + Sets the selected video device \a index. + \since 1.0 +*/ + +/*! + \fn QVideoDeviceControl::devicesChanged() + + Signals that the list of available video devices has changed. + \since 1.0 +*/ + +/*! + \fn QVideoDeviceControl::selectedDeviceChanged(int index) + + Signals that the selected video device \a index has changed. + \since 1.0 +*/ + +/*! + \fn QVideoDeviceControl::selectedDeviceChanged(const QString &name) + + Signals that the selected video device \a name has changed. + \since 1.0 +*/ + +#include "moc_qvideodevicecontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qvideodevicecontrol.h b/src/multimediakit/qvideodevicecontrol.h new file mode 100644 index 000000000..0d204739c --- /dev/null +++ b/src/multimediakit/qvideodevicecontrol.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEODEVICECONTROL_H +#define QVIDEODEVICECONTROL_H + +#include "qmediacontrol.h" + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QVideoDeviceControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QVideoDeviceControl(); + + virtual int deviceCount() const = 0; + + virtual QString deviceName(int index) const = 0; + virtual QString deviceDescription(int index) const = 0; + virtual QIcon deviceIcon(int index) const = 0; + + virtual int defaultDevice() const = 0; + virtual int selectedDevice() const = 0; + +public Q_SLOTS: + virtual void setSelectedDevice(int index) = 0; + +Q_SIGNALS: + void selectedDeviceChanged(int index); + void selectedDeviceChanged(const QString &deviceName); + void devicesChanged(); + +protected: + QVideoDeviceControl(QObject *parent = 0); +}; + +#define QVideoDeviceControl_iid "com.nokia.Qt.QVideoDeviceControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoDeviceControl, QVideoDeviceControl_iid) + + +QT_END_NAMESPACE + +#endif // QVIDEODEVICECONTROL_H diff --git a/src/multimediakit/qvideoencodercontrol.cpp b/src/multimediakit/qvideoencodercontrol.cpp new file mode 100644 index 000000000..b06286f9b --- /dev/null +++ b/src/multimediakit/qvideoencodercontrol.cpp @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideoencodercontrol.h" +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoEncoderControl + + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + \brief The QVideoEncoderControl class provides access to the settings + of a media service that performs video encoding. + + If a QMediaService supports encoding video data it will implement + QVideoEncoderControl. This control provides information about the limits + of restricted video encoder options and allows the selection of a set of + video encoder settings as specified in a QVideoEncoderSettings object. + + The functionality provided by this control is exposed to application code + through the QMediaRecorder class. + + The interface name of QVideoEncoderControl is \c com.nokia.Qt.QVideoEncoderControl/1.0 as + defined in QVideoEncoderControl_iid. + + \sa QMediaRecorder, QVideoEncoderSettings, QMediaService::requestControl() +*/ + +/*! + \macro QVideoEncoderControl_iid + + \c com.nokia.Qt.QVideoEncoderControl/1.0 + + Defines the interface name of the QVideoEncoderControl class. + + \relates QVideoEncoderControl +*/ + +/*! + Create a new video encoder control object with the given \a parent. +*/ +QVideoEncoderControl::QVideoEncoderControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys a video encoder control. +*/ +QVideoEncoderControl::~QVideoEncoderControl() +{ +} + +/*! + \fn QVideoEncoderControl::supportedVideoCodecs() const + + Returns the list of supported video codecs. + \since 1.0 +*/ + +/*! + \fn QVideoEncoderControl::videoCodecDescription(const QString &codec) const + + Returns a description of a video \a codec. + \since 1.0 +*/ + +/*! + \fn QVideoEncoderControl::supportedEncodingOptions(const QString &codec) const + + Returns a list of supported encoding options for a video \a codec. + + The names and types of the options in the list is system dependent. + \since 1.0 +*/ + +/*! + \fn QVideoEncoderControl::encodingOption(const QString &codec, const QString &option) const + + Returns the value of a video \a codec \a option. + \since 1.0 +*/ + +/*! + \fn QVideoEncoderControl::setEncodingOption(const QString &codec, const QString &option, const QVariant &value) + + Sets the \a value of a \a codec specific \a option. + \since 1.0 +*/ + +/*! + \fn QVideoEncoderControl::supportedResolutions(const QVideoEncoderSettings &settings = QVideoEncoderSettings(), + bool *continuous = 0) const + + Returns a list of supported resolutions. + + If non null video \a settings parameter is passed, + the returned list is reduced to resolution supported with partial settings like + \l {QVideoEncoderSettings::setCodec()}{video codec} or + \l {QVideoEncoderSettings::setFrameRate()}{frame rate} applied. + + If the encoder supports arbitrary resolutions within the supported resolutions range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + + \since 1.0 + \sa QVideoEncoderSettings::resolution() +*/ + +/*! + \fn QVideoEncoderControl::supportedFrameRates(const QVideoEncoderSettings &settings = QVideoEncoderSettings(), + bool *continuous = 0) const + + Returns a list of supported frame rates. + + If non null video \a settings parameter is passed, + the returned list is reduced to frame rates supported with partial settings like + \l {QVideoEncoderSettings::setCodec()}{video codec} or + \l {QVideoEncoderSettings::setResolution()}{video resolution} applied. + + If the encoder supports arbitrary frame rates within the supported range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + + \since 1.0 + \sa QVideoEncoderSettings::frameRate() +*/ + +/*! + \fn QVideoEncoderControl::videoSettings() const + + Returns the video encoder settings. + + The returned value may be different tha passed to QVideoEncoderControl::setVideoSettings() + if the settings contains the default or undefined parameters. + In this case if the undefined parameters are already resolved, they should be returned. + \since 1.0 +*/ + +/*! + \fn QVideoEncoderControl::setVideoSettings(const QVideoEncoderSettings &settings) + + Sets the selected video encoder \a settings. + \since 1.0 +*/ + +#include "moc_qvideoencodercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qvideoencodercontrol.h b/src/multimediakit/qvideoencodercontrol.h new file mode 100644 index 000000000..2952d7a71 --- /dev/null +++ b/src/multimediakit/qvideoencodercontrol.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOENCODERCONTROL_H +#define QVIDEOENCODERCONTROL_H + +#include "qmediacontrol.h" +#include "qmediarecorder.h" + +#include +#include + +QT_BEGIN_NAMESPACE +class QByteArray; +class QStringList; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QVideoEncoderControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QVideoEncoderControl(); + + virtual QList supportedResolutions(const QVideoEncoderSettings &settings, + bool *continuous = 0) const = 0; + + virtual QList supportedFrameRates(const QVideoEncoderSettings &settings, + bool *continuous = 0) const = 0; + + virtual QStringList supportedVideoCodecs() const = 0; + virtual QString videoCodecDescription(const QString &codecName) const = 0; + + virtual QVideoEncoderSettings videoSettings() const = 0; + virtual void setVideoSettings(const QVideoEncoderSettings &settings) = 0; + + virtual QStringList supportedEncodingOptions(const QString &codec) const = 0; + virtual QVariant encodingOption(const QString &codec, const QString &name) const = 0; + virtual void setEncodingOption(const QString &codec, const QString &name, const QVariant &value) = 0; + +protected: + QVideoEncoderControl(QObject *parent = 0); +}; + +#define QVideoEncoderControl_iid "com.nokia.Qt.QVideoEncoderControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoEncoderControl, QVideoEncoderControl_iid) + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/qvideorenderercontrol.cpp b/src/multimediakit/qvideorenderercontrol.cpp new file mode 100644 index 000000000..1368fb0b7 --- /dev/null +++ b/src/multimediakit/qvideorenderercontrol.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideorenderercontrol.h" + +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoRendererControl + + + \brief The QVideoRendererControl class provides a control for rendering + to a video surface. + + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + Using the surface() property of QVideoRendererControl a + QAbstractVideoSurface may be set as the video render target of a + QMediaService. + + \snippet doc/src/snippets/multimedia-snippets/video.cpp Video renderer control + + QVideoRendererControl is one of a number of possible video output controls. + + The interface name of QVideoRendererControl is \c com.nokia.Qt.QVideoRendererControl/1.0 as + defined in QVideoRendererControl_iid. + + \sa QMediaService::requestControl(), QVideoWidget +*/ + +/*! + \macro QVideoRendererControl_iid + + \c com.nokia.Qt.QVideoRendererControl/1.0 + + Defines the interface name of the QVideoRendererControl class. + + \relates QVideoRendererControl +*/ + +/*! + Constructs a new video renderer media end point with the given \a parent. +*/ +QVideoRendererControl::QVideoRendererControl(QObject *parent) + : QMediaControl(parent) +{ +} + +/*! + Destroys a video renderer media end point. +*/ +QVideoRendererControl::~QVideoRendererControl() +{ +} + +/*! + \fn QVideoRendererControl::surface() const + + Returns the surface a video producer renders to. + \since 1.0 +*/ + +/*! + \fn QVideoRendererControl::setSurface(QAbstractVideoSurface *surface) + + Sets the \a surface a video producer renders to. + \since 1.0 +*/ + +#include "moc_qvideorenderercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qvideorenderercontrol.h b/src/multimediakit/qvideorenderercontrol.h new file mode 100644 index 000000000..aa815b986 --- /dev/null +++ b/src/multimediakit/qvideorenderercontrol.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEORENDERERCONTROL_H +#define QVIDEORENDERERCONTROL_H + +#include "qmediacontrol.h" + +QT_BEGIN_NAMESPACE +class QAbstractVideoSurface; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + + +class Q_MULTIMEDIA_EXPORT QVideoRendererControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QVideoRendererControl(); + + virtual QAbstractVideoSurface *surface() const = 0; + virtual void setSurface(QAbstractVideoSurface *surface) = 0; + +protected: + QVideoRendererControl(QObject *parent = 0); +}; + +#define QVideoRendererControl_iid "com.nokia.Qt.QVideoRendererControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoRendererControl, QVideoRendererControl_iid) + +QT_END_NAMESPACE + +#endif // QVIDEORENDERERCONTROL_H diff --git a/src/multimediakit/qvideosurfaceoutput.cpp b/src/multimediakit/qvideosurfaceoutput.cpp new file mode 100644 index 000000000..9dfbaaa43 --- /dev/null +++ b/src/multimediakit/qvideosurfaceoutput.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideosurfaceoutput_p.h" + +#include +#include +#include + + +QVideoSurfaceOutput::QVideoSurfaceOutput(QObject*parent) + : QObject(parent) +{ +} + +QVideoSurfaceOutput::~QVideoSurfaceOutput() +{ + if (m_control) { + m_control.data()->setSurface(0); + m_service.data()->releaseControl(m_control.data()); + } +} + +QMediaObject *QVideoSurfaceOutput::mediaObject() const +{ + return m_object.data(); +} + +void QVideoSurfaceOutput::setVideoSurface(QAbstractVideoSurface *surface) +{ + m_surface = surface; + + if (m_control) + m_control.data()->setSurface(surface); +} + +bool QVideoSurfaceOutput::setMediaObject(QMediaObject *object) +{ + if (m_control) { + m_control.data()->setSurface(0); + m_service.data()->releaseControl(m_control.data()); + } + m_control.clear(); + m_service.clear(); + m_object.clear(); + + if (object) { + if (QMediaService *service = object->service()) { + if (QMediaControl *control = service->requestControl(QVideoRendererControl_iid)) { + if ((m_control = qobject_cast(control))) { + m_service = service; + m_object = object; + m_control.data()->setSurface(m_surface.data()); + + return true; + } + service->releaseControl(control); + } + } + } + return false; +} diff --git a/src/multimediakit/qvideosurfaceoutput_p.h b/src/multimediakit/qvideosurfaceoutput_p.h new file mode 100644 index 000000000..3ef93fd27 --- /dev/null +++ b/src/multimediakit/qvideosurfaceoutput_p.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOSURFACEOUTPUT_P_H +#define QVIDEOSURFACEOUTPUT_P_H + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QAbstractVideoSurface; +class QVideoRendererControl; + +class QVideoSurfaceOutput : public QObject, public QMediaBindableInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaBindableInterface) +public: + QVideoSurfaceOutput(QObject*parent = 0); + ~QVideoSurfaceOutput(); + + QMediaObject *mediaObject() const; + + void setVideoSurface(QAbstractVideoSurface *surface); + +protected: + bool setMediaObject(QMediaObject *object); + +private: + QWeakPointer m_surface; + QWeakPointer m_control; + QWeakPointer m_service; + QWeakPointer m_object; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/qvideowidget.cpp b/src/multimediakit/qvideowidget.cpp new file mode 100644 index 000000000..6d6811d6f --- /dev/null +++ b/src/multimediakit/qvideowidget.cpp @@ -0,0 +1,1049 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideowidget_p.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace Qt; + +QT_BEGIN_NAMESPACE + +QVideoWidgetControlBackend::QVideoWidgetControlBackend( + QMediaService *service, QVideoWidgetControl *control, QWidget *widget) + : m_service(service) + , m_widgetControl(control) +{ + connect(control, SIGNAL(brightnessChanged(int)), widget, SLOT(_q_brightnessChanged(int))); + connect(control, SIGNAL(contrastChanged(int)), widget, SLOT(_q_contrastChanged(int))); + connect(control, SIGNAL(hueChanged(int)), widget, SLOT(_q_hueChanged(int))); + connect(control, SIGNAL(saturationChanged(int)), widget, SLOT(_q_saturationChanged(int))); + connect(control, SIGNAL(fullScreenChanged(bool)), widget, SLOT(_q_fullScreenChanged(bool))); + + QBoxLayout *layout = new QVBoxLayout; + layout->setMargin(0); + layout->setSpacing(0); + +#ifdef Q_OS_SYMBIAN + // On some cases the flag is not reset automatically + // This would lead to viewfinder not being visible on Symbian + control->videoWidget()->setAttribute(Qt::WA_WState_ExplicitShowHide, false); +#endif // Q_OS_SYMBIAN + + layout->addWidget(control->videoWidget()); + + widget->setLayout(layout); +} + +void QVideoWidgetControlBackend::releaseControl() +{ + m_service->releaseControl(m_widgetControl); +} + +void QVideoWidgetControlBackend::setBrightness(int brightness) +{ + m_widgetControl->setBrightness(brightness); +} + +void QVideoWidgetControlBackend::setContrast(int contrast) +{ + m_widgetControl->setContrast(contrast); +} + +void QVideoWidgetControlBackend::setHue(int hue) +{ + m_widgetControl->setHue(hue); +} + +void QVideoWidgetControlBackend::setSaturation(int saturation) +{ + m_widgetControl->setSaturation(saturation); +} + +void QVideoWidgetControlBackend::setFullScreen(bool fullScreen) +{ + m_widgetControl->setFullScreen(fullScreen); +} + + +Qt::AspectRatioMode QVideoWidgetControlBackend::aspectRatioMode() const +{ + return m_widgetControl->aspectRatioMode(); +} + +void QVideoWidgetControlBackend::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + m_widgetControl->setAspectRatioMode(mode); +} + +QRendererVideoWidgetBackend::QRendererVideoWidgetBackend( + QMediaService *service, QVideoRendererControl *control, QWidget *widget) + : m_service(service) + , m_rendererControl(control) + , m_widget(widget) + , m_surface(new QPainterVideoSurface) + , m_aspectRatioMode(Qt::KeepAspectRatio) + , m_updatePaintDevice(true) +{ + connect(this, SIGNAL(brightnessChanged(int)), m_widget, SLOT(_q_brightnessChanged(int))); + connect(this, SIGNAL(contrastChanged(int)), m_widget, SLOT(_q_contrastChanged(int))); + connect(this, SIGNAL(hueChanged(int)), m_widget, SLOT(_q_hueChanged(int))); + connect(this, SIGNAL(saturationChanged(int)), m_widget, SLOT(_q_saturationChanged(int))); + connect(m_surface, SIGNAL(frameChanged()), this, SLOT(frameChanged())); + connect(m_surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + this, SLOT(formatChanged(QVideoSurfaceFormat))); + + m_rendererControl->setSurface(m_surface); +} + +QRendererVideoWidgetBackend::~QRendererVideoWidgetBackend() +{ + delete m_surface; +} + +void QRendererVideoWidgetBackend::releaseControl() +{ + m_service->releaseControl(m_rendererControl); +} + +void QRendererVideoWidgetBackend::clearSurface() +{ + m_rendererControl->setSurface(0); +} + +void QRendererVideoWidgetBackend::setBrightness(int brightness) +{ + m_surface->setBrightness(brightness); + + emit brightnessChanged(brightness); +} + +void QRendererVideoWidgetBackend::setContrast(int contrast) +{ + m_surface->setContrast(contrast); + + emit contrastChanged(contrast); +} + +void QRendererVideoWidgetBackend::setHue(int hue) +{ + m_surface->setHue(hue); + + emit hueChanged(hue); +} + +void QRendererVideoWidgetBackend::setSaturation(int saturation) +{ + m_surface->setSaturation(saturation); + + emit saturationChanged(saturation); +} + +Qt::AspectRatioMode QRendererVideoWidgetBackend::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void QRendererVideoWidgetBackend::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + m_aspectRatioMode = mode; + + m_widget->updateGeometry(); +} + +void QRendererVideoWidgetBackend::setFullScreen(bool) +{ +} + +QSize QRendererVideoWidgetBackend::sizeHint() const +{ + return m_surface->surfaceFormat().sizeHint(); +} + +void QRendererVideoWidgetBackend::showEvent() +{ +} + +void QRendererVideoWidgetBackend::hideEvent(QHideEvent *) +{ +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + m_updatePaintDevice = true; + m_surface->setGLContext(0); +#endif +} + +void QRendererVideoWidgetBackend::resizeEvent(QResizeEvent *) +{ + updateRects(); +} + +void QRendererVideoWidgetBackend::moveEvent(QMoveEvent *) +{ +} + +void QRendererVideoWidgetBackend::paintEvent(QPaintEvent *event) +{ + QPainter painter(m_widget); + + if (m_widget->testAttribute(Qt::WA_OpaquePaintEvent)) { + QRegion borderRegion = event->region(); + borderRegion = borderRegion.subtracted(m_boundingRect); + + QBrush brush = m_widget->palette().window(); + + QVector rects = borderRegion.rects(); + for (QVector::iterator it = rects.begin(), end = rects.end(); it != end; ++it) { + painter.fillRect(*it, brush); + } + } + + if (m_surface->isActive() && m_boundingRect.intersects(event->rect())) { + m_surface->paint(&painter, m_boundingRect, m_sourceRect); + + m_surface->setReady(true); + } else { + #if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + if (m_updatePaintDevice && (painter.paintEngine()->type() == QPaintEngine::OpenGL + || painter.paintEngine()->type() == QPaintEngine::OpenGL2)) { + m_updatePaintDevice = false; + + m_surface->setGLContext(const_cast(QGLContext::currentContext())); + if (m_surface->supportedShaderTypes() & QPainterVideoSurface::GlslShader) { + m_surface->setShaderType(QPainterVideoSurface::GlslShader); + } else { + m_surface->setShaderType(QPainterVideoSurface::FragmentProgramShader); + } + } +#endif + } + +} + +void QRendererVideoWidgetBackend::formatChanged(const QVideoSurfaceFormat &format) +{ + m_nativeSize = format.sizeHint(); + + updateRects(); + + m_widget->updateGeometry(); + m_widget->update(); +} + +void QRendererVideoWidgetBackend::frameChanged() +{ + m_widget->update(m_boundingRect); +} + +void QRendererVideoWidgetBackend::updateRects() +{ + QRect rect = m_widget->rect(); + + if (m_nativeSize.isEmpty()) { + m_boundingRect = QRect(); + } else if (m_aspectRatioMode == Qt::IgnoreAspectRatio) { + m_boundingRect = rect; + m_sourceRect = QRectF(0, 0, 1, 1); + } else if (m_aspectRatioMode == Qt::KeepAspectRatio) { + QSize size = m_nativeSize; + size.scale(rect.size(), Qt::KeepAspectRatio); + + m_boundingRect = QRect(0, 0, size.width(), size.height()); + m_boundingRect.moveCenter(rect.center()); + + m_sourceRect = QRectF(0, 0, 1, 1); + } else if (m_aspectRatioMode == Qt::KeepAspectRatioByExpanding) { + m_boundingRect = rect; + + QSizeF size = rect.size(); + size.scale(m_nativeSize, Qt::KeepAspectRatio); + + m_sourceRect = QRectF( + 0, 0, size.width() / m_nativeSize.width(), size.height() / m_nativeSize.height()); + m_sourceRect.moveCenter(QPointF(0.5, 0.5)); + } +} + +QWindowVideoWidgetBackend::QWindowVideoWidgetBackend( + QMediaService *service, QVideoWindowControl *control, QWidget *widget) + : m_service(service) + , m_windowControl(control) + , m_widget(widget) + , m_aspectRatioMode(Qt::KeepAspectRatio) +{ + connect(control, SIGNAL(brightnessChanged(int)), m_widget, SLOT(_q_brightnessChanged(int))); + connect(control, SIGNAL(contrastChanged(int)), m_widget, SLOT(_q_contrastChanged(int))); + connect(control, SIGNAL(hueChanged(int)), m_widget, SLOT(_q_hueChanged(int))); + connect(control, SIGNAL(saturationChanged(int)), m_widget, SLOT(_q_saturationChanged(int))); + connect(control, SIGNAL(fullScreenChanged(bool)), m_widget, SLOT(_q_fullScreenChanged(bool))); + connect(control, SIGNAL(nativeSizeChanged()), m_widget, SLOT(_q_dimensionsChanged())); + + control->setWinId(widget->winId()); +} + +QWindowVideoWidgetBackend::~QWindowVideoWidgetBackend() +{ +} + +void QWindowVideoWidgetBackend::releaseControl() +{ + m_service->releaseControl(m_windowControl); +} + +void QWindowVideoWidgetBackend::setBrightness(int brightness) +{ + m_windowControl->setBrightness(brightness); +} + +void QWindowVideoWidgetBackend::setContrast(int contrast) +{ + m_windowControl->setContrast(contrast); +} + +void QWindowVideoWidgetBackend::setHue(int hue) +{ + m_windowControl->setHue(hue); +} + +void QWindowVideoWidgetBackend::setSaturation(int saturation) +{ + m_windowControl->setSaturation(saturation); +} + +void QWindowVideoWidgetBackend::setFullScreen(bool fullScreen) +{ + m_windowControl->setFullScreen(fullScreen); +} + +Qt::AspectRatioMode QWindowVideoWidgetBackend::aspectRatioMode() const +{ + return m_windowControl->aspectRatioMode(); +} + +void QWindowVideoWidgetBackend::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + m_windowControl->setAspectRatioMode(mode); +} + +QSize QWindowVideoWidgetBackend::sizeHint() const +{ + return m_windowControl->nativeSize(); +} + +void QWindowVideoWidgetBackend::showEvent() +{ + m_windowControl->setWinId(m_widget->winId()); + + m_windowControl->setDisplayRect(m_widget->rect()); + +#if defined(Q_WS_WIN) + m_widget->setUpdatesEnabled(false); +#endif +} + +void QWindowVideoWidgetBackend::hideEvent(QHideEvent *) +{ +#if defined(Q_WS_WIN) + m_widget->setUpdatesEnabled(true); +#endif +} + +void QWindowVideoWidgetBackend::moveEvent(QMoveEvent *) +{ + m_windowControl->setDisplayRect(m_widget->rect()); +} + +void QWindowVideoWidgetBackend::resizeEvent(QResizeEvent *) +{ + m_windowControl->setDisplayRect(m_widget->rect()); +} + +void QWindowVideoWidgetBackend::paintEvent(QPaintEvent *event) +{ + if (m_widget->testAttribute(Qt::WA_OpaquePaintEvent)) { + QPainter painter(m_widget); + + painter.fillRect(event->rect(), m_widget->palette().window()); + } + + m_windowControl->repaint(); + + event->accept(); +} + +#if defined(Q_WS_WIN) +bool QWindowVideoWidgetBackend::winEvent(MSG *message, long *) +{ + if (message->message == WM_PAINT) + m_windowControl->repaint(); + + return false; +} +#endif + +void QVideoWidgetPrivate::setCurrentControl(QVideoWidgetControlInterface *control) +{ + if (currentControl != control) { + currentControl = control; + + currentControl->setBrightness(brightness); + currentControl->setContrast(contrast); + currentControl->setHue(hue); + currentControl->setSaturation(saturation); + currentControl->setAspectRatioMode(aspectRatioMode); + } +} + +void QVideoWidgetPrivate::clearService() +{ + if (service) { + QObject::disconnect(service, SIGNAL(destroyed()), q_func(), SLOT(_q_serviceDestroyed())); + + if (widgetBackend) { + QLayout *layout = q_func()->layout(); + + for (QLayoutItem *item = layout->takeAt(0); item; item = layout->takeAt(0)) { + item->widget()->setParent(0); + delete item; + } + delete layout; + + widgetBackend->releaseControl(); + + delete widgetBackend; + widgetBackend = 0; + } else if (rendererBackend) { + rendererBackend->clearSurface(); + rendererBackend->releaseControl(); + + delete rendererBackend; + rendererBackend = 0; + } else { + windowBackend->releaseControl(); + + delete windowBackend; + windowBackend = 0; + } + + currentBackend = 0; + currentControl = 0; + service = 0; + } +} + +bool QVideoWidgetPrivate::createWidgetBackend() +{ + if (QMediaControl *control = service->requestControl(QVideoWidgetControl_iid)) { + if (QVideoWidgetControl *widgetControl = qobject_cast(control)) { + widgetBackend = new QVideoWidgetControlBackend(service, widgetControl, q_func()); + + setCurrentControl(widgetBackend); + + return true; + } + service->releaseControl(control); + } + return false; +} + +bool QVideoWidgetPrivate::createWindowBackend() +{ + if (QMediaControl *control = service->requestControl(QVideoWindowControl_iid)) { + if (QVideoWindowControl *windowControl = qobject_cast(control)) { + windowBackend = new QWindowVideoWidgetBackend(service, windowControl, q_func()); + currentBackend = windowBackend; + + setCurrentControl(windowBackend); + + return true; + } + service->releaseControl(control); + } + return false; +} + +bool QVideoWidgetPrivate::createRendererBackend() +{ + if (QMediaControl *control = service->requestControl(QVideoRendererControl_iid)) { + if (QVideoRendererControl *rendererControl = qobject_cast(control)) { + rendererBackend = new QRendererVideoWidgetBackend(service, rendererControl, q_func()); + currentBackend = rendererBackend; + + setCurrentControl(rendererBackend); + + return true; + } + service->releaseControl(control); + } + return false; +} + +void QVideoWidgetPrivate::_q_serviceDestroyed() +{ + if (widgetBackend) + delete q_func()->layout(); + + delete widgetBackend; + delete windowBackend; + delete rendererBackend; + + widgetBackend = 0; + windowBackend = 0; + rendererBackend = 0; + currentControl = 0; + currentBackend = 0; + service = 0; +} + +void QVideoWidgetPrivate::_q_brightnessChanged(int b) +{ + if (b != brightness) + emit q_func()->brightnessChanged(brightness = b); +} + +void QVideoWidgetPrivate::_q_contrastChanged(int c) +{ + if (c != contrast) + emit q_func()->contrastChanged(contrast = c); +} + +void QVideoWidgetPrivate::_q_hueChanged(int h) +{ + if (h != hue) + emit q_func()->hueChanged(hue = h); +} + +void QVideoWidgetPrivate::_q_saturationChanged(int s) +{ + if (s != saturation) + emit q_func()->saturationChanged(saturation = s); +} + + +void QVideoWidgetPrivate::_q_fullScreenChanged(bool fullScreen) +{ + if (!fullScreen && q_func()->isFullScreen()) + q_func()->showNormal(); +} + +void QVideoWidgetPrivate::_q_dimensionsChanged() +{ + q_func()->updateGeometry(); + q_func()->update(); +} + +/*! + \class QVideoWidget + + + \brief The QVideoWidget class provides a widget which presents video + produced by a media object. + \ingroup multimedia + \inmodule QtMultimediaKit + \since 1.0 + + \inmodule QtMultimediaKit + + Attaching a QVideoWidget to a QMediaObject allows it to display the + video or image output of that media object. A QVideoWidget is attached + to media object by passing a pointer to the QMediaObject in its + constructor, and detached by destroying the QVideoWidget. + + \snippet doc/src/snippets/multimedia-snippets/video.cpp Video widget + + \bold {Note}: Only a single display output can be attached to a media + object at one time. + + \sa QMediaObject, QMediaPlayer, QGraphicsVideoItem +*/ + +/*! + Constructs a new video widget. + + The \a parent is passed to QWidget. +*/ +QVideoWidget::QVideoWidget(QWidget *parent) + : QWidget(parent, 0) + , d_ptr(new QVideoWidgetPrivate) +{ + d_ptr->q_ptr = this; +} + +/*! + \internal +*/ +QVideoWidget::QVideoWidget(QVideoWidgetPrivate &dd, QWidget *parent) + : QWidget(parent, 0) + , d_ptr(&dd) +{ + d_ptr->q_ptr = this; + + QPalette palette = QWidget::palette(); + palette.setColor(QPalette::Background, Qt::black); + setPalette(palette); +} + +/*! + Destroys a video widget. +*/ +QVideoWidget::~QVideoWidget() +{ + d_ptr->clearService(); + + delete d_ptr; +} + +/*! + \property QVideoWidget::mediaObject + \brief the media object which provides the video displayed by a widget. + \since 1.0 +*/ + +QMediaObject *QVideoWidget::mediaObject() const +{ + return d_func()->mediaObject; +} + +/*! + \internal + \since 1.0 +*/ +bool QVideoWidget::setMediaObject(QMediaObject *object) +{ + Q_D(QVideoWidget); + + if (object == d->mediaObject) + return true; + + d->clearService(); + + d->mediaObject = object; + + if (d->mediaObject) + d->service = d->mediaObject->service(); + + if (d->service) { + if (d->createWidgetBackend()) { + // Nothing to do here. + } else if ((!window() || !window()->testAttribute(Qt::WA_DontShowOnScreen)) + && d->createWindowBackend()) { + if (isVisible()) + d->windowBackend->showEvent(); + } else if (d->createRendererBackend()) { + if (isVisible()) + d->rendererBackend->showEvent(); + } else { + d->service = 0; + d->mediaObject = 0; + + return false; + } + + connect(d->service, SIGNAL(destroyed()), SLOT(_q_serviceDestroyed())); + } else { + d->mediaObject = 0; + + return false; + } + + return true; +} + +/*! + \property QVideoWidget::aspectRatioMode + \brief how video is scaled with respect to its aspect ratio. + \since 1.0 +*/ + +Qt::AspectRatioMode QVideoWidget::aspectRatioMode() const +{ + return d_func()->aspectRatioMode; +} + +void QVideoWidget::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + Q_D(QVideoWidget); + + if (d->currentControl) { + d->currentControl->setAspectRatioMode(mode); + d->aspectRatioMode = d->currentControl->aspectRatioMode(); + } else { + d->aspectRatioMode = mode; + } +} + +/*! + \property QVideoWidget::fullScreen + \brief whether video display is confined to a window or is fullScreen. + \since 1.0 +*/ + +void QVideoWidget::setFullScreen(bool fullScreen) +{ + Q_D(QVideoWidget); + + if (fullScreen) { + Qt::WindowFlags flags = windowFlags(); + + d->nonFullScreenFlags = flags & (Qt::Window | Qt::SubWindow); + flags |= Qt::Window; + flags &= ~Qt::SubWindow; + setWindowFlags(flags); + + showFullScreen(); + } else { + showNormal(); + } +} + +/*! + \fn QVideoWidget::fullScreenChanged(bool fullScreen) + + Signals that the \a fullScreen mode of a video widget has changed. + + \since 1.0 + \sa fullScreen +*/ + +/*! + \property QVideoWidget::brightness + \brief an adjustment to the brightness of displayed video. + + Valid brightness values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +int QVideoWidget::brightness() const +{ + return d_func()->brightness; +} + +void QVideoWidget::setBrightness(int brightness) +{ + Q_D(QVideoWidget); + + int boundedBrightness = qBound(-100, brightness, 100); + + if (d->currentControl) + d->currentControl->setBrightness(boundedBrightness); + else if (d->brightness != boundedBrightness) + emit brightnessChanged(d->brightness = boundedBrightness); +} + +/*! + \fn QVideoWidget::brightnessChanged(int brightness) + + Signals that a video widgets's \a brightness adjustment has changed. + + \since 1.0 + \sa brightness +*/ + +/*! + \property QVideoWidget::contrast + \brief an adjustment to the contrast of displayed video. + + Valid contrast values range between -100 and 100, the default is 0. + + \since 1.0 +*/ + +int QVideoWidget::contrast() const +{ + return d_func()->contrast; +} + +void QVideoWidget::setContrast(int contrast) +{ + Q_D(QVideoWidget); + + int boundedContrast = qBound(-100, contrast, 100); + + if (d->currentControl) + d->currentControl->setContrast(boundedContrast); + else if (d->contrast != boundedContrast) + emit contrastChanged(d->contrast = boundedContrast); +} + +/*! + \fn QVideoWidget::contrastChanged(int contrast) + + Signals that a video widgets's \a contrast adjustment has changed. + + \since 1.0 + \sa contrast +*/ + +/*! + \property QVideoWidget::hue + \brief an adjustment to the hue of displayed video. + + Valid hue values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +int QVideoWidget::hue() const +{ + return d_func()->hue; +} + +void QVideoWidget::setHue(int hue) +{ + Q_D(QVideoWidget); + + int boundedHue = qBound(-100, hue, 100); + + if (d->currentControl) + d->currentControl->setHue(boundedHue); + else if (d->hue != boundedHue) + emit hueChanged(d->hue = boundedHue); +} + +/*! + \fn QVideoWidget::hueChanged(int hue) + + Signals that a video widgets's \a hue has changed. + + \since 1.0 + \sa hue +*/ + +/*! + \property QVideoWidget::saturation + \brief an adjustment to the saturation of displayed video. + + Valid saturation values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +int QVideoWidget::saturation() const +{ + return d_func()->saturation; +} + +void QVideoWidget::setSaturation(int saturation) +{ + Q_D(QVideoWidget); + + int boundedSaturation = qBound(-100, saturation, 100); + + if (d->currentControl) + d->currentControl->setSaturation(boundedSaturation); + else if (d->saturation != boundedSaturation) + emit saturationChanged(d->saturation = boundedSaturation); + +} + +/*! + \fn QVideoWidget::saturationChanged(int saturation) + + Signals that a video widgets's \a saturation has changed. + + \since 1.0 + \sa saturation +*/ + +/*! + Returns the size hint for the current back end, + if there is one, or else the size hint from QWidget. + \since 1.0 + */ +QSize QVideoWidget::sizeHint() const +{ + Q_D(const QVideoWidget); + + if (d->currentBackend) + return d->currentBackend->sizeHint(); + else + return QWidget::sizeHint(); + + +} + +/*! + Current event \a event. + Returns the value of the baseclass QWidget::event(QEvent *event) function. + \since 1.0 +*/ +bool QVideoWidget::event(QEvent *event) +{ + Q_D(QVideoWidget); + + if (event->type() == QEvent::WindowStateChange) { + Qt::WindowFlags flags = windowFlags(); + + if (windowState() & Qt::WindowFullScreen) { + if (d->currentControl) + d->currentControl->setFullScreen(true); + + if (!d->wasFullScreen) + emit fullScreenChanged(d->wasFullScreen = true); + } else { + if (d->currentControl) + d->currentControl->setFullScreen(false); + + if (d->wasFullScreen) { + flags &= ~(Qt::Window | Qt::SubWindow); //clear the flags... + flags |= d->nonFullScreenFlags; //then we reset the flags (window and subwindow) + setWindowFlags(flags); + + emit fullScreenChanged(d->wasFullScreen = false); + } + } + } + return QWidget::event(event); +} + +/*! + Handles the show \a event. + \since 1.0 + */ +void QVideoWidget::showEvent(QShowEvent *event) +{ + Q_D(QVideoWidget); + + QWidget::showEvent(event); + + // The window backend won't work for re-directed windows so use the renderer backend instead. + if (d->windowBackend && window()->testAttribute(Qt::WA_DontShowOnScreen)) { + d->windowBackend->releaseControl(); + + delete d->windowBackend; + d->windowBackend = 0; + + d->createRendererBackend(); + } + + if (d->currentBackend) + d->currentBackend->showEvent(); +} + +/*! + + Handles the hide \a event. + \since 1.0 +*/ +void QVideoWidget::hideEvent(QHideEvent *event) +{ + Q_D(QVideoWidget); + + if (d->currentBackend) + d->currentBackend->hideEvent(event); + + QWidget::hideEvent(event); +} + +/*! + Handles the resize \a event. + \since 1.0 + */ +void QVideoWidget::resizeEvent(QResizeEvent *event) +{ + Q_D(QVideoWidget); + + QWidget::resizeEvent(event); + + if (d->currentBackend) + d->currentBackend->resizeEvent(event); +} + +/*! + Handles the move \a event. + \since 1.0 + */ +void QVideoWidget::moveEvent(QMoveEvent *event) +{ + Q_D(QVideoWidget); + + if (d->currentBackend) + d->currentBackend->moveEvent(event); +} + +/*! + Handles the paint \a event. + \since 1.0 + */ +void QVideoWidget::paintEvent(QPaintEvent *event) +{ + Q_D(QVideoWidget); + + if (d->currentBackend) { + d->currentBackend->paintEvent(event); + } else if (testAttribute(Qt::WA_OpaquePaintEvent)) { + QPainter painter(this); + + painter.fillRect(event->rect(), palette().window()); + } +} + + +#if defined(Q_WS_WIN) +/*! + \reimp + \internal + \since 1.1 +*/ +bool QVideoWidget::winEvent(MSG *message, long *result) +{ + return d_func()->windowBackend && d_func()->windowBackend->winEvent(message, result) + ? true + : QWidget::winEvent(message, result); +} +#endif + + +#include "moc_qvideowidget.cpp" +#include "moc_qvideowidget_p.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qvideowidget.h b/src/multimediakit/qvideowidget.h new file mode 100644 index 000000000..87da76588 --- /dev/null +++ b/src/multimediakit/qvideowidget.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOWIDGET_H +#define QVIDEOWIDGET_H + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QMediaObject; + +class QVideoWidgetPrivate; +class Q_MULTIMEDIA_EXPORT QVideoWidget : public QWidget, public QMediaBindableInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaBindableInterface) + Q_PROPERTY(QMediaObject* mediaObject READ mediaObject WRITE setMediaObject) + Q_PROPERTY(bool fullScreen READ isFullScreen WRITE setFullScreen NOTIFY fullScreenChanged) + Q_PROPERTY(Qt::AspectRatioMode aspectRatioMode READ aspectRatioMode WRITE setAspectRatioMode) + Q_PROPERTY(int brightness READ brightness WRITE setBrightness NOTIFY brightnessChanged) + Q_PROPERTY(int contrast READ contrast WRITE setContrast NOTIFY contrastChanged) + Q_PROPERTY(int hue READ hue WRITE setHue NOTIFY hueChanged) + Q_PROPERTY(int saturation READ saturation WRITE setSaturation NOTIFY saturationChanged) + +public: + QVideoWidget(QWidget *parent = 0); + ~QVideoWidget(); + + QMediaObject *mediaObject() const; + +#ifdef Q_QDOC + bool isFullScreen() const; +#endif + + Qt::AspectRatioMode aspectRatioMode() const; + + int brightness() const; + int contrast() const; + int hue() const; + int saturation() const; + + QSize sizeHint() const; + +public Q_SLOTS: + void setFullScreen(bool fullScreen); + void setAspectRatioMode(Qt::AspectRatioMode mode); + void setBrightness(int brightness); + void setContrast(int contrast); + void setHue(int hue); + void setSaturation(int saturation); + +Q_SIGNALS: + void fullScreenChanged(bool fullScreen); + void brightnessChanged(int brightness); + void contrastChanged(int contrast); + void hueChanged(int hue); + void saturationChanged(int saturation); + +protected: + bool event(QEvent *event); + void showEvent(QShowEvent *event); + void hideEvent(QHideEvent *event); + void resizeEvent(QResizeEvent *event); + void moveEvent(QMoveEvent *event); + void paintEvent(QPaintEvent *event); + + bool setMediaObject(QMediaObject *object); + +#if defined(Q_WS_WIN) + bool winEvent(MSG *message, long *result); +#endif + + QVideoWidget(QVideoWidgetPrivate &dd, QWidget *parent); + QVideoWidgetPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QVideoWidget) + Q_PRIVATE_SLOT(d_func(), void _q_serviceDestroyed()) + Q_PRIVATE_SLOT(d_func(), void _q_brightnessChanged(int)) + Q_PRIVATE_SLOT(d_func(), void _q_contrastChanged(int)) + Q_PRIVATE_SLOT(d_func(), void _q_hueChanged(int)) + Q_PRIVATE_SLOT(d_func(), void _q_saturationChanged(int)) + Q_PRIVATE_SLOT(d_func(), void _q_fullScreenChanged(bool)) + Q_PRIVATE_SLOT(d_func(), void _q_dimensionsChanged()) +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/qvideowidget_p.h b/src/multimediakit/qvideowidget_p.h new file mode 100644 index 000000000..b5cc704f4 --- /dev/null +++ b/src/multimediakit/qvideowidget_p.h @@ -0,0 +1,282 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOWIDGET_P_H +#define QVIDEOWIDGET_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 +#include "qvideowidget.h" + +#ifndef QT_NO_OPENGL +#include +#endif + +#include "qpaintervideosurface_p.h" + +#include + +QT_BEGIN_NAMESPACE + +class QMediaService; + +class QVideoWidgetControlInterface +{ +public: + virtual ~QVideoWidgetControlInterface() {} + + virtual void setBrightness(int brightness) = 0; + virtual void setContrast(int contrast) = 0; + virtual void setHue(int hue) = 0; + virtual void setSaturation(int saturation) = 0; + + virtual void setFullScreen(bool fullScreen) = 0; + + virtual Qt::AspectRatioMode aspectRatioMode() const = 0; + virtual void setAspectRatioMode(Qt::AspectRatioMode mode) = 0; +}; + +class QVideoWidgetBackend : public QObject, public QVideoWidgetControlInterface +{ + Q_OBJECT +public: + virtual QSize sizeHint() const = 0; + + virtual void showEvent() = 0; + virtual void hideEvent(QHideEvent *event) = 0; + virtual void resizeEvent(QResizeEvent *event) = 0; + virtual void moveEvent(QMoveEvent *event) = 0; + virtual void paintEvent(QPaintEvent *event) = 0; +}; + +class QVideoWidgetControl; + +class QVideoWidgetControlBackend : public QObject, public QVideoWidgetControlInterface +{ + Q_OBJECT +public: + QVideoWidgetControlBackend(QMediaService *service, QVideoWidgetControl *control, QWidget *widget); + + void releaseControl(); + + void setBrightness(int brightness); + void setContrast(int contrast); + void setHue(int hue); + void setSaturation(int saturation); + + void setFullScreen(bool fullScreen); + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + +private: + QMediaService *m_service; + QVideoWidgetControl *m_widgetControl; +}; + + +class QVideoRendererControl; + +class QRendererVideoWidgetBackend : public QVideoWidgetBackend +{ + Q_OBJECT +public: + QRendererVideoWidgetBackend(QMediaService *service, QVideoRendererControl *control, QWidget *widget); + ~QRendererVideoWidgetBackend(); + + void releaseControl(); + void clearSurface(); + + void setBrightness(int brightness); + void setContrast(int contrast); + void setHue(int hue); + void setSaturation(int saturation); + + void setFullScreen(bool fullScreen); + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + + QSize sizeHint() const; + + void showEvent(); + void hideEvent(QHideEvent *event); + void resizeEvent(QResizeEvent *event); + void moveEvent(QMoveEvent *event); + void paintEvent(QPaintEvent *event); + +Q_SIGNALS: + void fullScreenChanged(bool fullScreen); + void brightnessChanged(int brightness); + void contrastChanged(int contrast); + void hueChanged(int hue); + void saturationChanged(int saturation); + +private Q_SLOTS: + void formatChanged(const QVideoSurfaceFormat &format); + void frameChanged(); + +private: + void updateRects(); + + QMediaService *m_service; + QVideoRendererControl *m_rendererControl; + QWidget *m_widget; + QPainterVideoSurface *m_surface; + Qt::AspectRatioMode m_aspectRatioMode; + QRect m_boundingRect; + QRectF m_sourceRect; + QSize m_nativeSize; + bool m_updatePaintDevice; +}; + +class QVideoWindowControl; + +class QWindowVideoWidgetBackend : public QVideoWidgetBackend +{ + Q_OBJECT +public: + QWindowVideoWidgetBackend(QMediaService *service, QVideoWindowControl *control, QWidget *widget); + ~QWindowVideoWidgetBackend(); + + void releaseControl(); + + void setBrightness(int brightness); + void setContrast(int contrast); + void setHue(int hue); + void setSaturation(int saturation); + + void setFullScreen(bool fullScreen); + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + + QSize sizeHint() const; + + void showEvent(); + void hideEvent(QHideEvent *event); + void resizeEvent(QResizeEvent *event); + void moveEvent(QMoveEvent *event); + void paintEvent(QPaintEvent *event); + +#if defined(Q_WS_WIN) + bool winEvent(MSG *message, long *result); +#endif + +private: + QMediaService *m_service; + QVideoWindowControl *m_windowControl; + QWidget *m_widget; + Qt::AspectRatioMode m_aspectRatioMode; + QSize m_pixelAspectRatio; +}; + +class QMediaService; +class QVideoOutputControl; + +class QVideoWidgetPrivate +{ + Q_DECLARE_PUBLIC(QVideoWidget) +public: + QVideoWidgetPrivate() + : q_ptr(0) + , mediaObject(0) + , service(0) + , widgetBackend(0) + , windowBackend(0) + , rendererBackend(0) + , currentControl(0) + , currentBackend(0) + , brightness(0) + , contrast(0) + , hue(0) + , saturation(0) + , aspectRatioMode(Qt::KeepAspectRatio) + , nonFullScreenFlags(0) + , wasFullScreen(false) + { + } + + QVideoWidget *q_ptr; + QPointer mediaObject; + QMediaService *service; + QVideoWidgetControlBackend *widgetBackend; + QWindowVideoWidgetBackend *windowBackend; + QRendererVideoWidgetBackend *rendererBackend; + QVideoWidgetControlInterface *currentControl; + QVideoWidgetBackend *currentBackend; + int brightness; + int contrast; + int hue; + int saturation; + Qt::AspectRatioMode aspectRatioMode; + Qt::WindowFlags nonFullScreenFlags; + bool wasFullScreen; + + bool createWidgetBackend(); + bool createWindowBackend(); + bool createRendererBackend(); + + void setCurrentControl(QVideoWidgetControlInterface *control); + void clearService(); + + void _q_serviceDestroyed(); + void _q_brightnessChanged(int brightness); + void _q_contrastChanged(int contrast); + void _q_hueChanged(int hue); + void _q_saturationChanged(int saturation); + void _q_fullScreenChanged(bool fullScreen); + void _q_dimensionsChanged(); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/qvideowidgetcontrol.cpp b/src/multimediakit/qvideowidgetcontrol.cpp new file mode 100644 index 000000000..e6e5743ec --- /dev/null +++ b/src/multimediakit/qvideowidgetcontrol.cpp @@ -0,0 +1,245 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideowidgetcontrol.h" +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoWidgetControl + + + \brief The QVideoWidgetControl class provides a media control which + implements a video widget. + + \inmodule QtMultimediaKit + \ingroup multimedia + \since 1.0 + + The videoWidget() property of QVideoWidgetControl provides a pointer to a + video widget implemented by the control's media service. This widget is + owned by the media service and so care should be taken not to delete it. + + \snippet doc/src/snippets/multimedia-snippets/video.cpp Video widget control + + QVideoWidgetControl is one of number of possible video output controls. + + The interface name of QVideoWidgetControl is \c com.nokia.Qt.QVideoWidgetControl/1.0 as + defined in QVideoWidgetControl_iid. + + \sa QMediaService::requestControl(), QVideoWidget +*/ + +/*! + \macro QVideoWidgetControl_iid + + \c com.nokia.Qt.QVideoWidgetControl/1.0 + + Defines the interface name of the QVideoWidgetControl class. + + \relates QVideoWidgetControl +*/ + +/*! + Constructs a new video widget control with the given \a parent. +*/ +QVideoWidgetControl::QVideoWidgetControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys a video widget control. +*/ +QVideoWidgetControl::~QVideoWidgetControl() +{ +} + +/*! + \fn QVideoWidgetControl::isFullScreen() const + + Returns true if the video is shown using the complete screen. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::setFullScreen(bool fullScreen) + + Sets whether a video widget is in \a fullScreen mode. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::fullScreenChanged(bool fullScreen) + + Signals that the \a fullScreen state of a video widget has changed. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::aspectRatioMode() const + + Returns how video is scaled to fit the widget with respect to its aspect ratio. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::setAspectRatioMode(Qt::AspectRatioMode mode) + + Sets the aspect ratio \a mode which determines how video is scaled to the fit the widget with + respect to its aspect ratio. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::brightness() const + + Returns the brightness adjustment applied to a video. + + Valid brightness values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::setBrightness(int brightness) + + Sets a \a brightness adjustment for a video. + + Valid brightness values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::brightnessChanged(int brightness) + + Signals that a video widget's \a brightness adjustment has changed. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::contrast() const + + Returns the contrast adjustment applied to a video. + + Valid contrast values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::setContrast(int contrast) + + Sets the contrast adjustment for a video widget to \a contrast. + + Valid contrast values range between -100 and 100, the default is 0. + \since 1.0 +*/ + + +/*! + \fn QVideoWidgetControl::contrastChanged(int contrast) + + Signals that a video widget's \a contrast adjustment has changed. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::hue() const + + Returns the hue adjustment applied to a video widget. + + Value hue values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::setHue(int hue) + + Sets a \a hue adjustment for a video widget. + + Valid hue values range between -100 and 100, the default is 0. + \since 1.0 +*/ + + +/*! + \fn QVideoWidgetControl::hueChanged(int hue) + + Signals that a video widget's \a hue adjustment has changed. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::saturation() const + + Returns the saturation adjustment applied to a video widget. + + Value saturation values range between -100 and 100, the default is 0. + \since 1.0 +*/ + + +/*! + \fn QVideoWidgetControl::setSaturation(int saturation) + + Sets a \a saturation adjustment for a video widget. + + Valid saturation values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::saturationChanged(int saturation) + + Signals that a video widget's \a saturation adjustment has changed. + \since 1.0 +*/ + +/*! + \fn QVideoWidgetControl::videoWidget() + + Returns the QWidget. + \since 1.0 +*/ + +#include "moc_qvideowidgetcontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qvideowidgetcontrol.h b/src/multimediakit/qvideowidgetcontrol.h new file mode 100644 index 000000000..44e11bedc --- /dev/null +++ b/src/multimediakit/qvideowidgetcontrol.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOWIDGETCONTROL_H +#define QVIDEOWIDGETCONTROL_H + +#include "qvideowidget.h" +#include "qmediacontrol.h" + +#include + +QT_BEGIN_NAMESPACE + +class QVideoWidgetControlPrivate; + +class Q_MULTIMEDIA_EXPORT QVideoWidgetControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QVideoWidgetControl(); + + virtual QWidget *videoWidget() = 0; + + virtual Qt::AspectRatioMode aspectRatioMode() const = 0; + virtual void setAspectRatioMode(Qt::AspectRatioMode mode) = 0; + + virtual bool isFullScreen() const = 0; + virtual void setFullScreen(bool fullScreen) = 0; + + virtual int brightness() const = 0; + virtual void setBrightness(int brightness) = 0; + + virtual int contrast() const = 0; + virtual void setContrast(int contrast) = 0; + + virtual int hue() const = 0; + virtual void setHue(int hue) = 0; + + virtual int saturation() const = 0; + virtual void setSaturation(int saturation) = 0; + +Q_SIGNALS: + void fullScreenChanged(bool fullScreen); + void brightnessChanged(int brightness); + void contrastChanged(int contrast); + void hueChanged(int hue); + void saturationChanged(int saturation); + +protected: + QVideoWidgetControl(QObject *parent = 0); +}; + +#define QVideoWidgetControl_iid "com.nokia.Qt.QVideoWidgetControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoWidgetControl, QVideoWidgetControl_iid) + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/qvideowindowcontrol.cpp b/src/multimediakit/qvideowindowcontrol.cpp new file mode 100644 index 000000000..fec15e002 --- /dev/null +++ b/src/multimediakit/qvideowindowcontrol.cpp @@ -0,0 +1,284 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideowindowcontrol.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoWindowControl + + \inmodule QtMultimediaKit + \ingroup multimedia + \brief The QVideoWindowControl class provides a media control for rendering video to a window. + \since 1.0 + + + The winId() property QVideoWindowControl allows a platform specific window + ID to be set as the video render target of a QMediaService. The + displayRect() property is used to set the region of the window the video + should be rendered to, and the aspectRatioMode() property indicates how the + video should be scaled to fit the displayRect(). + + \snippet doc/src/snippets/multimedia-snippets/video.cpp Video window control + + QVideoWindowControl is one of a number of possible video output controls. + + The interface name of QVideoWindowControl is \c com.nokia.Qt.QVideoWindowControl/1.0 as + defined in QVideoWindowControl_iid. + + \sa QMediaService::requestControl(), QVideoWidget +*/ + +/*! + \macro QVideoWindowControl_iid + + \c com.nokia.Qt.QVideoWindowControl/1.0 + + Defines the interface name of the QVideoWindowControl class. + + \relates QVideoWindowControl +*/ + +/*! + Constructs a new video window control with the given \a parent. +*/ +QVideoWindowControl::QVideoWindowControl(QObject *parent) + : QMediaControl(parent) +{ +} + +/*! + Destroys a video window control. +*/ +QVideoWindowControl::~QVideoWindowControl() +{ +} + +/*! + \fn QVideoWindowControl::winId() const + + Returns the ID of the window a video overlay end point renders to. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::setWinId(WId id) + + Sets the \a id of the window a video overlay end point renders to. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::displayRect() const + Returns the sub-rect of a window where video is displayed. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::setDisplayRect(const QRect &rect) + Sets the sub-\a rect of a window where video is displayed. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::isFullScreen() const + + Identifies if a video overlay is a fullScreen overlay. + + Returns true if the video overlay is fullScreen, and false otherwise. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::setFullScreen(bool fullScreen) + + Sets whether a video overlay is a \a fullScreen overlay. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::fullScreenChanged(bool fullScreen) + + Signals that the \a fullScreen state of a video overlay has changed. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::repaint() + + Repaints the last frame. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::nativeSize() const + + Returns a suggested size for the video display based on the resolution and aspect ratio of the + video. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::nativeSizeChanged() + + Signals that the native dimensions of the video have changed. + \since 1.0 +*/ + + +/*! + \fn QVideoWindowControl::aspectRatioMode() const + + Returns how video is scaled to fit the display region with respect to its aspect ratio. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::setAspectRatioMode(Qt::AspectRatioMode mode) + + Sets the aspect ratio \a mode which determines how video is scaled to the fit the display region + with respect to its aspect ratio. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::brightness() const + + Returns the brightness adjustment applied to a video overlay. + + Valid brightness values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::setBrightness(int brightness) + + Sets a \a brightness adjustment for a video overlay. + + Valid brightness values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::brightnessChanged(int brightness) + + Signals that a video overlay's \a brightness adjustment has changed. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::contrast() const + + Returns the contrast adjustment applied to a video overlay. + + Valid contrast values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::setContrast(int contrast) + + Sets the \a contrast adjustment for a video overlay. + + Valid contrast values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::contrastChanged(int contrast) + + Signals that a video overlay's \a contrast adjustment has changed. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::hue() const + + Returns the hue adjustment applied to a video overlay. + + Value hue values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::setHue(int hue) + + Sets a \a hue adjustment for a video overlay. + + Valid hue values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::hueChanged(int hue) + + Signals that a video overlay's \a hue adjustment has changed. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::saturation() const + + Returns the saturation adjustment applied to a video overlay. + + Value saturation values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::setSaturation(int saturation) + Sets a \a saturation adjustment for a video overlay. + + Valid saturation values range between -100 and 100, the default is 0. + \since 1.0 +*/ + +/*! + \fn QVideoWindowControl::saturationChanged(int saturation) + + Signals that a video overlay's \a saturation adjustment has changed. + \since 1.0 +*/ + +#include "moc_qvideowindowcontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimediakit/qvideowindowcontrol.h b/src/multimediakit/qvideowindowcontrol.h new file mode 100644 index 000000000..addb0b633 --- /dev/null +++ b/src/multimediakit/qvideowindowcontrol.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOWINDOWCONTROL_H +#define QVIDEOWINDOWCONTROL_H + +#include "qmediacontrol.h" +#include "qvideowidget.h" + +#include + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QVideoWindowControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QVideoWindowControl(); + + virtual WId winId() const = 0; + virtual void setWinId(WId id) = 0; + + virtual QRect displayRect() const = 0; + virtual void setDisplayRect(const QRect &rect) = 0; + + virtual bool isFullScreen() const = 0; + virtual void setFullScreen(bool fullScreen) = 0; + + virtual void repaint() = 0; + + virtual QSize nativeSize() const = 0; + + virtual Qt::AspectRatioMode aspectRatioMode() const = 0; + virtual void setAspectRatioMode(Qt::AspectRatioMode mode) = 0; + + virtual int brightness() const = 0; + virtual void setBrightness(int brightness) = 0; + + virtual int contrast() const = 0; + virtual void setContrast(int contrast) = 0; + + virtual int hue() const = 0; + virtual void setHue(int hue) = 0; + + virtual int saturation() const = 0; + virtual void setSaturation(int saturation) = 0; + +Q_SIGNALS: + void fullScreenChanged(bool fullScreen); + void brightnessChanged(int brightness); + void contrastChanged(int contrast); + void hueChanged(int hue); + void saturationChanged(int saturation); + void nativeSizeChanged(); + +protected: + QVideoWindowControl(QObject *parent = 0); +}; + +#define QVideoWindowControl_iid "com.nokia.Qt.QVideoWindowControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoWindowControl, QVideoWindowControl_iid) + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/qxvideosurface_maemo5.cpp b/src/multimediakit/qxvideosurface_maemo5.cpp new file mode 100644 index 000000000..1289055f2 --- /dev/null +++ b/src/multimediakit/qxvideosurface_maemo5.cpp @@ -0,0 +1,497 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#include "qxvideosurface_maemo5_p.h" + +//#define DEBUG_XV_SURFACE + +struct XvFormatRgb +{ + QVideoFrame::PixelFormat pixelFormat; + int bits_per_pixel; + int format; + int num_planes; + + int depth; + unsigned int red_mask; + unsigned int green_mask; + unsigned int blue_mask; + +}; + +bool operator ==(const XvImageFormatValues &format, const XvFormatRgb &rgb) +{ + return format.type == XvRGB + && format.bits_per_pixel == rgb.bits_per_pixel + && format.format == rgb.format + && format.num_planes == rgb.num_planes + && format.depth == rgb.depth + && format.red_mask == rgb.red_mask + && format.blue_mask == rgb.blue_mask; +} + +static const XvFormatRgb qt_xvRgbLookup[] = +{ + { QVideoFrame::Format_ARGB32, 32, XvPacked, 1, 32, 0x00FF0000, 0x0000FF00, 0x000000FF }, + { QVideoFrame::Format_RGB32 , 32, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF }, + { QVideoFrame::Format_RGB24 , 24, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF }, + { QVideoFrame::Format_RGB565, 16, XvPacked, 1, 16, 0x0000F800, 0x000007E0, 0x0000001F }, + { QVideoFrame::Format_BGRA32, 32, XvPacked, 1, 32, 0xFF000000, 0x00FF0000, 0x0000FF00 }, + { QVideoFrame::Format_BGR32 , 32, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF }, + { QVideoFrame::Format_BGR24 , 24, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF }, + { QVideoFrame::Format_BGR565, 16, XvPacked, 1, 16, 0x0000F800, 0x000007E0, 0x0000001F } +}; + +struct XvFormatYuv +{ + QVideoFrame::PixelFormat pixelFormat; + int bits_per_pixel; + int format; + int num_planes; + + unsigned int y_sample_bits; + unsigned int u_sample_bits; + unsigned int v_sample_bits; + unsigned int horz_y_period; + unsigned int horz_u_period; + unsigned int horz_v_period; + unsigned int vert_y_period; + unsigned int vert_u_period; + unsigned int vert_v_period; + char component_order[32]; +}; + +bool operator ==(const XvImageFormatValues &format, const XvFormatYuv &yuv) +{ + return format.type == XvYUV + && format.bits_per_pixel == yuv.bits_per_pixel + && format.format == yuv.format + && format.num_planes == yuv.num_planes + && format.y_sample_bits == yuv.y_sample_bits + && format.u_sample_bits == yuv.u_sample_bits + && format.v_sample_bits == yuv.v_sample_bits + && format.horz_y_period == yuv.horz_y_period + && format.horz_u_period == yuv.horz_u_period + && format.horz_v_period == yuv.horz_v_period + && format.horz_y_period == yuv.vert_y_period + && format.vert_u_period == yuv.vert_u_period + && format.vert_v_period == yuv.vert_v_period + && qstrncmp(format.component_order, yuv.component_order, 32) == 0; +} + +static const XvFormatYuv qt_xvYuvLookup[] = +{ + { QVideoFrame::Format_YUV444 , 24, XvPacked, 1, 8, 8, 8, 1, 1, 1, 1, 1, 1, "YUV" }, + { QVideoFrame::Format_YUV420P, 12, XvPlanar, 3, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YUV" }, + { QVideoFrame::Format_YV12 , 12, XvPlanar, 3, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YVU" }, + { QVideoFrame::Format_UYVY , 16, XvPacked, 1, 8, 8, 8, 1, 2, 2, 1, 1, 1, "UYVY" }, + { QVideoFrame::Format_YUYV , 16, XvPacked, 1, 8, 8, 8, 1, 2, 2, 1, 1, 1, "YUY2" }, + { QVideoFrame::Format_YUYV , 16, XvPacked, 1, 8, 8, 8, 1, 2, 2, 1, 1, 1, "YUYV" }, + { QVideoFrame::Format_NV12 , 12, XvPlanar, 2, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YUV" }, + { QVideoFrame::Format_NV12 , 12, XvPlanar, 2, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YVU" }, + { QVideoFrame::Format_Y8 , 8 , XvPlanar, 1, 8, 0, 0, 1, 0, 0, 1, 0, 0, "Y" } +}; + +QXVideoSurface::QXVideoSurface(QObject *parent) + : QAbstractVideoSurface(parent) + , m_winId(0) + , m_portId(0) + , m_gc(0) + , m_image(0) + , m_colorKey(24,0,24) +{ +} + +QXVideoSurface::~QXVideoSurface() +{ + if (m_gc) + XFreeGC(QX11Info::display(), m_gc); + + if (m_portId != 0) + XvUngrabPort(QX11Info::display(), m_portId, 0); +} + +WId QXVideoSurface::winId() const +{ + return m_winId; +} + +void QXVideoSurface::setWinId(WId id) +{ + if (id == m_winId) + return; + +#ifdef DEBUG_XV_SURFACE + qDebug() << "QXVideoSurface::setWinId" << id; +#endif + + if (m_image) + XFree(m_image); + + if (m_gc) { + XFreeGC(QX11Info::display(), m_gc); + m_gc = 0; + } + + if (m_portId != 0) + XvUngrabPort(QX11Info::display(), m_portId, 0); + + QList prevFormats = m_supportedPixelFormats; + m_supportedPixelFormats.clear(); + m_formatIds.clear(); + + m_winId = id; + + if (m_winId && findPort()) { + querySupportedFormats(); + + m_gc = XCreateGC(QX11Info::display(), m_winId, 0, 0); + + if (m_image) { + m_image = 0; + + if (!start(surfaceFormat())) + QAbstractVideoSurface::stop(); + } + } else if (m_image) { + m_image = 0; + + QAbstractVideoSurface::stop(); + } + + if (m_supportedPixelFormats != prevFormats) { +#ifdef DEBUG_XV_SURFACE + qDebug() << "QXVideoSurface: supportedFormatsChanged"; +#endif + emit supportedFormatsChanged(); + } +} + +QRect QXVideoSurface::displayRect() const +{ + return m_displayRect; +} + +void QXVideoSurface::setDisplayRect(const QRect &rect) +{ + m_displayRect = rect; +} + +QColor QXVideoSurface::colorKey() const +{ + return m_colorKey; +} + +void QXVideoSurface::setColorKey(QColor key) +{ + m_colorKey = key; +} + +int QXVideoSurface::getAttribute(const char *attribute) const +{ + if (m_portId != 0) { + Display *display = QX11Info::display(); + + Atom atom = XInternAtom(display, attribute, True); + + int value = 0; + + XvGetPortAttribute(display, m_portId, atom, &value); + + return value; + } else { + return 0; + } +} + +void QXVideoSurface::setAttribute(const char *attribute, int value) +{ + if (m_portId != 0) { + Display *display = QX11Info::display(); + + Atom atom = XInternAtom(display, attribute, True); + + XvSetPortAttribute(display, m_portId, atom, value); + } +} + +QList QXVideoSurface::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + if ( handleType == QAbstractVideoBuffer::NoHandle || + handleType == QAbstractVideoBuffer::XvShmImageHandle ) + return m_supportedPixelFormats; + else + return QList(); +} + +bool QXVideoSurface::start(const QVideoSurfaceFormat &format) +{ +#ifdef DEBUG_XV_SURFACE + qDebug() << "QXVideoSurface::start" << format; +#endif + + m_lastFrame = QVideoFrame(); + + if (m_image) + XFree(m_image); + + m_xvFormatId = 0; + for (int i = 0; i < m_supportedPixelFormats.count(); ++i) { + if (m_supportedPixelFormats.at(i) == format.pixelFormat()) { + m_xvFormatId = m_formatIds.at(i); + break; + } + } + + if (m_xvFormatId == 0) { + setError(UnsupportedFormatError); + } else { + XvImage *image = XvShmCreateImage( + QX11Info::display(), + m_portId, + m_xvFormatId, + 0, + format.frameWidth(), + format.frameHeight(), + &m_shminfo + ); + + if (!image) { + setError(ResourceError); + return false; + } + + m_shminfo.shmid = shmget(IPC_PRIVATE, image->data_size, IPC_CREAT | 0777); + m_shminfo.shmaddr = image->data = (char*)shmat(m_shminfo.shmid, 0, 0); + m_shminfo.readOnly = False; + + if (!XShmAttach(QX11Info::display(), &m_shminfo)) { + qWarning() << "XShmAttach failed" << format; + return false; + } + + if (!image) { + setError(ResourceError); + } else { + m_viewport = format.viewport(); + m_image = image; + + quint32 c = m_colorKey.rgb(); + quint16 colorKey16 = ((c >> 3) & 0x001f) + | ((c >> 5) & 0x07e0) + | ((c >> 8) & 0xf800); + + setAttribute("XV_AUTOPAINT_COLORKEY", 0); + setAttribute("XV_COLORKEY", colorKey16); + setAttribute("XV_OMAP_VSYNC", 1); + setAttribute("XV_DOUBLE_BUFFER", 0); + + QVideoSurfaceFormat newFormat = format; + newFormat.setProperty("portId", QVariant(quint64(m_portId))); + newFormat.setProperty("xvFormatId", m_xvFormatId); + newFormat.setProperty("dataSize", image->data_size); + + return QAbstractVideoSurface::start(newFormat); + } + } + + if (m_image) { + m_image = 0; + + QAbstractVideoSurface::stop(); + } + + return false; +} + +void QXVideoSurface::stop() +{ + if (m_image) { + XFree(m_image); + m_image = 0; + m_lastFrame = QVideoFrame(); + + QAbstractVideoSurface::stop(); + } +} + +bool QXVideoSurface::present(const QVideoFrame &frame) +{ + if (!m_image) { + setError(StoppedError); + return false; + } else if (m_image->width != frame.width() || m_image->height != frame.height()) { + setError(IncorrectFormatError); + return false; + } else { + m_lastFrame = frame; + + if (!m_lastFrame.map(QAbstractVideoBuffer::ReadOnly)) { + qWarning() << "Failed to map video frame"; + setError(IncorrectFormatError); + return false; + } else { + bool presented = false; + + if (frame.handleType() != QAbstractVideoBuffer::XvShmImageHandle && + m_image->data_size > m_lastFrame.mappedBytes()) { + qWarning("Insufficient frame buffer size"); + setError(IncorrectFormatError); + } else if (frame.handleType() != QAbstractVideoBuffer::XvShmImageHandle && + m_image->num_planes > 0 && + m_image->pitches[0] != m_lastFrame.bytesPerLine()) { + qWarning("Incompatible frame pitches"); + setError(IncorrectFormatError); + } else { + XvImage *img = 0; + + if (frame.handleType() == QAbstractVideoBuffer::XvShmImageHandle) { + img = frame.handle().value(); + } else { + img = m_image; + memcpy(m_image->data, m_lastFrame.bits(), qMin(m_lastFrame.mappedBytes(), m_image->data_size)); + } + + if (img) + XvShmPutImage( + QX11Info::display(), + m_portId, + m_winId, + m_gc, + img, + m_viewport.x(), + m_viewport.y(), + m_viewport.width(), + m_viewport.height(), + m_displayRect.x(), + m_displayRect.y(), + m_displayRect.width(), + m_displayRect.height(), + false); + + presented = true; + } + + m_lastFrame.unmap(); + + return presented; + } + } +} + +void QXVideoSurface::repaintLastFrame() +{ + if (m_lastFrame.isValid()) + present(QVideoFrame(m_lastFrame)); +} + +bool QXVideoSurface::findPort() +{ + unsigned int count = 0; + XvAdaptorInfo *adaptors = 0; + bool portFound = false; + + if (XvQueryAdaptors(QX11Info::display(), m_winId, &count, &adaptors) == Success) { + for (unsigned int i = 0; i < count && !portFound; ++i) { + if (adaptors[i].type & XvImageMask) { + m_portId = adaptors[i].base_id; + + for (unsigned int j = 0; j < adaptors[i].num_ports && !portFound; ++j, ++m_portId) + portFound = XvGrabPort(QX11Info::display(), m_portId, 0) == Success; + } + } + XvFreeAdaptorInfo(adaptors); + } + + if (!portFound) + qWarning() << "QXVideoSurface::findPort: failed to find XVideo port"; + + return portFound; +} + +void QXVideoSurface::querySupportedFormats() +{ + int count = 0; + if (XvImageFormatValues *imageFormats = XvListImageFormats( + QX11Info::display(), m_portId, &count)) { + const int rgbCount = sizeof(qt_xvRgbLookup) / sizeof(XvFormatRgb); + const int yuvCount = sizeof(qt_xvYuvLookup) / sizeof(XvFormatYuv); + + for (int i = 0; i < count; ++i) { + switch (imageFormats[i].type) { + case XvRGB: + for (int j = 0; j < rgbCount; ++j) { + if (imageFormats[i] == qt_xvRgbLookup[j]) { + m_supportedPixelFormats.append(qt_xvRgbLookup[j].pixelFormat); + m_formatIds.append(imageFormats[i].id); + break; + } + } + break; + case XvYUV: + for (int j = 0; j < yuvCount; ++j) { + //skip YUV420P and YV12 formats, they don't work correctly and slow, + //YUV2 == YUYV is just slow + if (imageFormats[i] == qt_xvYuvLookup[j] && + qt_xvYuvLookup[j].pixelFormat != QVideoFrame::Format_YUV420P && + qt_xvYuvLookup[j].pixelFormat != QVideoFrame::Format_YV12) { + m_supportedPixelFormats.append(qt_xvYuvLookup[j].pixelFormat); + m_formatIds.append(imageFormats[i].id); + break; + } + } + break; + } + } + XFree(imageFormats); + } + +#ifdef DEBUG_XV_SURFACE + qDebug() << "Supported pixel formats:" << m_supportedPixelFormats; +#endif + +} diff --git a/src/multimediakit/qxvideosurface_maemo5_p.h b/src/multimediakit/qxvideosurface_maemo5_p.h new file mode 100644 index 000000000..351cf8805 --- /dev/null +++ b/src/multimediakit/qxvideosurface_maemo5_p.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXVIDEOSURFACE_MAEMO5_H +#define QXVIDEOSURFACE_MAEMO5_H + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +QT_USE_NAMESPACE + +class QXVideoSurface : public QAbstractVideoSurface +{ + Q_OBJECT +public: + QXVideoSurface(QObject *parent = 0); + ~QXVideoSurface(); + + WId winId() const; + void setWinId(WId id); + + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + + QColor colorKey() const; + void setColorKey(QColor key); + + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const; + + QVideoFrame lastFrame() const { return m_lastFrame; } + +public slots: + bool start(const QVideoSurfaceFormat &format); + void stop(); + + bool present(const QVideoFrame &frame); + void repaintLastFrame(); + +private: + WId m_winId; + XvPortID m_portId; + int m_xvFormatId; + GC m_gc; + XvImage *m_image; + XShmSegmentInfo m_shminfo; + QList m_supportedPixelFormats; + QVector m_formatIds; + QRect m_viewport; + QRect m_displayRect; + QColor m_colorKey; + + QVideoFrame m_lastFrame; + + bool findPort(); + void querySupportedFormats(); + + int getAttribute(const char *attribute) const; + void setAttribute(const char *attribute, int value); +}; + +Q_DECLARE_METATYPE(XvImage*) + +#endif diff --git a/src/multimediakit/video/qabstractvideobuffer.cpp b/src/multimediakit/video/qabstractvideobuffer.cpp new file mode 100644 index 000000000..2ed2ddad5 --- /dev/null +++ b/src/multimediakit/video/qabstractvideobuffer.cpp @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qabstractvideobuffer_p.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QAbstractVideoBuffer + \brief The QAbstractVideoBuffer class is an abstraction for video data. + \since 1.0 + \inmodule QtMultimediaKit + + The QVideoFrame class makes use of a QAbstractVideoBuffer internally to reference a buffer of + video data. Creating a subclass of QAbstractVideoBuffer will allow you to construct video + frames from preallocated or static buffers. + + XXX where do these come from? + + The contents of a buffer can be accessed by mapping the buffer to memory using the map() + function which returns a pointer to memory containing the contents of the the video buffer. + The memory returned by map() is released by calling the unmap() function. + + The handle() of a buffer may also be used to manipulate its contents using type specific APIs. + The type of a buffer's handle is given by the handleType() function. + + XXX example of handle stuff (opengl etc) + + \sa QVideoFrame +*/ + +/*! + \enum QAbstractVideoBuffer::HandleType + + Identifies the type of a video buffers handle. + + \value NoHandle The buffer has no handle, its data can only be accessed by mapping the buffer. + \value GLTextureHandle The handle of the buffer is an OpenGL texture ID. + \value XvShmImageHandle The handle contains pointer to shared memory XVideo image. + \value CoreImageHandle The handle contains pointer to Mac OS X CIImage. + \value QPixmapHandle The handle of the buffer is a QPixmap. + \value UserHandle Start value for user defined handle types. + + \sa handleType() +*/ + +/*! + \enum QAbstractVideoBuffer::MapMode + + Enumerates how a video buffer's data is mapped to memory. + + \value NotMapped The video buffer has is not mapped to memory. + \value ReadOnly The mapped memory is populated with data from the video buffer when mapped, but + the content of the mapped memory may be discarded when unmapped. + \value WriteOnly The mapped memory is uninitialized when mapped, and the content will be used to + populate the video buffer when unmapped. + \value ReadWrite The mapped memory is populated with data from the video buffer, and the + video buffer is repopulated with the content of the mapped memory. + + \sa mapMode(), map() +*/ + +/*! + Constructs an abstract video buffer of the given \a type. +*/ +QAbstractVideoBuffer::QAbstractVideoBuffer(HandleType type) + : d_ptr(new QAbstractVideoBufferPrivate) +{ + Q_D(QAbstractVideoBuffer); + + d->handleType = type; +} + +/*! + \internal +*/ +QAbstractVideoBuffer::QAbstractVideoBuffer(QAbstractVideoBufferPrivate &dd, HandleType type) + : d_ptr(&dd) +{ + Q_D(QAbstractVideoBuffer); + + d->handleType = type; +} + +/*! + Destroys an abstract video buffer. +*/ +QAbstractVideoBuffer::~QAbstractVideoBuffer() +{ + delete d_ptr; +} + +/*! + Returns the type of a video buffer's handle. + + \since 1.0 + \sa handle() +*/ +QAbstractVideoBuffer::HandleType QAbstractVideoBuffer::handleType() const +{ + return d_func()->handleType; +} + +/*! + \fn QAbstractVideoBuffer::mapMode() const + + Returns the mode a video buffer is mapped in. + + \since 1.0 + \sa map() +*/ + +/*! + \fn QAbstractVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine) + + Maps the contents of a video buffer to memory. + + The map \a mode indicates whether the contents of the mapped memory should be read from and/or + written to the buffer. If the map mode includes the QAbstractVideoBuffer::ReadOnly flag the + mapped memory will be populated with the content of the video buffer when mapped. If the map + mode includes the QAbstractVideoBuffer::WriteOnly flag the content of the mapped memory will be + persisted in the buffer when unmapped. + + When access to the data is no longer needed be sure to call the unmap() function to release the + mapped memory. + + Returns a pointer to the mapped memory region, or a null pointer if the mapping failed. The + size in bytes of the mapped memory region is returned in \a numBytes, and the line stride in \a + bytesPerLine. + + When access to the data is no longer needed be sure to unmap() the buffer. + + \note Writing to memory that is mapped as read-only is undefined, and may result in changes + to shared data. + + \since 1.0 + \sa unmap(), mapMode() +*/ + +/*! + \fn QAbstractVideoBuffer::unmap() + + Releases the memory mapped by the map() function + + If the \l {QAbstractVideoBuffer::MapMode}{MapMode} included the QAbstractVideoBuffer::WriteOnly + flag this will persist the current content of the mapped memory to the video frame. + + \since 1.0 + \sa map() +*/ + +/*! + Returns a type specific handle to the data buffer. + + The type of the handle is given by handleType() function. + + XXX put a table here too + + \since 1.0 + \sa handleType() +*/ +QVariant QAbstractVideoBuffer::handle() const +{ + return QVariant(); +} + + +QT_END_NAMESPACE diff --git a/src/multimediakit/video/qabstractvideobuffer.h b/src/multimediakit/video/qabstractvideobuffer.h new file mode 100644 index 000000000..44f4247e7 --- /dev/null +++ b/src/multimediakit/video/qabstractvideobuffer.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTVIDEOBUFFER_H +#define QABSTRACTVIDEOBUFFER_H + +#include +#include + + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QVariant; + +class QAbstractVideoBufferPrivate; + +class Q_MULTIMEDIA_EXPORT QAbstractVideoBuffer +{ +public: + enum HandleType + { + NoHandle, + GLTextureHandle, + XvShmImageHandle, + CoreImageHandle, + QPixmapHandle, + UserHandle = 1000 + }; + + enum MapMode + { + NotMapped = 0x00, + ReadOnly = 0x01, + WriteOnly = 0x02, + ReadWrite = ReadOnly | WriteOnly + }; + + QAbstractVideoBuffer(HandleType type); + virtual ~QAbstractVideoBuffer(); + + HandleType handleType() const; + + virtual MapMode mapMode() const = 0; + + virtual uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) = 0; + virtual void unmap() = 0; + + virtual QVariant handle() const; + +protected: + QAbstractVideoBuffer(QAbstractVideoBufferPrivate &dd, HandleType type); + + QAbstractVideoBufferPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QAbstractVideoBuffer) + Q_DISABLE_COPY(QAbstractVideoBuffer) +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QAbstractVideoBuffer::HandleType) +Q_DECLARE_METATYPE(QAbstractVideoBuffer::MapMode) + +QT_END_HEADER + +#endif diff --git a/src/multimediakit/video/qabstractvideobuffer_p.h b/src/multimediakit/video/qabstractvideobuffer_p.h new file mode 100644 index 000000000..acfa1ee74 --- /dev/null +++ b/src/multimediakit/video/qabstractvideobuffer_p.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTVIDEOBUFFER_P_H +#define QABSTRACTVIDEOBUFFER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include "qabstractvideobuffer.h" + +#include +#include + + +QT_BEGIN_NAMESPACE + +class QAbstractVideoBufferPrivate +{ +public: + QAbstractVideoBufferPrivate() + : handleType(QAbstractVideoBuffer::NoHandle) + {} + + virtual ~QAbstractVideoBufferPrivate() + {} + + QAbstractVideoBuffer::HandleType handleType; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/video/qabstractvideosurface.cpp b/src/multimediakit/video/qabstractvideosurface.cpp new file mode 100644 index 000000000..59c55c242 --- /dev/null +++ b/src/multimediakit/video/qabstractvideosurface.cpp @@ -0,0 +1,344 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//TESTED_COMPONENT=src/multimedia + +#include "qabstractvideosurface.h" + +#include "qvideosurfaceformat.h" + +#include + +QT_BEGIN_NAMESPACE + +Q_DECLARE_METATYPE(QVideoSurfaceFormat) +Q_DECLARE_METATYPE(QAbstractVideoSurface::Error) + +/*! + \class QAbstractVideoSurface + \brief The QAbstractVideoSurface class is a base class for video presentation surfaces. + \since 1.0 + \inmodule QtMultimediaKit + + A video surface presents a continuous stream of identically formatted frames, where the format + of each frame is compatible with a stream format supplied when starting a presentation. + + XXX Why do I carE? + + The QAbstractVideoSurface class defines the standard interface that video producers use to + inter-operate with video presentation surfaces. It is not supposed to be instantiated directly. + Instead, you should subclass it to create new video surfaces. + + A list of pixel formats a surface can present is given by the supportedPixelFormats() function, + and the isFormatSupported() function will test if a video surface format is supported. If a + format is not supported the nearestFormat() function may be able to suggest a similar format. + For example, if a surface supports fixed set of resolutions it may suggest the smallest + supported resolution that contains the proposed resolution. + + The start() function takes a supported format and enables a video surface. Once started a + surface will begin displaying the frames it receives in the present() function. Surfaces may + hold a reference to the buffer of a presented video frame until a new frame is presented or + streaming is stopped. The stop() function will disable a surface and a release any video + buffers it holds references to. + + XXX Example? +*/ + +/*! + \enum QAbstractVideoSurface::Error + This enum describes the errors that may be returned by the error() function. + + \value NoError No error occurred. + \value UnsupportedFormatError A video format was not supported. + \value IncorrectFormatError A video frame was not compatible with the format of the surface. + \value StoppedError The surface has not been started. + \value ResourceError The surface could not allocate some resource. +*/ + +/*! + Constructs a video surface with the given \a parent. +*/ +QAbstractVideoSurface::QAbstractVideoSurface(QObject *parent) + : QObject(parent) +{ + setProperty("_q_surfaceFormat", QVariant::fromValue(QVideoSurfaceFormat())); + setProperty("_q_active", false); + setProperty("_q_error", QVariant::fromValue(QAbstractVideoSurface::NoError)); + setProperty("_q_nativeResolution", QSize()); +} + +// XXX Qt5 +/*! + \internal + + This is deprecated. + + Since we need to build without access to Qt's private headers we can't reliably inherit + from QObjectPrivate. Binary compatibility means we can't remove this constructor or + add a d pointer to QAbstractVideoSurface. +*/ +QAbstractVideoSurface::QAbstractVideoSurface(QAbstractVideoSurfacePrivate &, QObject *parent) + : QObject(parent) +{ +} + +/*! + Destroys a video surface. +*/ +QAbstractVideoSurface::~QAbstractVideoSurface() +{ +} + +/*! + \fn QAbstractVideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const + + Returns a list of pixel formats a video surface can present for a given handle \a type. + + The pixel formats returned for the QAbstractVideoBuffer::NoHandle type are valid for any buffer + that can be mapped in read-only mode. + + Types that are first in the list can be assumed to be faster to render. + \since 1.0 +*/ + +/*! + Tests a video surface \a format to determine if a surface can accept it. + + Returns true if the format is supported by the surface, and false otherwise. + \since 1.0 +*/ +bool QAbstractVideoSurface::isFormatSupported(const QVideoSurfaceFormat &format) const +{ + return supportedPixelFormats(format.handleType()).contains(format.pixelFormat()); +} + +/*! + Returns a supported video surface format that is similar to \a format. + + A similar surface format is one that has the same \l {QVideoSurfaceFormat::pixelFormat()}{pixel + format} and \l {QVideoSurfaceFormat::handleType()}{handle type} but may differ in some of the other + properties. For example, if there are restrictions on the \l {QVideoSurfaceFormat::frameSize()} + {frame sizes} a video surface can accept it may suggest a format with a larger frame size and + a \l {QVideoSurfaceFormat::viewport()}{viewport} the size of the original frame size. + + If the format is already supported it will be returned unchanged, or if there is no similar + supported format an invalid format will be returned. + \since 1.0 +*/ +QVideoSurfaceFormat QAbstractVideoSurface::nearestFormat(const QVideoSurfaceFormat &format) const +{ + return isFormatSupported(format) + ? format + : QVideoSurfaceFormat(); +} + +/*! + \fn QAbstractVideoSurface::supportedFormatsChanged() + + Signals that the set of formats supported by a video surface has changed. + + \since 1.0 + \sa supportedPixelFormats(), isFormatSupported() +*/ + +/*! + Returns the format of a video surface. + \since 1.0 +*/ +QVideoSurfaceFormat QAbstractVideoSurface::surfaceFormat() const +{ + return property("_q_format").value(); +} + +/*! + \fn QAbstractVideoSurface::surfaceFormatChanged(const QVideoSurfaceFormat &format) + + Signals that the configured \a format of a video surface has changed. + + \since 1.0 + \sa surfaceFormat(), start() +*/ + +/*! + Starts a video surface presenting \a format frames. + + Returns true if the surface was started, and false if an error occurred. + + \since 1.0 + \sa isActive(), stop() +*/ +bool QAbstractVideoSurface::start(const QVideoSurfaceFormat &format) +{ + bool wasActive = property("_q_active").toBool(); + + setProperty("_q_active", true); + setProperty("_q_format", QVariant::fromValue(format)); + setProperty("_q_error", QVariant::fromValue(NoError)); + + emit surfaceFormatChanged(format); + + if (!wasActive) + emit activeChanged(true); + + return true; +} + +/*! + Stops a video surface presenting frames and releases any resources acquired in start(). + + \since 1.0 + \sa isActive(), start() +*/ +void QAbstractVideoSurface::stop() +{ + if (property("_q_active").toBool()) { + setProperty("_q_format", QVariant::fromValue(QVideoSurfaceFormat())); + setProperty("_q_active", false); + + emit activeChanged(false); + emit surfaceFormatChanged(surfaceFormat()); + } +} + +/*! + Indicates whether a video surface has been started. + + Returns true if the surface has been started, and false otherwise. + \since 1.0 +*/ +bool QAbstractVideoSurface::isActive() const +{ + return property("_q_active").toBool(); +} + +/*! + \fn QAbstractVideoSurface::activeChanged(bool active) + + Signals that the \a active state of a video surface has changed. + + \since 1.0 + \sa isActive(), start(), stop() +*/ + +/*! + \fn QAbstractVideoSurface::present(const QVideoFrame &frame) + + Presents a video \a frame. + + Returns true if the frame was presented, and false if an error occurred. + + Not all surfaces will block until the presentation of a frame has completed. Calling present() + on a non-blocking surface may fail if called before the presentation of a previous frame has + completed. In such cases the surface may not return to a ready state until it has had an + opportunity to process events. + + If present() fails for any other reason the surface will immediately enter the stopped state + and an error() value will be set. + + A video surface must be in the started state for present() to succeed, and the format of the + video frame must be compatible with the current video surface format. + + \since 1.0 + \sa error() +*/ + +/*! + Returns the last error that occurred. + + If a surface fails to start(), or stops unexpectedly this function can be called to discover + what error occurred. + \since 1.0 +*/ + +QAbstractVideoSurface::Error QAbstractVideoSurface::error() const +{ + return property("_q_error").value(); +} + +/*! + Sets the value of error() to \a error. + \since 1.0 +*/ +void QAbstractVideoSurface::setError(Error error) +{ + setProperty("_q_error", QVariant::fromValue(error)); +} + +/*! + \property QAbstractVideoSurface::nativeResolution + + The native resolution of video surface. + This is the resolution of video frames the surface + can render with optimal quality and/or performance. + + The native resolution is not always known and can be changed during playback. + \since 1.1 + */ +QSize QAbstractVideoSurface::nativeResolution() const +{ + return property("_q_nativeResolution").toSize(); +} + +/*! + Set the video surface native \a resolution. + \since 1.1 + */ +void QAbstractVideoSurface::setNativeResolution(const QSize &resolution) +{ + const QSize nativeResolution = property("_q_nativeResolution").toSize(); + + if (nativeResolution != resolution) { + setProperty("_q_nativeResolution", resolution); + + emit nativeResolutionChanged(resolution); + } +} +/*! + \fn QAbstractVideoSurface::nativeResolutionChanged(const QSize &resolution); + + Signals the native \a resolution of video surface has changed. + \since 1.1 +*/ + +QT_END_NAMESPACE + +#include "moc_qabstractvideosurface.cpp" + diff --git a/src/multimediakit/video/qabstractvideosurface.h b/src/multimediakit/video/qabstractvideosurface.h new file mode 100644 index 000000000..a23b31698 --- /dev/null +++ b/src/multimediakit/video/qabstractvideosurface.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTVIDEOSURFACE_H +#define QABSTRACTVIDEOSURFACE_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QRectF; +class QVideoSurfaceFormat; + +class QAbstractVideoSurfacePrivate; + +class Q_MULTIMEDIA_EXPORT QAbstractVideoSurface : public QObject +{ + Q_OBJECT + Q_PROPERTY(QSize nativeResolution READ nativeResolution NOTIFY nativeResolutionChanged) +public: + enum Error + { + NoError, + UnsupportedFormatError, + IncorrectFormatError, + StoppedError, + ResourceError + }; + + explicit QAbstractVideoSurface(QObject *parent = 0); + ~QAbstractVideoSurface(); + + virtual QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const = 0; + virtual bool isFormatSupported(const QVideoSurfaceFormat &format) const; + virtual QVideoSurfaceFormat nearestFormat(const QVideoSurfaceFormat &format) const; + + QVideoSurfaceFormat surfaceFormat() const; + + QSize nativeResolution() const; + + virtual bool start(const QVideoSurfaceFormat &format); + virtual void stop(); + + bool isActive() const; + + virtual bool present(const QVideoFrame &frame) = 0; + + Error error() const; + +Q_SIGNALS: + void activeChanged(bool active); + void surfaceFormatChanged(const QVideoSurfaceFormat &format); + void supportedFormatsChanged(); + void nativeResolutionChanged(const QSize &); + +protected: + QAbstractVideoSurface(QAbstractVideoSurfacePrivate &dd, QObject *parent); + + void setError(Error error); + void setNativeResolution(const QSize &resolution); + +private: + Q_DECLARE_PRIVATE(QAbstractVideoSurface) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimediakit/video/qimagevideobuffer.cpp b/src/multimediakit/video/qimagevideobuffer.cpp new file mode 100644 index 000000000..0c932ff90 --- /dev/null +++ b/src/multimediakit/video/qimagevideobuffer.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qimagevideobuffer_p.h" + +#include "qabstractvideobuffer_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class QImageVideoBufferPrivate : public QAbstractVideoBufferPrivate +{ +public: + QImageVideoBufferPrivate() + : mapMode(QAbstractVideoBuffer::NotMapped) + { + } + + QAbstractVideoBuffer::MapMode mapMode; + QImage image; +}; + +QImageVideoBuffer::QImageVideoBuffer(const QImage &image) + : QAbstractVideoBuffer(*new QImageVideoBufferPrivate, NoHandle) +{ + Q_D(QImageVideoBuffer); + + d->image = image; +} + +QImageVideoBuffer::~QImageVideoBuffer() +{ +} + +QAbstractVideoBuffer::MapMode QImageVideoBuffer::mapMode() const +{ + return d_func()->mapMode; +} + +uchar *QImageVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine) +{ + Q_D(QImageVideoBuffer); + + if (d->mapMode == NotMapped && d->image.bits() && mode != NotMapped) { + d->mapMode = mode; + + if (numBytes) + *numBytes = d->image.byteCount(); + + if (bytesPerLine) + *bytesPerLine = d->image.bytesPerLine(); + + return d->image.bits(); + } else { + return 0; + } +} + +void QImageVideoBuffer::unmap() +{ + Q_D(QImageVideoBuffer); + + d->mapMode = NotMapped; +} + +QT_END_NAMESPACE diff --git a/src/multimediakit/video/qimagevideobuffer_p.h b/src/multimediakit/video/qimagevideobuffer_p.h new file mode 100644 index 000000000..993ec57b4 --- /dev/null +++ b/src/multimediakit/video/qimagevideobuffer_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QIMAGEVIDEOBUFFER_P_H +#define QIMAGEVIDEOBUFFER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QImage; + +class QImageVideoBufferPrivate; + +class Q_MULTIMEDIA_EXPORT QImageVideoBuffer : public QAbstractVideoBuffer +{ + Q_DECLARE_PRIVATE(QImageVideoBuffer) +public: + QImageVideoBuffer(const QImage &image); + ~QImageVideoBuffer(); + + MapMode mapMode() const; + + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine); + void unmap(); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/multimediakit/video/qmemoryvideobuffer.cpp b/src/multimediakit/video/qmemoryvideobuffer.cpp new file mode 100644 index 000000000..92d16a264 --- /dev/null +++ b/src/multimediakit/video/qmemoryvideobuffer.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmemoryvideobuffer_p.h" + +#include "qabstractvideobuffer_p.h" +#include + +QT_BEGIN_NAMESPACE + +class QMemoryVideoBufferPrivate : public QAbstractVideoBufferPrivate +{ +public: + QMemoryVideoBufferPrivate() + : bytesPerLine(0) + , mapMode(QAbstractVideoBuffer::NotMapped) + { + } + + int bytesPerLine; + QAbstractVideoBuffer::MapMode mapMode; + QByteArray data; +}; + +/*! + \class QMemoryVideoBuffer + \brief The QMemoryVideoBuffer class provides a system memory allocated video data buffer. + \internal + \since QtMobility 1.0 + + QMemoryVideoBuffer is the default video buffer for allocating system memory. It may be used to + allocate memory for a QVideoFrame without implementing your own QAbstractVideoBuffer. +*/ + +/*! + Constructs a video buffer with an image stride of \a bytesPerLine from a byte \a array. +*/ +QMemoryVideoBuffer::QMemoryVideoBuffer(const QByteArray &array, int bytesPerLine) + : QAbstractVideoBuffer(*new QMemoryVideoBufferPrivate, NoHandle) +{ + Q_D(QMemoryVideoBuffer); + + d->data = array; + d->bytesPerLine = bytesPerLine; +} + +/*! + Destroys a system memory allocated video buffer. +*/ +QMemoryVideoBuffer::~QMemoryVideoBuffer() +{ +} + +/*! + \reimp + \since 1.1 +*/ +QAbstractVideoBuffer::MapMode QMemoryVideoBuffer::mapMode() const +{ + return d_func()->mapMode; +} + +/*! + \reimp + \since 1.1 +*/ +uchar *QMemoryVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine) +{ + Q_D(QMemoryVideoBuffer); + + if (d->mapMode == NotMapped && d->data.data() && mode != NotMapped) { + d->mapMode = mode; + + if (numBytes) + *numBytes = d->data.size(); + + if (bytesPerLine) + *bytesPerLine = d->bytesPerLine; + + return reinterpret_cast(d->data.data()); + } else { + return 0; + } +} + +/*! + \reimp + \since 1.1 +*/ +void QMemoryVideoBuffer::unmap() +{ + d_func()->mapMode = NotMapped; +} + +QT_END_NAMESPACE diff --git a/src/multimediakit/video/qmemoryvideobuffer_p.h b/src/multimediakit/video/qmemoryvideobuffer_p.h new file mode 100644 index 000000000..1889df0e2 --- /dev/null +++ b/src/multimediakit/video/qmemoryvideobuffer_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEMORYVIDEOBUFFER_P_H +#define QMEMORYVIDEOBUFFER_P_H + +#include + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It 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_HEADER + +QT_BEGIN_NAMESPACE + +class QMemoryVideoBufferPrivate; + +class Q_MULTIMEDIA_EXPORT QMemoryVideoBuffer : public QAbstractVideoBuffer +{ + Q_DECLARE_PRIVATE(QMemoryVideoBuffer) +public: + QMemoryVideoBuffer(const QByteArray &data, int bytesPerLine); + ~QMemoryVideoBuffer(); + + MapMode mapMode() const; + + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine); + void unmap(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimediakit/video/qvideoframe.cpp b/src/multimediakit/video/qvideoframe.cpp new file mode 100644 index 000000000..f974e3294 --- /dev/null +++ b/src/multimediakit/video/qvideoframe.cpp @@ -0,0 +1,793 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideoframe.h" + +#include "qimagevideobuffer_p.h" +#include "qmemoryvideobuffer_p.h" + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace +{ +class QVideoFramePrivateRegisterMetaTypes +{ +public: + QVideoFramePrivateRegisterMetaTypes() + { + qRegisterMetaType("QVideoFrame::PixelFormat"); + } +} _registerMetaTypes; +} + + +class QVideoFramePrivate : public QSharedData +{ +public: + QVideoFramePrivate() + : startTime(-1) + , endTime(-1) + , data(0) + , mappedBytes(0) + , bytesPerLine(0) + , pixelFormat(QVideoFrame::Format_Invalid) + , fieldType(QVideoFrame::ProgressiveFrame) + , buffer(0) + { + } + + QVideoFramePrivate(const QSize &size, QVideoFrame::PixelFormat format) + : size(size) + , startTime(-1) + , endTime(-1) + , data(0) + , mappedBytes(0) + , bytesPerLine(0) + , pixelFormat(format) + , fieldType(QVideoFrame::ProgressiveFrame) + , buffer(0) + { + } + + ~QVideoFramePrivate() + { + delete buffer; + } + + QSize size; + qint64 startTime; + qint64 endTime; + uchar *data; + int mappedBytes; + int bytesPerLine; + QVideoFrame::PixelFormat pixelFormat; + QVideoFrame::FieldType fieldType; + QAbstractVideoBuffer *buffer; + +private: + Q_DISABLE_COPY(QVideoFramePrivate) +}; + +/*! + \class QVideoFrame + \brief The QVideoFrame class provides a representation of a frame of video data. + \since 1.0 + \inmodule QtMultimediaKit + + A QVideoFrame encapsulates the data of a video frame, and information about the frame. + + XXX why do I care + + The contents of a video frame can be mapped to memory using the map() function. While + mapped, the video data can accessed using the bits() function, which returns a pointer to a + buffer. The total size of this buffer is given by the mappedBytes() function, and the size of each line is given + by bytesPerLine(). The return value of the handle() function may be used to access frame data + using the internal buffer's native APIs. + + The video data in a QVideoFrame is encapsulated in a QAbstractVideoBuffer. A QVideoFrame + may be constructed from any buffer type by subclassing the QAbstractVideoBuffer class. + + \note QVideoFrame is explicitly shared, any change made to video frame will also apply to any + copies. + + XXX example +*/ + +/*! + \enum QVideoFrame::PixelFormat + + Enumerates video data types. + + \value Format_Invalid + The frame is invalid. + + \value Format_ARGB32 + The frame is stored using a 32-bit ARGB format (0xAARRGGBB). This is equivalent to + QImage::Format_ARGB32. + + \value Format_ARGB32_Premultiplied + The frame stored using a premultiplied 32-bit ARGB format (0xAARRGGBB). This is equivalent + to QImage::Format_ARGB32_Premultiplied. + + \value Format_RGB32 + The frame stored using a 32-bit RGB format (0xffRRGGBB). This is equivalent to + QImage::Format_RGB32 + + \value Format_RGB24 + The frame is stored using a 24-bit RGB format (8-8-8). This is equivalent to + QImage::Format_RGB888 + + \value Format_RGB565 + The frame is stored using a 16-bit RGB format (5-6-5). This is equivalent to + QImage::Format_RGB16. + + \value Format_RGB555 + The frame is stored using a 16-bit RGB format (5-5-5). This is equivalent to + QImage::Format_RGB555. + + \value Format_ARGB8565_Premultiplied + The frame is stored using a 24-bit premultiplied ARGB format (8-6-6-5). + + \value Format_BGRA32 + The frame is stored using a 32-bit ARGB format (0xBBGGRRAA). + + \value Format_BGRA32_Premultiplied + The frame is stored using a premultiplied 32bit BGRA format. + + \value Format_BGR32 + The frame is stored using a 32-bit BGR format (0xBBGGRRff). + + \value Format_BGR24 + The frame is stored using a 24-bit BGR format (0xBBGGRR). + + \value Format_BGR565 + The frame is stored using a 16-bit BGR format (5-6-5). + + \value Format_BGR555 + The frame is stored using a 16-bit BGR format (5-5-5). + + \value Format_BGRA5658_Premultiplied + The frame is stored using a 24-bit premultiplied BGRA format (5-6-5-8). + + \value Format_AYUV444 + The frame is stored using a packed 32-bit AYUV format (0xAAYYUUVV). + + \value Format_AYUV444_Premultiplied + The frame is stored using a packed premultiplied 32-bit AYUV format (0xAAYYUUVV). + + \value Format_YUV444 + The frame is stored using a 24-bit packed YUV format (8-8-8). + + \value Format_YUV420P + The frame is stored using an 8-bit per component planar YUV format with the U and V planes + horizontally and vertically sub-sampled, i.e. the height and width of the U and V planes are + half that of the Y plane. + + \value Format_YV12 + The frame is stored using an 8-bit per component planar YVU format with the V and U planes + horizontally and vertically sub-sampled, i.e. the height and width of the V and U planes are + half that of the Y plane. + + \value Format_UYVY + The frame is stored using an 8-bit per component packed YUV format with the U and V planes + horizontally sub-sampled (U-Y-V-Y), i.e. two horizontally adjacent pixels are stored as a 32-bit + macropixel which has a Y value for each pixel and common U and V values. + + \value Format_YUYV + The frame is stored using an 8-bit per component packed YUV format with the U and V planes + horizontally sub-sampled (Y-U-Y-V), i.e. two horizontally adjacent pixels are stored as a 32-bit + macropixel which has a Y value for each pixel and common U and V values. + + \value Format_NV12 + The frame is stored using an 8-bit per component semi-planar YUV format with a Y plane (Y) + followed by a horizontally and vertically sub-sampled, packed UV plane (U-V). + + \value Format_NV21 + The frame is stored using an 8-bit per component semi-planar YUV format with a Y plane (Y) + followed by a horizontally and vertically sub-sampled, packed VU plane (V-U). + + \value Format_IMC1 + The frame is stored using an 8-bit per component planar YUV format with the U and V planes + horizontally and vertically sub-sampled. This is similar to the Format_YUV420P type, except + that the bytes per line of the U and V planes are padded out to the same stride as the Y plane. + + \value Format_IMC2 + The frame is stored using an 8-bit per component planar YUV format with the U and V planes + horizontally and vertically sub-sampled. This is similar to the Format_YUV420P type, except + that the lines of the U and V planes are interleaved, i.e. each line of U data is followed by a + line of V data creating a single line of the same stride as the Y data. + + \value Format_IMC3 + The frame is stored using an 8-bit per component planar YVU format with the V and U planes + horizontally and vertically sub-sampled. This is similar to the Format_YV12 type, except that + the bytes per line of the V and U planes are padded out to the same stride as the Y plane. + + \value Format_IMC4 + The frame is stored using an 8-bit per component planar YVU format with the V and U planes + horizontally and vertically sub-sampled. This is similar to the Format_YV12 type, except that + the lines of the V and U planes are interleaved, i.e. each line of V data is followed by a line + of U data creating a single line of the same stride as the Y data. + + \value Format_Y8 + The frame is stored using an 8-bit greyscale format. + + \value Format_Y16 + The frame is stored using a 16-bit linear greyscale format. Little endian. + + \value Format_Jpeg + The frame is stored in compressed Jpeg format. + + \value Format_CameraRaw + The frame is stored using a device specific camera raw format. + + \value Format_AdobeDng + The frame is stored using raw Adobe Digital Negative (DNG) format. + + \value Format_User + Start value for user defined pixel formats. +*/ + +/*! + \enum QVideoFrame::FieldType + + Specifies the field an interlaced video frame belongs to. + + \value ProgressiveFrame The frame is not interlaced. + \value TopField The frame contains a top field. + \value BottomField The frame contains a bottom field. + \value InterlacedFrame The frame contains a merged top and bottom field. +*/ + +/*! + Constructs a null video frame. +*/ +QVideoFrame::QVideoFrame() + : d(new QVideoFramePrivate) +{ +} + +/*! + Constructs a video frame from a \a buffer with the given pixel \a format and \a size in pixels. + + \note This doesn't increment the reference count of the video buffer. + \since 1.0 +*/ +QVideoFrame::QVideoFrame( + QAbstractVideoBuffer *buffer, const QSize &size, PixelFormat format) + : d(new QVideoFramePrivate(size, format)) +{ + d->buffer = buffer; +} + +/*! + Constructs a video frame of the given pixel \a format and \a size in pixels. + + The \a bytesPerLine (stride) is the length of each scan line in bytes, and \a bytes is the total + number of bytes that must be allocated for the frame. + \since 1.0 +*/ +QVideoFrame::QVideoFrame(int bytes, const QSize &size, int bytesPerLine, PixelFormat format) + : d(new QVideoFramePrivate(size, format)) +{ + if (bytes > 0) { + QByteArray data; + data.resize(bytes); + + // Check the memory was successfully allocated. + if (!data.isEmpty()) + d->buffer = new QMemoryVideoBuffer(data, bytesPerLine); + } +} + +/*! + Constructs a video frame from an \a image. + + \note This will construct an invalid video frame if there is no frame type equivalent to the + image format. + + \since 1.0 + \sa pixelFormatFromImageFormat() +*/ +QVideoFrame::QVideoFrame(const QImage &image) + : d(new QVideoFramePrivate( + image.size(), pixelFormatFromImageFormat(image.format()))) +{ + if (d->pixelFormat != Format_Invalid) + d->buffer = new QImageVideoBuffer(image); +} + +/*! + Constructs a copy of \a other. + + XXX reference count + + \since 1.0 +*/ +QVideoFrame::QVideoFrame(const QVideoFrame &other) + : d(other.d) +{ +} + +/*! + Assigns the contents of \a other to a video frame. + \since 1.0 +*/ +QVideoFrame &QVideoFrame::operator =(const QVideoFrame &other) +{ + d = other.d; + + return *this; +} + +/*! + Destroys a video frame. + + XXX reference count +*/ +QVideoFrame::~QVideoFrame() +{ +} + +/*! + Identifies whether a video frame is valid. + + An invalid frame has no video buffer associated with it. + + Returns true if the frame is valid, and false if it is not. + \since 1.0 +*/ +bool QVideoFrame::isValid() const +{ + return d->buffer != 0; +} + +/*! + Returns the color format of a video frame. + \since 1.0 +*/ +QVideoFrame::PixelFormat QVideoFrame::pixelFormat() const +{ + return d->pixelFormat; +} + +/*! + Returns the type of a video frame's handle. + + XXX What about it? + + \since 1.0 +*/ +QAbstractVideoBuffer::HandleType QVideoFrame::handleType() const +{ + return d->buffer ? d->buffer->handleType() : QAbstractVideoBuffer::NoHandle; +} + +/*! + Returns the dimensions of a video frame. + \since 1.0 +*/ +QSize QVideoFrame::size() const +{ + return d->size; +} + +/*! + Returns the width of a video frame. + \since 1.0 +*/ +int QVideoFrame::width() const +{ + return d->size.width(); +} + +/*! + Returns the height of a video frame. + \since 1.0 +*/ +int QVideoFrame::height() const +{ + return d->size.height(); +} + +/*! + Returns the field an interlaced video frame belongs to. + + If the video is not interlaced this will return WholeFrame. + \since 1.0 +*/ +QVideoFrame::FieldType QVideoFrame::fieldType() const +{ + return d->fieldType; +} + +/*! + Sets the \a field an interlaced video frame belongs to. + \since 1.0 +*/ +void QVideoFrame::setFieldType(QVideoFrame::FieldType field) +{ + d->fieldType = field; +} + +/*! + Identifies if a video frame's contents are currently mapped to system memory. + + This is a convenience function which checks that the \l {QAbstractVideoBuffer::MapMode}{MapMode} + of the frame is not equal to QAbstractVideoBuffer::NotMapped. + + Returns true if the contents of the video frame are mapped to system memory, and false + otherwise. + + \since 1.0 + \sa mapMode(), QAbstractVideoBuffer::MapMode +*/ + +bool QVideoFrame::isMapped() const +{ + return d->buffer != 0 && d->buffer->mapMode() != QAbstractVideoBuffer::NotMapped; +} + +/*! + Identifies if the mapped contents of a video frame will be persisted when the frame is unmapped. + + This is a convenience function which checks if the \l {QAbstractVideoBuffer::MapMode}{MapMode} + contains the QAbstractVideoBuffer::WriteOnly flag. + + Returns true if the video frame will be updated when unmapped, and false otherwise. + + \note The result of altering the data of a frame that is mapped in read-only mode is undefined. + Depending on the buffer implementation the changes may be persisted, or worse alter a shared + buffer. + + \since 1.0 + \sa mapMode(), QAbstractVideoBuffer::MapMode +*/ +bool QVideoFrame::isWritable() const +{ + return d->buffer != 0 && (d->buffer->mapMode() & QAbstractVideoBuffer::WriteOnly); +} + +/*! + Identifies if the mapped contents of a video frame were read from the frame when it was mapped. + + This is a convenience function which checks if the \l {QAbstractVideoBuffer::MapMode}{MapMode} + contains the QAbstractVideoBuffer::WriteOnly flag. + + Returns true if the contents of the mapped memory were read from the video frame, and false + otherwise. + + \since 1.0 + \sa mapMode(), QAbstractVideoBuffer::MapMode +*/ +bool QVideoFrame::isReadable() const +{ + return d->buffer != 0 && (d->buffer->mapMode() & QAbstractVideoBuffer::ReadOnly); +} + +/*! + Returns the mode a video frame was mapped to system memory in. + + \since 1.0 + \sa map(), QAbstractVideoBuffer::MapMode +*/ +QAbstractVideoBuffer::MapMode QVideoFrame::mapMode() const +{ + return d->buffer != 0 ? d->buffer->mapMode() : QAbstractVideoBuffer::NotMapped; +} + +/*! + Maps the contents of a video frame to memory. + + The map \a mode indicates whether the contents of the mapped memory should be read from and/or + written to the frame. If the map mode includes the QAbstractVideoBuffer::ReadOnly flag the + mapped memory will be populated with the content of the video frame when mapped. If the map + mode inclues the QAbstractVideoBuffer::WriteOnly flag the content of the mapped memory will be + persisted in the frame when unmapped. + + While mapped the contents of a video frame can be accessed directly through the pointer returned + by the bits() function. + + When access to the data is no longer needed be sure to call the unmap() function to release the + mapped memory and possibly update the video frame contents. + + Returns true if the buffer was mapped to memory in the given \a mode and false otherwise. + + XXX examples and why do I care + + \since 1.0 + \sa unmap(), mapMode(), bits() +*/ +bool QVideoFrame::map(QAbstractVideoBuffer::MapMode mode) +{ + if (d->buffer != 0 && d->data == 0) { + Q_ASSERT(d->bytesPerLine == 0); + Q_ASSERT(d->mappedBytes == 0); + + d->data = d->buffer->map(mode, &d->mappedBytes, &d->bytesPerLine); + + return d->data != 0; + } + + return false; +} + +/*! + Releases the memory mapped by the map() function. + + If the \l {QAbstractVideoBuffer::MapMode}{MapMode} included the QAbstractVideoBuffer::WriteOnly + flag this will persist the current content of the mapped memory to the video frame. + + \since 1.0 + \sa map() +*/ +void QVideoFrame::unmap() +{ + if (d->data != 0) { + d->mappedBytes = 0; + d->bytesPerLine = 0; + d->data = 0; + + d->buffer->unmap(); + } +} + +/*! + Returns the number of bytes in a scan line. + + \note This is the bytes per line of the first plane only. The bytes per line of subsequent + planes should be calculated as per the frame type. + + XXX examples of these calculations + + This value is only valid while the frame data is \l {map()}{mapped}. + + \since 1.0 + \sa bits(), map(), mappedBytes() +*/ +int QVideoFrame::bytesPerLine() const +{ + return d->bytesPerLine; +} + +/*! + Returns a pointer to the start of the frame data buffer. + + This value is only valid while the frame data is \l {map()}{mapped}. + + Changes made to data accessed via this pointer (when mapped with write access) + are only guaranteed to have been persisted when unmap() is called. + + \since 1.0 + \sa map(), mappedBytes(), bytesPerLine() +*/ +uchar *QVideoFrame::bits() +{ + return d->data; +} + +/*! + Returns a pointer to the start of the frame data buffer. + + This value is only valid while the frame data is \l {map()}{mapped}. + + If the buffer was not mapped with read access, the contents of this + buffer will initially be uninitialized. + + \since 1.0 + \sa map(), mappedBytes(), bytesPerLine() +*/ +const uchar *QVideoFrame::bits() const +{ + return d->data; +} + +/*! + Returns the number of bytes occupied by the mapped frame data. + + This value is only valid while the frame data is \l {map()}{mapped}. + + \since 1.0 + \sa map() +*/ +int QVideoFrame::mappedBytes() const +{ + return d->mappedBytes; +} + +/*! + Returns a type specific handle to a video frame's buffer. + + For an OpenGL texture this would be the texture ID. + + XXX Perhaps a table with corresondence + + \since 1.0 + \sa QAbstractVideoBuffer::handle() +*/ +QVariant QVideoFrame::handle() const +{ + return d->buffer != 0 ? d->buffer->handle() : QVariant(); +} + +/*! + Returns the presentation time when the frame should be displayed. + \since 1.0 +*/ +qint64 QVideoFrame::startTime() const +{ + return d->startTime; +} + +/*! + Sets the presentation \a time when the frame should be displayed. + \since 1.0 +*/ +void QVideoFrame::setStartTime(qint64 time) +{ + d->startTime = time; +} + +/*! + Returns the presentation time when a frame should stop being displayed. + + XXX example? if start=end what happens? + \since 1.0 +*/ +qint64 QVideoFrame::endTime() const +{ + return d->endTime; +} + +/*! + Sets the presentation \a time when a frame should stop being displayed. + \since 1.0 +*/ +void QVideoFrame::setEndTime(qint64 time) +{ + d->endTime = time; +} + +/*! + Returns a video pixel format equivalent to an image \a format. If there is no equivalent + format QVideoFrame::InvalidType is returned instead. + \since 1.0 +*/ +QVideoFrame::PixelFormat QVideoFrame::pixelFormatFromImageFormat(QImage::Format format) +{ + switch (format) { + case QImage::Format_Invalid: + case QImage::Format_Mono: + case QImage::Format_MonoLSB: + case QImage::Format_Indexed8: + return Format_Invalid; + case QImage::Format_RGB32: + return Format_RGB32; + case QImage::Format_ARGB32: + return Format_ARGB32; + case QImage::Format_ARGB32_Premultiplied: + return Format_ARGB32_Premultiplied; + case QImage::Format_RGB16: + return Format_RGB565; + case QImage::Format_ARGB8565_Premultiplied: + return Format_ARGB8565_Premultiplied; + case QImage::Format_RGB666: + case QImage::Format_ARGB6666_Premultiplied: + return Format_Invalid; + case QImage::Format_RGB555: + return Format_RGB555; + case QImage::Format_ARGB8555_Premultiplied: + return Format_Invalid; + case QImage::Format_RGB888: + return Format_RGB24; + case QImage::Format_RGB444: + case QImage::Format_ARGB4444_Premultiplied: + return Format_Invalid; + case QImage::NImageFormats: + return Format_Invalid; + } + return Format_Invalid; +} + +/*! + Returns an image format equivalent to a video frame pixel \a format. If there is no equivalent + format QImage::Format_Invalid is returned instead. + \since 1.0 +*/ +QImage::Format QVideoFrame::imageFormatFromPixelFormat(PixelFormat format) +{ + switch (format) { + case Format_Invalid: + return QImage::Format_Invalid; + case Format_ARGB32: + return QImage::Format_ARGB32; + case Format_ARGB32_Premultiplied: + return QImage::Format_ARGB32_Premultiplied; + case Format_RGB32: + return QImage::Format_RGB32; + case Format_RGB24: + return QImage::Format_RGB888; + case Format_RGB565: + return QImage::Format_RGB16; + case Format_RGB555: + return QImage::Format_RGB555; + case Format_ARGB8565_Premultiplied: + return QImage::Format_ARGB8565_Premultiplied; + case Format_BGRA32: + case Format_BGRA32_Premultiplied: + case Format_BGR32: + case Format_BGR24: + return QImage::Format_Invalid; + case Format_BGR565: + case Format_BGR555: + case Format_BGRA5658_Premultiplied: + case Format_AYUV444: + case Format_AYUV444_Premultiplied: + case Format_YUV444: + case Format_YUV420P: + case Format_YV12: + case Format_UYVY: + case Format_YUYV: + case Format_NV12: + case Format_NV21: + case Format_IMC1: + case Format_IMC2: + case Format_IMC3: + case Format_IMC4: + case Format_Y8: + case Format_Y16: + case Format_Jpeg: + case Format_CameraRaw: + case Format_AdobeDng: + return QImage::Format_Invalid; + case Format_User: + return QImage::Format_Invalid; + } + return QImage::Format_Invalid; +} + +QT_END_NAMESPACE + diff --git a/src/multimediakit/video/qvideoframe.h b/src/multimediakit/video/qvideoframe.h new file mode 100644 index 000000000..8d90dbb96 --- /dev/null +++ b/src/multimediakit/video/qvideoframe.h @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOFRAME_H +#define QVIDEOFRAME_H + +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QSize; +class QVariant; + +class QVideoFramePrivate; + +class Q_MULTIMEDIA_EXPORT QVideoFrame +{ +public: + enum FieldType + { + ProgressiveFrame, + TopField, + BottomField, + InterlacedFrame + }; + + enum PixelFormat + { + Format_Invalid, + Format_ARGB32, + Format_ARGB32_Premultiplied, + Format_RGB32, + Format_RGB24, + Format_RGB565, + Format_RGB555, + Format_ARGB8565_Premultiplied, + Format_BGRA32, + Format_BGRA32_Premultiplied, + Format_BGR32, + Format_BGR24, + Format_BGR565, + Format_BGR555, + Format_BGRA5658_Premultiplied, + + Format_AYUV444, + Format_AYUV444_Premultiplied, + Format_YUV444, + Format_YUV420P, + Format_YV12, + Format_UYVY, + Format_YUYV, + Format_NV12, + Format_NV21, + Format_IMC1, + Format_IMC2, + Format_IMC3, + Format_IMC4, + Format_Y8, + Format_Y16, + + Format_Jpeg, + + Format_CameraRaw, + Format_AdobeDng, + + Format_User = 1000 + }; + + QVideoFrame(); + QVideoFrame(QAbstractVideoBuffer *buffer, const QSize &size, PixelFormat format); + QVideoFrame(int bytes, const QSize &size, int bytesPerLine, PixelFormat format); + QVideoFrame(const QImage &image); + QVideoFrame(const QVideoFrame &other); + ~QVideoFrame(); + + QVideoFrame &operator =(const QVideoFrame &other); + + bool isValid() const; + + PixelFormat pixelFormat() const; + + QAbstractVideoBuffer::HandleType handleType() const; + + QSize size() const; + int width() const; + int height() const; + + FieldType fieldType() const; + void setFieldType(FieldType); + + bool isMapped() const; + bool isReadable() const; + bool isWritable() const; + + QAbstractVideoBuffer::MapMode mapMode() const; + + bool map(QAbstractVideoBuffer::MapMode mode); + void unmap(); + + int bytesPerLine() const; + + uchar *bits(); + const uchar *bits() const; + int mappedBytes() const; + + QVariant handle() const; + + qint64 startTime() const; + void setStartTime(qint64 time); + + qint64 endTime() const; + void setEndTime(qint64 time); + + static PixelFormat pixelFormatFromImageFormat(QImage::Format format); + static QImage::Format imageFormatFromPixelFormat(PixelFormat format); + +private: + QExplicitlySharedDataPointer d; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QVideoFrame::FieldType) +Q_DECLARE_METATYPE(QVideoFrame::PixelFormat) + +QT_END_HEADER + +#endif + diff --git a/src/multimediakit/video/qvideosurfaceformat.cpp b/src/multimediakit/video/qvideosurfaceformat.cpp new file mode 100644 index 000000000..58b2baa44 --- /dev/null +++ b/src/multimediakit/video/qvideosurfaceformat.cpp @@ -0,0 +1,709 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideosurfaceformat.h" + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QVideoSurfaceFormatPrivate : public QSharedData +{ +public: + QVideoSurfaceFormatPrivate() + : pixelFormat(QVideoFrame::Format_Invalid) + , handleType(QAbstractVideoBuffer::NoHandle) + , scanLineDirection(QVideoSurfaceFormat::TopToBottom) + , pixelAspectRatio(1, 1) + , ycbcrColorSpace(QVideoSurfaceFormat::YCbCr_Undefined) + , frameRate(0.0) + { + } + + QVideoSurfaceFormatPrivate( + const QSize &size, + QVideoFrame::PixelFormat format, + QAbstractVideoBuffer::HandleType type) + : pixelFormat(format) + , handleType(type) + , scanLineDirection(QVideoSurfaceFormat::TopToBottom) + , frameSize(size) + , pixelAspectRatio(1, 1) + , ycbcrColorSpace(QVideoSurfaceFormat::YCbCr_Undefined) + , viewport(QPoint(0, 0), size) + , frameRate(0.0) + { + } + + QVideoSurfaceFormatPrivate(const QVideoSurfaceFormatPrivate &other) + : QSharedData(other) + , pixelFormat(other.pixelFormat) + , handleType(other.handleType) + , scanLineDirection(other.scanLineDirection) + , frameSize(other.frameSize) + , pixelAspectRatio(other.pixelAspectRatio) + , ycbcrColorSpace(other.ycbcrColorSpace) + , viewport(other.viewport) + , frameRate(other.frameRate) + , propertyNames(other.propertyNames) + , propertyValues(other.propertyValues) + { + } + + bool operator ==(const QVideoSurfaceFormatPrivate &other) const + { + if (pixelFormat == other.pixelFormat + && handleType == other.handleType + && scanLineDirection == other.scanLineDirection + && frameSize == other.frameSize + && pixelAspectRatio == other.pixelAspectRatio + && viewport == other.viewport + && frameRatesEqual(frameRate, other.frameRate) + && ycbcrColorSpace == other.ycbcrColorSpace + && propertyNames.count() == other.propertyNames.count()) { + for (int i = 0; i < propertyNames.count(); ++i) { + int j = other.propertyNames.indexOf(propertyNames.at(i)); + + if (j == -1 || propertyValues.at(i) != other.propertyValues.at(j)) + return false; + } + return true; + } else { + return false; + } + } + + inline static bool frameRatesEqual(qreal r1, qreal r2) + { + return qAbs(r1 - r2) <= 0.00001 * qMin(qAbs(r1), qAbs(r2)); + } + + QVideoFrame::PixelFormat pixelFormat; + QAbstractVideoBuffer::HandleType handleType; + QVideoSurfaceFormat::Direction scanLineDirection; + QSize frameSize; + QSize pixelAspectRatio; + QVideoSurfaceFormat::YCbCrColorSpace ycbcrColorSpace; + QRect viewport; + qreal frameRate; + QList propertyNames; + QList propertyValues; +}; + +/*! + \class QVideoSurfaceFormat + \brief The QVideoSurfaceFormat class specifies the stream format of a video presentation + surface. + \since 1.0 + \inmodule QtMultimediaKit + + A video surface presents a stream of video frames. The surface's format describes the type of + the frames and determines how they should be presented. + + XXX Why do I care + XXX why isn't it videostreamformat then? + + The core properties of a video stream required to setup a video surface are the pixel format + given by pixelFormat(), and the frame dimensions given by frameSize(). + + If the surface is to present frames using a frame's handle a surface format will also include + a handle type which is given by the handleType() function. + + The region of a frame that is actually displayed on a video surface is given by the viewport(). + A stream may have a viewport less than the entire region of a frame to allow for videos smaller + than the nearest optimal size of a video frame. For example the width of a frame may be + extended so that the start of each scan line is eight byte aligned. + + Other common properties are the pixelAspectRatio(), scanLineDirection(), and frameRate(). + Additionally a stream may have some additional type specific properties which are listed by the + dynamicPropertyNames() function and can be accessed using the property(), and setProperty() + functions. +*/ + +/*! + \enum QVideoSurfaceFormat::Direction + + Enumerates the layout direction of video scan lines. + + \value TopToBottom Scan lines are arranged from the top of the frame to the bottom. + \value BottomToTop Scan lines are arranged from the bottom of the frame to the top. +*/ + +/*! + \enum QVideoSurfaceFormat::YCbCrColorSpace + + Enumerates the Y'CbCr color space of video frames. + + \value YCbCr_Undefined + No color space is specified. + + \value YCbCr_BT601 + A Y'CbCr color space defined by ITU-R recommendation BT.601 + with Y value range from 16 to 235, and Cb/Cr range from 16 to 240. + Used in standard definition video. + + \value YCbCr_BT709 + A Y'CbCr color space defined by ITU-R BT.709 with the same values range as YCbCr_BT601. Used + for HDTV. + + \value YCbCr_xvYCC601 + The BT.601 color space with the value range extended to 0 to 255. + It is backward compatibile with BT.601 and uses values outside BT.601 range to represent a + wider range of colors. + + \value YCbCr_xvYCC709 + The BT.709 color space with the value range extended to 0 to 255. + + \value YCbCr_JPEG + The full range Y'CbCr color space used in JPEG files. +*/ + +/*! + Constructs a null video stream format. +*/ +QVideoSurfaceFormat::QVideoSurfaceFormat() + : d(new QVideoSurfaceFormatPrivate) +{ +} + +/*! + Contructs a description of stream which receives stream of \a type buffers with given frame + \a size and pixel \a format. + \since 1.0 +*/ +QVideoSurfaceFormat::QVideoSurfaceFormat( + const QSize& size, QVideoFrame::PixelFormat format, QAbstractVideoBuffer::HandleType type) + : d(new QVideoSurfaceFormatPrivate(size, format, type)) +{ +} + +/*! + Constructs a copy of \a other. + \since 1.0 +*/ +QVideoSurfaceFormat::QVideoSurfaceFormat(const QVideoSurfaceFormat &other) + : d(other.d) +{ +} + +/*! + Assigns the values of \a other to this object. + \since 1.0 +*/ +QVideoSurfaceFormat &QVideoSurfaceFormat::operator =(const QVideoSurfaceFormat &other) +{ + d = other.d; + + return *this; +} + +/*! + Destroys a video stream description. +*/ +QVideoSurfaceFormat::~QVideoSurfaceFormat() +{ +} + +/*! + Identifies if a video surface format has a valid pixel format and frame size. + + Returns true if the format is valid, and false otherwise. + \since 1.0 +*/ +bool QVideoSurfaceFormat::isValid() const +{ + return d->pixelFormat != QVideoFrame::Format_Invalid && d->frameSize.isValid(); +} + +/*! + Returns true if \a other is the same as this video format, and false if they are different. + \since 1.0 +*/ +bool QVideoSurfaceFormat::operator ==(const QVideoSurfaceFormat &other) const +{ + return d == other.d || *d == *other.d; +} + +/*! + Returns true if \a other is different to a video format, and false if they are the same. + \since 1.0 +*/ +bool QVideoSurfaceFormat::operator !=(const QVideoSurfaceFormat &other) const +{ + return d != other.d && !(*d == *other.d); +} + +/*! + Returns the pixel format of frames in a video stream. + \since 1.0 +*/ +QVideoFrame::PixelFormat QVideoSurfaceFormat::pixelFormat() const +{ + return d->pixelFormat; +} + +/*! + Returns the type of handle the surface uses to present the frame data. + + If the handle type is QAbstractVideoBuffer::NoHandle buffers with any handle type are valid + provided they can be \l {QAbstractVideoBuffer::map()}{mapped} with the + QAbstractVideoBuffer::ReadOnly flag. If the handleType() is not QAbstractVideoBuffer::NoHandle + then the handle type of the buffer must be the same as that of the surface format. + \since 1.0 +*/ +QAbstractVideoBuffer::HandleType QVideoSurfaceFormat::handleType() const +{ + return d->handleType; +} + +/*! + Returns the dimensions of frames in a video stream. + + \sa frameWidth(), frameHeight() + \since 1.0 +*/ +QSize QVideoSurfaceFormat::frameSize() const +{ + return d->frameSize; +} + +/*! + Returns the width of frames in a video stream. + + \sa frameSize(), frameHeight() + \since 1.0 +*/ +int QVideoSurfaceFormat::frameWidth() const +{ + return d->frameSize.width(); +} + +/*! + Returns the height of frame in a video stream. + \since 1.0 +*/ +int QVideoSurfaceFormat::frameHeight() const +{ + return d->frameSize.height(); +} + +/*! + Sets the size of frames in a video stream to \a size. + + This will reset the viewport() to fill the entire frame. + \since 1.0 +*/ +void QVideoSurfaceFormat::setFrameSize(const QSize &size) +{ + d->frameSize = size; + d->viewport = QRect(QPoint(0, 0), size); +} + +/*! + \overload + + Sets the \a width and \a height of frames in a video stream. + + This will reset the viewport() to fill the entire frame. + \since 1.0 +*/ +void QVideoSurfaceFormat::setFrameSize(int width, int height) +{ + d->frameSize = QSize(width, height); + d->viewport = QRect(0, 0, width, height); +} + +/*! + Returns the viewport of a video stream. + + The viewport is the region of a video frame that is actually displayed. + + By default the viewport covers an entire frame. + \since 1.0 +*/ +QRect QVideoSurfaceFormat::viewport() const +{ + return d->viewport; +} + +/*! + Sets the viewport of a video stream to \a viewport. + \since 1.0 +*/ +void QVideoSurfaceFormat::setViewport(const QRect &viewport) +{ + d->viewport = viewport; +} + +/*! + Returns the direction of scan lines. + \since 1.0 +*/ +QVideoSurfaceFormat::Direction QVideoSurfaceFormat::scanLineDirection() const +{ + return d->scanLineDirection; +} + +/*! + Sets the \a direction of scan lines. + \since 1.0 +*/ +void QVideoSurfaceFormat::setScanLineDirection(Direction direction) +{ + d->scanLineDirection = direction; +} + +/*! + Returns the frame rate of a video stream in frames per second. + \since 1.0 +*/ +qreal QVideoSurfaceFormat::frameRate() const +{ + return d->frameRate; +} + +/*! + Sets the frame \a rate of a video stream in frames per second. + \since 1.0 +*/ +void QVideoSurfaceFormat::setFrameRate(qreal rate) +{ + d->frameRate = rate; +} + +/*! + Returns a video stream's pixel aspect ratio. + \since 1.0 +*/ +QSize QVideoSurfaceFormat::pixelAspectRatio() const +{ + return d->pixelAspectRatio; +} + +/*! + Sets a video stream's pixel aspect \a ratio. + \since 1.0 +*/ +void QVideoSurfaceFormat::setPixelAspectRatio(const QSize &ratio) +{ + d->pixelAspectRatio = ratio; +} + +/*! + \overload + + Sets the \a horizontal and \a vertical elements of a video stream's pixel aspect ratio. + \since 1.0 +*/ +void QVideoSurfaceFormat::setPixelAspectRatio(int horizontal, int vertical) +{ + d->pixelAspectRatio = QSize(horizontal, vertical); +} + +/*! + Returns the Y'CbCr color space of a video stream. + \since 1.0 +*/ +QVideoSurfaceFormat::YCbCrColorSpace QVideoSurfaceFormat::yCbCrColorSpace() const +{ + return d->ycbcrColorSpace; +} + +/*! + Sets the Y'CbCr color \a space of a video stream. + It is only used with raw YUV frame types. + \since 1.0 +*/ +void QVideoSurfaceFormat::setYCbCrColorSpace(QVideoSurfaceFormat::YCbCrColorSpace space) +{ + d->ycbcrColorSpace = space; +} + +/*! + Returns a suggested size in pixels for the video stream. + + This is the size of the viewport scaled according to the pixel aspect ratio. + \since 1.0 +*/ +QSize QVideoSurfaceFormat::sizeHint() const +{ + QSize size = d->viewport.size(); + + if (d->pixelAspectRatio.height() != 0) + size.setWidth(size.width() * d->pixelAspectRatio.width() / d->pixelAspectRatio.height()); + + return size; +} + +/*! + Returns a list of video format dynamic property names. + \since 1.0 +*/ +QList QVideoSurfaceFormat::propertyNames() const +{ + return (QList() + << "handleType" + << "pixelFormat" + << "frameSize" + << "frameWidth" + << "viewport" + << "scanLineDirection" + << "frameRate" + << "pixelAspectRatio" + << "sizeHint" + << "yCbCrColorSpace") + + d->propertyNames; +} + +/*! + Returns the value of the video format's \a name property. + \since 1.0 +*/ +QVariant QVideoSurfaceFormat::property(const char *name) const +{ + if (qstrcmp(name, "handleType") == 0) { + return qVariantFromValue(d->handleType); + } else if (qstrcmp(name, "pixelFormat") == 0) { + return qVariantFromValue(d->pixelFormat); + } else if (qstrcmp(name, "handleType") == 0) { + return qVariantFromValue(d->handleType); + } else if (qstrcmp(name, "frameSize") == 0) { + return d->frameSize; + } else if (qstrcmp(name, "frameWidth") == 0) { + return d->frameSize.width(); + } else if (qstrcmp(name, "frameHeight") == 0) { + return d->frameSize.height(); + } else if (qstrcmp(name, "viewport") == 0) { + return d->viewport; + } else if (qstrcmp(name, "scanLineDirection") == 0) { + return qVariantFromValue(d->scanLineDirection); + } else if (qstrcmp(name, "frameRate") == 0) { + return qVariantFromValue(d->frameRate); + } else if (qstrcmp(name, "pixelAspectRatio") == 0) { + return qVariantFromValue(d->pixelAspectRatio); + } else if (qstrcmp(name, "sizeHint") == 0) { + return sizeHint(); + } else if (qstrcmp(name, "yCbCrColorSpace") == 0) { + return qVariantFromValue(d->ycbcrColorSpace); + } else { + int id = 0; + for (; id < d->propertyNames.count() && d->propertyNames.at(id) != name; ++id) {} + + return id < d->propertyValues.count() + ? d->propertyValues.at(id) + : QVariant(); + } +} + +/*! + Sets the video format's \a name property to \a value. + + Trying to set a read only property will be ignored. + + \since 1.0 +*/ +void QVideoSurfaceFormat::setProperty(const char *name, const QVariant &value) +{ + if (qstrcmp(name, "handleType") == 0) { + // read only. + } else if (qstrcmp(name, "pixelFormat") == 0) { + // read only. + } else if (qstrcmp(name, "frameSize") == 0) { + if (qVariantCanConvert(value)) { + d->frameSize = qvariant_cast(value); + d->viewport = QRect(QPoint(0, 0), d->frameSize); + } + } else if (qstrcmp(name, "frameWidth") == 0) { + // read only. + } else if (qstrcmp(name, "frameHeight") == 0) { + // read only. + } else if (qstrcmp(name, "viewport") == 0) { + if (qVariantCanConvert(value)) + d->viewport = qvariant_cast(value); + } else if (qstrcmp(name, "scanLineDirection") == 0) { + if (qVariantCanConvert(value)) + d->scanLineDirection = qvariant_cast(value); + } else if (qstrcmp(name, "frameRate") == 0) { + if (qVariantCanConvert(value)) + d->frameRate = qvariant_cast(value); + } else if (qstrcmp(name, "pixelAspectRatio") == 0) { + if (qVariantCanConvert(value)) + d->pixelAspectRatio = qvariant_cast(value); + } else if (qstrcmp(name, "sizeHint") == 0) { + // read only. + } else if (qstrcmp(name, "yCbCrColorSpace") == 0) { + if (qVariantCanConvert(value)) + d->ycbcrColorSpace = qvariant_cast(value); + } else { + int id = 0; + for (; id < d->propertyNames.count() && d->propertyNames.at(id) != name; ++id) {} + + if (id < d->propertyValues.count()) { + if (value.isNull()) { + d->propertyNames.removeAt(id); + d->propertyValues.removeAt(id); + } else { + d->propertyValues[id] = value; + } + } else if (!value.isNull()) { + d->propertyNames.append(QByteArray(name)); + d->propertyValues.append(value); + } + } +} + + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const QVideoSurfaceFormat &f) +{ + QString typeName; + switch (f.pixelFormat()) { + case QVideoFrame::Format_Invalid: + typeName = QLatin1String("Format_Invalid"); + break; + case QVideoFrame::Format_ARGB32: + typeName = QLatin1String("Format_ARGB32"); + break; + case QVideoFrame::Format_ARGB32_Premultiplied: + typeName = QLatin1String("Format_ARGB32_Premultiplied"); + break; + case QVideoFrame::Format_RGB32: + typeName = QLatin1String("Format_RGB32"); + break; + case QVideoFrame::Format_RGB24: + typeName = QLatin1String("Format_RGB24"); + break; + case QVideoFrame::Format_RGB565: + typeName = QLatin1String("Format_RGB565"); + break; + case QVideoFrame::Format_RGB555: + typeName = QLatin1String("Format_RGB555"); + break; + case QVideoFrame::Format_ARGB8565_Premultiplied: + typeName = QLatin1String("Format_ARGB8565_Premultiplied"); + break; + case QVideoFrame::Format_BGRA32: + typeName = QLatin1String("Format_BGRA32"); + break; + case QVideoFrame::Format_BGRA32_Premultiplied: + typeName = QLatin1String("Format_BGRA32_Premultiplied"); + break; + case QVideoFrame::Format_BGR32: + typeName = QLatin1String("Format_BGR32"); + break; + case QVideoFrame::Format_BGR24: + typeName = QLatin1String("Format_BGR24"); + break; + case QVideoFrame::Format_BGR565: + typeName = QLatin1String("Format_BGR565"); + break; + case QVideoFrame::Format_BGR555: + typeName = QLatin1String("Format_BGR555"); + break; + case QVideoFrame::Format_BGRA5658_Premultiplied: + typeName = QLatin1String("Format_BGRA5658_Premultiplied"); + break; + case QVideoFrame::Format_AYUV444: + typeName = QLatin1String("Format_AYUV444"); + break; + case QVideoFrame::Format_AYUV444_Premultiplied: + typeName = QLatin1String("Format_AYUV444_Premultiplied"); + break; + case QVideoFrame::Format_YUV444: + typeName = QLatin1String("Format_YUV444"); + break; + case QVideoFrame::Format_YUV420P: + typeName = QLatin1String("Format_YUV420P"); + break; + case QVideoFrame::Format_YV12: + typeName = QLatin1String("Format_YV12"); + break; + case QVideoFrame::Format_UYVY: + typeName = QLatin1String("Format_UYVY"); + break; + case QVideoFrame::Format_YUYV: + typeName = QLatin1String("Format_YUYV"); + break; + case QVideoFrame::Format_NV12: + typeName = QLatin1String("Format_NV12"); + break; + case QVideoFrame::Format_NV21: + typeName = QLatin1String("Format_NV21"); + break; + case QVideoFrame::Format_IMC1: + typeName = QLatin1String("Format_IMC1"); + break; + case QVideoFrame::Format_IMC2: + typeName = QLatin1String("Format_IMC2"); + break; + case QVideoFrame::Format_IMC3: + typeName = QLatin1String("Format_IMC3"); + break; + case QVideoFrame::Format_IMC4: + typeName = QLatin1String("Format_IMC4"); + break; + case QVideoFrame::Format_Y8: + typeName = QLatin1String("Format_Y8"); + break; + case QVideoFrame::Format_Y16: + typeName = QLatin1String("Format_Y16"); + default: + typeName = QString(QLatin1String("UserType(%1)" )).arg(int(f.pixelFormat())); + } + + dbg.nospace() << "QVideoSurfaceFormat(" << typeName; + dbg.nospace() << ", " << f.frameSize(); + dbg.nospace() << ", viewport=" << f.viewport(); + dbg.nospace() << ", pixelAspectRatio=" << f.pixelAspectRatio(); + dbg.nospace() << ")"; + + foreach(const QByteArray& propertyName, f.propertyNames()) + dbg << "\n " << propertyName.data() << " = " << f.property(propertyName.data()); + + return dbg.space(); +} +#endif + +QT_END_NAMESPACE diff --git a/src/multimediakit/video/qvideosurfaceformat.h b/src/multimediakit/video/qvideosurfaceformat.h new file mode 100644 index 000000000..7baf18fd8 --- /dev/null +++ b/src/multimediakit/video/qvideosurfaceformat.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOSURFACEFORMAT_H +#define QVIDEOSURFACEFORMAT_H + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QDebug; + +class QVideoSurfaceFormatPrivate; + +class Q_MULTIMEDIA_EXPORT QVideoSurfaceFormat +{ +public: + enum Direction + { + TopToBottom, + BottomToTop + }; + + enum YCbCrColorSpace + { + YCbCr_Undefined, + YCbCr_BT601, + YCbCr_BT709, + YCbCr_xvYCC601, + YCbCr_xvYCC709, + YCbCr_JPEG, +#ifndef qdoc + YCbCr_CustomMatrix +#endif + }; + + QVideoSurfaceFormat(); + QVideoSurfaceFormat( + const QSize &size, + QVideoFrame::PixelFormat pixelFormat, + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle); + QVideoSurfaceFormat(const QVideoSurfaceFormat &format); + ~QVideoSurfaceFormat(); + + QVideoSurfaceFormat &operator =(const QVideoSurfaceFormat &format); + + bool operator ==(const QVideoSurfaceFormat &format) const; + bool operator !=(const QVideoSurfaceFormat &format) const; + + bool isValid() const; + + QVideoFrame::PixelFormat pixelFormat() const; + QAbstractVideoBuffer::HandleType handleType() const; + + QSize frameSize() const; + void setFrameSize(const QSize &size); + void setFrameSize(int width, int height); + + int frameWidth() const; + int frameHeight() const; + + QRect viewport() const; + void setViewport(const QRect &viewport); + + Direction scanLineDirection() const; + void setScanLineDirection(Direction direction); + + qreal frameRate() const; + void setFrameRate(qreal rate); + + QSize pixelAspectRatio() const; + void setPixelAspectRatio(const QSize &ratio); + void setPixelAspectRatio(int width, int height); + + YCbCrColorSpace yCbCrColorSpace() const; + void setYCbCrColorSpace(YCbCrColorSpace colorSpace); + + QSize sizeHint() const; + + QList propertyNames() const; + QVariant property(const char *name) const; + void setProperty(const char *name, const QVariant &value); + +private: + QSharedDataPointer d; +}; + +#ifndef QT_NO_DEBUG_STREAM +Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, const QVideoSurfaceFormat &); +#endif + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QVideoSurfaceFormat::Direction) +Q_DECLARE_METATYPE(QVideoSurfaceFormat::YCbCrColorSpace) + +QT_END_HEADER + +#endif + diff --git a/src/multimediakit/video/video.pri b/src/multimediakit/video/video.pri new file mode 100644 index 000000000..accaa3371 --- /dev/null +++ b/src/multimediakit/video/video.pri @@ -0,0 +1,22 @@ + +INCLUDEPATH += video + +PUBLIC_HEADERS += \ + video/qabstractvideobuffer.h \ + video/qabstractvideosurface.h \ + video/qvideoframe.h \ + video/qvideosurfaceformat.h + +PRIVATE_HEADERS += \ + video/qabstractvideobuffer_p.h \ + video/qimagevideobuffer_p.h \ + video/qmemoryvideobuffer_p.h + +SOURCES += \ + video/qabstractvideobuffer.cpp \ + video/qabstractvideosurface.cpp \ + video/qimagevideobuffer.cpp \ + video/qmemoryvideobuffer.cpp \ + video/qvideoframe.cpp \ + video/qvideosurfaceformat.cpp + diff --git a/src/plugins/audiocapture/audiocapture.pro b/src/plugins/audiocapture/audiocapture.pro new file mode 100644 index 000000000..ceb554067 --- /dev/null +++ b/src/plugins/audiocapture/audiocapture.pro @@ -0,0 +1,25 @@ +load(qt_module) + +TARGET = qtmedia_audioengine +QT += multimediakit-private +PLUGIN_TYPE=mediaservice + +load(qt_plugin) +DESTDIR = $$QT.multimediakit.plugins/$${PLUGIN_TYPE} + +# Input +HEADERS += audioencodercontrol.h \ + audiocontainercontrol.h \ + audiomediarecordercontrol.h \ + audioendpointselector.h \ + audiocaptureservice.h \ + audiocaptureserviceplugin.h \ + audiocapturesession.h + +SOURCES += audioencodercontrol.cpp \ + audiocontainercontrol.cpp \ + audiomediarecordercontrol.cpp \ + audioendpointselector.cpp \ + audiocaptureservice.cpp \ + audiocaptureserviceplugin.cpp \ + audiocapturesession.cpp diff --git a/src/plugins/audiocapture/audiocaptureservice.cpp b/src/plugins/audiocapture/audiocaptureservice.cpp new file mode 100644 index 000000000..2859eb557 --- /dev/null +++ b/src/plugins/audiocapture/audiocaptureservice.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "audiocaptureservice.h" +#include "audiocapturesession.h" +#include "audioendpointselector.h" +#include "audioencodercontrol.h" +#include "audiocontainercontrol.h" +#include "audiomediarecordercontrol.h" + +AudioCaptureService::AudioCaptureService(QObject *parent): + QMediaService(parent) +{ + m_session = new AudioCaptureSession(this); + m_encoderControl = new AudioEncoderControl(m_session); + m_containerControl = new AudioContainerControl(m_session); + m_mediaControl = new AudioMediaRecorderControl(m_session); + m_endpointSelector = new AudioEndpointSelector(m_session); +} + +AudioCaptureService::~AudioCaptureService() +{ + delete m_encoderControl; + delete m_containerControl; + delete m_endpointSelector; + delete m_mediaControl; + delete m_session; +} + +QMediaControl *AudioCaptureService::requestControl(const char *name) +{ + if (qstrcmp(name,QMediaRecorderControl_iid) == 0) + return m_mediaControl; + + if (qstrcmp(name,QAudioEncoderControl_iid) == 0) + return m_encoderControl; + + if (qstrcmp(name,QAudioEndpointSelector_iid) == 0) + return m_endpointSelector; + + if (qstrcmp(name,QMediaContainerControl_iid) == 0) + return m_containerControl; + + return 0; +} + +void AudioCaptureService::releaseControl(QMediaControl *control) +{ + Q_UNUSED(control) +} + + diff --git a/src/plugins/audiocapture/audiocaptureservice.h b/src/plugins/audiocapture/audiocaptureservice.h new file mode 100644 index 000000000..22d70029d --- /dev/null +++ b/src/plugins/audiocapture/audiocaptureservice.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AUDIOCAPTURESERVICE_H +#define AUDIOCAPTURESERVICE_H + +#include + +#include "qmediaservice.h" + +class AudioCaptureSession; +class AudioEncoderControl; +class AudioContainerControl; +class AudioMediaRecorderControl; +class AudioEndpointSelector; + +QT_USE_NAMESPACE + +class AudioCaptureService : public QMediaService +{ + Q_OBJECT +public: + AudioCaptureService(QObject *parent = 0); + ~AudioCaptureService(); + + QMediaControl *requestControl(const char *interface); + void releaseControl(QMediaControl *control); +private: + AudioCaptureSession *m_session; + AudioEncoderControl *m_encoderControl; + AudioContainerControl *m_containerControl; + AudioEndpointSelector *m_endpointSelector; + AudioMediaRecorderControl *m_mediaControl; +}; + +#endif diff --git a/src/plugins/audiocapture/audiocaptureserviceplugin.cpp b/src/plugins/audiocapture/audiocaptureserviceplugin.cpp new file mode 100644 index 000000000..5ebaf12b9 --- /dev/null +++ b/src/plugins/audiocapture/audiocaptureserviceplugin.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "audiocaptureserviceplugin.h" +#include "audiocaptureservice.h" + +#include "qmediaserviceprovider.h" + + +QStringList AudioCaptureServicePlugin::keys() const +{ + return QStringList() << QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE); +} + +QMediaService* AudioCaptureServicePlugin::create(QString const& key) +{ + if (key == QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE)) + return new AudioCaptureService; + + return 0; +} + +void AudioCaptureServicePlugin::release(QMediaService *service) +{ + delete service; +} + +Q_EXPORT_PLUGIN2(qtmedia_audioengine, AudioCaptureServicePlugin); + diff --git a/src/plugins/audiocapture/audiocaptureserviceplugin.h b/src/plugins/audiocapture/audiocaptureserviceplugin.h new file mode 100644 index 000000000..e244b9951 --- /dev/null +++ b/src/plugins/audiocapture/audiocaptureserviceplugin.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef AUDIOCAPTURESERVICEPLUGIN_H +#define AUDIOCAPTURESERVICEPLUGIN_H + +#include "qmediaserviceproviderplugin.h" + +QT_USE_NAMESPACE + +class AudioCaptureServicePlugin : public QMediaServiceProviderPlugin +{ + Q_OBJECT + +public: + QStringList keys() const; + QMediaService* create(QString const& key); + void release(QMediaService *service); +}; + +#endif // AUDIOCAPTURESERVICEPLUGIN_H diff --git a/src/plugins/audiocapture/audiocapturesession.cpp b/src/plugins/audiocapture/audiocapturesession.cpp new file mode 100644 index 000000000..da6268adc --- /dev/null +++ b/src/plugins/audiocapture/audiocapturesession.cpp @@ -0,0 +1,358 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#include "qmediarecorder.h" + +#include "audiocapturesession.h" + +AudioCaptureSession::AudioCaptureSession(QObject *parent): + QObject(parent) +{ + m_deviceInfo = new QAudioDeviceInfo(QAudioDeviceInfo::defaultInputDevice()); + m_audioInput = 0; + m_position = 0; + m_state = QMediaRecorder::StoppedState; + + m_format.setFrequency(8000); + m_format.setChannels(1); + m_format.setSampleSize(8); + m_format.setSampleType(QAudioFormat::UnSignedInt); + m_format.setCodec("audio/pcm"); + wavFile = true; +} + +AudioCaptureSession::~AudioCaptureSession() +{ + stop(); + + if(m_audioInput) + delete m_audioInput; +} + +QAudioDeviceInfo* AudioCaptureSession::deviceInfo() const +{ + return m_deviceInfo; +} + +QAudioFormat AudioCaptureSession::format() const +{ + return m_format; +} + +bool AudioCaptureSession::isFormatSupported(const QAudioFormat &format) const +{ + if(m_deviceInfo) { + if(format.codec().contains(QLatin1String("audio/x-wav"))) { + QAudioFormat fmt = format; + fmt.setCodec("audio/pcm"); + return m_deviceInfo->isFormatSupported(fmt); + } else + return m_deviceInfo->isFormatSupported(format); + } + return false; +} + +bool AudioCaptureSession::setFormat(const QAudioFormat &format) +{ + if(m_deviceInfo) { + + QAudioFormat fmt = format; + + if(m_deviceInfo->isFormatSupported(fmt)) { + m_format = fmt; + if(m_audioInput) delete m_audioInput; + m_audioInput = 0; + QList devices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput); + for(int i=0;ideviceName().toLocal8Bit().constData(), + devices.at(i).deviceName().toLocal8Bit().constData()) == 0) { + m_audioInput = new QAudioInput(devices.at(i),m_format); + connect(m_audioInput,SIGNAL(stateChanged(QAudio::State)),this,SLOT(stateChanged(QAudio::State))); + connect(m_audioInput,SIGNAL(notify()),this,SLOT(notify())); + break; + } + } + } else { + m_format = m_deviceInfo->preferredFormat(); + qWarning()<<"failed to setFormat using preferred..."; + } + } + return false; +} + +QStringList AudioCaptureSession::supportedContainers() const +{ + QStringList list; + if(m_deviceInfo) { + if (m_deviceInfo->supportedCodecs().size() > 0) { + list << "audio/x-wav"; + list << "audio/pcm"; + } + } + return list; +} + +QString AudioCaptureSession::containerDescription(const QString &formatMimeType) const +{ + if(m_deviceInfo) { + if (formatMimeType.contains(QLatin1String("audio/pcm"))) + return tr("RAW file format"); + if (formatMimeType.contains(QLatin1String("audio/x-wav"))) + return tr("WAV file format"); + } + return QString(); +} + +void AudioCaptureSession::setContainerMimeType(const QString &formatMimeType) +{ + if (!formatMimeType.contains(QLatin1String("audio/x-wav")) && + !formatMimeType.contains(QLatin1String("audio/pcm")) && + !formatMimeType.isEmpty()) + return; + + if(m_deviceInfo) { + if (!m_deviceInfo->supportedCodecs().contains(QLatin1String("audio/pcm"))) + return; + + if (formatMimeType.isEmpty() || formatMimeType.contains(QLatin1String("audio/x-wav"))) { + wavFile = true; + m_format.setCodec("audio/pcm"); + } else { + wavFile = false; + m_format.setCodec(formatMimeType); + } + } +} + +QString AudioCaptureSession::containerMimeType() const +{ + if(wavFile) + return QString("audio/x-wav"); + + return QString("audio/pcm"); +} + +QUrl AudioCaptureSession::outputLocation() const +{ + return m_actualSink; +} + +bool AudioCaptureSession::setOutputLocation(const QUrl& sink) +{ + m_sink = m_actualSink = sink; + return true; +} + +qint64 AudioCaptureSession::position() const +{ + return m_position; +} + +int AudioCaptureSession::state() const +{ + return int(m_state); +} + +QDir AudioCaptureSession::defaultDir() const +{ + QStringList dirCandidates; + +#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) + dirCandidates << QLatin1String("/home/user/MyDocs"); +#endif + + dirCandidates << QDir::home().filePath("Documents"); + dirCandidates << QDir::home().filePath("My Documents"); + dirCandidates << QDir::homePath(); + dirCandidates << QDir::currentPath(); + dirCandidates << QDir::tempPath(); + + foreach (const QString &path, dirCandidates) { + QDir dir(path); + if (dir.exists() && QFileInfo(path).isWritable()) + return dir; + } + + return QDir(); +} + +QString AudioCaptureSession::generateFileName(const QDir &dir, const QString &ext) const +{ + + int lastClip = 0; + foreach(QString fileName, dir.entryList(QStringList() << QString("clip_*.%1").arg(ext))) { + int imgNumber = fileName.mid(5, fileName.size()-6-ext.length()).toInt(); + lastClip = qMax(lastClip, imgNumber); + } + + QString name = QString("clip_%1.%2").arg(lastClip+1, + 4, //fieldWidth + 10, + QLatin1Char('0')).arg(ext); + + return dir.absoluteFilePath(name); +} + +void AudioCaptureSession::record() +{ + if(!m_audioInput) { + setFormat(m_format); + } + + m_actualSink = m_sink; + + if (m_actualSink.isEmpty()) { + QString ext = wavFile ? QLatin1String("wav") : QLatin1String("raw"); + m_actualSink = generateFileName(defaultDir(), ext); + } + + if(m_actualSink.toLocalFile().length() > 0) + file.setFileName(m_actualSink.toLocalFile()); + else + file.setFileName(m_actualSink.toString()); + + if(m_audioInput) { + if(m_state == QMediaRecorder::StoppedState) { + if(file.open(QIODevice::WriteOnly)) { + memset(&header,0,sizeof(CombinedHeader)); + memcpy(header.riff.descriptor.id,"RIFF",4); + header.riff.descriptor.size = 0xFFFFFFFF; // This should be updated on stop(), filesize-8 + memcpy(header.riff.type,"WAVE",4); + memcpy(header.wave.descriptor.id,"fmt ",4); + header.wave.descriptor.size = 16; + header.wave.audioFormat = 1; // for PCM data + header.wave.numChannels = m_format.channels(); + header.wave.sampleRate = m_format.frequency(); + header.wave.byteRate = m_format.frequency()*m_format.channels()*m_format.sampleSize()/8; + header.wave.blockAlign = m_format.channels()*m_format.sampleSize()/8; + header.wave.bitsPerSample = m_format.sampleSize(); + memcpy(header.data.descriptor.id,"data",4); + header.data.descriptor.size = 0xFFFFFFFF; // This should be updated on stop(),samples*channels*sampleSize/8 + if (wavFile) + file.write((char*)&header,sizeof(CombinedHeader)); + + m_audioInput->start(qobject_cast(&file)); + } else { + emit error(1,QString("can't open source, failed")); + m_state = QMediaRecorder::StoppedState; + emit stateChanged(m_state); + } + } + } + + m_state = QMediaRecorder::RecordingState; +} + +void AudioCaptureSession::pause() +{ + if(m_audioInput) + m_audioInput->stop(); + + m_state = QMediaRecorder::PausedState; +} + +void AudioCaptureSession::stop() +{ + if(m_audioInput) { + m_audioInput->stop(); + file.close(); + if (wavFile) { + qint32 fileSize = file.size()-8; + file.open(QIODevice::ReadWrite | QIODevice::Unbuffered); + file.read((char*)&header,sizeof(CombinedHeader)); + header.riff.descriptor.size = fileSize; // filesize-8 + header.data.descriptor.size = fileSize-44; // samples*channels*sampleSize/8 + file.seek(0); + file.write((char*)&header,sizeof(CombinedHeader)); + file.close(); + } + m_position = 0; + } + m_state = QMediaRecorder::StoppedState; +} + +void AudioCaptureSession::stateChanged(QAudio::State state) +{ + switch(state) { + case QAudio::ActiveState: + emit stateChanged(QMediaRecorder::RecordingState); + break; + default: + if(!((m_state == QMediaRecorder::PausedState)||(m_state == QMediaRecorder::StoppedState))) + m_state = QMediaRecorder::StoppedState; + + emit stateChanged(m_state); + break; + } +} + +void AudioCaptureSession::notify() +{ + m_position += m_audioInput->notifyInterval(); + emit positionChanged(m_position); +} + +void AudioCaptureSession::setCaptureDevice(const QString &deviceName) +{ + m_captureDevice = deviceName; + if(m_deviceInfo) + delete m_deviceInfo; + + m_deviceInfo = 0; + + QList devices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput); + for(int i = 0; i < devices.size(); i++) { + if(qstrcmp(m_captureDevice.toLocal8Bit().constData(), + devices.at(i).deviceName().toLocal8Bit().constData())==0){ + m_deviceInfo = new QAudioDeviceInfo(QAudioDeviceInfo::defaultInputDevice()); + return; + } + } + m_deviceInfo = new QAudioDeviceInfo(QAudioDeviceInfo::defaultInputDevice()); +} + + + diff --git a/src/plugins/audiocapture/audiocapturesession.h b/src/plugins/audiocapture/audiocapturesession.h new file mode 100644 index 000000000..0ce139f9a --- /dev/null +++ b/src/plugins/audiocapture/audiocapturesession.h @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AUDIOCAPTURESESSION_H +#define AUDIOCAPTURESESSION_H + +#include +#include +#include + +#include "audioencodercontrol.h" +#include "audioendpointselector.h" +#include "audiomediarecordercontrol.h" + +#include +#include +#include + +QT_USE_NAMESPACE + +class AudioCaptureSession : public QObject +{ + Q_OBJECT + +public: + AudioCaptureSession(QObject *parent = 0); + ~AudioCaptureSession(); + + QAudioFormat format() const; + QAudioDeviceInfo* deviceInfo() const; + bool isFormatSupported(const QAudioFormat &format) const; + bool setFormat(const QAudioFormat &format); + QStringList supportedContainers() const; + QString containerMimeType() const; + void setContainerMimeType(const QString &formatMimeType); + QString containerDescription(const QString &formatMimeType) const; + + QUrl outputLocation() const; + bool setOutputLocation(const QUrl& sink); + qint64 position() const; + int state() const; + void record(); + void pause(); + void stop(); + +public slots: + void setCaptureDevice(const QString &deviceName); + +signals: + void stateChanged(QMediaRecorder::State state); + void positionChanged(qint64 position); + void error(int error, const QString &errorString); + +private slots: + void stateChanged(QAudio::State state); + void notify(); + +private: + QDir defaultDir() const; + QString generateFileName(const QDir &dir, const QString &ext) const; + + QFile file; + QString m_captureDevice; + QUrl m_sink; + QUrl m_actualSink; + QMediaRecorder::State m_state; + QAudioInput *m_audioInput; + QAudioDeviceInfo *m_deviceInfo; + QAudioFormat m_format; + qint64 m_position; + bool wavFile; + + // WAV header stuff + + struct chunk + { + char id[4]; + quint32 size; + }; + + struct RIFFHeader + { + chunk descriptor; + char type[4]; + }; + + struct WAVEHeader + { + chunk descriptor; + quint16 audioFormat; // PCM = 1 + quint16 numChannels; + quint32 sampleRate; + quint32 byteRate; + quint16 blockAlign; + quint16 bitsPerSample; + }; + + struct DATAHeader + { + chunk descriptor; +// quint8 data[]; + }; + + struct CombinedHeader + { + RIFFHeader riff; + WAVEHeader wave; + DATAHeader data; + }; + + CombinedHeader header; +}; + +#endif diff --git a/src/plugins/audiocapture/audiocontainercontrol.cpp b/src/plugins/audiocapture/audiocontainercontrol.cpp new file mode 100644 index 000000000..454f43eda --- /dev/null +++ b/src/plugins/audiocapture/audiocontainercontrol.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "audiocontainercontrol.h" +#include "audiocapturesession.h" + +AudioContainerControl::AudioContainerControl(QObject *parent) + :QMediaContainerControl(parent) +{ + m_session = qobject_cast(parent); +} + +AudioContainerControl::~AudioContainerControl() +{ +} + +QStringList AudioContainerControl::supportedContainers() const +{ + return m_session->supportedContainers(); +} + +QString AudioContainerControl::containerMimeType() const +{ + return m_session->containerMimeType(); +} + +void AudioContainerControl::setContainerMimeType(const QString &formatMimeType) +{ + m_session->setContainerMimeType(formatMimeType); +} + +QString AudioContainerControl::containerDescription(const QString &formatMimeType) const +{ + return m_session->containerDescription(formatMimeType); +} + diff --git a/src/plugins/audiocapture/audiocontainercontrol.h b/src/plugins/audiocapture/audiocontainercontrol.h new file mode 100644 index 000000000..5c8d7b267 --- /dev/null +++ b/src/plugins/audiocapture/audiocontainercontrol.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AUDIOCONTAINERCONTROL_H +#define AUDIOCONTAINERCONTROL_H + +#include "qmediacontainercontrol.h" + +#include +#include + +class AudioCaptureSession; + +QT_USE_NAMESPACE + +class AudioContainerControl : public QMediaContainerControl +{ + Q_OBJECT +public: + AudioContainerControl(QObject *parent); + virtual ~AudioContainerControl(); + + QStringList supportedContainers() const; + QString containerMimeType() const; + void setContainerMimeType(const QString &formatMimeType); + QString containerDescription(const QString &formatMimeType) const; + +private: + AudioCaptureSession* m_session; +}; + +#endif diff --git a/src/plugins/audiocapture/audioencodercontrol.cpp b/src/plugins/audiocapture/audioencodercontrol.cpp new file mode 100644 index 000000000..888deac45 --- /dev/null +++ b/src/plugins/audiocapture/audioencodercontrol.cpp @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "audioencodercontrol.h" +#include "audiocapturesession.h" + +#include + +#include + +AudioEncoderControl::AudioEncoderControl(QObject *parent) + :QAudioEncoderControl(parent) +{ + m_session = qobject_cast(parent); + + QT_PREPEND_NAMESPACE(QAudioFormat) fmt; + fmt.setSampleSize(8); + fmt.setChannels(1); + fmt.setFrequency(8000); + fmt.setSampleType(QT_PREPEND_NAMESPACE(QAudioFormat)::SignedInt); + fmt.setCodec("audio/pcm"); + fmt.setByteOrder(QAudioFormat::LittleEndian); + m_session->setFormat(fmt); + + m_settings.setEncodingMode(QtMultimediaKit::ConstantQualityEncoding); + m_settings.setCodec("audio/pcm"); + m_settings.setBitRate(8000); + m_settings.setChannelCount(1); + m_settings.setSampleRate(8000); + m_settings.setQuality(QtMultimediaKit::LowQuality); +} + +AudioEncoderControl::~AudioEncoderControl() +{ +} + +QStringList AudioEncoderControl::supportedAudioCodecs() const +{ + QStringList list; + if (m_session->supportedContainers().size() > 0) + list.append("audio/pcm"); + + return list; +} + +QString AudioEncoderControl::codecDescription(const QString &codecName) const +{ + if (codecName.contains(QLatin1String("audio/pcm"))) + return tr("PCM audio data"); + + return QString(); +} + +QStringList AudioEncoderControl::supportedEncodingOptions(const QString &codec) const +{ + Q_UNUSED(codec) + + QStringList list; + return list; +} + +QVariant AudioEncoderControl::encodingOption(const QString &codec, const QString &name) const +{ + Q_UNUSED(codec) + Q_UNUSED(name) + + return QVariant(); +} + +void AudioEncoderControl::setEncodingOption( + const QString &codec, const QString &name, const QVariant &value) +{ + Q_UNUSED(value) + Q_UNUSED(codec) + Q_UNUSED(name) +} + +QList AudioEncoderControl::supportedSampleRates(const QAudioEncoderSettings &, bool *continuous) const +{ + if (continuous) + *continuous = false; + + return m_session->deviceInfo()->supportedFrequencies(); +} + +QAudioEncoderSettings AudioEncoderControl::audioSettings() const +{ + return m_settings; +} + +void AudioEncoderControl::setAudioSettings(const QAudioEncoderSettings &settings) +{ + QAudioFormat fmt = m_session->format(); + + if (settings.encodingMode() == QtMultimediaKit::ConstantQualityEncoding) { + if (settings.quality() == QtMultimediaKit::LowQuality) { + fmt.setSampleSize(8); + fmt.setChannels(1); + fmt.setFrequency(8000); + fmt.setSampleType(QAudioFormat::UnSignedInt); + + } else if (settings.quality() == QtMultimediaKit::NormalQuality) { + fmt.setSampleSize(16); + fmt.setChannels(1); + fmt.setFrequency(22050); + fmt.setSampleType(QAudioFormat::SignedInt); + + } else { + fmt.setSampleSize(16); + fmt.setChannels(1); + fmt.setFrequency(44100); + fmt.setSampleType(QAudioFormat::SignedInt); + } + + } else { + fmt.setChannels(settings.channelCount()); + fmt.setFrequency(settings.sampleRate()); + if (settings.sampleRate() == 8000 && settings.bitRate() == 8000) { + fmt.setSampleType(QAudioFormat::UnSignedInt); + fmt.setSampleSize(8); + } else { + fmt.setSampleSize(16); + fmt.setSampleType(QAudioFormat::SignedInt); + } + } + fmt.setCodec("audio/pcm"); + + m_session->setFormat(fmt); + m_settings = settings; +} diff --git a/src/plugins/audiocapture/audioencodercontrol.h b/src/plugins/audiocapture/audioencodercontrol.h new file mode 100644 index 000000000..09ac8b2b2 --- /dev/null +++ b/src/plugins/audiocapture/audioencodercontrol.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AUDIOENCODERCONTROL_H +#define AUDIOENCODERCONTROL_H + +#include "qaudioencodercontrol.h" + +#include +#include + +#include + +class AudioCaptureSession; + +QT_USE_NAMESPACE + +class AudioEncoderControl : public QAudioEncoderControl +{ + Q_OBJECT +public: + AudioEncoderControl(QObject *parent); + virtual ~AudioEncoderControl(); + + QStringList supportedAudioCodecs() const; + QString codecDescription(const QString &codecName) const; + QList supportedSampleRates(const QAudioEncoderSettings &, bool *continuous = 0) const; + + QAudioEncoderSettings audioSettings() const; + void setAudioSettings(const QAudioEncoderSettings&); + + QStringList supportedEncodingOptions(const QString &codec) const; + QVariant encodingOption(const QString &codec, const QString &name) const; + void setEncodingOption(const QString &codec, const QString &name, const QVariant &value); + +private: + AudioCaptureSession* m_session; + QAudioEncoderSettings m_settings; +}; + +#endif diff --git a/src/plugins/audiocapture/audioendpointselector.cpp b/src/plugins/audiocapture/audioendpointselector.cpp new file mode 100644 index 000000000..dc7ca8e90 --- /dev/null +++ b/src/plugins/audiocapture/audioendpointselector.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "audiocapturesession.h" +#include "audioendpointselector.h" + +#include + + +AudioEndpointSelector::AudioEndpointSelector(QObject *parent) + :QAudioEndpointSelector(parent) +{ + m_session = qobject_cast(parent); + + update(); + + m_audioInput = defaultEndpoint(); +} + +AudioEndpointSelector::~AudioEndpointSelector() +{ +} + +QList AudioEndpointSelector::availableEndpoints() const +{ + return m_names; +} + +QString AudioEndpointSelector::endpointDescription(const QString& name) const +{ + QString desc; + + for(int i = 0; i < m_names.count(); i++) { + if (m_names.at(i).compare(name) == 0) { + desc = m_names.at(i); + break; + } + } + return desc; +} + +QString AudioEndpointSelector::defaultEndpoint() const +{ + return QAudioDeviceInfo(QAudioDeviceInfo::defaultInputDevice()).deviceName(); +} + +QString AudioEndpointSelector::activeEndpoint() const +{ + return m_audioInput; +} + +void AudioEndpointSelector::setActiveEndpoint(const QString& name) +{ + if (m_audioInput.compare(name) != 0) { + m_audioInput = name; + m_session->setCaptureDevice(name); + emit activeEndpointChanged(name); + } +} + +void AudioEndpointSelector::update() +{ + m_names.clear(); + m_descriptions.clear(); + + QList devices; + devices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput); + for(int i = 0; i < devices.size(); ++i) { + m_names.append(devices.at(i).deviceName()); + m_descriptions.append(devices.at(i).deviceName()); + } +} diff --git a/src/plugins/audiocapture/audioendpointselector.h b/src/plugins/audiocapture/audioendpointselector.h new file mode 100644 index 000000000..dda3c59c7 --- /dev/null +++ b/src/plugins/audiocapture/audioendpointselector.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AUDIOENDPOINTSELECTOR_H +#define AUDIOENDPOINTSELECTOR_H + +#include + +#include "qaudioendpointselector.h" + +class AudioCaptureSession; + +QT_USE_NAMESPACE + +class AudioEndpointSelector : public QAudioEndpointSelector +{ +Q_OBJECT +public: + AudioEndpointSelector(QObject *parent); + virtual ~AudioEndpointSelector(); + + QList availableEndpoints() const; + QString endpointDescription(const QString& name) const; + QString defaultEndpoint() const; + QString activeEndpoint() const; + +public Q_SLOTS: + void setActiveEndpoint(const QString& name); + +private: + void update(); + + QString m_audioInput; + QList m_names; + QList m_descriptions; + AudioCaptureSession* m_session; +}; + +#endif // AUDIOENDPOINTSELECTOR_H diff --git a/src/plugins/audiocapture/audiomediarecordercontrol.cpp b/src/plugins/audiocapture/audiomediarecordercontrol.cpp new file mode 100644 index 000000000..b1f550a04 --- /dev/null +++ b/src/plugins/audiocapture/audiomediarecordercontrol.cpp @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "audiocapturesession.h" +#include "audiomediarecordercontrol.h" + +#include + +AudioMediaRecorderControl::AudioMediaRecorderControl(QObject *parent) + :QMediaRecorderControl(parent) +{ + m_session = qobject_cast(parent); + connect(m_session,SIGNAL(positionChanged(qint64)),this,SIGNAL(durationChanged(qint64))); + connect(m_session,SIGNAL(stateChanged(QMediaRecorder::State)),this,SIGNAL(stateChanged(QMediaRecorder::State))); + connect(m_session,SIGNAL(error(int,QString)),this,SIGNAL(error(int,QString))); +} + +AudioMediaRecorderControl::~AudioMediaRecorderControl() +{ +} + +QUrl AudioMediaRecorderControl::outputLocation() const +{ + return m_session->outputLocation(); +} + +bool AudioMediaRecorderControl::setOutputLocation(const QUrl& sink) +{ + return m_session->setOutputLocation(sink); +} + +QMediaRecorder::State AudioMediaRecorderControl::state() const +{ + return (QMediaRecorder::State)m_session->state(); +} + +qint64 AudioMediaRecorderControl::duration() const +{ + return m_session->position(); +} + +void AudioMediaRecorderControl::record() +{ + m_session->record(); +} + +void AudioMediaRecorderControl::pause() +{ + m_session->stop(); +} + +void AudioMediaRecorderControl::stop() +{ + m_session->stop(); +} + +bool AudioMediaRecorderControl::isMuted() const +{ + return false; +} + +void AudioMediaRecorderControl::setMuted(bool) +{ +} diff --git a/src/plugins/audiocapture/audiomediarecordercontrol.h b/src/plugins/audiocapture/audiomediarecordercontrol.h new file mode 100644 index 000000000..a3528a875 --- /dev/null +++ b/src/plugins/audiocapture/audiomediarecordercontrol.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AUDIOMEDIARECORDERCONTROL_H +#define AUDIOMEDIARECORDERCONTROL_H + +#include + +#include "qmediarecorder.h" +#include "qmediarecordercontrol.h" + +class AudioCaptureSession; + +QT_USE_NAMESPACE + +class AudioMediaRecorderControl : public QMediaRecorderControl +{ + Q_OBJECT +public: + AudioMediaRecorderControl(QObject *parent = 0); + ~AudioMediaRecorderControl(); + + QUrl outputLocation() const; + bool setOutputLocation(const QUrl &sink); + + QMediaRecorder::State state() const; + + qint64 duration() const; + + bool isMuted() const; + + void applySettings() {} + +public slots: + void record(); + void pause(); + void stop(); + void setMuted(bool); + +private: + AudioCaptureSession* m_session; +}; + +#endif diff --git a/src/plugins/directshow/camera/camera.pri b/src/plugins/directshow/camera/camera.pri new file mode 100644 index 000000000..42f5999a2 --- /dev/null +++ b/src/plugins/directshow/camera/camera.pri @@ -0,0 +1,31 @@ +INCLUDEPATH += $$PWD + +DEFINES += QMEDIA_DIRECTSHOW_CAMERA + +win32-g++: DEFINES += QT_NO_WMSDK + +win32: DEFINES += _CRT_SECURE_NO_WARNINGS + +HEADERS += \ + $$PWD/dscameraservice.h \ + $$PWD/dscameracontrol.h \ + $$PWD/dsvideorenderer.h \ + $$PWD/dsvideodevicecontrol.h \ + $$PWD/dsimagecapturecontrol.h \ + $$PWD/dscamerasession.h \ + $$PWD/dsvideowidgetcontrol.h \ + $$PWD/dscameraservice.h \ + $$PWD/directshowglobal.h + + +SOURCES += \ + $$PWD/dscameraservice.cpp \ + $$PWD/dscameracontrol.cpp \ + $$PWD/dsvideorenderer.cpp \ + $$PWD/dsvideodevicecontrol.cpp \ + $$PWD/dsimagecapturecontrol.cpp \ + $$PWD/dscamerasession.cpp \ + $$PWD/dsvideowidgetcontrol.cpp + +INCLUDEPATH += $(DXSDK_DIR)/include +LIBS += -lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32 diff --git a/src/plugins/directshow/camera/directshowglobal.h b/src/plugins/directshow/camera/directshowglobal.h new file mode 100644 index 000000000..76c143798 --- /dev/null +++ b/src/plugins/directshow/camera/directshowglobal.h @@ -0,0 +1,236 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DIRECTSHOWGLOBAL_H +#define DIRECTSHOWGLOBAL_H + +#include + +#include + +DEFINE_GUID(MEDIASUBTYPE_I420, + 0x30323449,0x0000,0x0010,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71); + +extern const GUID MEDIASUBTYPE_RGB24; +extern const GUID MEDIASUBTYPE_RGB32; +extern const GUID MEDIASUBTYPE_YUY2; +extern const GUID MEDIASUBTYPE_MJPG; +extern const GUID MEDIASUBTYPE_RGB555; +extern const GUID MEDIASUBTYPE_YVU9; +extern const GUID MEDIASUBTYPE_UYVY; +extern const GUID PIN_CATEGORY_CAPTURE; +extern const GUID PIN_CATEGORY_PREVIEW; + +extern const IID IID_IPropertyBag; +extern const IID IID_ISampleGrabber; +extern const IID IID_ICaptureGraphBuilder2; +extern const IID IID_IAMStreamConfig; + + +extern const CLSID CLSID_CVidCapClassManager; +extern const CLSID CLSID_VideoInputDeviceCategory; +extern const CLSID CLSID_SampleGrabber; +extern const CLSID CLSID_CaptureGraphBuilder2; + +#define SAFE_RELEASE(x) { if(x) x->Release(); x = NULL; } + +typedef struct IFileSinkFilter *LPFILESINKFILTER; +typedef struct IAMCopyCaptureFileProgress *LPAMCOPYCAPTUREFILEPROGRESS; + +#ifndef __ICaptureGraphBuilder2_INTERFACE_DEFINED__ +#define __ICaptureGraphBuilder2_INTERFACE_DEFINED__ +struct ICaptureGraphBuilder2 : public IUnknown +{ +public: + virtual HRESULT STDMETHODCALLTYPE SetFiltergraph( + /* [in] */ IGraphBuilder *pfg) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFiltergraph( + /* [out] */ IGraphBuilder **ppfg) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetOutputFileName( + /* [in] */ const GUID *pType, + /* [in] */ LPCOLESTR lpstrFile, + /* [out] */ IBaseFilter **ppf, + /* [out] */ IFileSinkFilter **ppSink) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE FindInterface( + /* [in] */ const GUID *pCategory, + /* [in] */ const GUID *pType, + /* [in] */ IBaseFilter *pf, + /* [in] */ REFIID riid, + /* [out] */ void **ppint) = 0; + + virtual HRESULT STDMETHODCALLTYPE RenderStream( + /* [in] */ const GUID *pCategory, + /* [in] */ const GUID *pType, + /* [in] */ IUnknown *pSource, + /* [in] */ IBaseFilter *pfCompressor, + /* [in] */ IBaseFilter *pfRenderer) = 0; + + virtual HRESULT STDMETHODCALLTYPE ControlStream( + /* [in] */ const GUID *pCategory, + /* [in] */ const GUID *pType, + /* [in] */ IBaseFilter *pFilter, + /* [in] */ REFERENCE_TIME *pstart, + /* [in] */ REFERENCE_TIME *pstop, + /* [in] */ WORD wStartCookie, + /* [in] */ WORD wStopCookie) = 0; + + virtual HRESULT STDMETHODCALLTYPE AllocCapFile( + /* [in] */ LPCOLESTR lpstr, + /* [in] */ DWORDLONG dwlSize) = 0; + + virtual HRESULT STDMETHODCALLTYPE CopyCaptureFile( + /* [in] */ LPOLESTR lpwstrOld, + /* [in] */ LPOLESTR lpwstrNew, + /* [in] */ int fAllowEscAbort, + /* [in] */ IAMCopyCaptureFileProgress *pCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE FindPin( + /* [in] */ IUnknown *pSource, + /* [in] */ PIN_DIRECTION pindir, + /* [in] */ const GUID *pCategory, + /* [in] */ const GUID *pType, + /* [in] */ BOOL fUnconnected, + /* [in] */ int num, + /* [out] */ IPin **ppPin) = 0; + +}; +#endif + +#ifndef __IAMStreamConfig_INTERFACE_DEFINED__ +#define __IAMStreamConfig_INTERFACE_DEFINED__ +struct IAMStreamConfig : public IUnknown +{ +public: + virtual HRESULT STDMETHODCALLTYPE SetFormat( + /* [in] */ AM_MEDIA_TYPE *pmt) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFormat( + /* [out] */ AM_MEDIA_TYPE **ppmt) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetNumberOfCapabilities( + /* [out] */ int *piCount, + /* [out] */ int *piSize) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetStreamCaps( + /* [in] */ int iIndex, + /* [out] */ AM_MEDIA_TYPE **ppmt, + /* [out] */ BYTE *pSCC) = 0; + +}; +#endif + +#ifndef __IErrorLog_INTERFACE_DEFINED__ +#define __IErrorLog_INTERFACE_DEFINED__ +struct IErrorLog : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE AddError( + /* [in] */ LPCOLESTR pszPropName, + /* [in] */ EXCEPINFO *pExcepInfo) = 0; + + }; +#endif + +#ifndef __IPropertyBag_INTERFACE_DEFINED__ +#define __IPropertyBag_INTERFACE_DEFINED__ +struct IPropertyBag : public IUnknown +{ +public: + virtual /* [local] */ HRESULT STDMETHODCALLTYPE Read( + /* [in] */ LPCOLESTR pszPropName, + /* [out][in] */ VARIANT *pVar, + /* [in] */ IErrorLog *pErrorLog) = 0; + + virtual HRESULT STDMETHODCALLTYPE Write( + /* [in] */ LPCOLESTR pszPropName, + /* [in] */ VARIANT *pVar) = 0; + +}; +#endif + +typedef struct IMediaSample *LPMEDIASAMPLE; + +EXTERN_C const IID IID_ISampleGrabberCB; + +#ifndef __ISampleGrabberCB_INTERFACE_DEFINED__ +#define __ISampleGrabberCB_INTERFACE_DEFINED__ + +#undef INTERFACE +#define INTERFACE ISampleGrabberCB +DECLARE_INTERFACE_(ISampleGrabberCB, IUnknown) +{ +// STDMETHOD(QueryInterface) (THIS_ const GUID *, void **) PURE; + STDMETHOD(QueryInterface) (THIS_ REFIID riid, void **) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; + STDMETHOD_(HRESULT, SampleCB) (THIS_ double, LPMEDIASAMPLE) PURE; + STDMETHOD_(HRESULT, BufferCB) (THIS_ double, BYTE *, long) PURE; +}; +#undef INTERFACE + +#endif + + +#ifndef __ISampleGrabber_INTERFACE_DEFINED__ +#define __ISampleGrabber_INTERFACE_DEFINED__ + +#define INTERFACE ISampleGrabber +DECLARE_INTERFACE_(ISampleGrabber,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(SetOneShot)(THIS_ BOOL) PURE; + STDMETHOD(SetMediaType)(THIS_ const AM_MEDIA_TYPE*) PURE; + STDMETHOD(GetConnectedMediaType)(THIS_ AM_MEDIA_TYPE*) PURE; + STDMETHOD(SetBufferSamples)(THIS_ BOOL) PURE; + STDMETHOD(GetCurrentBuffer)(THIS_ long*,long*) PURE; + STDMETHOD(GetCurrentSample)(THIS_ IMediaSample**) PURE; + STDMETHOD(SetCallback)(THIS_ ISampleGrabberCB *,long) PURE; +}; +#undef INTERFACE +#endif + + +#endif diff --git a/src/plugins/directshow/camera/dscameracontrol.cpp b/src/plugins/directshow/camera/dscameracontrol.cpp new file mode 100644 index 000000000..b09064c2b --- /dev/null +++ b/src/plugins/directshow/camera/dscameracontrol.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "dscameracontrol.h" +#include "dscameraservice.h" +#include "dscamerasession.h" + +QT_BEGIN_NAMESPACE + +DSCameraControl::DSCameraControl(QObject *parent) + :QCameraControl(parent), m_captureMode(QCamera::CaptureStillImage) +{ + m_session = qobject_cast(parent); + connect(m_session, SIGNAL(stateChanged(QCamera::State)),this, SIGNAL(stateChanged(QCamera::State))); +} + +DSCameraControl::~DSCameraControl() +{ +} + +void DSCameraControl::setState(QCamera::State state) +{ + switch (state) { + case QCamera::ActiveState: + start(); + break; + case QCamera::UnloadedState: /* fall through */ + case QCamera::LoadedState: + stop(); + break; + } +} + +bool DSCameraControl::isCaptureModeSupported(QCamera::CaptureMode mode) const +{ + bool bCaptureSupported = false; + switch (mode) { + case QCamera::CaptureStillImage: + bCaptureSupported = true; + break; + case QCamera::CaptureVideo: + bCaptureSupported = false; + break; + } + return bCaptureSupported; +} + +void DSCameraControl::start() +{ + m_session->record(); +} + +void DSCameraControl::stop() +{ + m_session->stop(); +} + +QCamera::State DSCameraControl::state() const +{ + return (QCamera::State)m_session->state(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/dscameracontrol.h b/src/plugins/directshow/camera/dscameracontrol.h new file mode 100644 index 000000000..9b20563d2 --- /dev/null +++ b/src/plugins/directshow/camera/dscameracontrol.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DSCAMERACONTROL_H +#define DSCAMERACONTROL_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DSCameraService; +class DSCameraSession; + + +class DSCameraControl : public QCameraControl +{ + Q_OBJECT +public: + DSCameraControl(QObject *parent = 0); + ~DSCameraControl(); + + void start(); + void stop(); + QCamera::State state() const; + + QCamera::CaptureMode captureMode() const { return m_captureMode; } + void setCaptureMode(QCamera::CaptureMode mode) + { + if (m_captureMode != mode) { + m_captureMode = mode; + emit captureModeChanged(mode); + } + } + + void setState(QCamera::State state); + + QCamera::Status status() const { return QCamera::UnavailableStatus; } + bool isCaptureModeSupported(QCamera::CaptureMode mode) const; + bool canChangeProperty(PropertyChangeType /* changeType */, QCamera::Status /* status */) const {return false; } + +private: + DSCameraSession *m_session; + DSCameraService *m_service; + QCamera::CaptureMode m_captureMode; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif + + diff --git a/src/plugins/directshow/camera/dscameraservice.cpp b/src/plugins/directshow/camera/dscameraservice.cpp new file mode 100644 index 000000000..9d73da02c --- /dev/null +++ b/src/plugins/directshow/camera/dscameraservice.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + + +#include "dscameraservice.h" +#include "dscameracontrol.h" +#include "dscamerasession.h" +#include "dsvideorenderer.h" +#include "dsvideodevicecontrol.h" +#include "dsimagecapturecontrol.h" +#include "dsvideowidgetcontrol.h" + +QT_BEGIN_NAMESPACE + +DSCameraService::DSCameraService(QObject *parent): + QMediaService(parent) +{ + m_session = new DSCameraSession(this); + + m_control = new DSCameraControl(m_session); + + m_videoDevice = new DSVideoDeviceControl(m_session); + + m_videoRenderer = new DSVideoRendererControl(m_session, this); + + m_imageCapture = new DSImageCaptureControl(m_session); + + m_viewFinderWidget = new DSVideoWidgetControl(m_session); + + m_device = QByteArray("default"); +} + +DSCameraService::~DSCameraService() +{ + delete m_control; + delete m_videoDevice; + delete m_videoRenderer; + delete m_imageCapture; + delete m_viewFinderWidget; + delete m_session; +} + +QMediaControl* DSCameraService::requestControl(const char *name) +{ + if(qstrcmp(name,QCameraControl_iid) == 0) + return m_control; + + if (qstrcmp(name, QCameraImageCaptureControl_iid) == 0) + return m_imageCapture; + + if (qstrcmp(name, QVideoWidgetControl_iid) == 0) { + if (m_viewFinderWidget) { + return m_viewFinderWidget; + } + } + + if(qstrcmp(name,QVideoRendererControl_iid) == 0) + return m_videoRenderer; + + if(qstrcmp(name,QVideoDeviceControl_iid) == 0) + return m_videoDevice; + + return 0; +} + +void DSCameraService::releaseControl(QMediaControl *control) +{ + // Implemented as a singleton, so we do nothing. +} + +QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/dscameraservice.h b/src/plugins/directshow/camera/dscameraservice.h new file mode 100644 index 000000000..e8a9450fb --- /dev/null +++ b/src/plugins/directshow/camera/dscameraservice.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DSCAMERASERVICE_H +#define DSCAMERASERVICE_H + +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DSCameraControl; +class DSCameraSession; +class DSVideoOutputControl; +class DSVideoDeviceControl; +class DSVideoRendererControl; +class DSImageCaptureControl; +class DSVideoWidgetControl; + + +class DSCameraService : public QMediaService +{ + Q_OBJECT + +public: + DSCameraService(QObject *parent = 0); + ~DSCameraService(); + + virtual QMediaControl* requestControl(const char *name); + virtual void releaseControl(QMediaControl *control); + +private: + DSCameraControl *m_control; + DSCameraSession *m_session; + DSVideoOutputControl *m_videoOutput; + DSVideoWidgetControl *m_viewFinderWidget; + DSVideoDeviceControl *m_videoDevice; + DSVideoRendererControl *m_videoRenderer; + DSImageCaptureControl *m_imageCapture; + QByteArray m_device; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp new file mode 100644 index 000000000..a08fb318f --- /dev/null +++ b/src/plugins/directshow/camera/dscamerasession.cpp @@ -0,0 +1,1160 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "dscamerasession.h" +#include "dsvideorenderer.h" +#include "directshowglobal.h" + +QT_BEGIN_NAMESPACE + +// If frames come in quicker than we display them, we allow the queue to build +// up to this number before we start dropping them. +const int LIMIT_FRAME = 5; + +namespace { +// DirectShow helper implementation +void _FreeMediaType(AM_MEDIA_TYPE& mt) +{ + if (mt.cbFormat != 0) { + CoTaskMemFree((PVOID)mt.pbFormat); + mt.cbFormat = 0; + mt.pbFormat = NULL; + } + if (mt.pUnk != NULL) { + // pUnk should not be used. + mt.pUnk->Release(); + mt.pUnk = NULL; + } +} + +} // end namespace + +class SampleGrabberCallbackPrivate : public ISampleGrabberCB +{ +public: + STDMETHODIMP_(ULONG) AddRef() { return 1; } + STDMETHODIMP_(ULONG) Release() { return 2; } + + STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) + { + if (NULL == ppvObject) + return E_POINTER; + if (riid == IID_IUnknown /*__uuidof(IUnknown) */ ) { + *ppvObject = static_cast(this); + return S_OK; + } + if (riid == IID_ISampleGrabberCB /*__uuidof(ISampleGrabberCB)*/ ) { + *ppvObject = static_cast(this); + return S_OK; + } + return E_NOTIMPL; + } + + STDMETHODIMP SampleCB(double Time, IMediaSample *pSample) + { + return E_NOTIMPL; + } + + STDMETHODIMP BufferCB(double Time, BYTE *pBuffer, long BufferLen) + { + if (!cs || active) { + return S_OK; + } + + if ((cs->StillMediaType.majortype != MEDIATYPE_Video) || + (cs->StillMediaType.formattype != FORMAT_VideoInfo) || + (cs->StillMediaType.cbFormat < sizeof(VIDEOINFOHEADER))) { + return VFW_E_INVALIDMEDIATYPE; + } + + active = true; + + if(toggle == true) { + toggle = false; + } + else { + toggle = true; + } + + if(toggle) { + active = false; + return S_OK; + } + + bool check = false; + cs->mutex.lock(); + + if (cs->frames.size() > LIMIT_FRAME) { + check = true; + } + + if (check) { + cs->mutex.unlock(); + // Frames building up. We're going to drop some here + Sleep(100); + active = false; + return S_OK; + } + cs->mutex.unlock(); + + unsigned char* vidData = new unsigned char[BufferLen]; + memcpy(vidData, pBuffer, BufferLen); + + cs->mutex.lock(); + + video_buffer* buf = new video_buffer; + buf->buffer = vidData; + buf->length = BufferLen; + buf->time = (qint64)Time; + + cs->frames.append(buf); + + cs->mutex.unlock(); + + QMetaObject::invokeMethod(cs, "captureFrame", Qt::QueuedConnection); + + active = false; + + return S_OK; + } + + DSCameraSession* cs; + bool active; + bool toggle; +}; + + +DSCameraSession::DSCameraSession(QObject *parent) + : QObject(parent) + ,m_currentImageId(0) +{ + pBuild = NULL; + pGraph = NULL; + pCap = NULL; + pSG_Filter = NULL; + pSG = NULL; + + opened = false; + available = false; + resolutions.clear(); + m_state = QCamera::UnloadedState; + m_device = "default"; + + StillCapCB = new SampleGrabberCallbackPrivate; + StillCapCB->cs = this; + StillCapCB->active = false; + StillCapCB->toggle = false; + + m_output = 0; + m_surface = 0; + m_windowSize = QSize(320,240); + pixelF = QVideoFrame::Format_RGB24; + actualFormat = QVideoSurfaceFormat(m_windowSize,pixelF); + + graph = false; + active = false; + + ::CoInitialize(NULL); +} + +DSCameraSession::~DSCameraSession() +{ + if (opened) { + closeStream(); + } + + CoUninitialize(); + + SAFE_RELEASE(pCap); + SAFE_RELEASE(pSG_Filter); + SAFE_RELEASE(pGraph); + SAFE_RELEASE(pBuild); + + if (StillCapCB) { + delete StillCapCB; + } +} + +int DSCameraSession::captureImage(const QString &fileName) +{ + emit readyForCaptureChanged(false); + + // We're going to do this in one big synchronous call + m_currentImageId++; + if (fileName.isEmpty()) { + m_snapshot = "img.jpg"; + } else { + m_snapshot = fileName; + } + + if (!active) { + startStream(); + } + + return m_currentImageId; +} + +void DSCameraSession::setSurface(QAbstractVideoSurface* surface) +{ + m_surface = surface; +} + +bool DSCameraSession::deviceReady() +{ + return available; +} + +bool DSCameraSession::pictureInProgress() +{ + return m_snapshot.isEmpty(); +} + +int DSCameraSession::framerate() const +{ + return -1; +} + +void DSCameraSession::setFrameRate(int rate) +{ + Q_UNUSED(rate) +} + +int DSCameraSession::brightness() const +{ + return -1; +} + +void DSCameraSession::setBrightness(int b) +{ + Q_UNUSED(b) +} + +int DSCameraSession::contrast() const +{ + return -1; +} + +void DSCameraSession::setContrast(int c) +{ + Q_UNUSED(c) +} + +int DSCameraSession::saturation() const +{ + return -1; +} + +void DSCameraSession::setSaturation(int s) +{ + Q_UNUSED(s) +} + +int DSCameraSession::hue() const +{ + return -1; +} + +void DSCameraSession::setHue(int h) +{ + Q_UNUSED(h) +} + +int DSCameraSession::sharpness() const +{ + return -1; +} + +void DSCameraSession::setSharpness(int s) +{ + Q_UNUSED(s) +} + +int DSCameraSession::zoom() const +{ + return -1; +} + +void DSCameraSession::setZoom(int z) +{ + Q_UNUSED(z) +} + +bool DSCameraSession::backlightCompensation() const +{ + return false; +} + +void DSCameraSession::setBacklightCompensation(bool b) +{ + Q_UNUSED(b) +} + +int DSCameraSession::whitelevel() const +{ + return -1; +} + +void DSCameraSession::setWhitelevel(int w) +{ + Q_UNUSED(w) +} + +int DSCameraSession::rotation() const +{ + return 0; +} + +void DSCameraSession::setRotation(int r) +{ + Q_UNUSED(r) +} + +bool DSCameraSession::flash() const +{ + return false; +} + +void DSCameraSession::setFlash(bool f) +{ + Q_UNUSED(f) +} + +bool DSCameraSession::autofocus() const +{ + return false; +} + +void DSCameraSession::setAutofocus(bool f) +{ + Q_UNUSED(f) +} + +QSize DSCameraSession::frameSize() const +{ + return m_windowSize; +} + +void DSCameraSession::setFrameSize(const QSize& s) +{ + if (supportedResolutions(pixelF).contains(s)) + m_windowSize = s; + else + qWarning() << "frame size if not supported for current pixel format, no change"; +} + +void DSCameraSession::setDevice(const QString &device) +{ + if(opened) + stopStream(); + + if(graph) { + SAFE_RELEASE(pCap); + SAFE_RELEASE(pSG_Filter); + SAFE_RELEASE(pGraph); + SAFE_RELEASE(pBuild); + } + + available = false; + m_state = QCamera::LoadedState; + + CoInitialize(NULL); + + ICreateDevEnum* pDevEnum = NULL; + IEnumMoniker* pEnum = NULL; + + // Create the System device enumerator + HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, + CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, + reinterpret_cast(&pDevEnum)); + if(SUCCEEDED(hr)) { + // Create the enumerator for the video capture category + hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0); + if (S_OK == hr) { + pEnum->Reset(); + // go through and find all video capture devices + IMoniker* pMoniker = NULL; + while(pEnum->Next(1, &pMoniker, NULL) == S_OK) { + IPropertyBag *pPropBag; + hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, + (void**)(&pPropBag)); + if(FAILED(hr)) { + pMoniker->Release(); + continue; // skip this one + } + // Find the description + WCHAR str[120]; + VARIANT varName; + varName.vt = VT_BSTR; + hr = pPropBag->Read(L"Description", &varName, 0); + if(FAILED(hr)) + hr = pPropBag->Read(L"FriendlyName", &varName, 0); + if(SUCCEEDED(hr)) { + wcsncpy(str, varName.bstrVal, sizeof(str)/sizeof(str[0])); + QString temp(QString::fromUtf16((unsigned short*)str)); + if(temp.contains(device)) { + available = true; + } + } + pPropBag->Release(); + pMoniker->Release(); + } + pEnum->Release(); + } + pDevEnum->Release(); + } + CoUninitialize(); + + if(available) { + m_device = QByteArray(device.toLocal8Bit().constData()); + graph = createFilterGraph(); + if(!graph) + available = false; + } +} + +QList DSCameraSession::supportedPixelFormats() +{ + return types; +} + +QVideoFrame::PixelFormat DSCameraSession::pixelFormat() const +{ + return pixelF; +} + +void DSCameraSession::setPixelFormat(QVideoFrame::PixelFormat fmt) +{ + pixelF = fmt; +} + +QList DSCameraSession::supportedResolutions(QVideoFrame::PixelFormat format) +{ + if (!resolutions.contains(format)) + return QList(); + return resolutions.value(format); +} + +bool DSCameraSession::setOutputLocation(const QUrl &sink) +{ + m_sink = sink; + + return true; +} + +QUrl DSCameraSession::outputLocation() const +{ + return m_sink; +} + +qint64 DSCameraSession::position() const +{ + return timeStamp.elapsed(); +} + +int DSCameraSession::state() const +{ + return int(m_state); +} + +void DSCameraSession::record() +{ + if(opened) { + return; + } + + if(m_surface) { + bool match = false; + + if (!m_surface->isFormatSupported(actualFormat)) { + QList fmts; + foreach(QVideoFrame::PixelFormat f, types) { + if (fmts.contains(f)) { + match = true; + pixelF = f; + actualFormat = QVideoSurfaceFormat(m_windowSize,pixelF); + break; + } + } + } + if (!m_surface->isFormatSupported(actualFormat) && !match) { + // fallback + if (types.contains(QVideoFrame::Format_RGB24)) { + // get RGB24 from camera and convert to RGB32 for surface! + pixelF = QVideoFrame::Format_RGB32; + actualFormat = QVideoSurfaceFormat(m_windowSize,pixelF); + } + } + + if (m_surface->isFormatSupported(actualFormat)) { + m_surface->start(actualFormat); + m_state = QCamera::ActiveState; + emit stateChanged(QCamera::ActiveState); + } else { + qWarning() << "surface doesn't support camera format, cant start"; + m_state = QCamera::LoadedState; + emit stateChanged(QCamera::LoadedState); + return; + } + } else { + qWarning() << "no video surface, cant start"; + m_state = QCamera::LoadedState; + emit stateChanged(QCamera::LoadedState); + return; + } + + opened = startStream(); + + if (!opened) { + qWarning() << "Stream did not open"; + m_state = QCamera::LoadedState; + emit stateChanged(QCamera::LoadedState); + } +} + +void DSCameraSession::pause() +{ + suspendStream(); +} + +void DSCameraSession::stop() +{ + if(!opened) { + return; + } + + stopStream(); + opened = false; + m_state = QCamera::LoadedState; + emit stateChanged(QCamera::LoadedState); +} + +void DSCameraSession::captureFrame() +{ + if(m_surface && frames.count() > 0) { + + QImage image; + + if(pixelF == QVideoFrame::Format_RGB24) { + + mutex.lock(); + + image = QImage(frames.at(0)->buffer,m_windowSize.width(),m_windowSize.height(), + QImage::Format_RGB888).rgbSwapped().mirrored(true); + + QVideoFrame frame(image); + frame.setStartTime(frames.at(0)->time); + + mutex.unlock(); + + m_surface->present(frame); + + } else if (pixelF == QVideoFrame::Format_RGB32) { + + mutex.lock(); + + image = QImage(frames.at(0)->buffer,m_windowSize.width(),m_windowSize.height(), + QImage::Format_RGB888).rgbSwapped().mirrored(true); + + QVideoFrame frame(image.convertToFormat(QImage::Format_RGB32)); + frame.setStartTime(frames.at(0)->time); + + mutex.unlock(); + + m_surface->present(frame); + + } else { + qWarning() << "TODO:captureFrame() format =" << pixelF; + } + + if (m_snapshot.length() > 0) { + emit imageCaptured(m_currentImageId, image); + image.save(m_snapshot,"JPG"); + emit imageSaved(m_currentImageId, m_snapshot); + m_snapshot.clear(); + emit readyForCaptureChanged(true); + } + + mutex.lock(); + if (frames.isEmpty()) { + qWarning() << "Frames over-run"; + } + + video_buffer* buf = frames.takeFirst(); + delete buf->buffer; + delete buf; + mutex.unlock(); + } +} + +HRESULT DSCameraSession::getPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin) +{ + *ppPin = 0; + IEnumPins *pEnum = 0; + IPin *pPin = 0; + + HRESULT hr = pFilter->EnumPins(&pEnum); + if(FAILED(hr)) { + return hr; + } + + pEnum->Reset(); + while(pEnum->Next(1, &pPin, NULL) == S_OK) { + PIN_DIRECTION ThisPinDir; + pPin->QueryDirection(&ThisPinDir); + if(ThisPinDir == PinDir) { + pEnum->Release(); + *ppPin = pPin; + return S_OK; + } + pEnum->Release(); + } + pEnum->Release(); + return E_FAIL; +} + +bool DSCameraSession::createFilterGraph() +{ + HRESULT hr; + IMoniker* pMoniker = NULL; + ICreateDevEnum* pDevEnum = NULL; + IEnumMoniker* pEnum = NULL; + + CoInitialize(NULL); + + // Create the filter graph + hr = CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC, + IID_IGraphBuilder, (void**)&pGraph); + if (FAILED(hr)) { + qWarning()<<"failed to create filter graph"; + return false; + } + + // Create the capture graph builder + hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, + IID_ICaptureGraphBuilder2, (void**)&pBuild); + if (FAILED(hr)) { + qWarning()<<"failed to create graph builder"; + return false; + } + + // Attach the filter graph to the capture graph + hr = pBuild->SetFiltergraph(pGraph); + if (FAILED(hr)) { + qWarning()<<"failed to connect capture graph and filter graph"; + return false; + } + + // Find the Capture device + hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, + CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, + reinterpret_cast(&pDevEnum)); + if (SUCCEEDED(hr)) { + // Create an enumerator for the video capture category + hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0); + pDevEnum->Release(); + if (S_OK == hr) { + pEnum->Reset(); + //go through and find all video capture devices + while (pEnum->Next(1, &pMoniker, NULL) == S_OK) { + IPropertyBag *pPropBag; + hr = pMoniker->BindToStorage(0, 0, + IID_IPropertyBag, (void**)(&pPropBag)); + if(FAILED(hr)) { + pMoniker->Release(); + continue; // skip this one + } + // Find the description + WCHAR str[120]; + VARIANT varName; + varName.vt = VT_BSTR; + hr = pPropBag->Read(L"FriendlyName", &varName, 0); + if (SUCCEEDED(hr)) { + // check if it is the selected device + wcsncpy(str, varName.bstrVal, sizeof(str)/sizeof(str[0])); + QString output = QString::fromUtf16((unsigned short*)str); + if (m_device.contains(output.toLocal8Bit().constData())) { + hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap); + if (SUCCEEDED(hr)) { + pPropBag->Release(); + pMoniker->Release(); + break; + } + } + } + pPropBag->Release(); + pMoniker->Release(); + } + if (NULL == pCap) + { + if (m_device.contains("default")) + { + pEnum->Reset(); + // still have to loop to discard bind to storage failure case + while (pEnum->Next(1, &pMoniker, NULL) == S_OK) { + IPropertyBag *pPropBag = 0; + + hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)(&pPropBag)); + if (FAILED(hr)) { + pMoniker->Release(); + continue; // Don't panic yet + } + + // No need to get the description, just grab it + + hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap); + pPropBag->Release(); + pMoniker->Release(); + if (SUCCEEDED(hr)) { + break; // done, stop looping through + } + else + { + qWarning() << "Object bind failed"; + } + } + } + } + pEnum->Release(); + } + } + + // Sample grabber filter + hr = CoCreateInstance(CLSID_SampleGrabber, NULL,CLSCTX_INPROC, + IID_IBaseFilter, (void**)&pSG_Filter); + if (FAILED(hr)) { + qWarning() << "failed to create sample grabber"; + return false; + } + + pSG_Filter->QueryInterface(IID_ISampleGrabber, (void**)&pSG); + if (FAILED(hr)) { + qWarning() << "failed to get sample grabber"; + return false; + } + pSG->SetOneShot(FALSE); + pSG->SetBufferSamples(TRUE); + pSG->SetCallback(StillCapCB, 1); + + CoUninitialize(); + + return true; +} + +void DSCameraSession::updateProperties() +{ + HRESULT hr; + AM_MEDIA_TYPE *pmt = NULL; + VIDEOINFOHEADER *pvi = NULL; + VIDEO_STREAM_CONFIG_CAPS scc; + IAMStreamConfig* pConfig = 0; + + hr = pBuild->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,pCap, + IID_IAMStreamConfig, (void**)&pConfig); + if (FAILED(hr)) { + qWarning()<<"failed to get config on capture device"; + return; + } + + int iCount; + int iSize; + hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize); + if (FAILED(hr)) { + qWarning()<<"failed to get capabilities"; + return; + } + + QList sizes; + QVideoFrame::PixelFormat f = QVideoFrame::Format_Invalid; + + types.clear(); + resolutions.clear(); + + for (int iIndex = 0; iIndex < iCount; iIndex++) { + hr = pConfig->GetStreamCaps(iIndex, &pmt, reinterpret_cast(&scc)); + if (hr == S_OK) { + pvi = (VIDEOINFOHEADER*)pmt->pbFormat; + if ((pmt->majortype == MEDIATYPE_Video) && + (pmt->formattype == FORMAT_VideoInfo)) { + // Add types + if (pmt->subtype == MEDIASUBTYPE_RGB24) { + if (!types.contains(QVideoFrame::Format_RGB24)) { + types.append(QVideoFrame::Format_RGB24); + f = QVideoFrame::Format_RGB24; + } + } else if (pmt->subtype == MEDIASUBTYPE_RGB32) { + if (!types.contains(QVideoFrame::Format_RGB32)) { + types.append(QVideoFrame::Format_RGB32); + f = QVideoFrame::Format_RGB32; + } + } else if (pmt->subtype == MEDIASUBTYPE_YUY2) { + if (!types.contains(QVideoFrame::Format_YUYV)) { + types.append(QVideoFrame::Format_YUYV); + f = QVideoFrame::Format_YUYV; + } + } else if (pmt->subtype == MEDIASUBTYPE_MJPG) { + } else if (pmt->subtype == MEDIASUBTYPE_I420) { + if (!types.contains(QVideoFrame::Format_YUV420P)) { + types.append(QVideoFrame::Format_YUV420P); + f = QVideoFrame::Format_YUV420P; + } + } else if (pmt->subtype == MEDIASUBTYPE_RGB555) { + if (!types.contains(QVideoFrame::Format_RGB555)) { + types.append(QVideoFrame::Format_RGB555); + f = QVideoFrame::Format_RGB555; + } + } else if (pmt->subtype == MEDIASUBTYPE_YVU9) { + } else if (pmt->subtype == MEDIASUBTYPE_UYVY) { + if (!types.contains(QVideoFrame::Format_UYVY)) { + types.append(QVideoFrame::Format_UYVY); + f = QVideoFrame::Format_UYVY; + } + } else { + qWarning() << "UNKNOWN FORMAT: " << pmt->subtype.Data1; + } + // Add resolutions + QSize res(pvi->bmiHeader.biWidth, pvi->bmiHeader.biHeight); + if (!resolutions.contains(f)) { + sizes.clear(); + resolutions.insert(f,sizes); + } + resolutions[f].append(res); + } + } + } + pConfig->Release(); +} + +bool DSCameraSession::setProperties() +{ + CoInitialize(NULL); + + HRESULT hr; + AM_MEDIA_TYPE am_media_type; + AM_MEDIA_TYPE *pmt = NULL; + VIDEOINFOHEADER *pvi = NULL; + VIDEO_STREAM_CONFIG_CAPS scc; + + IAMStreamConfig* pConfig = 0; + hr = pBuild->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pCap, + IID_IAMStreamConfig, (void**)&pConfig); + if(FAILED(hr)) { + qWarning()<<"failed to get config on capture device"; + return false; + } + + int iCount; + int iSize; + hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize); + if(FAILED(hr)) { + qWarning()<<"failed to get capabilities"; + return false; + } + + bool setFormatOK = false; + for (int iIndex = 0; iIndex < iCount; iIndex++) { + hr = pConfig->GetStreamCaps(iIndex, &pmt, reinterpret_cast(&scc)); + if (hr == S_OK) { + pvi = (VIDEOINFOHEADER*)pmt->pbFormat; + + if ((pmt->majortype == MEDIATYPE_Video) && + (pmt->formattype == FORMAT_VideoInfo)) { + if ((actualFormat.frameWidth() == pvi->bmiHeader.biWidth) && + (actualFormat.frameHeight() == pvi->bmiHeader.biHeight)) { + hr = pConfig->SetFormat(pmt); + _FreeMediaType(*pmt); + if(FAILED(hr)) { + qWarning()<<"failed to set format:" << hr; + qWarning()<<"but going to continue"; + continue; // We going to continue + } else { + setFormatOK = true; + break; + } + } + } + } + } + pConfig->Release(); + + if (!setFormatOK) { + qWarning() << "unable to set any format for camera"; + return false; + } + + // Set Sample Grabber config to match capture + ZeroMemory(&am_media_type, sizeof(am_media_type)); + am_media_type.majortype = MEDIATYPE_Video; + + if (actualFormat.pixelFormat() == QVideoFrame::Format_RGB32) + am_media_type.subtype = MEDIASUBTYPE_RGB24; + else if (actualFormat.pixelFormat() == QVideoFrame::Format_RGB24) + am_media_type.subtype = MEDIASUBTYPE_RGB24; + else if (actualFormat.pixelFormat() == QVideoFrame::Format_YUYV) + am_media_type.subtype = MEDIASUBTYPE_YUY2; + else if (actualFormat.pixelFormat() == QVideoFrame::Format_YUV420P) + am_media_type.subtype = MEDIASUBTYPE_I420; + else if (actualFormat.pixelFormat() == QVideoFrame::Format_RGB555) + am_media_type.subtype = MEDIASUBTYPE_RGB555; + else if (actualFormat.pixelFormat() == QVideoFrame::Format_UYVY) + am_media_type.subtype = MEDIASUBTYPE_UYVY; + else { + qWarning()<<"unknown format? for SG"; + return false; + } + + am_media_type.formattype = FORMAT_VideoInfo; + hr = pSG->SetMediaType(&am_media_type); + if (FAILED(hr)) { + qWarning()<<"failed to set video format on grabber"; + return false; + } + + pSG->GetConnectedMediaType(&StillMediaType); + + CoUninitialize(); + + return true; +} + +bool DSCameraSession::openStream() +{ + //Opens the stream for reading and allocates any necessary resources needed + //Return true if success, false otherwise + + if (opened) { + return true; + } + + if (!graph) { + graph = createFilterGraph(); + if(!graph) { + qWarning()<<"failed to create filter graph in openStream"; + return false; + } + } + + CoInitialize(NULL); + + HRESULT hr; + + hr = pGraph->AddFilter(pCap, L"Capture Filter"); + if (FAILED(hr)) { + qWarning()<<"failed to create capture filter"; + return false; + } + + hr = pGraph->AddFilter(pSG_Filter, L"Sample Grabber"); + if (FAILED(hr)) { + qWarning()<<"failed to add sample grabber"; + return false; + } + + hr = pBuild->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, + pCap, NULL, pSG_Filter); + if (FAILED(hr)) { + qWarning() << "failed to renderstream" << hr; + return false; + } + pSG->GetConnectedMediaType(&StillMediaType); + pSG_Filter->Release(); + + CoUninitialize(); + + return true; +} + +void DSCameraSession::closeStream() +{ + // Closes the stream and internally frees any resources used + HRESULT hr; + IMediaControl* pControl = 0; + + hr = pGraph->QueryInterface(IID_IMediaControl,(void**)&pControl); + if (FAILED(hr)) { + qWarning()<<"failed to get stream control"; + return; + } + + hr = pControl->StopWhenReady(); + if (FAILED(hr)) { + qWarning()<<"failed to stop"; + pControl->Release(); + return; + } + + pControl->Release(); + + opened = false; + IPin *pPin = 0; + + if (pCap) + { + hr = getPin(pCap, PINDIR_OUTPUT, &pPin); + if(FAILED(hr)) { + qWarning()<<"failed to disconnect capture filter"; + return; + } + } + + pGraph->Disconnect(pPin); + if (FAILED(hr)) { + qWarning()<<"failed to disconnect grabber filter"; + return; + } + + hr = getPin(pSG_Filter,PINDIR_INPUT,&pPin); + pGraph->Disconnect(pPin); + pGraph->RemoveFilter(pSG_Filter); + pGraph->RemoveFilter(pCap); + + SAFE_RELEASE(pCap); + SAFE_RELEASE(pSG_Filter); + SAFE_RELEASE(pGraph); + SAFE_RELEASE(pBuild); + + graph = false; +} + +bool DSCameraSession::startStream() +{ + // Starts the stream, by emitting either QVideoPackets + // or QvideoFrames, depending on Format chosen + if (!graph) + graph = createFilterGraph(); + + if (!setProperties()) { + qWarning() << "Couldn't set properties (retrying)"; + closeStream(); + if (!openStream()) { + qWarning() << "Retry to open strean failed"; + return false; + } + } + + if (!opened) { + opened = openStream(); + if (!opened) { + qWarning() << "failed to openStream()"; + return false; + } + } + + HRESULT hr; + IMediaControl* pControl = 0; + + hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl); + if (FAILED(hr)) { + qWarning() << "failed to get stream control"; + return false; + } + + hr = pControl->Run(); + pControl->Release(); + + if (FAILED(hr)) { + qWarning() << "failed to start"; + return false; + } + active = true; + return true; +} + +void DSCameraSession::stopStream() +{ + // Stops the stream from emitting packets + HRESULT hr; + + IMediaControl* pControl = 0; + hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl); + if (FAILED(hr)) { + qWarning() << "failed to get stream control"; + return; + } + + hr = pControl->Stop(); + pControl->Release(); + if (FAILED(hr)) { + qWarning() << "failed to stop"; + return; + } + active = false; + + if (opened) { + closeStream(); + } +} + +void DSCameraSession::suspendStream() +{ + // Pauses the stream + HRESULT hr; + + IMediaControl* pControl = 0; + hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl); + if (FAILED(hr)) { + qWarning() << "failed to get stream control"; + return; + } + + hr = pControl->Pause(); + pControl->Release(); + if (FAILED(hr)) { + qWarning() << "failed to pause"; + return; + } + + active = false; +} + +void DSCameraSession::resumeStream() +{ + // Resumes a paused stream + startStream(); +} + +QT_END_NAMESPACE + diff --git a/src/plugins/directshow/camera/dscamerasession.h b/src/plugins/directshow/camera/dscamerasession.h new file mode 100644 index 000000000..72a0e5077 --- /dev/null +++ b/src/plugins/directshow/camera/dscamerasession.h @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DSCAMERASESSION_H +#define DSCAMERASESSION_H + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#pragma comment(lib, "strmiids.lib") +#pragma comment(lib, "ole32.lib") +#include + +#pragma include_alias("dxtrans.h","qedit.h") +#define __IDxtCompositor_INTERFACE_DEFINED__ +#define __IDxtAlphaSetter_INTERFACE_DEFINED__ +#define __IDxtJpeg_INTERFACE_DEFINED__ +#define __IDxtKey_INTERFACE_DEFINED__ +#include + +struct ICaptureGraphBuilder2; +struct ISampleGrabber; + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DSVideoRenderer; +class SampleGrabberCallbackPrivate; + + +struct video_buffer { + unsigned char* buffer; + int length; + qint64 time; +}; + +typedef QMap > FormatResolutionMap; + +class DSCameraSession : public QObject +{ + Q_OBJECT +public: + DSCameraSession(QObject *parent = 0); + ~DSCameraSession(); + + bool deviceReady(); + bool pictureInProgress(); + + // camera controls + + int framerate() const; + void setFrameRate(int rate); + int brightness() const; + void setBrightness(int b); + int contrast() const; + void setContrast(int c); + int saturation() const; + void setSaturation(int s); + int hue() const; + void setHue(int h); + int sharpness() const; + void setSharpness(int s); + int zoom() const; + void setZoom(int z); + bool backlightCompensation() const; + void setBacklightCompensation(bool); + int whitelevel() const; + void setWhitelevel(int w); + int rotation() const; + void setRotation(int r); + bool flash() const; + void setFlash(bool f); + bool autofocus() const; + void setAutofocus(bool f); + + QSize frameSize() const; + void setFrameSize(const QSize& s); + void setDevice(const QString &device); + QList supportedPixelFormats(); + QVideoFrame::PixelFormat pixelFormat() const; + void setPixelFormat(QVideoFrame::PixelFormat fmt); + QList supportedResolutions(QVideoFrame::PixelFormat format); + + // media control + + bool setOutputLocation(const QUrl &sink); + QUrl outputLocation() const; + qint64 position() const; + int state() const; + void record(); + void pause(); + void stop(); + + void setSurface(QAbstractVideoSurface* surface); + + int captureImage(const QString &fileName); + + AM_MEDIA_TYPE StillMediaType; + QList frames; + SampleGrabberCallbackPrivate* StillCapCB; + + QMutex mutex; + +Q_SIGNALS: + void stateChanged(QCamera::State); + void imageCaptured(int id, const QImage &preview); + void imageSaved(int id, const QString &fileName); + void readyForCaptureChanged(bool); + +private Q_SLOTS: + void captureFrame(); + +private: + QVideoSurfaceFormat actualFormat; + QList types; + + QTime timeStamp; + bool graph; + bool active; + bool opened; + bool available; + QCamera::State m_state; + QByteArray m_device; + QUrl m_sink; + DSVideoRenderer* m_output; + QAbstractVideoSurface* m_surface; + QVideoFrame::PixelFormat pixelF; + QSize m_windowSize; + FormatResolutionMap resolutions; + + ICaptureGraphBuilder2* pBuild; + IGraphBuilder* pGraph; + IBaseFilter* pCap; + IBaseFilter* pSG_Filter; + ISampleGrabber *pSG; + + + QString m_snapshot; + int m_currentImageId; +protected: + HRESULT getPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin); + bool createFilterGraph(); + void updateProperties(); + bool setProperties(); + bool openStream(); + void closeStream(); + bool startStream(); + void stopStream(); + void suspendStream(); + void resumeStream(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/plugins/directshow/camera/dsimagecapturecontrol.cpp b/src/plugins/directshow/camera/dsimagecapturecontrol.cpp new file mode 100644 index 000000000..17654c4a5 --- /dev/null +++ b/src/plugins/directshow/camera/dsimagecapturecontrol.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "dsimagecapturecontrol.h" + +QT_BEGIN_NAMESPACE + +DSImageCaptureControl::DSImageCaptureControl(DSCameraSession *session) + :QCameraImageCaptureControl(session), m_session(session), m_ready(false) +{ + connect(m_session, SIGNAL(stateChanged(QCamera::State)), SLOT(updateState())); + connect(m_session, SIGNAL(imageCaptured(const int, QImage)), + this, SIGNAL(imageCaptured(const int, QImage))); + connect(m_session, SIGNAL(imageSaved(const int, const QString &)), + this, SIGNAL(imageSaved(const int, const QString &))); + connect(m_session, SIGNAL(readyForCaptureChanged(bool)), + this, SIGNAL(readyForCaptureChanged(bool))); +} + +DSImageCaptureControl::~DSImageCaptureControl() +{ +} + +bool DSImageCaptureControl::isReadyForCapture() const +{ + return m_ready; +} + +int DSImageCaptureControl::capture(const QString &fileName) +{ + return m_session->captureImage(fileName); +} + +void DSImageCaptureControl::updateState() +{ + bool ready = (m_session->state() == QCamera::ActiveState) && + !m_session->pictureInProgress(); + if(m_ready != ready) + emit readyForCaptureChanged(m_ready = ready); +} + +QT_END_NAMESPACE + diff --git a/src/plugins/directshow/camera/dsimagecapturecontrol.h b/src/plugins/directshow/camera/dsimagecapturecontrol.h new file mode 100644 index 000000000..8eca7b4e7 --- /dev/null +++ b/src/plugins/directshow/camera/dsimagecapturecontrol.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DSIMAGECAPTURECONTROL_H +#define DSIMAGECAPTURECONTROL_H + +#include +#include "dscamerasession.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DSImageCaptureControl : public QCameraImageCaptureControl +{ + Q_OBJECT +public: + DSImageCaptureControl(DSCameraSession *session); + virtual ~DSImageCaptureControl(); + + bool isReadyForCapture() const; + int capture(const QString &fileName); + + virtual QCameraImageCapture::DriveMode driveMode() const { return QCameraImageCapture::SingleImageCapture; } + virtual void setDriveMode(QCameraImageCapture::DriveMode mode) { } + + virtual void cancelCapture() {} + +private slots: + void updateState(); + + +private: + DSCameraSession *m_session; + bool m_ready; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // DSCAPTURECONTROL_H diff --git a/src/plugins/directshow/camera/dsvideodevicecontrol.cpp b/src/plugins/directshow/camera/dsvideodevicecontrol.cpp new file mode 100644 index 000000000..8c9b03000 --- /dev/null +++ b/src/plugins/directshow/camera/dsvideodevicecontrol.cpp @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +#include "dsvideodevicecontrol.h" +#include "dscamerasession.h" + +#include +#include +#include +#include +#include +#include + +extern const CLSID CLSID_VideoInputDeviceCategory; + +QT_BEGIN_NAMESPACE + +DSVideoDeviceControl::DSVideoDeviceControl(QObject *parent) + : QVideoDeviceControl(parent) +{ + m_session = qobject_cast(parent); + + devices.clear(); + descriptions.clear(); + + CoInitialize(NULL); + ICreateDevEnum* pDevEnum = NULL; + IEnumMoniker* pEnum = NULL; + // Create the System device enumerator + HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, + CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, + reinterpret_cast(&pDevEnum)); + if(SUCCEEDED(hr)) { + // Create the enumerator for the video capture category + hr = pDevEnum->CreateClassEnumerator( + CLSID_VideoInputDeviceCategory, &pEnum, 0); + if (S_OK == hr) { + pEnum->Reset(); + // go through and find all video capture devices + IMoniker* pMoniker = NULL; + while(pEnum->Next(1, &pMoniker, NULL) == S_OK) { + IPropertyBag *pPropBag; + hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, + (void**)(&pPropBag)); + if(FAILED(hr)) { + pMoniker->Release(); + continue; // skip this one + } + // Find the description + WCHAR str[120]; + VARIANT varName; + varName.vt = VT_BSTR; + hr = pPropBag->Read(L"FriendlyName", &varName, 0); + if(SUCCEEDED(hr)) { + wcsncpy(str, varName.bstrVal, sizeof(str)/sizeof(str[0])); + QString temp(QString::fromUtf16((unsigned short*)str)); + devices.append(QString("ds:%1").arg(temp).toLocal8Bit().constData()); + hr = pPropBag->Read(L"Description", &varName, 0); + wcsncpy(str, varName.bstrVal, sizeof(str)/sizeof(str[0])); + QString temp2(QString::fromUtf16((unsigned short*)str)); + descriptions.append(temp2.toLocal8Bit().constData()); + } + pPropBag->Release(); + pMoniker->Release(); + } + pEnum->Release(); + } + pDevEnum->Release(); + } + CoUninitialize(); + + selected = 0; +} + +int DSVideoDeviceControl::deviceCount() const +{ + return devices.count(); +} + +QString DSVideoDeviceControl::deviceName(int index) const +{ + if(index >= 0 && index <= devices.count()) + return devices.at(index); + + return QString(); +} + +QString DSVideoDeviceControl::deviceDescription(int index) const +{ + if(index >= 0 && index <= descriptions.count()) + return descriptions.at(index); + + return QString(); +} + +QIcon DSVideoDeviceControl::deviceIcon(int index) const +{ + Q_UNUSED(index) + + return QIcon(); +} + +int DSVideoDeviceControl::defaultDevice() const +{ + return 0; +} + +int DSVideoDeviceControl::selectedDevice() const +{ + return selected; +} + +void DSVideoDeviceControl::setSelectedDevice(int index) +{ + if(index >= 0 && index <= devices.count()) { + if (m_session) { + QString device = devices.at(index); + if (device.startsWith("ds:")) + device.remove(0,3); + m_session->setDevice(device); + } + selected = index; + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/dsvideodevicecontrol.h b/src/plugins/directshow/camera/dsvideodevicecontrol.h new file mode 100644 index 000000000..8391c4eda --- /dev/null +++ b/src/plugins/directshow/camera/dsvideodevicecontrol.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DSVIDEODEVICECONTROL_H +#define DSVIDEODEVICECONTROL_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE +class DSCameraSession; + +//QTM_USE_NAMESPACE + +class DSVideoDeviceControl : public QVideoDeviceControl +{ + Q_OBJECT +public: + DSVideoDeviceControl(QObject *parent = 0); + + int deviceCount() const; + QString deviceName(int index) const; + QString deviceDescription(int index) const; + QIcon deviceIcon(int index) const; + int defaultDevice() const; + int selectedDevice() const; + +public Q_SLOTS: + void setSelectedDevice(int index); + +private: + DSCameraSession* m_session; + + QList devices; + QList descriptions; + + int selected; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/directshow/camera/dsvideorenderer.cpp b/src/plugins/directshow/camera/dsvideorenderer.cpp new file mode 100644 index 000000000..0fbdb15b1 --- /dev/null +++ b/src/plugins/directshow/camera/dsvideorenderer.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "dsvideorenderer.h" + +QT_BEGIN_NAMESPACE + +DSVideoRendererControl::DSVideoRendererControl(DSCameraSession* session, QObject *parent) + :QVideoRendererControl(parent), + m_surface(0), + m_session(session) +{ +} + +DSVideoRendererControl::~DSVideoRendererControl() +{ +} + +QAbstractVideoSurface* DSVideoRendererControl::surface() const +{ + return m_surface; +} + +void DSVideoRendererControl::setSurface(QAbstractVideoSurface *surface) +{ + m_surface = surface; + if(m_session) + m_session->setSurface(m_surface); +} + +QT_END_NAMESPACE + diff --git a/src/plugins/directshow/camera/dsvideorenderer.h b/src/plugins/directshow/camera/dsvideorenderer.h new file mode 100644 index 000000000..b941504ac --- /dev/null +++ b/src/plugins/directshow/camera/dsvideorenderer.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DSVIDEORENDERER_H +#define DSVIDEORENDERER_H + +#include +#include "dscamerasession.h" + +class CameraFormatConverter; + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class DSVideoRendererControl : public QVideoRendererControl +{ + Q_OBJECT +public: + DSVideoRendererControl(DSCameraSession* session, QObject *parent = 0); + ~DSVideoRendererControl(); + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + + void setSession(DSCameraSession* session); + +private: + QAbstractVideoSurface* m_surface; + DSCameraSession* m_session; + CameraFormatConverter* converter; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // DSVIDEORENDERER_H diff --git a/src/plugins/directshow/camera/dsvideowidgetcontrol.cpp b/src/plugins/directshow/camera/dsvideowidgetcontrol.cpp new file mode 100644 index 000000000..8298c0275 --- /dev/null +++ b/src/plugins/directshow/camera/dsvideowidgetcontrol.cpp @@ -0,0 +1,250 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "DSVideoWidgetControl.h" +#include "dscamerasession.h" + +QT_BEGIN_NAMESPACE + +DSVideoWidgetSurface::DSVideoWidgetSurface(QLabel *pWidget, QObject *parent) +{ + widget = pWidget; + myPixmap = 0; +} + +QList DSVideoWidgetSurface::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + if (handleType == QAbstractVideoBuffer::NoHandle) { + return QList() + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_RGB24; + } else { + return QList(); + } +} + + +bool DSVideoWidgetSurface::present(const QVideoFrame &frame) +{ + QVideoFrame myFrame = frame; + myFrame.map(QAbstractVideoBuffer::ReadOnly); + QImage image( + frame.bits(), + frame.width(), + frame.height(), + frame.bytesPerLine(), + imageFormat); + if (image.isNull()) + { + // Try to adapt + QImage image2( + frame.bits(), + frame.width(), + frame.height(), + frame.bytesPerLine(), + QImage::Format_RGB888); + image = image2; + } + myFrame.unmap(); + delete myPixmap; + myPixmap = new QPixmap(QPixmap::fromImage(image).scaled(widget->size())); + widget->setPixmap(*myPixmap); + widget->repaint(); + return true; +} + +void DSVideoWidgetSurface::setImageFormat(QImage::Format fmt) +{ + imageFormat = fmt; +} + +void DSVideoWidgetSurface::updateVideoRect() +{ +} + +void DSVideoWidgetSurface::paint(QPainter *painter) +{ +} + + +DSVideoWidgetControl::DSVideoWidgetControl(DSCameraSession* session, QObject *parent) : + m_session(session), QVideoWidgetControl(parent), + m_widget(new QLabel()), + m_fullScreen(false) +{ + m_widget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + m_widget->setAlignment(Qt::AlignCenter); + m_widget->setAttribute(Qt::WA_NoSystemBackground, true); + + surface = new DSVideoWidgetSurface(m_widget); + + QPalette palette; + palette.setColor(QPalette::Background, Qt::black); + m_widget->setPalette(palette); + m_widget->setAutoFillBackground( true ); + + // Request QEvents + m_widget->installEventFilter(this); + m_windowId = m_widget->effectiveWinId(); + + surface->setImageFormat(QImage::Format_RGB888); + session->setSurface(surface); +} + +DSVideoWidgetControl::~DSVideoWidgetControl() +{ + delete m_widget; +} + +bool DSVideoWidgetControl::eventFilter(QObject *object, QEvent *e) +{ + if (object == m_widget) { + switch (e->type()) { + case QEvent::ParentChange: + case QEvent::WinIdChange: + case QEvent::Show: + m_windowId = m_widget->effectiveWinId(); + emit widgetUpdated(); + break; + case QEvent::Resize: + emit widgetResized(m_widget->size()); + break; + case QEvent::PolishRequest: + m_widget->ensurePolished(); + break; + + default: + // Do nothing + break; + } + } + return false; +} + +QWidget *DSVideoWidgetControl::videoWidget() +{ + return m_widget; +} + +Qt::AspectRatioMode DSVideoWidgetControl::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void DSVideoWidgetControl::setAspectRatioMode(Qt::AspectRatioMode ratio) +{ + if (m_aspectRatioMode==ratio) { + return; + } + m_aspectRatioMode = ratio; + + if (m_aspectRatioMode == Qt::KeepAspectRatio) + m_widget->setScaledContents(false); + else { + m_widget->setScaledContents(true); + } +} + +bool DSVideoWidgetControl::isFullScreen() const +{ + return m_fullScreen; +} + +void DSVideoWidgetControl::setFullScreen(bool fullScreen) +{ + if (m_widget && !fullScreen && m_fullScreen) { + m_widget->showNormal(); + m_fullScreen = false; + } else if (m_widget && fullScreen) { + m_widget->showFullScreen(); + m_fullScreen = true; + } + + emit fullScreenChanged(fullScreen); +} + +int DSVideoWidgetControl::brightness() const +{ + return 0; +} + +void DSVideoWidgetControl::setBrightness(int brightness) +{ + Q_UNUSED(brightness); +} + +int DSVideoWidgetControl::contrast() const +{ + return 0; +} + +void DSVideoWidgetControl::setContrast(int contrast) +{ + Q_UNUSED(contrast); +} + +int DSVideoWidgetControl::hue() const +{ + return 0; +} + +void DSVideoWidgetControl::setHue(int hue) +{ + Q_UNUSED(hue); +} + +int DSVideoWidgetControl::saturation() const +{ + return 0; +} + +void DSVideoWidgetControl::setSaturation(int saturation) +{ + Q_UNUSED(saturation); +} + +QT_END_NAMESPACE + +// End of file diff --git a/src/plugins/directshow/camera/dsvideowidgetcontrol.h b/src/plugins/directshow/camera/dsvideowidgetcontrol.h new file mode 100644 index 000000000..e17827453 --- /dev/null +++ b/src/plugins/directshow/camera/dsvideowidgetcontrol.h @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DSVIDEOWIDGETCONTROL_H +#define DSVIDEOWIDGETCONTROL_H + +#include +#include +#include +#include +#include + +#include +#include "DsCameraControl.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DSVideoWidgetSurface : public QAbstractVideoSurface +{ + Q_OBJECT + public: + DSVideoWidgetSurface(QLabel *pWidget, QObject *parent = 0); + + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const; + + bool present(const QVideoFrame &frame); + + QRect videoRect() const { return targetRect; } + void updateVideoRect(); + + void paint(QPainter *painter); + void setImageFormat(QImage::Format fmt); + + private: + QLabel *widget; + QImage::Format imageFormat; + QRect targetRect; + QSize imageSize; + QRect sourceRect; + QPixmap* myPixmap; + }; + +class DSVideoWidgetControl : public QVideoWidgetControl +{ + Q_OBJECT + + DSVideoWidgetSurface* surface; +public: // Constructor & Destructor + + DSVideoWidgetControl(DSCameraSession* session, QObject *parent = 0); + virtual ~DSVideoWidgetControl(); + +public: // QVideoWidgetControl + + QWidget *videoWidget(); + + // Aspect Ratio + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode ratio); + + // Full Screen + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + // Brightness + int brightness() const; + void setBrightness(int brightness); + + // Contrast + int contrast() const; + void setContrast(int contrast); + + // Hue + int hue() const; + void setHue(int hue); + + // Saturation + int saturation() const; + void setSaturation(int saturation); + +public: // Internal + + bool eventFilter(QObject *object, QEvent *event); + +/* +Q_SIGNALS: // QVideoWidgetControl + + void fullScreenChanged(bool fullScreen); + void brightnessChanged(int brightness); + void contrastChanged(int contrast); + void hueChanged(int hue); + void saturationChanged(int saturation); +*/ + +Q_SIGNALS: // Internal Signals + + void widgetResized(QSize size); + void widgetUpdated(); + +private: // Data + + DSCameraSession* m_session; + QLabel *m_widget; + WId m_windowId; + Qt::AspectRatioMode m_aspectRatioMode; + bool m_fullScreen; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // DSVideoWidgetControl_H diff --git a/src/plugins/directshow/directshow.pro b/src/plugins/directshow/directshow.pro new file mode 100644 index 000000000..58e98c385 --- /dev/null +++ b/src/plugins/directshow/directshow.pro @@ -0,0 +1,23 @@ +TEMPLATE = lib + +CONFIG += plugin +TARGET = $$qtLibraryTarget(dsengine) + +PLUGIN_TYPE=mediaservice + +include (../../../common.pri) +INCLUDEPATH+=../../multimediakit \ + ../../multimediakit/audio \ + ../../multimediakit/video + +qtAddLibrary(QtMultimediaKit) + +DEPENDPATH += . + +HEADERS += dsserviceplugin.h +SOURCES += dsserviceplugin.cpp + +!contains(wmsdk_enabled, yes): DEFINES += QT_NO_WMSDK + +include (player/player.pri) +include (camera/camera.pri) diff --git a/src/plugins/directshow/dsserviceplugin.cpp b/src/plugins/directshow/dsserviceplugin.cpp new file mode 100644 index 000000000..9c0a21449 --- /dev/null +++ b/src/plugins/directshow/dsserviceplugin.cpp @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +#include "dsserviceplugin.h" + + +#ifdef QMEDIA_DIRECTSHOW_CAMERA +#include "dscameraservice.h" +#endif + +#ifdef QMEDIA_DIRECTSHOW_PLAYER +#include "directshowplayerservice.h" +#endif + +#include + + +#ifdef QMEDIA_DIRECTSHOW_CAMERA + +extern const CLSID CLSID_VideoInputDeviceCategory; + + +#ifndef _STRSAFE_H_INCLUDED_ +#include +#endif +#include +#include +#include +#pragma comment(lib, "strmiids.lib") +#pragma comment(lib, "ole32.lib") +#include +#include +#endif + +QT_USE_NAMESPACE + +QStringList DSServicePlugin::keys() const +{ + return QStringList() +#ifdef QMEDIA_DIRECTSHOW_CAMERA + << QLatin1String(Q_MEDIASERVICE_CAMERA) +#endif +#ifdef QMEDIA_DIRECTSHOW_PLAYER + << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER) +#endif + ; +} + +QMediaService* DSServicePlugin::create(QString const& key) +{ +#ifdef QMEDIA_DIRECTSHOW_CAMERA + if (key == QLatin1String(Q_MEDIASERVICE_CAMERA)) + return new DSCameraService; +#endif +#ifdef QMEDIA_DIRECTSHOW_PLAYER + if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER)) + return new DirectShowPlayerService; +#endif + + qDebug() << "unsupported key:" << key; + return 0; +} + +void DSServicePlugin::release(QMediaService *service) +{ + delete service; +} + +QMediaServiceProviderHint::Features DSServicePlugin::supportedFeatures( + const QByteArray &service) const +{ + if (service == Q_MEDIASERVICE_MEDIAPLAYER) + return QMediaServiceProviderHint::StreamPlayback | QMediaServiceProviderHint::VideoSurface; + else + return QMediaServiceProviderHint::Features(); +} + +QList DSServicePlugin::devices(const QByteArray &service) const +{ +#ifdef QMEDIA_DIRECTSHOW_CAMERA + if (service == Q_MEDIASERVICE_CAMERA) { + if (m_cameraDevices.isEmpty()) + updateDevices(); + + return m_cameraDevices; + } +#endif + + return QList(); +} + +QString DSServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device) +{ +#ifdef QMEDIA_DIRECTSHOW_CAMERA + if (service == Q_MEDIASERVICE_CAMERA) { + if (m_cameraDevices.isEmpty()) + updateDevices(); + + for (int i=0; i(&pDevEnum)); + if(SUCCEEDED(hr)) { + // Create the enumerator for the video capture category + hr = pDevEnum->CreateClassEnumerator( + CLSID_VideoInputDeviceCategory, &pEnum, 0); + if (S_OK == hr) { + pEnum->Reset(); + // go through and find all video capture devices + IMoniker* pMoniker = NULL; + while(pEnum->Next(1, &pMoniker, NULL) == S_OK) { + IPropertyBag *pPropBag; + hr = pMoniker->BindToStorage(0,0,IID_IPropertyBag, + (void**)(&pPropBag)); + if(FAILED(hr)) { + pMoniker->Release(); + continue; // skip this one + } + bFound = TRUE; + // Find the description + WCHAR str[120]; + VARIANT varName; + varName.vt = VT_BSTR; + hr = pPropBag->Read(L"FriendlyName", &varName, 0); + if(SUCCEEDED(hr)) { + wcsncpy(str, varName.bstrVal, sizeof(str)/sizeof(str[0])); + QString temp(QString::fromUtf16((unsigned short*)str)); + m_cameraDevices.append(QString("ds:%1").arg(temp).toLocal8Bit().constData()); + hr = pPropBag->Read(L"Description", &varName, 0); + wcsncpy(str, varName.bstrVal, sizeof(str)/sizeof(str[0])); + QString temp2(QString::fromUtf16((unsigned short*)str)); + m_cameraDescriptions.append(temp2); + } else { + qWarning() << "No friendly name"; + } + pPropBag->Release(); + pMoniker->Release(); + } + pEnum->Release(); + } + pDevEnum->Release(); + } + CoUninitialize(); + if (!bFound) { + qWarning() << "No camera devices found"; + } +} +#endif + +Q_EXPORT_PLUGIN2(qtmedia_dsengine, DSServicePlugin); + diff --git a/src/plugins/directshow/dsserviceplugin.h b/src/plugins/directshow/dsserviceplugin.h new file mode 100644 index 000000000..336da0a3f --- /dev/null +++ b/src/plugins/directshow/dsserviceplugin.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DSSERVICEPLUGIN_H +#define DSSERVICEPLUGIN_H + +#include "qmediaserviceproviderplugin.h" + +QT_USE_NAMESPACE + +class DSServicePlugin + : public QMediaServiceProviderPlugin + , public QMediaServiceSupportedDevicesInterface + , public QMediaServiceFeaturesInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceSupportedDevicesInterface) + Q_INTERFACES(QMediaServiceFeaturesInterface) +public: + QStringList keys() const; + QMediaService* create(QString const& key); + void release(QMediaService *service); + + QMediaServiceProviderHint::Features supportedFeatures(const QByteArray &service) const; + + QList devices(const QByteArray &service) const; + QString deviceDescription(const QByteArray &service, const QByteArray &device); + +private: +#ifdef QMEDIA_DIRECTSHOW_CAMERA + void updateDevices() const; + + mutable QList m_cameraDevices; + mutable QStringList m_cameraDescriptions; +#endif +}; + +#endif // DSSERVICEPLUGIN_H diff --git a/src/plugins/directshow/player/directshowaudioendpointcontrol.cpp b/src/plugins/directshow/player/directshowaudioendpointcontrol.cpp new file mode 100644 index 000000000..01c879732 --- /dev/null +++ b/src/plugins/directshow/player/directshowaudioendpointcontrol.cpp @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "directshowaudioendpointcontrol.h" + +#include "directshowglobal.h" +#include "directshowplayerservice.h" + +DirectShowAudioEndpointControl::DirectShowAudioEndpointControl( + DirectShowPlayerService *service, QObject *parent) + : QAudioEndpointSelector(parent) + , m_service(service) + , m_bindContext(0) + , m_deviceEnumerator(0) +{ + if (CreateBindCtx(0, &m_bindContext) == S_OK) { + m_deviceEnumerator = com_new(CLSID_SystemDeviceEnum, IID_ICreateDevEnum); + + updateEndpoints(); + + setActiveEndpoint(m_defaultEndpoint); + } +} + +DirectShowAudioEndpointControl::~DirectShowAudioEndpointControl() +{ + foreach (IMoniker *moniker, m_devices) + moniker->Release(); + + if (m_bindContext) + m_bindContext->Release(); + + if (m_deviceEnumerator) + m_deviceEnumerator->Release(); +} + +QList DirectShowAudioEndpointControl::availableEndpoints() const +{ + return m_devices.keys(); +} + +QString DirectShowAudioEndpointControl::endpointDescription(const QString &name) const +{ +#ifdef __IPropertyBag_INTERFACE_DEFINED__ + QString description; + + if (IMoniker *moniker = m_devices.value(name, 0)) { + IPropertyBag *propertyBag = 0; + if (SUCCEEDED(moniker->BindToStorage( + 0, 0, IID_IPropertyBag, reinterpret_cast(&propertyBag)))) { + VARIANT name; + VariantInit(&name); + if (SUCCEEDED(propertyBag->Read(L"FriendlyName", &name, 0))) + description = QString::fromWCharArray(name.bstrVal); + VariantClear(&name); + propertyBag->Release(); + } + } + + return description; +#else + return name.section(QLatin1Char('\\'), -1); +#endif +} + +QString DirectShowAudioEndpointControl::defaultEndpoint() const +{ + return m_defaultEndpoint; +} + +QString DirectShowAudioEndpointControl::activeEndpoint() const +{ + return m_activeEndpoint; +} + +void DirectShowAudioEndpointControl::setActiveEndpoint(const QString &name) +{ + if (m_activeEndpoint == name) + return; + + if (IMoniker *moniker = m_devices.value(name, 0)) { + IBaseFilter *filter = 0; + + if (moniker->BindToObject( + m_bindContext, + 0, + IID_IBaseFilter, + reinterpret_cast(&filter)) == S_OK) { + m_service->setAudioOutput(filter); + + filter->Release(); + } + } +} + +void DirectShowAudioEndpointControl::updateEndpoints() +{ + IMalloc *oleMalloc = 0; + if (m_deviceEnumerator && CoGetMalloc(1, &oleMalloc) == S_OK) { + IEnumMoniker *monikers = 0; + + if (m_deviceEnumerator->CreateClassEnumerator( + CLSID_AudioRendererCategory, &monikers, 0) == S_OK) { + for (IMoniker *moniker = 0; monikers->Next(1, &moniker, 0) == S_OK; moniker->Release()) { + OLECHAR *string = 0; + if (moniker->GetDisplayName(m_bindContext, 0, &string) == S_OK) { + QString deviceId = QString::fromWCharArray(string); + oleMalloc->Free(string); + + moniker->AddRef(); + m_devices.insert(deviceId, moniker); + + if (m_defaultEndpoint.isEmpty() + || deviceId.endsWith(QLatin1String("Default DirectSound Device"))) { + m_defaultEndpoint = deviceId; + } + } + } + monikers->Release(); + } + oleMalloc->Release(); + } +} diff --git a/src/plugins/directshow/player/directshowaudioendpointcontrol.h b/src/plugins/directshow/player/directshowaudioendpointcontrol.h new file mode 100644 index 000000000..62a0bd47f --- /dev/null +++ b/src/plugins/directshow/player/directshowaudioendpointcontrol.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DIRECTSHOWAUDIOENDPOINTCONTROL_H +#define DIRECTSHOWAUDIOENDPOINTCONTROL_H + +#include "qaudioendpointselector.h" + +#include + +class DirectShowPlayerService; + +QT_USE_NAMESPACE + +class DirectShowAudioEndpointControl : public QAudioEndpointSelector +{ + Q_OBJECT +public: + DirectShowAudioEndpointControl(DirectShowPlayerService *service, QObject *parent = 0); + ~DirectShowAudioEndpointControl(); + + QList availableEndpoints() const; + + QString endpointDescription(const QString &name) const; + + QString defaultEndpoint() const; + QString activeEndpoint() const; + + void setActiveEndpoint(const QString& name); + +private: + void updateEndpoints(); + + DirectShowPlayerService *m_service; + IBindCtx *m_bindContext; + ICreateDevEnum *m_deviceEnumerator; + + QMap m_devices; + QString m_defaultEndpoint; + QString m_activeEndpoint; +}; + +#endif + diff --git a/src/plugins/directshow/player/directshoweventloop.cpp b/src/plugins/directshow/player/directshoweventloop.cpp new file mode 100644 index 000000000..f863aa835 --- /dev/null +++ b/src/plugins/directshow/player/directshoweventloop.cpp @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include +#include + +class DirectShowPostedEvent +{ +public: + DirectShowPostedEvent(QObject *receiver, QEvent *event) + : receiver(receiver) + , event(event) + , next(0) + { + } + + ~DirectShowPostedEvent() + { + delete event; + } + + QObject *receiver; + QEvent *event; + DirectShowPostedEvent *next; +}; + +DirectShowEventLoop::DirectShowEventLoop(QObject *parent) + : QObject(parent) + , m_postsHead(0) + , m_postsTail(0) + , m_eventHandle(::CreateEvent(0, 0, 0, 0)) + , m_waitHandle(::CreateEvent(0, 0, 0, 0)) +{ +} + +DirectShowEventLoop::~DirectShowEventLoop() +{ + ::CloseHandle(m_eventHandle); + ::CloseHandle(m_waitHandle); + + for (DirectShowPostedEvent *post = m_postsHead; post; post = m_postsHead) { + m_postsHead = m_postsHead->next; + + delete post; + } +} + +void DirectShowEventLoop::wait(QMutex *mutex) +{ + ::ResetEvent(m_waitHandle); + + mutex->unlock(); + + HANDLE handles[] = { m_eventHandle, m_waitHandle }; + while (::WaitForMultipleObjects(2, handles, false, INFINITE) == WAIT_OBJECT_0) + processEvents(); + + mutex->lock(); +} + +void DirectShowEventLoop::wake() +{ + ::SetEvent(m_waitHandle); +} + +void DirectShowEventLoop::postEvent(QObject *receiver, QEvent *event) +{ + QMutexLocker locker(&m_mutex); + + DirectShowPostedEvent *post = new DirectShowPostedEvent(receiver, event); + + if (m_postsTail) + m_postsTail->next = post; + else + m_postsHead = post; + + m_postsTail = post; + + QCoreApplication::postEvent(this, new QEvent(QEvent::User)); + ::SetEvent(m_eventHandle); +} + +void DirectShowEventLoop::customEvent(QEvent *event) +{ + if (event->type() == QEvent::User) { + processEvents(); + } else { + QObject::customEvent(event); + } +} + +void DirectShowEventLoop::processEvents() +{ + QMutexLocker locker(&m_mutex); + + ::ResetEvent(m_eventHandle); + + while(m_postsHead) { + DirectShowPostedEvent *post = m_postsHead; + m_postsHead = m_postsHead->next; + + if (!m_postsHead) + m_postsTail = 0; + + locker.unlock(); + QCoreApplication::sendEvent(post->receiver, post->event); + delete post; + locker.relock(); + } +} diff --git a/src/plugins/directshow/player/directshoweventloop.h b/src/plugins/directshow/player/directshoweventloop.h new file mode 100644 index 000000000..6f1a51cd5 --- /dev/null +++ b/src/plugins/directshow/player/directshoweventloop.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DIRECTSHOWEVENTLOOP_H +#define DIRECTSHOWEVENTLOOP_H + +#include +#include +#include + +#include + +class DirectShowPostedEvent; + +class DirectShowEventLoop : public QObject +{ + Q_OBJECT +public: + DirectShowEventLoop(QObject *parent = 0); + ~DirectShowEventLoop(); + + void wait(QMutex *mutex); + void wake(); + + void postEvent(QObject *object, QEvent *event); + +protected: + void customEvent(QEvent *event); + +private: + void processEvents(); + + DirectShowPostedEvent *m_postsHead; + DirectShowPostedEvent *m_postsTail; + HANDLE m_eventHandle; + HANDLE m_waitHandle; + QMutex m_mutex; +}; + +#endif diff --git a/src/plugins/directshow/player/directshowglobal.h b/src/plugins/directshow/player/directshowglobal.h new file mode 100644 index 000000000..d14c117ec --- /dev/null +++ b/src/plugins/directshow/player/directshowglobal.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DIRECTSHOWGLOBAL_H +#define DIRECTSHOWGLOBAL_H + +#include + +#include + +template T *com_cast(IUnknown *unknown, const IID &iid) +{ + T *iface = 0; + return unknown && unknown->QueryInterface(iid, reinterpret_cast(&iface)) == S_OK + ? iface + : 0; +} + +template T *com_new(const IID &clsid, const IID &iid) +{ + T *object = 0; + return CoCreateInstance( + clsid, + NULL, + CLSCTX_INPROC_SERVER, + iid, + reinterpret_cast(&object)) == S_OK + ? object + : 0; +} + +#ifndef __IFilterGraph2_INTERFACE_DEFINED__ +#define __IFilterGraph2_INTERFACE_DEFINED__ +#define INTERFACE IFilterGraph2 +DECLARE_INTERFACE_(IFilterGraph2 ,IGraphBuilder) +{ + STDMETHOD(AddSourceFilterForMoniker)(THIS_ IMoniker *, IBindCtx *, LPCWSTR,IBaseFilter **) PURE; + STDMETHOD(ReconnectEx)(THIS_ IPin *, const AM_MEDIA_TYPE *) PURE; + STDMETHOD(RenderEx)(IPin *, DWORD, DWORD *) PURE; +}; +#undef INTERFACE +#endif + +#ifndef __IAMFilterMiscFlags_INTERFACE_DEFINED__ +#define __IAMFilterMiscFlags_INTERFACE_DEFINED__ +#define INTERFACE IAMFilterMiscFlags +DECLARE_INTERFACE_(IAMFilterMiscFlags ,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD_(ULONG,GetMiscFlags)(THIS) PURE; +}; +#undef INTERFACE +#endif + +#ifndef __IFileSourceFilter_INTERFACE_DEFINED__ +#define __IFileSourceFilter_INTERFACE_DEFINED__ +#define INTERFACE IFileSourceFilter +DECLARE_INTERFACE_(IFileSourceFilter ,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(Load)(THIS_ LPCOLESTR, const AM_MEDIA_TYPE *) PURE; + STDMETHOD(GetCurFile)(THIS_ LPOLESTR *ppszFileName, AM_MEDIA_TYPE *) PURE; +}; +#undef INTERFACE +#endif + +#ifndef __IAMOpenProgress_INTERFACE_DEFINED__ +#define __IAMOpenProgress_INTERFACE_DEFINED__ +#define INTERFACE IAMOpenProgress +DECLARE_INTERFACE_(IAMOpenProgress ,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(QueryProgress)(THIS_ LONGLONG *, LONGLONG *) PURE; + STDMETHOD(AbortOperation)(THIS) PURE; +}; +#undef INTERFACE +#endif + +#ifndef __IFilterChain_INTERFACE_DEFINED__ +#define __IFilterChain_INTERFACE_DEFINED__ +#define INTERFACE IFilterChain +DECLARE_INTERFACE_(IFilterChain ,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(StartChain)(IBaseFilter *, IBaseFilter *) PURE; + STDMETHOD(PauseChain)(IBaseFilter *, IBaseFilter *) PURE; + STDMETHOD(StopChain)(IBaseFilter *, IBaseFilter *) PURE; + STDMETHOD(RemoveChain)(IBaseFilter *, IBaseFilter *) PURE; +}; +#undef INTERFACE +#endif + +#endif diff --git a/src/plugins/directshow/player/directshowioreader.cpp b/src/plugins/directshow/player/directshowioreader.cpp new file mode 100644 index 000000000..5442f30d9 --- /dev/null +++ b/src/plugins/directshow/player/directshowioreader.cpp @@ -0,0 +1,496 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "directshowioreader.h" + +#include "directshoweventloop.h" +#include "directshowglobal.h" +#include "directshowiosource.h" + +#include +#include +#include +#include + +class DirectShowSampleRequest +{ +public: + DirectShowSampleRequest( + IMediaSample *sample, DWORD_PTR userData, LONGLONG position, LONG length, BYTE *buffer) + : next(0) + , sample(sample) + , userData(userData) + , position(position) + , length(length) + , buffer(buffer) + , result(S_FALSE) + { + } + + DirectShowSampleRequest *remove() { DirectShowSampleRequest *n = next; delete this; return n; } + + DirectShowSampleRequest *next; + IMediaSample *sample; + DWORD_PTR userData; + LONGLONG position; + LONG length; + BYTE *buffer; + HRESULT result; +}; + +DirectShowIOReader::DirectShowIOReader( + QIODevice *device, DirectShowIOSource *source, DirectShowEventLoop *loop) + : m_source(source) + , m_device(device) + , m_loop(loop) + , m_pendingHead(0) + , m_pendingTail(0) + , m_readyHead(0) + , m_readyTail(0) + , m_synchronousPosition(0) + , m_synchronousLength(0) + , m_synchronousBytesRead(0) + , m_synchronousBuffer(0) + , m_synchronousResult(S_OK) + , m_totalLength(0) + , m_availableLength(0) + , m_flushing(false) +{ + moveToThread(device->thread()); + + connect(device, SIGNAL(readyRead()), this, SLOT(readyRead())); +} + +DirectShowIOReader::~DirectShowIOReader() +{ + flushRequests(); +} + +HRESULT DirectShowIOReader::QueryInterface(REFIID riid, void **ppvObject) +{ + return m_source->QueryInterface(riid, ppvObject); +} + +ULONG DirectShowIOReader::AddRef() +{ + return m_source->AddRef(); +} + +ULONG DirectShowIOReader::Release() +{ + return m_source->Release(); +} + +// IAsyncReader +HRESULT DirectShowIOReader::RequestAllocator( + IMemAllocator *pPreferred, ALLOCATOR_PROPERTIES *pProps, IMemAllocator **ppActual) +{ + if (!ppActual || !pProps) { + return E_POINTER; + } else { + ALLOCATOR_PROPERTIES actualProperties; + + if (pProps->cbAlign == 0) + pProps->cbAlign = 1; + + if (pPreferred && pPreferred->SetProperties(pProps, &actualProperties) == S_OK) { + pPreferred->AddRef(); + + *ppActual = pPreferred; + + m_source->setAllocator(*ppActual); + + return S_OK; + } else { + *ppActual = com_new(CLSID_MemoryAllocator, IID_IMemAllocator); + + if (*ppActual) { + if ((*ppActual)->SetProperties(pProps, &actualProperties) != S_OK) { + (*ppActual)->Release(); + } else { + m_source->setAllocator(*ppActual); + + return S_OK; + } + } + } + ppActual = 0; + + return E_FAIL; + } +} + +HRESULT DirectShowIOReader::Request(IMediaSample *pSample, DWORD_PTR dwUser) +{ + QMutexLocker locker(&m_mutex); + + if (!pSample) { + return E_POINTER; + } else if (m_flushing) { + return VFW_E_WRONG_STATE; + } else { + REFERENCE_TIME startTime = 0; + REFERENCE_TIME endTime = 0; + BYTE *buffer; + + if (pSample->GetTime(&startTime, &endTime) != S_OK + || pSample->GetPointer(&buffer) != S_OK) { + return VFW_E_SAMPLE_TIME_NOT_SET; + } else { + LONGLONG position = startTime / 10000000; + LONG length = (endTime - startTime) / 10000000; + + DirectShowSampleRequest *request = new DirectShowSampleRequest( + pSample, dwUser, position, length, buffer); + + if (m_pendingTail) { + m_pendingTail->next = request; + } else { + m_pendingHead = request; + + m_loop->postEvent(this, new QEvent(QEvent::User)); + } + m_pendingTail = request; + + return S_OK; + } + } +} + +HRESULT DirectShowIOReader::WaitForNext( + DWORD dwTimeout, IMediaSample **ppSample, DWORD_PTR *pdwUser) +{ + if (!ppSample || !pdwUser) + return E_POINTER; + + QMutexLocker locker(&m_mutex); + + do { + if (m_readyHead) { + DirectShowSampleRequest *request = m_readyHead; + + *ppSample = request->sample; + *pdwUser = request->userData; + + HRESULT hr = request->result; + + m_readyHead = request->next; + + if (!m_readyHead) + m_readyTail = 0; + + delete request; + + return hr; + } else if (m_flushing) { + *ppSample = 0; + *pdwUser = 0; + + return VFW_E_WRONG_STATE; + } + } while (m_wait.wait(&m_mutex, dwTimeout)); + + *ppSample = 0; + *pdwUser = 0; + + return VFW_E_TIMEOUT; +} + +HRESULT DirectShowIOReader::SyncReadAligned(IMediaSample *pSample) +{ + if (!pSample) { + return E_POINTER; + } else { + REFERENCE_TIME startTime = 0; + REFERENCE_TIME endTime = 0; + BYTE *buffer; + + if (pSample->GetTime(&startTime, &endTime) != S_OK + || pSample->GetPointer(&buffer) != S_OK) { + return VFW_E_SAMPLE_TIME_NOT_SET; + } else { + LONGLONG position = startTime / 10000000; + LONG length = (endTime - startTime) / 10000000; + + QMutexLocker locker(&m_mutex); + + if (thread() == QThread::currentThread()) { + qint64 bytesRead = 0; + + HRESULT hr = blockingRead(position, length, buffer, &bytesRead); + + if (SUCCEEDED(hr)) + pSample->SetActualDataLength(bytesRead); + + return hr; + } else { + m_synchronousPosition = position; + m_synchronousLength = length; + m_synchronousBuffer = buffer; + + m_loop->postEvent(this, new QEvent(QEvent::User)); + + m_wait.wait(&m_mutex); + + m_synchronousBuffer = 0; + + if (SUCCEEDED(m_synchronousResult)) + pSample->SetActualDataLength(m_synchronousBytesRead); + + return m_synchronousResult; + } + } + } +} + +HRESULT DirectShowIOReader::SyncRead(LONGLONG llPosition, LONG lLength, BYTE *pBuffer) +{ + if (!pBuffer) { + return E_POINTER; + } else { + if (thread() == QThread::currentThread()) { + qint64 bytesRead; + + return blockingRead(llPosition, lLength, pBuffer, &bytesRead); + } else { + QMutexLocker locker(&m_mutex); + + m_synchronousPosition = llPosition; + m_synchronousLength = lLength; + m_synchronousBuffer = pBuffer; + + m_loop->postEvent(this, new QEvent(QEvent::User)); + + m_wait.wait(&m_mutex); + + m_synchronousBuffer = 0; + + return m_synchronousResult; + } + } +} + +HRESULT DirectShowIOReader::Length(LONGLONG *pTotal, LONGLONG *pAvailable) +{ + if (!pTotal || !pAvailable) { + return E_POINTER; + } else { + QMutexLocker locker(&m_mutex); + + *pTotal = m_totalLength; + *pAvailable = m_availableLength; + + return S_OK; + } +} + + +HRESULT DirectShowIOReader::BeginFlush() +{ + QMutexLocker locker(&m_mutex); + + if (m_flushing) + return S_FALSE; + + m_flushing = true; + + flushRequests(); + + m_wait.wakeAll(); + + return S_OK; +} + +HRESULT DirectShowIOReader::EndFlush() +{ + QMutexLocker locker(&m_mutex); + + if (!m_flushing) + return S_FALSE; + + m_flushing = false; + + return S_OK; +} + +void DirectShowIOReader::customEvent(QEvent *event) +{ + if (event->type() == QEvent::User) { + readyRead(); + } else { + QObject::customEvent(event); + } +} + +void DirectShowIOReader::readyRead() +{ + QMutexLocker locker(&m_mutex); + + m_availableLength = m_device->bytesAvailable() + m_device->pos(); + m_totalLength = m_device->size(); + + if (m_synchronousBuffer) { + if (nonBlockingRead( + m_synchronousPosition, + m_synchronousLength, + m_synchronousBuffer, + &m_synchronousBytesRead, + &m_synchronousResult)) { + m_wait.wakeAll(); + } + } else { + qint64 bytesRead = 0; + + while (m_pendingHead && nonBlockingRead( + m_pendingHead->position, + m_pendingHead->length, + m_pendingHead->buffer, + &bytesRead, + &m_pendingHead->result)) { + m_pendingHead->sample->SetActualDataLength(bytesRead); + + if (m_readyTail) + m_readyTail->next = m_pendingHead; + m_readyTail = m_pendingHead; + + m_pendingHead = m_pendingHead->next; + + m_readyTail->next = 0; + + if (!m_pendingHead) + m_pendingTail = 0; + + if (!m_readyHead) + m_readyHead = m_readyTail; + + m_wait.wakeAll(); + } + } +} + +HRESULT DirectShowIOReader::blockingRead( + LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead) +{ + *bytesRead = 0; + + if (qint64(position) > m_device->size()) + return S_FALSE; + + const qint64 maxSize = qMin(m_device->size(), position + length); + + while (m_device->bytesAvailable() + m_device->pos() < maxSize) { + if (!m_device->waitForReadyRead(-1)) + return S_FALSE; + } + + if (m_device->pos() != position && !m_device->seek(position)) + return S_FALSE; + + const qint64 maxBytes = qMin(length, m_device->bytesAvailable()); + + *bytesRead = m_device->read(reinterpret_cast(buffer), maxBytes); + + if (*bytesRead != length) { + qMemSet(buffer + *bytesRead, 0, length - *bytesRead); + + return S_FALSE; + } else { + return S_OK; + } +} + +bool DirectShowIOReader::nonBlockingRead( + LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead, HRESULT *result) +{ + const qint64 maxSize = qMin(m_device->size(), position + length); + + if (position > m_device->size()) { + *bytesRead = 0; + *result = S_FALSE; + + return true; + } else if (m_device->bytesAvailable() + m_device->pos() >= maxSize) { + if (m_device->pos() != position && !m_device->seek(position)) { + *bytesRead = 0; + *result = S_FALSE; + + return true; + } else { + const qint64 maxBytes = qMin(length, m_device->bytesAvailable()); + + *bytesRead = m_device->read(reinterpret_cast(buffer), maxBytes); + + if (*bytesRead != length) { + qMemSet(buffer + *bytesRead, 0, length - *bytesRead); + + *result = S_FALSE; + } else { + *result = S_OK; + } + + return true; + } + } else { + return false; + } +} + +void DirectShowIOReader::flushRequests() +{ + while (m_pendingHead) { + m_pendingHead->result = VFW_E_WRONG_STATE; + + if (m_readyTail) + m_readyTail->next = m_pendingHead; + + m_readyTail = m_pendingHead; + + m_pendingHead = m_pendingHead->next; + + m_readyTail->next = 0; + + if (!m_pendingHead) + m_pendingTail = 0; + + if (!m_readyHead) + m_readyHead = m_readyTail; + } +} diff --git a/src/plugins/directshow/player/directshowioreader.h b/src/plugins/directshow/player/directshowioreader.h new file mode 100644 index 000000000..ca398f12e --- /dev/null +++ b/src/plugins/directshow/player/directshowioreader.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DIRECTSHOWIOREADER_H +#define DIRECTSHOWIOREADER_H + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE +class QIODevice; +QT_END_NAMESPACE + +class DirectShowEventLoop; +class DirectShowIOSource; +class DirectShowSampleRequest; + +class DirectShowIOReader : public QObject, public IAsyncReader +{ + Q_OBJECT +public: + DirectShowIOReader(QIODevice *device, DirectShowIOSource *source, DirectShowEventLoop *loop); + ~DirectShowIOReader(); + + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + // IAsyncReader + HRESULT STDMETHODCALLTYPE RequestAllocator( + IMemAllocator *pPreferred, ALLOCATOR_PROPERTIES *pProps, IMemAllocator **ppActual); + + HRESULT STDMETHODCALLTYPE Request(IMediaSample *pSample, DWORD_PTR dwUser); + + HRESULT STDMETHODCALLTYPE WaitForNext( + DWORD dwTimeout, IMediaSample **ppSample, DWORD_PTR *pdwUser); + + HRESULT STDMETHODCALLTYPE SyncReadAligned(IMediaSample *pSample); + + HRESULT STDMETHODCALLTYPE SyncRead(LONGLONG llPosition, LONG lLength, BYTE *pBuffer); + + HRESULT STDMETHODCALLTYPE Length(LONGLONG *pTotal, LONGLONG *pAvailable); + + HRESULT STDMETHODCALLTYPE BeginFlush(); + HRESULT STDMETHODCALLTYPE EndFlush(); + +protected: + void customEvent(QEvent *event); + +private Q_SLOTS: + void readyRead(); + +private: + HRESULT blockingRead(LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead); + bool nonBlockingRead( + LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead, HRESULT *result); + void flushRequests(); + + DirectShowIOSource *m_source; + QIODevice *m_device; + DirectShowEventLoop *m_loop; + DirectShowSampleRequest *m_pendingHead; + DirectShowSampleRequest *m_pendingTail; + DirectShowSampleRequest *m_readyHead; + DirectShowSampleRequest *m_readyTail; + LONGLONG m_synchronousPosition; + LONG m_synchronousLength; + qint64 m_synchronousBytesRead; + BYTE *m_synchronousBuffer; + HRESULT m_synchronousResult; + LONGLONG m_totalLength; + LONGLONG m_availableLength; + bool m_flushing; + QMutex m_mutex; + QWaitCondition m_wait; +}; + +#endif diff --git a/src/plugins/directshow/player/directshowiosource.cpp b/src/plugins/directshow/player/directshowiosource.cpp new file mode 100644 index 000000000..c8f3e6a97 --- /dev/null +++ b/src/plugins/directshow/player/directshowiosource.cpp @@ -0,0 +1,639 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "directshowiosource.h" + +#include "directshowglobal.h" +#include "directshowmediatype.h" +#include "directshowpinenum.h" + +#include +#include + +static const GUID directshow_subtypes[] = +{ + MEDIASUBTYPE_Avi, + MEDIASUBTYPE_WAVE, + MEDIASUBTYPE_NULL +}; + +DirectShowIOSource::DirectShowIOSource(DirectShowEventLoop *loop) + : m_ref(1) + , m_state(State_Stopped) + , m_reader(0) + , m_loop(loop) + , m_graph(0) + , m_clock(0) + , m_allocator(0) + , m_peerPin(0) + , m_pinId(QLatin1String("Data")) +{ + QVector mediaTypes; + + AM_MEDIA_TYPE type = + { + MEDIATYPE_Stream, // majortype + MEDIASUBTYPE_NULL, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 1, // lSampleSize + GUID_NULL, // formattype + 0, // pUnk + 0, // cbFormat + 0, // pbFormat + }; + + static const int count = sizeof(directshow_subtypes) / sizeof(GUID); + + for (int i = 0; i < count; ++i) { + type.subtype = directshow_subtypes[i]; + mediaTypes.append(type); + } + + setMediaTypes(mediaTypes); +} + +DirectShowIOSource::~DirectShowIOSource() +{ + Q_ASSERT(m_ref == 0); + + delete m_reader; +} + +void DirectShowIOSource::setDevice(QIODevice *device) +{ + Q_ASSERT(!m_reader); + + m_reader = new DirectShowIOReader(device, this, m_loop); +} + +void DirectShowIOSource::setAllocator(IMemAllocator *allocator) +{ + if (m_allocator) + m_allocator->Release(); + + m_allocator = allocator; + + if (m_allocator) + m_allocator->AddRef(); +} + +// IUnknown +HRESULT DirectShowIOSource::QueryInterface(REFIID riid, void **ppvObject) +{ + // 2dd74950-a890-11d1-abe8-00a0c905f375 + static const GUID iid_IAmFilterMiscFlags = { + 0x2dd74950, 0xa890, 0x11d1, {0xab, 0xe8, 0x00, 0xa0, 0xc9, 0x05, 0xf3, 0x75}}; + + if (!ppvObject) { + return E_POINTER; + } else if (riid == IID_IUnknown + || riid == IID_IPersist + || riid == IID_IMediaFilter + || riid == IID_IBaseFilter) { + *ppvObject = static_cast(this); + } else if (riid == iid_IAmFilterMiscFlags) { + *ppvObject = static_cast(this); + } else if (riid == IID_IPin) { + *ppvObject = static_cast(this); + } else if (riid == IID_IAsyncReader) { + *ppvObject = static_cast(m_reader); + } else { + *ppvObject = 0; + + return E_NOINTERFACE; + } + + AddRef(); + + return S_OK; +} + +ULONG DirectShowIOSource::AddRef() +{ + return InterlockedIncrement(&m_ref); +} + +ULONG DirectShowIOSource::Release() +{ + ULONG ref = InterlockedDecrement(&m_ref); + + if (ref == 0) { + delete this; + } + + return ref; +} + +// IPersist +HRESULT DirectShowIOSource::GetClassID(CLSID *pClassID) +{ + *pClassID = CLSID_NULL; + + return S_OK; +} + +// IMediaFilter +HRESULT DirectShowIOSource::Run(REFERENCE_TIME tStart) +{ + QMutexLocker locker(&m_mutex); + + m_state = State_Running; + + return S_OK; +} + +HRESULT DirectShowIOSource::Pause() +{ + QMutexLocker locker(&m_mutex); + + m_state = State_Paused; + + return S_OK; +} + +HRESULT DirectShowIOSource::Stop() +{ + QMutexLocker locker(&m_mutex); + + m_state = State_Stopped; + + return S_OK; +} + +HRESULT DirectShowIOSource::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *pState) +{ + Q_UNUSED(dwMilliSecsTimeout); + + if (!pState) { + return E_POINTER; + } else { + QMutexLocker locker(&m_mutex); + + *pState = m_state; + + return S_OK; + } +} + +HRESULT DirectShowIOSource::SetSyncSource(IReferenceClock *pClock) +{ + QMutexLocker locker(&m_mutex); + + if (m_clock) + m_clock->Release(); + + m_clock = pClock; + + if (m_clock) + m_clock->AddRef(); + + return S_OK; +} + +HRESULT DirectShowIOSource::GetSyncSource(IReferenceClock **ppClock) +{ + if (!ppClock) { + return E_POINTER; + } else { + if (!m_clock) { + *ppClock = 0; + + return S_FALSE; + } else { + m_clock->AddRef(); + + *ppClock = m_clock; + + return S_OK; + } + } +} + +// IBaseFilter +HRESULT DirectShowIOSource::EnumPins(IEnumPins **ppEnum) +{ + if (!ppEnum) { + return E_POINTER; + } else { + *ppEnum = new DirectShowPinEnum(QList() << this); + + return S_OK; + } +} + +HRESULT DirectShowIOSource::FindPin(LPCWSTR Id, IPin **ppPin) +{ + if (!ppPin || !Id) { + return E_POINTER; + } else { + QMutexLocker locker(&m_mutex); + if (QString::fromWCharArray(Id) == m_pinId) { + AddRef(); + + *ppPin = this; + + return S_OK; + } else { + *ppPin = 0; + + return VFW_E_NOT_FOUND; + } + } +} + +HRESULT DirectShowIOSource::JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName) +{ + QMutexLocker locker(&m_mutex); + + m_graph = pGraph; + m_filterName = QString::fromWCharArray(pName); + + return S_OK; +} + +HRESULT DirectShowIOSource::QueryFilterInfo(FILTER_INFO *pInfo) +{ + if (!pInfo) { + return E_POINTER; + } else { + QString name = m_filterName; + + if (name.length() >= MAX_FILTER_NAME) + name.truncate(MAX_FILTER_NAME - 1); + + int length = name.toWCharArray(pInfo->achName); + pInfo->achName[length] = '\0'; + + if (m_graph) + m_graph->AddRef(); + + pInfo->pGraph = m_graph; + + return S_OK; + } +} + +HRESULT DirectShowIOSource::QueryVendorInfo(LPWSTR *pVendorInfo) +{ + Q_UNUSED(pVendorInfo); + + return E_NOTIMPL; +} + +// IAMFilterMiscFlags +ULONG DirectShowIOSource::GetMiscFlags() +{ + return AM_FILTER_MISC_FLAGS_IS_SOURCE; +} + +// IPin +HRESULT DirectShowIOSource::Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt) +{ + QMutexLocker locker(&m_mutex); + if (!pReceivePin) { + return E_POINTER; + } else if (m_state != State_Stopped) { + return VFW_E_NOT_STOPPED; + } else if (m_peerPin) { + return VFW_E_ALREADY_CONNECTED; + } else { + HRESULT hr = VFW_E_TYPE_NOT_ACCEPTED; + + m_peerPin = pReceivePin; + m_peerPin->AddRef(); + + if (!pmt) { + IEnumMediaTypes *mediaTypes = 0; + if (pReceivePin->EnumMediaTypes(&mediaTypes) == S_OK) { + for (AM_MEDIA_TYPE *type = 0; + mediaTypes->Next(1, &type, 0) == S_OK; + DirectShowMediaType::deleteType(type)) { + switch (tryConnect(pReceivePin, type)) { + case S_OK: + DirectShowMediaType::freeData(type); + mediaTypes->Release(); + return S_OK; + case VFW_E_NO_TRANSPORT: + hr = VFW_E_NO_TRANSPORT; + break; + default: + break; + } + } + mediaTypes->Release(); + } + AM_MEDIA_TYPE type = + { + MEDIATYPE_Stream, // majortype + MEDIASUBTYPE_NULL, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 1, // lSampleSize + GUID_NULL, // formattype + 0, // pUnk + 0, // cbFormat + 0, // pbFormat + }; + + static const int count = sizeof(directshow_subtypes) / sizeof(GUID); + + for (int i = 0; i < count; ++i) { + type.subtype = directshow_subtypes[i]; + + switch (tryConnect(pReceivePin, &type)) { + case S_OK: + return S_OK; + case VFW_E_NO_TRANSPORT: + hr = VFW_E_NO_TRANSPORT; + break; + default: + break; + } + } + } else if (pmt->majortype == MEDIATYPE_Stream && (hr = tryConnect(pReceivePin, pmt))) { + return S_OK; + } + + m_peerPin->Release(); + m_peerPin = 0; + + m_mediaType.clear(); + + return hr; + } +} + +HRESULT DirectShowIOSource::tryConnect(IPin *pin, const AM_MEDIA_TYPE *type) +{ + m_mediaType = *type; + + HRESULT hr = pin->ReceiveConnection(this, type); + + if (!SUCCEEDED(hr)) { + if (m_allocator) { + m_allocator->Release(); + m_allocator = 0; + } + } else if (!m_allocator) { + hr = VFW_E_NO_TRANSPORT; + + if (IMemInputPin *memPin = com_cast(pin, IID_IMemInputPin)) { + if ((m_allocator = com_new(CLSID_MemoryAllocator, IID_IMemAllocator))) { + ALLOCATOR_PROPERTIES properties; + if (memPin->GetAllocatorRequirements(&properties) == S_OK + || m_allocator->GetProperties(&properties) == S_OK) { + if (properties.cbAlign == 0) + properties.cbAlign = 1; + + ALLOCATOR_PROPERTIES actualProperties; + if (SUCCEEDED(hr = m_allocator->SetProperties(&properties, &actualProperties))) + hr = memPin->NotifyAllocator(m_allocator, TRUE); + } + if (!SUCCEEDED(hr)) { + m_allocator->Release(); + m_allocator = 0; + } + } + memPin->Release(); + } + if (!SUCCEEDED(hr)) + pin->Disconnect(); + } + return hr; +} + +HRESULT DirectShowIOSource::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt) +{ + Q_UNUSED(pConnector); + Q_UNUSED(pmt); + // Output pin. + return E_NOTIMPL; +} + +HRESULT DirectShowIOSource::Disconnect() +{ + if (!m_peerPin) { + return S_FALSE; + } else if (m_state != State_Stopped) { + return VFW_E_NOT_STOPPED; + } else { + HRESULT hr = m_peerPin->Disconnect(); + + if (!SUCCEEDED(hr)) + return hr; + + if (m_allocator) { + m_allocator->Release(); + m_allocator = 0; + } + + m_peerPin->Release(); + m_peerPin = 0; + + m_mediaType.clear(); + + return S_OK; + } +} + +HRESULT DirectShowIOSource::ConnectedTo(IPin **ppPin) +{ + if (!ppPin) { + return E_POINTER; + } else { + QMutexLocker locker(&m_mutex); + + if (!m_peerPin) { + *ppPin = 0; + + return VFW_E_NOT_CONNECTED; + } else { + m_peerPin->AddRef(); + + *ppPin = m_peerPin; + + return S_OK; + } + } +} + +HRESULT DirectShowIOSource::ConnectionMediaType(AM_MEDIA_TYPE *pmt) +{ + if (!pmt) { + return E_POINTER; + } else { + QMutexLocker locker(&m_mutex); + + if (!m_peerPin) { + pmt = 0; + + return VFW_E_NOT_CONNECTED; + } else { + DirectShowMediaType::copy(pmt, m_mediaType); + + return S_OK; + } + } +} + +HRESULT DirectShowIOSource::QueryPinInfo(PIN_INFO *pInfo) +{ + if (!pInfo) { + return E_POINTER; + } else { + AddRef(); + + pInfo->pFilter = this; + pInfo->dir = PINDIR_OUTPUT; + + const int bytes = qMin(MAX_FILTER_NAME, (m_pinId.length() + 1) * 2); + + qMemCopy(pInfo->achName, m_pinId.utf16(), bytes); + + return S_OK; + } +} + +HRESULT DirectShowIOSource::QueryId(LPWSTR *Id) +{ + if (!Id) { + return E_POINTER; + } else { + const int bytes = (m_pinId.length() + 1) * 2; + + *Id = static_cast(::CoTaskMemAlloc(bytes)); + + qMemCopy(*Id, m_pinId.utf16(), bytes); + + return S_OK; + } +} + +HRESULT DirectShowIOSource::QueryAccept(const AM_MEDIA_TYPE *pmt) +{ + if (!pmt) { + return E_POINTER; + } else if (pmt->majortype == MEDIATYPE_Stream) { + return S_OK; + } else { + return S_FALSE; + } +} + +HRESULT DirectShowIOSource::EnumMediaTypes(IEnumMediaTypes **ppEnum) +{ + if (!ppEnum) { + return E_POINTER; + } else { + *ppEnum = createMediaTypeEnum(); + + return S_OK; + } +} + +HRESULT DirectShowIOSource::QueryInternalConnections(IPin **apPin, ULONG *nPin) +{ + Q_UNUSED(apPin); + Q_UNUSED(nPin); + + return E_NOTIMPL; +} + +HRESULT DirectShowIOSource::EndOfStream() +{ + return S_OK; +} + +HRESULT DirectShowIOSource::BeginFlush() +{ + return m_reader->BeginFlush(); +} + +HRESULT DirectShowIOSource::EndFlush() +{ + return m_reader->EndFlush(); +} + +HRESULT DirectShowIOSource::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + Q_UNUSED(tStart); + Q_UNUSED(tStop); + Q_UNUSED(dRate); + + return S_OK; +} + +HRESULT DirectShowIOSource::QueryDirection(PIN_DIRECTION *pPinDir) +{ + if (!pPinDir) { + return E_POINTER; + } else { + *pPinDir = PINDIR_OUTPUT; + + return S_OK; + } +} + +DirectShowRcSource::DirectShowRcSource(DirectShowEventLoop *loop) + : DirectShowIOSource(loop) +{ +} + +bool DirectShowRcSource::open(const QUrl &url) +{ + m_file.moveToThread(QCoreApplication::instance()->thread()); + + m_file.setFileName(QLatin1Char(':') + url.path()); + + qDebug("qrc file %s", qPrintable(m_file.fileName())); + + if (m_file.open(QIODevice::ReadOnly)) { + qDebug("Size %d", m_file.size()); + qDebug("Sequential %d", int(m_file.isSequential())); + + setDevice(&m_file); + + return true; + } else { + return false; + } +} diff --git a/src/plugins/directshow/player/directshowiosource.h b/src/plugins/directshow/player/directshowiosource.h new file mode 100644 index 000000000..3019bdbe9 --- /dev/null +++ b/src/plugins/directshow/player/directshowiosource.h @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DIRECTSHOWIOSOURCE_H +#define DIRECTSHOWIOSOURCE_H + +#include "directshowglobal.h" +#include "directshowioreader.h" +#include "directshowmediatype.h" +#include "directshowmediatypelist.h" + +#include + +class DirectShowIOSource + : public DirectShowMediaTypeList + , public IBaseFilter + , public IAMFilterMiscFlags + , public IPin +{ +public: + DirectShowIOSource(DirectShowEventLoop *loop); + ~DirectShowIOSource(); + + void setDevice(QIODevice *device); + void setAllocator(IMemAllocator *allocator); + + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + // IPersist + HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID); + + // IMediaFilter + HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart); + HRESULT STDMETHODCALLTYPE Pause(); + HRESULT STDMETHODCALLTYPE Stop(); + + HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *pState); + + HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock *pClock); + HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock **ppClock); + + // IBaseFilter + HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins **ppEnum); + HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, IPin **ppPin); + + HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName); + + HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO *pInfo); + HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR *pVendorInfo); + + // IAMFilterMiscFlags + ULONG STDMETHODCALLTYPE GetMiscFlags(); + + // IPin + HRESULT STDMETHODCALLTYPE Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt); + HRESULT STDMETHODCALLTYPE ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt); + HRESULT STDMETHODCALLTYPE Disconnect(); + HRESULT STDMETHODCALLTYPE ConnectedTo(IPin **ppPin); + + HRESULT STDMETHODCALLTYPE ConnectionMediaType(AM_MEDIA_TYPE *pmt); + + HRESULT STDMETHODCALLTYPE QueryPinInfo(PIN_INFO *pInfo); + HRESULT STDMETHODCALLTYPE QueryId(LPWSTR *Id); + + HRESULT STDMETHODCALLTYPE QueryAccept(const AM_MEDIA_TYPE *pmt); + + HRESULT STDMETHODCALLTYPE EnumMediaTypes(IEnumMediaTypes **ppEnum); + + HRESULT STDMETHODCALLTYPE QueryInternalConnections(IPin **apPin, ULONG *nPin); + + HRESULT STDMETHODCALLTYPE EndOfStream(); + + HRESULT STDMETHODCALLTYPE BeginFlush(); + HRESULT STDMETHODCALLTYPE EndFlush(); + + HRESULT STDMETHODCALLTYPE NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + + HRESULT STDMETHODCALLTYPE QueryDirection(PIN_DIRECTION *pPinDir); + +private: + HRESULT tryConnect(IPin *pin, const AM_MEDIA_TYPE *type); + + volatile LONG m_ref; + FILTER_STATE m_state; + DirectShowIOReader *m_reader; + DirectShowEventLoop *m_loop; + IFilterGraph *m_graph; + IReferenceClock *m_clock; + IMemAllocator *m_allocator; + IPin *m_peerPin; + DirectShowMediaType m_mediaType; + QString m_filterName; + const QString m_pinId; + QMutex m_mutex; +}; + +class DirectShowRcSource : public DirectShowIOSource +{ +public: + DirectShowRcSource(DirectShowEventLoop *loop); + + bool open(const QUrl &url); + +private: + QFile m_file; +}; + +#endif diff --git a/src/plugins/directshow/player/directshowmediatype.cpp b/src/plugins/directshow/player/directshowmediatype.cpp new file mode 100644 index 000000000..667d9491e --- /dev/null +++ b/src/plugins/directshow/player/directshowmediatype.cpp @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "directshowmediatype.h" + +namespace +{ + struct TypeLookup + { + QVideoFrame::PixelFormat pixelFormat; + GUID mediaType; + }; + + static const TypeLookup qt_typeLookup[] = + { + { QVideoFrame::Format_RGB32, /*MEDIASUBTYPE_RGB32*/ {0xe436eb7e, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}} }, + { QVideoFrame::Format_BGR24, /*MEDIASUBTYPE_RGB24*/ {0xe436eb7d, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}} }, + { QVideoFrame::Format_RGB565, /*MEDIASUBTYPE_RGB565*/ {0xe436eb7b, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}} }, + { QVideoFrame::Format_RGB555, /*MEDIASUBTYPE_RGB555*/ {0xe436eb7c, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}} }, + { QVideoFrame::Format_AYUV444, /*MEDIASUBTYPE_AYUV*/ {0x56555941, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} }, + { QVideoFrame::Format_YUYV, /*MEDIASUBTYPE_YUY2*/ {0x32595559, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} }, + { QVideoFrame::Format_UYVY, /*MEDIASUBTYPE_UYVY*/ {0x59565955, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} }, + { QVideoFrame::Format_IMC1, /*MEDIASUBTYPE_IMC1*/ {0x31434D49, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} }, + { QVideoFrame::Format_IMC2, /*MEDIASUBTYPE_IMC2*/ {0x32434D49, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} }, + { QVideoFrame::Format_IMC3, /*MEDIASUBTYPE_IMC3*/ {0x33434D49, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} }, + { QVideoFrame::Format_IMC4, /*MEDIASUBTYPE_IMC4*/ {0x34434D49, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} }, + { QVideoFrame::Format_YV12, /*MEDIASUBTYPE_YV12*/ {0x32315659, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} }, + { QVideoFrame::Format_NV12, /*MEDIASUBTYPE_NV12*/ {0x3231564E, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} }, + { QVideoFrame::Format_YUV420P, /*MEDIASUBTYPE_IYUV*/ {0x56555949, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} } + }; +} + +void DirectShowMediaType::copy(AM_MEDIA_TYPE *target, const AM_MEDIA_TYPE &source) +{ + *target = source; + + if (source.cbFormat > 0) { + target->pbFormat = reinterpret_cast(CoTaskMemAlloc(source.cbFormat)); + memcpy(target->pbFormat, source.pbFormat, source.cbFormat); + } + if (target->pUnk) + target->pUnk->AddRef(); +} + +void DirectShowMediaType::deleteType(AM_MEDIA_TYPE *type) +{ + freeData(type); + + CoTaskMemFree(type); +} + +void DirectShowMediaType::freeData(AM_MEDIA_TYPE *type) +{ + if (type->cbFormat > 0) + CoTaskMemFree(type->pbFormat); + + if (type->pUnk) + type->pUnk->Release(); +} + + +GUID DirectShowMediaType::convertPixelFormat(QVideoFrame::PixelFormat format) +{ + // MEDIASUBTYPE_None; + static const GUID none = { + 0xe436eb8e, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70} }; + + const int count = sizeof(qt_typeLookup) / sizeof(TypeLookup); + + for (int i = 0; i < count; ++i) + if (qt_typeLookup[i].pixelFormat == format) + return qt_typeLookup[i].mediaType; + return none; +} + +QVideoSurfaceFormat DirectShowMediaType::formatFromType(const AM_MEDIA_TYPE &type) +{ + const int count = sizeof(qt_typeLookup) / sizeof(TypeLookup); + + for (int i = 0; i < count; ++i) { + if (IsEqualGUID(qt_typeLookup[i].mediaType, type.subtype) && type.cbFormat > 0) { + if (IsEqualGUID(type.formattype, FORMAT_VideoInfo)) { + VIDEOINFOHEADER *header = reinterpret_cast(type.pbFormat); + + QVideoSurfaceFormat format( + QSize(header->bmiHeader.biWidth, qAbs(header->bmiHeader.biHeight)), + qt_typeLookup[i].pixelFormat); + + if (header->AvgTimePerFrame > 0) + format.setFrameRate(10000 /header->AvgTimePerFrame); + + format.setScanLineDirection(header->bmiHeader.biHeight < 0 + ? QVideoSurfaceFormat::TopToBottom + : QVideoSurfaceFormat::BottomToTop); + + return format; + } else if (IsEqualGUID(type.formattype, FORMAT_VideoInfo2)) { + VIDEOINFOHEADER2 *header = reinterpret_cast(type.pbFormat); + + QVideoSurfaceFormat format( + QSize(header->bmiHeader.biWidth, qAbs(header->bmiHeader.biHeight)), + qt_typeLookup[i].pixelFormat); + + if (header->AvgTimePerFrame > 0) + format.setFrameRate(10000 / header->AvgTimePerFrame); + + format.setScanLineDirection(header->bmiHeader.biHeight < 0 + ? QVideoSurfaceFormat::TopToBottom + : QVideoSurfaceFormat::BottomToTop); + + return format; + } + } + } + return QVideoSurfaceFormat(); +} + +int DirectShowMediaType::bytesPerLine(const QVideoSurfaceFormat &format) +{ + switch (format.pixelFormat()) { + // 32 bpp packed formats. + case QVideoFrame::Format_RGB32: + case QVideoFrame::Format_AYUV444: + return format.frameWidth() * 4; + // 24 bpp packed formats. + case QVideoFrame::Format_RGB24: + return format.frameWidth() * 3 + 3 - format.frameWidth() % 4; + // 16 bpp packed formats. + case QVideoFrame::Format_RGB565: + case QVideoFrame::Format_RGB555: + case QVideoFrame::Format_YUYV: + case QVideoFrame::Format_UYVY: + return format.frameWidth() * 2 + 3 - format.frameWidth() % 4; + // Planar formats. + case QVideoFrame::Format_IMC1: + case QVideoFrame::Format_IMC2: + case QVideoFrame::Format_IMC3: + case QVideoFrame::Format_IMC4: + case QVideoFrame::Format_YV12: + case QVideoFrame::Format_NV12: + case QVideoFrame::Format_YUV420P: + return format.frameWidth() + 3 - format.frameWidth() % 4; + default: + return 0; + } +} diff --git a/src/plugins/directshow/player/directshowmediatype.h b/src/plugins/directshow/player/directshowmediatype.h new file mode 100644 index 000000000..7d37a5c29 --- /dev/null +++ b/src/plugins/directshow/player/directshowmediatype.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DIRECTSHOWMEDIATYPE_H +#define DIRECTSHOWMEDIATYPE_H + +#include + +#include +#include + +class DirectShowMediaType : public AM_MEDIA_TYPE +{ +public: + DirectShowMediaType() { memset(this, 0, sizeof(DirectShowMediaType)); } + DirectShowMediaType(const AM_MEDIA_TYPE &type) { copy(this, type); } + DirectShowMediaType(const DirectShowMediaType &other) { copy(this, other); } + DirectShowMediaType &operator =(const AM_MEDIA_TYPE &type) { + freeData(this); copy(this, type); return *this; } + DirectShowMediaType &operator =(const DirectShowMediaType &other) { + freeData(this); copy(this, other); return *this; } + ~DirectShowMediaType() { freeData(this); } + + void clear() { freeData(this); memset(this, 0, sizeof(DirectShowMediaType)); } + + static void copy(AM_MEDIA_TYPE *target, const AM_MEDIA_TYPE &source); + static void freeData(AM_MEDIA_TYPE *type); + static void deleteType(AM_MEDIA_TYPE *type); + + static GUID convertPixelFormat(QVideoFrame::PixelFormat format); + static QVideoSurfaceFormat formatFromType(const AM_MEDIA_TYPE &type); + + static int bytesPerLine(const QVideoSurfaceFormat &format); +}; + +#endif diff --git a/src/plugins/directshow/player/directshowmediatypelist.cpp b/src/plugins/directshow/player/directshowmediatypelist.cpp new file mode 100644 index 000000000..3060975fc --- /dev/null +++ b/src/plugins/directshow/player/directshowmediatypelist.cpp @@ -0,0 +1,226 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "directshowmediatypelist.h" + +#include "directshowmediatype.h" +#include "videosurfacefilter.h" + + +class DirectShowMediaTypeEnum : public IEnumMediaTypes +{ +public: + DirectShowMediaTypeEnum(DirectShowMediaTypeList *list, int token, int index = 0); + ~DirectShowMediaTypeEnum(); + + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + // IEnumMediaTypes + HRESULT STDMETHODCALLTYPE Next( + ULONG cMediaTypes, AM_MEDIA_TYPE **ppMediaTypes, ULONG *pcFetched); + HRESULT STDMETHODCALLTYPE Skip(ULONG cMediaTypes); + HRESULT STDMETHODCALLTYPE Reset(); + + HRESULT STDMETHODCALLTYPE Clone(IEnumMediaTypes **ppEnum); + +private: + LONG m_ref; + DirectShowMediaTypeList *m_list; + int m_mediaTypeToken; + int m_index; +}; + + +DirectShowMediaTypeEnum::DirectShowMediaTypeEnum( + DirectShowMediaTypeList *list, int token, int index) + : m_ref(1) + , m_list(list) + , m_mediaTypeToken(token) + , m_index(index) +{ + m_list->AddRef(); +} + +DirectShowMediaTypeEnum::~DirectShowMediaTypeEnum() +{ + m_list->Release(); +} + +HRESULT DirectShowMediaTypeEnum::QueryInterface(REFIID riid, void **ppvObject) +{ + if (!ppvObject) { + return E_POINTER; + } else if (riid == IID_IUnknown + || riid == IID_IEnumMediaTypes) { + *ppvObject = static_cast(this); + } else { + *ppvObject = 0; + + return E_NOINTERFACE; + } + + AddRef(); + + return S_OK; +} + +ULONG DirectShowMediaTypeEnum::AddRef() +{ + return InterlockedIncrement(&m_ref); +} + +ULONG DirectShowMediaTypeEnum::Release() +{ + ULONG ref = InterlockedDecrement(&m_ref); + + if (ref == 0) { + delete this; + } + + return ref; +} + +HRESULT DirectShowMediaTypeEnum::Next( + ULONG cMediaTypes, AM_MEDIA_TYPE **ppMediaTypes, ULONG *pcFetched) +{ + return m_list->nextMediaType(m_mediaTypeToken, &m_index, cMediaTypes, ppMediaTypes, pcFetched); +} + +HRESULT DirectShowMediaTypeEnum::Skip(ULONG cMediaTypes) +{ + return m_list->skipMediaType(m_mediaTypeToken, &m_index, cMediaTypes); +} + +HRESULT DirectShowMediaTypeEnum::Reset() +{ + m_mediaTypeToken = m_list->currentMediaTypeToken(); + m_index = 0; + + return S_OK; +} + +HRESULT DirectShowMediaTypeEnum::Clone(IEnumMediaTypes **ppEnum) +{ + return m_list->cloneMediaType(m_mediaTypeToken, m_index, ppEnum); +} + + +DirectShowMediaTypeList::DirectShowMediaTypeList() + : m_mediaTypeToken(0) +{ +} + +IEnumMediaTypes *DirectShowMediaTypeList::createMediaTypeEnum() +{ + return new DirectShowMediaTypeEnum(this, m_mediaTypeToken, 0); +} + + +void DirectShowMediaTypeList::setMediaTypes(const QVector &types) +{ + ++m_mediaTypeToken; + + m_mediaTypes = types; +} + + +int DirectShowMediaTypeList::currentMediaTypeToken() +{ + return m_mediaTypeToken; +} + +HRESULT DirectShowMediaTypeList::nextMediaType( + int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount) +{ + if (!types || (count != 1 && !fetchedCount)) { + return E_POINTER; + } else if (m_mediaTypeToken != token) { + return VFW_E_ENUM_OUT_OF_SYNC; + } else { + int boundedCount = qBound(0, count, m_mediaTypes.count() - *index); + + for (int i = 0; i < boundedCount; ++i, ++(*index)) { + types[i] = reinterpret_cast(CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))); + + if (types[i]) { + DirectShowMediaType::copy(types[i], m_mediaTypes.at(*index)); + } else { + for (--i; i >= 0; --i) + CoTaskMemFree(types[i]); + + if (fetchedCount) + *fetchedCount = 0; + + return E_OUTOFMEMORY; + } + } + if (fetchedCount) + *fetchedCount = boundedCount; + + return boundedCount == count ? S_OK : S_FALSE; + } +} + +HRESULT DirectShowMediaTypeList::skipMediaType(int token, int *index, ULONG count) +{ + if (m_mediaTypeToken != token) { + return VFW_E_ENUM_OUT_OF_SYNC; + } else { + *index = qMin(*index + count, m_mediaTypes.size()); + + return *index < m_mediaTypes.size() ? S_OK : S_FALSE; + } +} + +HRESULT DirectShowMediaTypeList::cloneMediaType(int token, int index, IEnumMediaTypes **enumeration) +{ + if (m_mediaTypeToken != token) { + return VFW_E_ENUM_OUT_OF_SYNC; + } else { + *enumeration = new DirectShowMediaTypeEnum(this, token, index); + + return S_OK; + } +} + diff --git a/src/plugins/directshow/player/directshowmediatypelist.h b/src/plugins/directshow/player/directshowmediatypelist.h new file mode 100644 index 000000000..1b33606cb --- /dev/null +++ b/src/plugins/directshow/player/directshowmediatypelist.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DIRECTSHOWMEDIATYPELIST_H +#define DIRECTSHOWMEDIATYPELIST_H + +#include + +#include + +class DirectShowMediaTypeList : public IUnknown +{ +public: + DirectShowMediaTypeList(); + + IEnumMediaTypes *createMediaTypeEnum(); + + void setMediaTypes(const QVector &types); + + virtual int currentMediaTypeToken(); + virtual HRESULT nextMediaType( + int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount); + virtual HRESULT skipMediaType(int token, int *index, ULONG count); + virtual HRESULT cloneMediaType(int token, int index, IEnumMediaTypes **enumeration); + +private: + int m_mediaTypeToken; + QVector m_mediaTypes; +}; + +#endif diff --git a/src/plugins/directshow/player/directshowmetadatacontrol.cpp b/src/plugins/directshow/player/directshowmetadatacontrol.cpp new file mode 100644 index 000000000..40c3920b4 --- /dev/null +++ b/src/plugins/directshow/player/directshowmetadatacontrol.cpp @@ -0,0 +1,352 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +#include "directshowmetadatacontrol.h" + +#include "directshowplayerservice.h" + +#include + +#ifndef QT_NO_WMSDK +namespace +{ + struct QWMMetaDataKeyLookup + { + QtMultimediaKit::MetaData key; + const wchar_t *token; + }; +} + +static const QWMMetaDataKeyLookup qt_wmMetaDataKeys[] = +{ + { QtMultimediaKit::Title, L"Title" }, + { QtMultimediaKit::SubTitle, L"WM/SubTitle" }, + { QtMultimediaKit::Author, L"Author" }, + { QtMultimediaKit::Comment, L"Comment" }, + { QtMultimediaKit::Description, L"Description" }, + { QtMultimediaKit::Category, L"WM/Category" }, + { QtMultimediaKit::Genre, L"WM/Genre" }, + //{ QtMultimediaKit::Date, 0 }, + { QtMultimediaKit::Year, L"WM/Year" }, + { QtMultimediaKit::UserRating, L"UserRating" }, + //{ QtMultimediaKit::MetaDatawords, 0 }, + { QtMultimediaKit::Language, L"Language" }, + { QtMultimediaKit::Publisher, L"WM/Publisher" }, + { QtMultimediaKit::Copyright, L"Copyright" }, + { QtMultimediaKit::ParentalRating, L"ParentalRating" }, + { QtMultimediaKit::RatingOrganisation, L"RatingOrganisation" }, + + // Media + { QtMultimediaKit::Size, L"FileSize" }, + { QtMultimediaKit::MediaType, L"MediaType" }, + { QtMultimediaKit::Duration, L"Duration" }, + + // Audio + { QtMultimediaKit::AudioBitRate, L"AudioBitRate" }, + { QtMultimediaKit::AudioCodec, L"AudioCodec" }, + { QtMultimediaKit::ChannelCount, L"ChannelCount" }, + { QtMultimediaKit::SampleRate, L"Frequency" }, + + // Music + { QtMultimediaKit::AlbumTitle, L"WM/AlbumTitle" }, + { QtMultimediaKit::AlbumArtist, L"WM/AlbumArtist" }, + { QtMultimediaKit::ContributingArtist, L"Author" }, + { QtMultimediaKit::Composer, L"WM/Composer" }, + { QtMultimediaKit::Conductor, L"WM/Conductor" }, + { QtMultimediaKit::Lyrics, L"WM/Lyrics" }, + { QtMultimediaKit::Mood, L"WM/Mood" }, + { QtMultimediaKit::TrackNumber, L"WM/TrackNumber" }, + //{ QtMultimediaKit::TrackCount, 0 }, + //{ QtMultimediaKit::CoverArtUriSmall, 0 }, + //{ QtMultimediaKit::CoverArtUriLarge, 0 }, + + // Image/Video + //{ QtMultimediaKit::Resolution, 0 }, + //{ QtMultimediaKit::PixelAspectRatio, 0 }, + + // Video + //{ QtMultimediaKit::FrameRate, 0 }, + { QtMultimediaKit::VideoBitRate, L"VideoBitRate" }, + { QtMultimediaKit::VideoCodec, L"VideoCodec" }, + + //{ QtMultimediaKit::PosterUri, 0 }, + + // Movie + { QtMultimediaKit::ChapterNumber, L"ChapterNumber" }, + { QtMultimediaKit::Director, L"WM/Director" }, + { QtMultimediaKit::LeadPerformer, L"LeadPerformer" }, + { QtMultimediaKit::Writer, L"WM/Writer" }, + + // Photos + { QtMultimediaKit::CameraManufacturer, L"CameraManufacturer" }, + { QtMultimediaKit::CameraModel, L"CameraModel" }, + { QtMultimediaKit::Event, L"Event" }, + { QtMultimediaKit::Subject, L"Subject" } +}; + +static QVariant getValue(IWMHeaderInfo *header, const wchar_t *key) +{ + WORD streamNumber = 0; + WMT_ATTR_DATATYPE type = WMT_TYPE_DWORD; + WORD size = 0; + + if (header->GetAttributeByName(&streamNumber, key, &type, 0, &size) == S_OK) { + switch (type) { + case WMT_TYPE_DWORD: + if (size == sizeof(DWORD)) { + DWORD word; + if (header->GetAttributeByName( + &streamNumber, + key, + &type, + reinterpret_cast(&word), + &size) == S_OK) { + return int(word); + } + } + break; + case WMT_TYPE_STRING: + { + QString string; + string.resize(size / 2 - 1); + + if (header->GetAttributeByName( + &streamNumber, + key, + &type, + reinterpret_cast(const_cast(string.utf16())), + &size) == S_OK) { + return string; + } + } + break; + case WMT_TYPE_BINARY: + { + QByteArray bytes; + bytes.resize(size); + if (header->GetAttributeByName( + &streamNumber, + key, + &type, + reinterpret_cast(bytes.data()), + &size) == S_OK) { + return bytes; + } + } + break; + case WMT_TYPE_BOOL: + if (size == sizeof(DWORD)) { + DWORD word; + if (header->GetAttributeByName( + &streamNumber, + key, + &type, + reinterpret_cast(&word), + &size) == S_OK) { + return bool(word); + } + } + break; + case WMT_TYPE_QWORD: + if (size == sizeof(QWORD)) { + QWORD word; + if (header->GetAttributeByName( + &streamNumber, + key, + &type, + reinterpret_cast(&word), + &size) == S_OK) { + return qint64(word); + } + } + break; + case WMT_TYPE_WORD: + if (size == sizeof(WORD)){ + WORD word; + if (header->GetAttributeByName( + &streamNumber, + key, + &type, + reinterpret_cast(&word), + &size) == S_OK) { + return short(word); + } + } + break; + case WMT_TYPE_GUID: + if (size == 16) { + } + break; + default: + break; + } + } + return QVariant(); +} +#endif + +DirectShowMetaDataControl::DirectShowMetaDataControl(QObject *parent) + : QMetaDataReaderControl(parent) + , m_content(0) +#ifndef QT_NO_WMSDK + , m_headerInfo(0) +#endif +{ +} + +DirectShowMetaDataControl::~DirectShowMetaDataControl() +{ +} + +bool DirectShowMetaDataControl::isMetaDataAvailable() const +{ +#ifndef QT_NO_WMSDK + return m_content || m_headerInfo; +#else + return m_content; +#endif +} + +QVariant DirectShowMetaDataControl::metaData(QtMultimediaKit::MetaData key) const +{ + QVariant value; + +#ifndef QT_NO_WMSDK + if (m_headerInfo) { + static const int count = sizeof(qt_wmMetaDataKeys) / sizeof(QWMMetaDataKeyLookup); + for (int i = 0; i < count; ++i) { + if (qt_wmMetaDataKeys[i].key == key) { + value = getValue(m_headerInfo, qt_wmMetaDataKeys[i].token); + break; + } + } + } else if (m_content) { +#else + if (m_content) { +#endif + BSTR string = 0; + + switch (key) { + case QtMultimediaKit::Author: + m_content->get_AuthorName(&string); + break; + case QtMultimediaKit::Title: + m_content->get_Title(&string); + break; + case QtMultimediaKit::ParentalRating: + m_content->get_Rating(&string); + break; + case QtMultimediaKit::Description: + m_content->get_Description(&string); + break; + case QtMultimediaKit::Copyright: + m_content->get_Copyright(&string); + break; + default: + break; + } + + if (string) { + value = QString::fromUtf16(reinterpret_cast(string), ::SysStringLen(string)); + + ::SysFreeString(string); + } + } + return value; +} + +QList DirectShowMetaDataControl::availableMetaData() const +{ + return QList(); +} + +QVariant DirectShowMetaDataControl::extendedMetaData(const QString &) const +{ + return QVariant(); +} + +QStringList DirectShowMetaDataControl::availableExtendedMetaData() const +{ + return QStringList(); +} + +void DirectShowMetaDataControl::updateGraph(IFilterGraph2 *graph, IBaseFilter *source) +{ + if (m_content) + m_content->Release(); + + if (!graph || graph->QueryInterface( + IID_IAMMediaContent, reinterpret_cast(&m_content)) != S_OK) { + m_content = 0; + } + +#ifdef QT_NO_WMSDK + Q_UNUSED(source); +#else + if (m_headerInfo) + m_headerInfo->Release(); + + m_headerInfo = com_cast(source, IID_IWMHeaderInfo); +#endif + // DirectShowMediaPlayerService holds a lock at this point so defer emitting signals to a later + // time. + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(MetaDataChanged))); +} + +void DirectShowMetaDataControl::customEvent(QEvent *event) +{ + if (event->type() == QEvent::Type(MetaDataChanged)) { + event->accept(); + + emit metaDataChanged(); +#ifndef QT_NO_WMSDK + emit metaDataAvailableChanged(m_content || m_headerInfo); +#else + emit metaDataAvailableChanged(m_content); +#endif + } else { + QMetaDataReaderControl::customEvent(event); + } +} diff --git a/src/plugins/directshow/player/directshowmetadatacontrol.h b/src/plugins/directshow/player/directshowmetadatacontrol.h new file mode 100644 index 000000000..6826d783d --- /dev/null +++ b/src/plugins/directshow/player/directshowmetadatacontrol.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DIRECTSHOWMETADATACONTROL_H +#define DIRECTSHOWMETADATACONTROL_H + +#include + +#include "directshowglobal.h" + +#include + +#ifndef QT_NO_WMSDK +#include +#endif + +#include + +class DirectShowPlayerService; + +QT_USE_NAMESPACE + +class DirectShowMetaDataControl : public QMetaDataReaderControl +{ + Q_OBJECT +public: + DirectShowMetaDataControl(QObject *parent = 0); + ~DirectShowMetaDataControl(); + + bool isMetaDataAvailable() const; + + QVariant metaData(QtMultimediaKit::MetaData key) const; + QList availableMetaData() const; + + QVariant extendedMetaData(const QString &key) const; + QStringList availableExtendedMetaData() const; + + void updateGraph(IFilterGraph2 *graph, IBaseFilter *source); + +protected: + void customEvent(QEvent *event); + +private: + enum Event + { + MetaDataChanged = QEvent::User + }; + + IAMMediaContent *m_content; +#ifndef QT_NO_WMSDK + IWMHeaderInfo *m_headerInfo; +#endif +}; + +#endif diff --git a/src/plugins/directshow/player/directshowpinenum.cpp b/src/plugins/directshow/player/directshowpinenum.cpp new file mode 100644 index 000000000..28093eaee --- /dev/null +++ b/src/plugins/directshow/player/directshowpinenum.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "directshowpinenum.h" + + +DirectShowPinEnum::DirectShowPinEnum(const QList &pins) + : m_ref(1) + , m_pins(pins) + , m_index(0) +{ + foreach (IPin *pin, m_pins) + pin->AddRef(); +} + +DirectShowPinEnum::~DirectShowPinEnum() +{ + foreach (IPin *pin, m_pins) + pin->Release(); +} + +HRESULT DirectShowPinEnum::QueryInterface(REFIID riid, void **ppvObject) +{ + if (riid == IID_IUnknown + || riid == IID_IEnumPins) { + AddRef(); + + *ppvObject = static_cast(this); + + return S_OK; + } else { + *ppvObject = 0; + + return E_NOINTERFACE; + } +} + +ULONG DirectShowPinEnum::AddRef() +{ + return InterlockedIncrement(&m_ref); +} + +ULONG DirectShowPinEnum::Release() +{ + ULONG ref = InterlockedDecrement(&m_ref); + + if (ref == 0) { + delete this; + } + + return ref; +} + +HRESULT DirectShowPinEnum::Next(ULONG cPins, IPin **ppPins, ULONG *pcFetched) +{ + if (ppPins && (pcFetched || cPins == 1)) { + ULONG count = qBound(0, cPins, m_pins.count() - m_index); + + for (ULONG i = 0; i < count; ++i, ++m_index) { + ppPins[i] = m_pins.at(m_index); + ppPins[i]->AddRef(); + } + + if (pcFetched) + *pcFetched = count; + + return count == cPins ? S_OK : S_FALSE; + } else { + return E_POINTER; + } +} + +HRESULT DirectShowPinEnum::Skip(ULONG cPins) +{ + m_index = qMin(int(m_index + cPins), m_pins.count()); + + return m_index < m_pins.count() ? S_OK : S_FALSE; +} + +HRESULT DirectShowPinEnum::Reset() +{ + m_index = 0; + + return S_OK; +} + +HRESULT DirectShowPinEnum::Clone(IEnumPins **ppEnum) +{ + if (ppEnum) { + *ppEnum = new DirectShowPinEnum(m_pins); + + return S_OK; + } else { + return E_POINTER; + } +} diff --git a/src/plugins/directshow/player/directshowpinenum.h b/src/plugins/directshow/player/directshowpinenum.h new file mode 100644 index 000000000..9fba3e84e --- /dev/null +++ b/src/plugins/directshow/player/directshowpinenum.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DIRECTSHOWPINENUM_H +#define DIRECTSHOWPINENUM_H + +#include + +#include + +class DirectShowPinEnum : public IEnumPins +{ +public: + DirectShowPinEnum(const QList &pins); + ~DirectShowPinEnum(); + + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + // IEnumPins + HRESULT STDMETHODCALLTYPE Next(ULONG cPins, IPin **ppPins, ULONG *pcFetched); + HRESULT STDMETHODCALLTYPE Skip(ULONG cPins); + HRESULT STDMETHODCALLTYPE Reset(); + HRESULT STDMETHODCALLTYPE Clone(IEnumPins **ppEnum); + +private: + LONG m_ref; + QList m_pins; + int m_index; +}; + +#endif diff --git a/src/plugins/directshow/player/directshowplayercontrol.cpp b/src/plugins/directshow/player/directshowplayercontrol.cpp new file mode 100644 index 000000000..9035a8b21 --- /dev/null +++ b/src/plugins/directshow/player/directshowplayercontrol.cpp @@ -0,0 +1,405 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "directshowplayercontrol.h" + +#include "directshowplayerservice.h" + +#include +#include + +static int volumeToDecibels(int volume) +{ + if (volume == 0) { + return -10000; + } else if (volume == 100) { + return 0; +#ifdef QT_USE_MATH_H_FLOATS + } else if (sizeof(qreal) == sizeof(float)) { + return qRound(::log10f(float(volume) / 100) * 5000); +#endif + } else { + return qRound(::log10(qreal(volume) / 100) * 5000); + } +} + +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) + , m_audio(0) + , m_updateProperties(0) + , m_state(QMediaPlayer::StoppedState) + , m_status(QMediaPlayer::NoMedia) + , m_error(QMediaPlayer::NoError) + , m_streamTypes(0) + , m_muteVolume(-1) + , m_position(0) + , m_duration(0) + , m_playbackRate(0) + , m_seekable(false) +{ +} + +DirectShowPlayerControl::~DirectShowPlayerControl() +{ + if (m_audio) + m_audio->Release(); +} + +QMediaPlayer::State DirectShowPlayerControl::state() const +{ + return m_state; +} + +QMediaPlayer::MediaStatus DirectShowPlayerControl::mediaStatus() const +{ + return m_status; +} + +qint64 DirectShowPlayerControl::duration() const +{ + return m_duration; +} + +qint64 DirectShowPlayerControl::position() const +{ + return const_cast(m_position) = m_service->position(); +} + +void DirectShowPlayerControl::setPosition(qint64 position) +{ + m_service->seek(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; + } +} + +void DirectShowPlayerControl::setVolume(int volume) +{ + int boundedVolume = qBound(0, volume, 100); + + if (m_muteVolume >= 0) { + m_muteVolume = boundedVolume; + + emit volumeChanged(m_muteVolume); + } else if (m_audio) { + m_audio->put_Volume(volumeToDecibels(volume)); + + emit volumeChanged(boundedVolume); + } +} + +bool DirectShowPlayerControl::isMuted() const +{ + return m_muteVolume >= 0; +} + +void DirectShowPlayerControl::setMuted(bool muted) +{ + if (muted && m_muteVolume < 0) { + if (m_audio) { + long dB = 0; + + m_audio->get_Volume(&dB); + + m_muteVolume = decibelsToVolume(dB); + + m_audio->put_Volume(-10000); + } else { + m_muteVolume = 0; + } + + emit mutedChanged(muted); + } else if (!muted && m_muteVolume >= 0) { + if (m_audio) { + m_audio->put_Volume(volumeToDecibels(m_muteVolume)); + } + m_muteVolume = -1; + + emit mutedChanged(muted); + } +} + +int DirectShowPlayerControl::bufferStatus() const +{ + return m_service->bufferStatus(); +} + +bool DirectShowPlayerControl::isAudioAvailable() const +{ + return m_streamTypes & DirectShowPlayerService::AudioStream; +} + +bool DirectShowPlayerControl::isVideoAvailable() const +{ + return m_streamTypes & DirectShowPlayerService::VideoStream; +} + +bool DirectShowPlayerControl::isSeekable() const +{ + return m_seekable; +} + +QMediaTimeRange DirectShowPlayerControl::availablePlaybackRanges() const +{ + return m_service->availablePlaybackRanges(); +} + +qreal DirectShowPlayerControl::playbackRate() const +{ + return m_playbackRate; +} + +void DirectShowPlayerControl::setPlaybackRate(qreal rate) +{ + if (m_playbackRate != rate) { + m_service->setRate(rate); + + emit playbackRateChanged(m_playbackRate = rate); + } +} + +QMediaContent DirectShowPlayerControl::media() const +{ + return m_media; +} + +const QIODevice *DirectShowPlayerControl::mediaStream() const +{ + return m_stream; +} + +void DirectShowPlayerControl::setMedia(const QMediaContent &media, QIODevice *stream) +{ + m_media = media; + m_stream = stream; + + m_updateProperties &= PlaybackRateProperty; + + m_service->load(media, stream); + + emit mediaChanged(m_media); + emitPropertyChanges(); +} + +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(); + emit stateChanged(m_state = QMediaPlayer::PlayingState); +} + +void DirectShowPlayerControl::pause() +{ + if (m_status == QMediaPlayer::NoMedia) + 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); +} + +void DirectShowPlayerControl::stop() +{ + m_service->stop(); + emit stateChanged(m_state = QMediaPlayer::StoppedState); +} + +void DirectShowPlayerControl::customEvent(QEvent *event) +{ + if (event->type() == QEvent::Type(PropertiesChanged)) { + emitPropertyChanges(); + + event->accept(); + } else { + QMediaPlayerControl::customEvent(event); + } +} + +void DirectShowPlayerControl::emitPropertyChanges() +{ + int properties = m_updateProperties; + m_updateProperties = 0; + + if ((properties & ErrorProperty) && m_error != QMediaPlayer::NoError) + emit error(m_error, m_errorString); + + if (properties & PlaybackRateProperty) + emit playbackRateChanged(m_playbackRate); + + if (properties & StreamTypesProperty) { + emit audioAvailableChanged(m_streamTypes & DirectShowPlayerService::AudioStream); + emit videoAvailableChanged(m_streamTypes & DirectShowPlayerService::VideoStream); + } + + if (properties & PositionProperty) + emit positionChanged(m_position); + + if (properties & DurationProperty) + emit durationChanged(m_duration); + + if (properties & SeekableProperty) + emit seekableChanged(m_seekable); + + if (properties & StatusProperty) + emit mediaStatusChanged(m_status); + + if (properties & StateProperty) + emit stateChanged(m_state); +} + +void DirectShowPlayerControl::scheduleUpdate(int properties) +{ + if (m_updateProperties == 0) + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(PropertiesChanged))); + + m_updateProperties |= properties; +} + +void DirectShowPlayerControl::updateState(QMediaPlayer::State state) +{ + if (m_state != state) { + m_state = state; + + scheduleUpdate(StateProperty); + } +} + +void DirectShowPlayerControl::updateStatus(QMediaPlayer::MediaStatus status) +{ + if (m_status != status) { + m_status = status; + + scheduleUpdate(StatusProperty); + } +} + +void DirectShowPlayerControl::updateMediaInfo(qint64 duration, int streamTypes, bool seekable) +{ + int properties = 0; + + if (m_duration != duration) { + m_duration = duration; + + properties |= DurationProperty; + } + if (m_streamTypes != streamTypes) { + m_streamTypes = streamTypes; + + properties |= StreamTypesProperty; + } + + if (m_seekable != seekable) { + m_seekable = seekable; + + properties |= SeekableProperty; + } + + if (properties != 0) + scheduleUpdate(properties); +} + +void DirectShowPlayerControl::updatePlaybackRate(qreal rate) +{ + if (m_playbackRate != rate) { + m_playbackRate = rate; + + scheduleUpdate(PlaybackRateProperty); + } +} + +void DirectShowPlayerControl::updateAudioOutput(IBaseFilter *filter) +{ + if (m_audio) + m_audio->Release(); + + m_audio = com_cast(filter, IID_IBasicAudio); +} + +void DirectShowPlayerControl::updateError(QMediaPlayer::Error error, const QString &errorString) +{ + m_error = error; + m_errorString = errorString; + + if (m_error != QMediaPlayer::NoError) + scheduleUpdate(ErrorProperty); +} + +void DirectShowPlayerControl::updatePosition(qint64 position) +{ + if (m_position != position) { + m_position = position; + + scheduleUpdate(PositionProperty); + } +} diff --git a/src/plugins/directshow/player/directshowplayercontrol.h b/src/plugins/directshow/player/directshowplayercontrol.h new file mode 100644 index 000000000..2c1cd6ad7 --- /dev/null +++ b/src/plugins/directshow/player/directshowplayercontrol.h @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DIRECTSHOWPLAYERCONTROL_H +#define DIRECTSHOWPLAYERCONTROL_H + +#include "qmediacontent.h" +#include "qmediaplayercontrol.h" + +#include + +#include "directshowplayerservice.h" + +QT_USE_NAMESPACE + +class DirectShowPlayerControl : public QMediaPlayerControl +{ + Q_OBJECT +public: + DirectShowPlayerControl(DirectShowPlayerService *service, QObject *parent = 0); + ~DirectShowPlayerControl(); + + QMediaPlayer::State state() const; + + QMediaPlayer::MediaStatus mediaStatus() const; + + qint64 duration() const; + + qint64 position() const; + void setPosition(qint64 position); + + int volume() const; + void setVolume(int volume); + + bool isMuted() const; + void setMuted(bool muted); + + int bufferStatus() const; + + bool isAudioAvailable() const; + bool isVideoAvailable() const; + + bool isSeekable() const; + + QMediaTimeRange availablePlaybackRanges() const; + + qreal playbackRate() const; + void setPlaybackRate(qreal rate); + + QMediaContent media() const; + const QIODevice *mediaStream() const; + void setMedia(const QMediaContent &media, QIODevice *stream); + + void play(); + void pause(); + void stop(); + + void updateState(QMediaPlayer::State state); + void updateStatus(QMediaPlayer::MediaStatus status); + void updateMediaInfo(qint64 duration, int streamTypes, bool seekable); + void updatePlaybackRate(qreal rate); + void updateAudioOutput(IBaseFilter *filter); + void updateError(QMediaPlayer::Error error, const QString &errorString); + void updatePosition(qint64 position); + +protected: + void customEvent(QEvent *event); + +private: + enum Properties + { + StateProperty = 0x01, + StatusProperty = 0x02, + StreamTypesProperty = 0x04, + DurationProperty = 0x08, + PlaybackRateProperty = 0x10, + SeekableProperty = 0x20, + ErrorProperty = 0x40, + PositionProperty = 0x80 + }; + + enum Event + { + PropertiesChanged = QEvent::User + }; + + void scheduleUpdate(int properties); + void emitPropertyChanges(); + + DirectShowPlayerService *m_service; + IBasicAudio *m_audio; + QIODevice *m_stream; + int m_updateProperties; + QMediaPlayer::State m_state; + QMediaPlayer::MediaStatus m_status; + QMediaPlayer::Error m_error; + int m_streamTypes; + int m_muteVolume; + qint64 m_position; + qint64 m_duration; + qreal m_playbackRate; + bool m_seekable; + QMediaContent m_media; + QString m_errorString; + +}; + +#endif diff --git a/src/plugins/directshow/player/directshowplayerservice.cpp b/src/plugins/directshow/player/directshowplayerservice.cpp new file mode 100644 index 000000000..ac93f592c --- /dev/null +++ b/src/plugins/directshow/player/directshowplayerservice.cpp @@ -0,0 +1,1408 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "directshowplayerservice.h" + +#include "directshowaudioendpointcontrol.h" +#include "directshowiosource.h" +#include "directshowmetadatacontrol.h" +#include "directshowplayercontrol.h" +#include "directshowvideorenderercontrol.h" +#ifndef Q_WS_SIMULATOR +#include "vmr9videowindowcontrol.h" +#endif + +#include "qmediacontent.h" + +#include +#include +#include +#include + +Q_GLOBAL_STATIC(DirectShowEventLoop, qt_directShowEventLoop) + + +// QMediaPlayer uses millisecond time units, direct show uses 100 nanosecond units. +static const int qt_directShowTimeScale = 10000; + +class DirectShowPlayerServiceThread : public QThread +{ +public: + DirectShowPlayerServiceThread(DirectShowPlayerService *service) + : m_service(service) + { + } + +protected: + void run() { m_service->run(); } + +private: + DirectShowPlayerService *m_service; +}; + +DirectShowPlayerService::DirectShowPlayerService(QObject *parent) + : QMediaService(parent) + , m_playerControl(0) + , m_metaDataControl(0) + , m_videoRendererControl(0) +#ifndef Q_WS_SIMULATOR + , m_videoWindowControl(0) +#endif + , m_audioEndpointControl(0) + , m_taskThread(0) + , m_loop(qt_directShowEventLoop()) + , m_pendingTasks(0) + , m_executingTask(0) + , m_executedTasks(0) + , m_taskHandle(::CreateEvent(0, 0, 0, 0)) + , m_eventHandle(0) + , m_graphStatus(NoMedia) + , m_stream(0) + , m_graph(0) + , m_source(0) + , m_audioOutput(0) + , m_videoOutput(0) + , m_rate(1.0) + , m_position(0) + , m_duration(0) + , m_buffering(false) + , m_seekable(false) + , m_atEnd(false) +{ + CoInitialize(NULL); + m_playerControl = new DirectShowPlayerControl(this); + m_metaDataControl = new DirectShowMetaDataControl(this); + m_audioEndpointControl = new DirectShowAudioEndpointControl(this); + + m_taskThread = new DirectShowPlayerServiceThread(this); + m_taskThread->start(); +} + +DirectShowPlayerService::~DirectShowPlayerService() +{ + { + QMutexLocker locker(&m_mutex); + + releaseGraph(); + + m_pendingTasks = Shutdown; + ::SetEvent(m_taskHandle); + } + + m_taskThread->wait(); + delete m_taskThread; + + if (m_audioOutput) { + m_audioOutput->Release(); + m_audioOutput = 0; + } + + if (m_videoOutput) { + m_videoOutput->Release(); + m_videoOutput = 0; + } + + delete m_playerControl; + delete m_audioEndpointControl; + delete m_metaDataControl; + delete m_videoRendererControl; +#ifndef Q_WS_SIMULATOR + delete m_videoWindowControl; +#endif + + ::CloseHandle(m_taskHandle); + CoUninitialize(); +} + +QMediaControl *DirectShowPlayerService::requestControl(const char *name) +{ + if (qstrcmp(name, QMediaPlayerControl_iid) == 0) { + return m_playerControl; + } else if (qstrcmp(name, QAudioEndpointSelector_iid) == 0) { + return m_audioEndpointControl; + } else if (qstrcmp(name, QMetaDataReaderControl_iid) == 0) { + return m_metaDataControl; + } else if (qstrcmp(name, QVideoRendererControl_iid) == 0) { +#ifndef Q_WS_SIMULATOR + if (!m_videoRendererControl && !m_videoWindowControl) { +#else + if (!m_videoRendererControl) { +#endif + m_videoRendererControl = new DirectShowVideoRendererControl(m_loop); + + connect(m_videoRendererControl, SIGNAL(filterChanged()), + this, SLOT(videoOutputChanged())); + + return m_videoRendererControl; + } +#ifndef Q_WS_SIMULATOR + } else if (qstrcmp(name, QVideoWindowControl_iid) == 0) { + if (!m_videoRendererControl && !m_videoWindowControl) { + m_videoWindowControl = new Vmr9VideoWindowControl; + + setVideoOutput(m_videoWindowControl->filter()); + + return m_videoWindowControl; + } +#endif + } + return 0; +} + +void DirectShowPlayerService::releaseControl(QMediaControl *control) +{ + if (!control) { + qWarning("QMediaService::releaseControl():" + " Attempted release of null control"); + } else if (control == m_videoRendererControl) { + setVideoOutput(0); + + delete m_videoRendererControl; + + m_videoRendererControl = 0; +#ifndef Q_WS_SIMULATOR + } else if (control == m_videoWindowControl) { + setVideoOutput(0); + + delete m_videoWindowControl; + + m_videoWindowControl = 0; +#endif + } +} + +void DirectShowPlayerService::load(const QMediaContent &media, QIODevice *stream) +{ + QMutexLocker locker(&m_mutex); + + m_pendingTasks = 0; + + if (m_graph) + releaseGraph(); + + m_resources = media.resources(); + m_stream = stream; + m_error = QMediaPlayer::NoError; + m_errorString = QString(); + m_position = 0; + m_duration = 0; + m_streamTypes = 0; + m_executedTasks = 0; + m_buffering = false; + m_seekable = false; + m_atEnd = false; + m_metaDataControl->updateGraph(0, 0); + + if (m_resources.isEmpty() && !stream) { + m_pendingTasks = 0; + m_graphStatus = NoMedia; + + m_url.clear(); + } else if (stream && (!stream->isReadable() || stream->isSequential())) { + m_pendingTasks = 0; + m_graphStatus = InvalidMedia; + m_error = QMediaPlayer::ResourceError; + } else { + // {36b73882-c2c8-11cf-8b46-00805f6cef60} + static const GUID iid_IFilterGraph2 = { + 0x36b73882, 0xc2c8, 0x11cf, {0x8b, 0x46, 0x00, 0x80, 0x5f, 0x6c, 0xef, 0x60} }; + m_graphStatus = Loading; + + m_graph = com_new(CLSID_FilterGraph, iid_IFilterGraph2); + + if (stream) + m_pendingTasks = SetStreamSource; + else + m_pendingTasks = SetUrlSource; + + ::SetEvent(m_taskHandle); + } + + m_playerControl->updateError(m_error, m_errorString); + m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable); + m_playerControl->updateState(QMediaPlayer::StoppedState); + m_playerControl->updatePosition(m_position); + updateStatus(); +} + +void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker) +{ + IBaseFilter *source = 0; + + QMediaResource resource = m_resources.takeFirst(); + QUrl url = resource.url(); + + HRESULT hr = E_FAIL; + + if (url.scheme() == QLatin1String("http") || url.scheme() == QLatin1String("https")) { + static const GUID clsid_WMAsfReader = { + 0x187463a0, 0x5bb7, 0x11d3, {0xac, 0xbe, 0x00, 0x80, 0xc7, 0x5e, 0x24, 0x6e} }; + + // {56a868a6-0ad4-11ce-b03a-0020af0ba770} + static const GUID iid_IFileSourceFilter = { + 0x56a868a6, 0x0ad4, 0x11ce, {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70} }; + + if (IFileSourceFilter *fileSource = com_new( + clsid_WMAsfReader, iid_IFileSourceFilter)) { + locker->unlock(); + hr = fileSource->Load(reinterpret_cast(url.toString().utf16()), 0); + + if (SUCCEEDED(hr)) { + source = com_cast(fileSource, IID_IBaseFilter); + + if (!SUCCEEDED(hr = m_graph->AddFilter(source, L"Source")) && source) { + source->Release(); + source = 0; + } + } + fileSource->Release(); + locker->relock(); + } + } else if (url.scheme() == QLatin1String("qrc")) { + DirectShowRcSource *rcSource = new DirectShowRcSource(m_loop); + + locker->unlock(); + if (rcSource->open(url) && SUCCEEDED(hr = m_graph->AddFilter(rcSource, L"Source"))) + source = rcSource; + else + rcSource->Release(); + locker->relock(); + } + + if (!SUCCEEDED(hr)) { + locker->unlock(); + hr = m_graph->AddSourceFilter( + reinterpret_cast(url.toString().utf16()), L"Source", &source); + locker->relock(); + } + + if (SUCCEEDED(hr)) { + m_executedTasks = SetSource; + m_pendingTasks |= Render; + + if (m_audioOutput) + m_pendingTasks |= SetAudioOutput; + if (m_videoOutput) + m_pendingTasks |= SetVideoOutput; + + if (m_rate != 1.0) + m_pendingTasks |= SetRate; + + m_source = source; + } else if (!m_resources.isEmpty()) { + m_pendingTasks |= SetUrlSource; + } else { + m_pendingTasks = 0; + m_graphStatus = InvalidMedia; + + switch (hr) { + case VFW_E_UNKNOWN_FILE_TYPE: + m_error = QMediaPlayer::FormatError; + m_errorString = QString(); + break; + case E_OUTOFMEMORY: + case VFW_E_CANNOT_LOAD_SOURCE_FILTER: + case VFW_E_NOT_FOUND: + m_error = QMediaPlayer::ResourceError; + m_errorString = QString(); + break; + default: + m_error = QMediaPlayer::ResourceError; + m_errorString = QString(); + qWarning("DirectShowPlayerService::doSetUrlSource: Unresolved error code %x", uint(hr)); + break; + } + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error))); + } +} + +void DirectShowPlayerService::doSetStreamSource(QMutexLocker *locker) +{ + DirectShowIOSource *source = new DirectShowIOSource(m_loop); + source->setDevice(m_stream); + + if (SUCCEEDED(m_graph->AddFilter(source, L"Source"))) { + m_executedTasks = SetSource; + m_pendingTasks |= Render; + + if (m_audioOutput) + m_pendingTasks |= SetAudioOutput; + if (m_videoOutput) + m_pendingTasks |= SetVideoOutput; + + if (m_rate != 1.0) + m_pendingTasks |= SetRate; + + m_source = source; + } else { + source->Release(); + + m_pendingTasks = 0; + m_graphStatus = InvalidMedia; + + m_error = QMediaPlayer::ResourceError; + m_errorString = QString(); + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error))); + } +} + +void DirectShowPlayerService::doRender(QMutexLocker *locker) +{ + m_pendingTasks |= m_executedTasks & (Play | Pause); + + if (IMediaControl *control = com_cast(m_graph, IID_IMediaControl)) { + control->Stop(); + control->Release(); + } + + if (m_pendingTasks & SetAudioOutput) { + m_graph->AddFilter(m_audioOutput, L"AudioOutput"); + + m_pendingTasks ^= SetAudioOutput; + m_executedTasks |= SetAudioOutput; + } + if (m_pendingTasks & SetVideoOutput) { + m_graph->AddFilter(m_videoOutput, L"VideoOutput"); + + m_pendingTasks ^= SetVideoOutput; + m_executedTasks |= SetVideoOutput; + } + + IFilterGraph2 *graph = m_graph; + graph->AddRef(); + + QVarLengthArray filters; + m_source->AddRef(); + filters.append(m_source); + + bool rendered = false; + + HRESULT renderHr = S_OK; + + while (!filters.isEmpty()) { + IEnumPins *pins = 0; + IBaseFilter *filter = filters[filters.size() - 1]; + filters.removeLast(); + + if (!(m_pendingTasks & ReleaseFilters) && SUCCEEDED(filter->EnumPins(&pins))) { + int outputs = 0; + for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) { + PIN_DIRECTION direction; + if (pin->QueryDirection(&direction) == S_OK && direction == PINDIR_OUTPUT) { + ++outputs; + + IPin *peer = 0; + if (pin->ConnectedTo(&peer) == S_OK) { + PIN_INFO peerInfo; + if (SUCCEEDED(peer->QueryPinInfo(&peerInfo))) + filters.append(peerInfo.pFilter); + peer->Release(); + } else { + locker->unlock(); + HRESULT hr; + if (SUCCEEDED(hr = graph->RenderEx( + pin, /*AM_RENDEREX_RENDERTOEXISTINGRENDERERS*/ 1, 0))) { + rendered = true; + } else if (renderHr == S_OK || renderHr == VFW_E_NO_DECOMPRESSOR){ + renderHr = hr; + } + locker->relock(); + } + } + } + + pins->Release(); + + if (outputs == 0) + rendered = true; + } + filter->Release(); + } + + if (m_audioOutput && !isConnected(m_audioOutput, PINDIR_INPUT)) { + graph->RemoveFilter(m_audioOutput); + + m_executedTasks &= ~SetAudioOutput; + } + + if (m_videoOutput && !isConnected(m_videoOutput, PINDIR_INPUT)) { + graph->RemoveFilter(m_videoOutput); + + m_executedTasks &= ~SetVideoOutput; + } + + graph->Release(); + + if (!(m_pendingTasks & ReleaseFilters)) { + if (rendered) { + if (!(m_executedTasks & FinalizeLoad)) + m_pendingTasks |= FinalizeLoad; + } else { + m_pendingTasks = 0; + + m_graphStatus = InvalidMedia; + + if (!m_audioOutput && !m_videoOutput) { + m_error = QMediaPlayer::ResourceError; + m_errorString = QString(); + } else { + switch (renderHr) { + case VFW_E_UNSUPPORTED_AUDIO: + case VFW_E_UNSUPPORTED_VIDEO: + case VFW_E_UNSUPPORTED_STREAM: + m_error = QMediaPlayer::FormatError; + m_errorString = QString(); + break; + default: + m_error = QMediaPlayer::ResourceError; + m_errorString = QString(); + qWarning("DirectShowPlayerService::doRender: Unresolved error code %x", + uint(renderHr)); + } + } + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error))); + } + + m_executedTasks |= Render; + } + + m_loop->wake(); +} + +void DirectShowPlayerService::doFinalizeLoad(QMutexLocker *locker) +{ + if (m_graphStatus != Loaded) { + if (IMediaEvent *event = com_cast(m_graph, IID_IMediaEvent)) { + event->GetEventHandle(reinterpret_cast(&m_eventHandle)); + event->Release(); + } + if (IMediaSeeking *seeking = com_cast(m_graph, IID_IMediaSeeking)) { + LONGLONG duration = 0; + seeking->GetDuration(&duration); + m_duration = duration / qt_directShowTimeScale; + + DWORD capabilities = 0; + seeking->GetCapabilities(&capabilities); + m_seekable = capabilities & AM_SEEKING_CanSeekAbsolute; + + seeking->Release(); + } + } + + if ((m_executedTasks & SetOutputs) == SetOutputs) { + m_streamTypes = AudioStream | VideoStream; + } else { + m_streamTypes = findStreamTypes(m_source); + } + + m_executedTasks |= FinalizeLoad; + + m_graphStatus = Loaded; + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(FinalizedLoad))); +} + +void DirectShowPlayerService::releaseGraph() +{ + if (m_graph) { + if (m_executingTask != 0) { + // {8E1C39A1-DE53-11cf-AA63-0080C744528D} + static const GUID iid_IAMOpenProgress = { + 0x8E1C39A1, 0xDE53, 0x11cf, {0xAA, 0x63, 0x00, 0x80, 0xC7, 0x44, 0x52, 0x8D} }; + + if (IAMOpenProgress *progress = com_cast( + m_graph, iid_IAMOpenProgress)) { + progress->AbortOperation(); + progress->Release(); + } + m_graph->Abort(); + } + + m_pendingTasks = ReleaseGraph; + + ::SetEvent(m_taskHandle); + + m_loop->wait(&m_mutex); + } +} + +void DirectShowPlayerService::doReleaseGraph(QMutexLocker *locker) +{ + Q_UNUSED(locker); + + if (IMediaControl *control = com_cast(m_graph, IID_IMediaControl)) { + control->Stop(); + control->Release(); + } + + if (m_source) { + m_source->Release(); + m_source = 0; + } + + m_eventHandle = 0; + + m_graph->Release(); + m_graph = 0; + + m_loop->wake(); +} + +int DirectShowPlayerService::findStreamTypes(IBaseFilter *source) const +{ + QVarLengthArray filters; + source->AddRef(); + filters.append(source); + + int streamTypes = 0; + + while (!filters.isEmpty()) { + IEnumPins *pins = 0; + IBaseFilter *filter = filters[filters.size() - 1]; + filters.removeLast(); + + if (SUCCEEDED(filter->EnumPins(&pins))) { + for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) { + PIN_DIRECTION direction; + if (pin->QueryDirection(&direction) == S_OK && direction == PINDIR_OUTPUT) { + AM_MEDIA_TYPE connectionType; + if (SUCCEEDED(pin->ConnectionMediaType(&connectionType))) { + IPin *peer = 0; + + if (connectionType.majortype == MEDIATYPE_Audio) { + streamTypes |= AudioStream; + } else if (connectionType.majortype == MEDIATYPE_Video) { + streamTypes |= VideoStream; + } else if (SUCCEEDED(pin->ConnectedTo(&peer))) { + PIN_INFO peerInfo; + if (SUCCEEDED(peer->QueryPinInfo(&peerInfo))) + filters.append(peerInfo.pFilter); + peer->Release(); + } + } else { + streamTypes |= findStreamType(pin); + } + } + } + } + filter->Release(); + } + return streamTypes; +} + +int DirectShowPlayerService::findStreamType(IPin *pin) const +{ + IEnumMediaTypes *types; + + if (SUCCEEDED(pin->EnumMediaTypes(&types))) { + bool video = false; + bool audio = false; + bool other = false; + + for (AM_MEDIA_TYPE *type = 0; + types->Next(1, &type, 0) == S_OK; + DirectShowMediaType::deleteType(type)) { + if (type->majortype == MEDIATYPE_Audio) + audio = true; + else if (type->majortype == MEDIATYPE_Video) + video = true; + else + other = true; + } + types->Release(); + + if (other) + return 0; + else if (audio && !video) + return AudioStream; + else if (!audio && video) + return VideoStream; + else + return 0; + } else { + return 0; + } +} + +void DirectShowPlayerService::play() +{ + QMutexLocker locker(&m_mutex); + + m_pendingTasks &= ~Pause; + m_pendingTasks |= Play; + + if (m_executedTasks & Render) { + if (m_executedTasks & Stop) { + m_atEnd = false; + m_position = 0; + m_pendingTasks |= Seek; + m_executedTasks ^= Stop; + } + + ::SetEvent(m_taskHandle); + } + + updateStatus(); +} + +void DirectShowPlayerService::doPlay(QMutexLocker *locker) +{ + if (IMediaControl *control = com_cast(m_graph, IID_IMediaControl)) { + locker->unlock(); + HRESULT hr = control->Run(); + locker->relock(); + + control->Release(); + + if (SUCCEEDED(hr)) { + m_executedTasks |= Play; + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StatusChange))); + } else { + m_error = QMediaPlayer::ResourceError; + m_errorString = QString(); + qWarning("DirectShowPlayerService::doPlay: Unresolved error code %x", uint(hr)); + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error))); + } + } +} + +void DirectShowPlayerService::pause() +{ + QMutexLocker locker(&m_mutex); + + m_pendingTasks &= ~Play; + m_pendingTasks |= Pause; + + if (m_executedTasks & Render) { + if (m_executedTasks & Stop) { + m_atEnd = false; + m_position = 0; + m_pendingTasks |= Seek; + m_executedTasks ^= Stop; + } + + ::SetEvent(m_taskHandle); + } + + updateStatus(); +} + +void DirectShowPlayerService::doPause(QMutexLocker *locker) +{ + if (IMediaControl *control = com_cast(m_graph, IID_IMediaControl)) { + locker->unlock(); + HRESULT hr = control->Pause(); + locker->relock(); + + control->Release(); + + if (SUCCEEDED(hr)) { + if (IMediaSeeking *seeking = com_cast(m_graph, IID_IMediaSeeking)) { + LONGLONG position = 0; + + seeking->GetCurrentPosition(&position); + seeking->Release(); + + m_position = position / qt_directShowTimeScale; + } else { + m_position = 0; + } + + m_executedTasks |= Pause; + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StatusChange))); + } else { + m_error = QMediaPlayer::ResourceError; + m_errorString = QString(); + qWarning("DirectShowPlayerService::doPause: Unresolved error code %x", uint(hr)); + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error))); + } + } +} + +void DirectShowPlayerService::stop() +{ + QMutexLocker locker(&m_mutex); + + m_pendingTasks &= ~(Play | Pause | Seek); + + if ((m_executingTask | m_executedTasks) & (Play | Pause | Seek)) { + m_pendingTasks |= Stop; + + ::SetEvent(m_taskHandle); + + m_loop->wait(&m_mutex); + } + + updateStatus(); +} + +void DirectShowPlayerService::doStop(QMutexLocker *locker) +{ + if (m_executedTasks & (Play | Pause)) { + if (IMediaControl *control = com_cast(m_graph, IID_IMediaControl)) { + control->Stop(); + control->Release(); + } + + m_position = 0; + m_pendingTasks |= Seek; + + m_executedTasks &= ~(Play | Pause); + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StatusChange))); + } + + m_executedTasks |= Stop; + + m_loop->wake(); +} + +void DirectShowPlayerService::setRate(qreal rate) +{ + QMutexLocker locker(&m_mutex); + + m_rate = rate; + + m_pendingTasks |= SetRate; + + if (m_executedTasks & FinalizeLoad) + ::SetEvent(m_taskHandle); +} + +void DirectShowPlayerService::doSetRate(QMutexLocker *locker) +{ + if (IMediaSeeking *seeking = com_cast(m_graph, IID_IMediaSeeking)) { + // 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(¤tPosition); + m_position = currentPosition / qt_directShowTimeScale; + + LONGLONG minimum = 0; + LONGLONG maximum = 0; + m_playbackRange = SUCCEEDED(seeking->GetAvailable(&minimum, &maximum)) + ? QMediaTimeRange(minimum / qt_directShowTimeScale, maximum / qt_directShowTimeScale) + : QMediaTimeRange(); + + locker->unlock(); + HRESULT hr = seeking->SetRate(m_rate); + locker->relock(); + + if (!SUCCEEDED(hr)) { + double rate = 0.0; + m_rate = seeking->GetRate(&rate) + ? rate + : 1.0; + } + + seeking->Release(); + } else if (m_rate != 1.0) { + m_rate = 1.0; + } + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(RateChange))); +} + +qint64 DirectShowPlayerService::position() const +{ + QMutexLocker locker(const_cast(&m_mutex)); + + if (m_graphStatus == Loaded) { + if (m_executingTask == Seek || m_executingTask == SetRate || (m_pendingTasks & Seek)) { + return m_position; + } else if (IMediaSeeking *seeking = com_cast(m_graph, IID_IMediaSeeking)) { + LONGLONG position = 0; + + seeking->GetCurrentPosition(&position); + seeking->Release(); + + const_cast(m_position) = position / qt_directShowTimeScale; + + return m_position; + } + } + return 0; +} + +QMediaTimeRange DirectShowPlayerService::availablePlaybackRanges() const +{ + QMutexLocker locker(const_cast(&m_mutex)); + + if (m_graphStatus == Loaded) { + if (m_executingTask == Seek || m_executingTask == SetRate || (m_pendingTasks & Seek)) { + return m_playbackRange; + } else if (IMediaSeeking *seeking = com_cast(m_graph, IID_IMediaSeeking)) { + LONGLONG minimum = 0; + LONGLONG maximum = 0; + + HRESULT hr = seeking->GetAvailable(&minimum, &maximum); + seeking->Release(); + + if (SUCCEEDED(hr)) + return QMediaTimeRange(minimum, maximum); + } + } + return QMediaTimeRange(); +} + +void DirectShowPlayerService::seek(qint64 position) +{ + QMutexLocker locker(&m_mutex); + + m_position = position; + + m_pendingTasks |= Seek; + + if (m_executedTasks & FinalizeLoad) + ::SetEvent(m_taskHandle); +} + +void DirectShowPlayerService::doSeek(QMutexLocker *locker) +{ + if (IMediaSeeking *seeking = com_cast(m_graph, IID_IMediaSeeking)) { + LONGLONG seekPosition = LONGLONG(m_position) * 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(¤tPosition); + m_position = currentPosition / qt_directShowTimeScale; + + LONGLONG minimum = 0; + LONGLONG maximum = 0; + m_playbackRange = SUCCEEDED(seeking->GetAvailable(&minimum, &maximum)) + ? QMediaTimeRange( + minimum / qt_directShowTimeScale, maximum / qt_directShowTimeScale) + : QMediaTimeRange(); + + locker->unlock(); + seeking->SetPositions( + &seekPosition, AM_SEEKING_AbsolutePositioning, 0, AM_SEEKING_NoPositioning); + locker->relock(); + + seeking->GetCurrentPosition(¤tPosition); + m_position = currentPosition / qt_directShowTimeScale; + + seeking->Release(); + } else { + m_position = 0; + } + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(PositionChange))); +} + +int DirectShowPlayerService::bufferStatus() const +{ +#ifndef QT_NO_WMSDK + QMutexLocker locker(const_cast(&m_mutex)); + + if (IWMReaderAdvanced2 *reader = com_cast( + m_source, IID_IWMReaderAdvanced2)) { + DWORD percentage = 0; + + reader->GetBufferProgress(&percentage, 0); + reader->Release(); + + return percentage; + } else { + return 0; + } +#else + return 0; +#endif +} + +void DirectShowPlayerService::setAudioOutput(IBaseFilter *filter) +{ + QMutexLocker locker(&m_mutex); + + if (m_graph) { + if (m_audioOutput) { + if (m_executedTasks & SetAudioOutput) { + m_pendingTasks |= ReleaseAudioOutput; + + ::SetEvent(m_taskHandle); + + m_loop->wait(&m_mutex); + } + m_audioOutput->Release(); + } + + m_audioOutput = filter; + + if (m_audioOutput) { + m_audioOutput->AddRef(); + + m_pendingTasks |= SetAudioOutput; + + if (m_executedTasks & SetSource) { + m_pendingTasks |= Render; + + ::SetEvent(m_taskHandle); + } + } else { + m_pendingTasks &= ~ SetAudioOutput; + } + } else { + if (m_audioOutput) + m_audioOutput->Release(); + + m_audioOutput = filter; + + if (m_audioOutput) + m_audioOutput->AddRef(); + } + + m_playerControl->updateAudioOutput(m_audioOutput); +} + +void DirectShowPlayerService::doReleaseAudioOutput(QMutexLocker *locker) +{ + m_pendingTasks |= m_executedTasks & (Play | Pause); + + if (IMediaControl *control = com_cast(m_graph, IID_IMediaControl)) { + control->Stop(); + control->Release(); + } + + IBaseFilter *decoder = getConnected(m_audioOutput, PINDIR_INPUT); + if (!decoder) { + decoder = m_audioOutput; + decoder->AddRef(); + } + + // {DCFBDCF6-0DC2-45f5-9AB2-7C330EA09C29} + static const GUID iid_IFilterChain = { + 0xDCFBDCF6, 0x0DC2, 0x45f5, {0x9A, 0xB2, 0x7C, 0x33, 0x0E, 0xA0, 0x9C, 0x29} }; + + if (IFilterChain *chain = com_cast(m_graph, iid_IFilterChain)) { + chain->RemoveChain(decoder, m_audioOutput); + chain->Release(); + } else { + m_graph->RemoveFilter(m_audioOutput); + } + + decoder->Release(); + + m_executedTasks &= ~SetAudioOutput; + + m_loop->wake(); +} + +void DirectShowPlayerService::setVideoOutput(IBaseFilter *filter) +{ + QMutexLocker locker(&m_mutex); + + if (m_graph) { + if (m_videoOutput) { + if (m_executedTasks & SetVideoOutput) { + m_pendingTasks |= ReleaseVideoOutput; + + ::SetEvent(m_taskHandle); + + m_loop->wait(&m_mutex); + } + m_videoOutput->Release(); + } + + m_videoOutput = filter; + + if (m_videoOutput) { + m_videoOutput->AddRef(); + + m_pendingTasks |= SetVideoOutput; + + if (m_executedTasks & SetSource) { + m_pendingTasks |= Render; + + ::SetEvent(m_taskHandle); + } + } + } else { + if (m_videoOutput) + m_videoOutput->Release(); + + m_videoOutput = filter; + + if (m_videoOutput) + m_videoOutput->AddRef(); + } +} + +void DirectShowPlayerService::doReleaseVideoOutput(QMutexLocker *locker) +{ + m_pendingTasks |= m_executedTasks & (Play | Pause); + + if (IMediaControl *control = com_cast(m_graph, IID_IMediaControl)) { + control->Stop(); + control->Release(); + } + + IBaseFilter *intermediate = 0; + if (!SUCCEEDED(m_graph->FindFilterByName(L"Color Space Converter", &intermediate))) { + intermediate = m_videoOutput; + intermediate->AddRef(); + } + + IBaseFilter *decoder = getConnected(intermediate, PINDIR_INPUT); + if (!decoder) { + decoder = intermediate; + decoder->AddRef(); + } + + // {DCFBDCF6-0DC2-45f5-9AB2-7C330EA09C29} + static const GUID iid_IFilterChain = { + 0xDCFBDCF6, 0x0DC2, 0x45f5, {0x9A, 0xB2, 0x7C, 0x33, 0x0E, 0xA0, 0x9C, 0x29} }; + + if (IFilterChain *chain = com_cast(m_graph, iid_IFilterChain)) { + chain->RemoveChain(decoder, m_videoOutput); + chain->Release(); + } else { + m_graph->RemoveFilter(m_videoOutput); + } + + intermediate->Release(); + decoder->Release(); + + m_executedTasks &= ~SetVideoOutput; + + m_loop->wake(); +} + +void DirectShowPlayerService::customEvent(QEvent *event) +{ + if (event->type() == QEvent::Type(FinalizedLoad)) { + QMutexLocker locker(&m_mutex); + + m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable); + m_metaDataControl->updateGraph(m_graph, m_source); + + updateStatus(); + } else if (event->type() == QEvent::Type(Error)) { + QMutexLocker locker(&m_mutex); + + if (m_error != QMediaPlayer::NoError) { + m_playerControl->updateError(m_error, m_errorString); + m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable); + m_playerControl->updateState(QMediaPlayer::StoppedState); + updateStatus(); + } + } else if (event->type() == QEvent::Type(RateChange)) { + QMutexLocker locker(&m_mutex); + + m_playerControl->updatePlaybackRate(m_rate); + } else if (event->type() == QEvent::Type(StatusChange)) { + QMutexLocker locker(&m_mutex); + + updateStatus(); + m_playerControl->updatePosition(m_position); + } else if (event->type() == QEvent::Type(DurationChange)) { + QMutexLocker locker(&m_mutex); + + m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable); + } else if (event->type() == QEvent::Type(EndOfMedia)) { + QMutexLocker locker(&m_mutex); + + if (m_atEnd) { + m_playerControl->updateState(QMediaPlayer::StoppedState); + m_playerControl->updateStatus(QMediaPlayer::EndOfMedia); + m_playerControl->updatePosition(m_position); + } + } else if (event->type() == QEvent::Type(PositionChange)) { + QMutexLocker locker(&m_mutex); + + if (m_playerControl->mediaStatus() == QMediaPlayer::EndOfMedia) + m_playerControl->updateStatus(QMediaPlayer::LoadedMedia); + m_playerControl->updatePosition(m_position); + } else { + QMediaService::customEvent(event); + } +} + +void DirectShowPlayerService::videoOutputChanged() +{ + setVideoOutput(m_videoRendererControl->filter()); +} + +void DirectShowPlayerService::graphEvent(QMutexLocker *locker) +{ + if (IMediaEvent *event = com_cast(m_graph, IID_IMediaEvent)) { + long eventCode; + LONG_PTR param1; + LONG_PTR param2; + + while (event->GetEvent(&eventCode, ¶m1, ¶m2, 0) == S_OK) { + switch (eventCode) { + case EC_BUFFERING_DATA: + m_buffering = param1; + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StatusChange))); + break; + case EC_COMPLETE: + m_executedTasks &= ~(Play | Pause); + m_executedTasks |= Stop; + + m_buffering = false; + m_atEnd = true; + + if (IMediaSeeking *seeking = com_cast(m_graph, IID_IMediaSeeking)) { + LONGLONG position = 0; + + seeking->GetCurrentPosition(&position); + seeking->Release(); + + m_position = position / qt_directShowTimeScale; + } + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(EndOfMedia))); + break; + case EC_LENGTH_CHANGED: + if (IMediaSeeking *seeking = com_cast(m_graph, IID_IMediaSeeking)) { + LONGLONG duration = 0; + seeking->GetDuration(&duration); + m_duration = duration / qt_directShowTimeScale; + + DWORD capabilities = 0; + seeking->GetCapabilities(&capabilities); + m_seekable = capabilities & AM_SEEKING_CanSeekAbsolute; + + seeking->Release(); + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(DurationChange))); + } + break; + default: + break; + } + + event->FreeEventParams(eventCode, param1, param2); + } + event->Release(); + } +} + +void DirectShowPlayerService::updateStatus() +{ + switch (m_graphStatus) { + case NoMedia: + m_playerControl->updateStatus(QMediaPlayer::NoMedia); + break; + case Loading: + m_playerControl->updateStatus(QMediaPlayer::LoadingMedia); + break; + case Loaded: + if ((m_pendingTasks | m_executingTask | m_executedTasks) & (Play | Pause)) { + if (m_buffering) + m_playerControl->updateStatus(QMediaPlayer::BufferingMedia); + else + m_playerControl->updateStatus(QMediaPlayer::BufferedMedia); + } else { + m_playerControl->updateStatus(QMediaPlayer::LoadedMedia); + } + break; + case InvalidMedia: + m_playerControl->updateStatus(QMediaPlayer::InvalidMedia); + break; + default: + m_playerControl->updateStatus(QMediaPlayer::UnknownMediaStatus); + } +} + +bool DirectShowPlayerService::isConnected(IBaseFilter *filter, PIN_DIRECTION direction) const +{ + bool connected = false; + + IEnumPins *pins = 0; + + if (SUCCEEDED(filter->EnumPins(&pins))) { + for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) { + PIN_DIRECTION dir; + if (SUCCEEDED(pin->QueryDirection(&dir)) && dir == direction) { + IPin *peer = 0; + if (SUCCEEDED(pin->ConnectedTo(&peer))) { + connected = true; + + peer->Release(); + } + } + } + pins->Release(); + } + return connected; +} + +IBaseFilter *DirectShowPlayerService::getConnected( + IBaseFilter *filter, PIN_DIRECTION direction) const +{ + IBaseFilter *connected = 0; + + IEnumPins *pins = 0; + + if (SUCCEEDED(filter->EnumPins(&pins))) { + for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) { + PIN_DIRECTION dir; + if (SUCCEEDED(pin->QueryDirection(&dir)) && dir == direction) { + IPin *peer = 0; + if (SUCCEEDED(pin->ConnectedTo(&peer))) { + PIN_INFO info; + + if (SUCCEEDED(peer->QueryPinInfo(&info))) { + if (connected) { + qWarning("DirectShowPlayerService::getConnected: " + "Multiple connected filters"); + connected->Release(); + } + connected = info.pFilter; + } + peer->Release(); + } + } + } + pins->Release(); + } + return connected; +} + +void DirectShowPlayerService::run() +{ + QMutexLocker locker(&m_mutex); + + for (;;) { + ::ResetEvent(m_taskHandle); + + while (m_pendingTasks == 0) { + DWORD result = 0; + + locker.unlock(); + if (m_eventHandle) { + HANDLE handles[] = { m_taskHandle, m_eventHandle }; + + result = ::WaitForMultipleObjects(2, handles, false, INFINITE); + } else { + result = ::WaitForSingleObject(m_taskHandle, INFINITE); + } + locker.relock(); + + if (result == WAIT_OBJECT_0 + 1) { + graphEvent(&locker); + } + } + + if (m_pendingTasks & ReleaseGraph) { + m_pendingTasks ^= ReleaseGraph; + m_executingTask = ReleaseGraph; + + doReleaseGraph(&locker); + //if the graph is released, we should not process other operations later + if (m_pendingTasks & Shutdown) { + m_pendingTasks = 0; + return; + } + m_pendingTasks = 0; + } else if (m_pendingTasks & Shutdown) { + return; + } else if (m_pendingTasks & ReleaseAudioOutput) { + m_pendingTasks ^= ReleaseAudioOutput; + m_executingTask = ReleaseAudioOutput; + + doReleaseAudioOutput(&locker); + } else if (m_pendingTasks & ReleaseVideoOutput) { + m_pendingTasks ^= ReleaseVideoOutput; + m_executingTask = ReleaseVideoOutput; + + doReleaseVideoOutput(&locker); + } else if (m_pendingTasks & SetUrlSource) { + m_pendingTasks ^= SetUrlSource; + m_executingTask = SetUrlSource; + + doSetUrlSource(&locker); + } else if (m_pendingTasks & SetStreamSource) { + m_pendingTasks ^= SetStreamSource; + m_executingTask = SetStreamSource; + + doSetStreamSource(&locker); + } else if (m_pendingTasks & Render) { + m_pendingTasks ^= Render; + m_executingTask = Render; + + doRender(&locker); + } else if (!(m_executedTasks & Render)) { + m_pendingTasks &= ~(FinalizeLoad | SetRate | Stop | Pause | Seek | Play); + } else if (m_pendingTasks & FinalizeLoad) { + m_pendingTasks ^= FinalizeLoad; + m_executingTask = FinalizeLoad; + + doFinalizeLoad(&locker); + } else if (m_pendingTasks & Stop) { + m_pendingTasks ^= Stop; + m_executingTask = Stop; + + doStop(&locker); + } else if (m_pendingTasks & SetRate) { + m_pendingTasks ^= SetRate; + m_executingTask = SetRate; + + doSetRate(&locker); + } else if (m_pendingTasks & Pause) { + m_pendingTasks ^= Pause; + m_executingTask = Pause; + + doPause(&locker); + } else if (m_pendingTasks & Seek) { + m_pendingTasks ^= Seek; + m_executingTask = Seek; + + doSeek(&locker); + } else if (m_pendingTasks & Play) { + m_pendingTasks ^= Play; + m_executingTask = Play; + + doPlay(&locker); + } + m_executingTask = 0; + } +} diff --git a/src/plugins/directshow/player/directshowplayerservice.h b/src/plugins/directshow/player/directshowplayerservice.h new file mode 100644 index 000000000..cc0cac1cf --- /dev/null +++ b/src/plugins/directshow/player/directshowplayerservice.h @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DIRECTSHOWPLAYERSERVICE_H +#define DIRECTSHOWPLAYERSERVICE_H + +#include "qmediaplayer.h" +#include "qmediaresource.h" +#include "qmediaservice.h" +#include "qmediatimerange.h" + +#include "directshoweventloop.h" +#include "directshowglobal.h" + +#include +#include +#include +#include + +class DirectShowAudioEndpointControl; +class DirectShowMetaDataControl; +class DirectShowPlayerControl; +class DirectShowVideoRendererControl; +#ifndef Q_WS_SIMULATOR +class Vmr9VideoWindowControl; +#endif + +QT_BEGIN_NAMESPACE +class QMediaContent; +QT_END_NAMESPACE + +QT_USE_NAMESPACE + +class DirectShowPlayerService : public QMediaService +{ + Q_OBJECT +public: + enum StreamType + { + AudioStream = 0x01, + VideoStream = 0x02 + }; + + DirectShowPlayerService(QObject *parent = 0); + ~DirectShowPlayerService(); + + QMediaControl* requestControl(const char *name); + void releaseControl(QMediaControl *control); + + void load(const QMediaContent &media, QIODevice *stream); + void play(); + void pause(); + void stop(); + + qint64 position() const; + QMediaTimeRange availablePlaybackRanges() const; + + void seek(qint64 position); + void setRate(qreal rate); + + int bufferStatus() const; + + void setAudioOutput(IBaseFilter *filter); + void setVideoOutput(IBaseFilter *filter); + +protected: + void customEvent(QEvent *event); + +private Q_SLOTS: + void videoOutputChanged(); + +private: + void releaseGraph(); + void updateStatus(); + + int findStreamTypes(IBaseFilter *source) const; + int findStreamType(IPin *pin) const; + + bool isConnected(IBaseFilter *filter, PIN_DIRECTION direction) const; + IBaseFilter *getConnected(IBaseFilter *filter, PIN_DIRECTION direction) const; + + void run(); + + void doSetUrlSource(QMutexLocker *locker); + void doSetStreamSource(QMutexLocker *locker); + void doRender(QMutexLocker *locker); + void doFinalizeLoad(QMutexLocker *locker); + void doSetRate(QMutexLocker *locker); + void doSeek(QMutexLocker *locker); + void doPlay(QMutexLocker *locker); + void doPause(QMutexLocker *locker); + void doStop(QMutexLocker *locker); + void doReleaseAudioOutput(QMutexLocker *locker); + void doReleaseVideoOutput(QMutexLocker *locker); + void doReleaseGraph(QMutexLocker *locker); + + void graphEvent(QMutexLocker *locker); + + enum Task + { + Shutdown = 0x0001, + SetUrlSource = 0x0002, + SetStreamSource = 0x0004, + SetSource = SetUrlSource | SetStreamSource, + SetAudioOutput = 0x0008, + SetVideoOutput = 0x0010, + SetOutputs = SetAudioOutput | SetVideoOutput, + Render = 0x0020, + FinalizeLoad = 0x0040, + SetRate = 0x0080, + Seek = 0x0100, + Play = 0x0200, + Pause = 0x0400, + Stop = 0x0800, + ReleaseGraph = 0x1000, + ReleaseAudioOutput = 0x2000, + ReleaseVideoOutput = 0x4000, + ReleaseFilters = ReleaseGraph | ReleaseAudioOutput | ReleaseVideoOutput + }; + + enum Event + { + FinalizedLoad = QEvent::User, + Error, + RateChange, + Started, + Paused, + DurationChange, + StatusChange, + EndOfMedia, + PositionChange + }; + + enum GraphStatus + { + NoMedia, + Loading, + Loaded, + InvalidMedia + }; + + DirectShowPlayerControl *m_playerControl; + DirectShowMetaDataControl *m_metaDataControl; + DirectShowVideoRendererControl *m_videoRendererControl; +#ifndef Q_WS_SIMULATOR + Vmr9VideoWindowControl *m_videoWindowControl; +#endif + DirectShowAudioEndpointControl *m_audioEndpointControl; + + QThread *m_taskThread; + DirectShowEventLoop *m_loop; + int m_pendingTasks; + int m_executingTask; + int m_executedTasks; + HANDLE m_taskHandle; + HANDLE m_eventHandle; + GraphStatus m_graphStatus; + QMediaPlayer::Error m_error; + QIODevice *m_stream; + IFilterGraph2 *m_graph; + IBaseFilter *m_source; + IBaseFilter *m_audioOutput; + IBaseFilter *m_videoOutput; + int m_streamTypes; + qreal m_rate; + qint64 m_position; + qint64 m_duration; + bool m_buffering; + bool m_seekable; + bool m_atEnd; + QMediaTimeRange m_playbackRange; + QUrl m_url; + QMediaResourceList m_resources; + QString m_errorString; + QMutex m_mutex; + + friend class DirectShowPlayerServiceThread; +}; + + +#endif diff --git a/src/plugins/directshow/player/directshowsamplescheduler.cpp b/src/plugins/directshow/player/directshowsamplescheduler.cpp new file mode 100644 index 000000000..48b7899c6 --- /dev/null +++ b/src/plugins/directshow/player/directshowsamplescheduler.cpp @@ -0,0 +1,437 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "directshowsamplescheduler.h" + +#include +#include + +class DirectShowTimedSample +{ +public: + DirectShowTimedSample(IMediaSample *sample) + : m_next(0) + , m_sample(sample) + , m_cookie(0) + , m_lastSample(false) + { + m_sample->AddRef(); + } + + ~DirectShowTimedSample() + { + m_sample->Release(); + } + + IMediaSample *sample() const { return m_sample; } + + DirectShowTimedSample *nextSample() const { return m_next; } + void setNextSample(DirectShowTimedSample *sample) { Q_ASSERT(!m_next); m_next = sample; } + + DirectShowTimedSample *remove() { + DirectShowTimedSample *next = m_next; delete this; return next; } + + bool schedule(IReferenceClock *clock, REFERENCE_TIME startTime, HANDLE handle); + void unschedule(IReferenceClock *clock); + + bool isReady(IReferenceClock *clock) const; + + bool isLast() const { return m_lastSample; } + void setLast() { m_lastSample = true; } + +private: + DirectShowTimedSample *m_next; + IMediaSample *m_sample; + DWORD_PTR m_cookie; + bool m_lastSample; +}; + +bool DirectShowTimedSample::schedule( + IReferenceClock *clock, REFERENCE_TIME startTime, HANDLE handle) +{ + REFERENCE_TIME sampleStartTime; + REFERENCE_TIME sampleEndTime; + if (m_sample->GetTime(&sampleStartTime, &sampleEndTime) == S_OK) { + if (clock->AdviseTime( + startTime, sampleStartTime, reinterpret_cast(handle), &m_cookie) == S_OK) { + return true; + } + } + return false; +} + +void DirectShowTimedSample::unschedule(IReferenceClock *clock) +{ + clock->Unadvise(m_cookie); +} + +bool DirectShowTimedSample::isReady(IReferenceClock *clock) const +{ + REFERENCE_TIME sampleStartTime; + REFERENCE_TIME sampleEndTime; + REFERENCE_TIME currentTime; + if (m_sample->GetTime(&sampleStartTime, &sampleEndTime) == S_OK) { + if (clock->GetTime(¤tTime) == S_OK) + return currentTime >= sampleStartTime; + } + return true; +} + +DirectShowSampleScheduler::DirectShowSampleScheduler(IUnknown *pin, QObject *parent) + : QObject(parent) + , m_pin(pin) + , m_clock(0) + , m_allocator(0) + , m_head(0) + , m_tail(0) + , m_maximumSamples(1) + , m_state(Stopped) + , m_startTime(0) + , m_timeoutEvent(::CreateEvent(0, 0, 0, 0)) + , m_flushEvent(::CreateEvent(0, 0, 0, 0)) +{ + m_semaphore.release(m_maximumSamples); +} + +DirectShowSampleScheduler::~DirectShowSampleScheduler() +{ + ::CloseHandle(m_timeoutEvent); + ::CloseHandle(m_flushEvent); + + Q_ASSERT(!m_clock); + Q_ASSERT(!m_allocator); +} + +HRESULT DirectShowSampleScheduler::QueryInterface(REFIID riid, void **ppvObject) +{ + return m_pin->QueryInterface(riid, ppvObject); +} + +ULONG DirectShowSampleScheduler::AddRef() +{ + return m_pin->AddRef(); +} + +ULONG DirectShowSampleScheduler::Release() +{ + return m_pin->Release(); +} + +// IMemInputPin +HRESULT DirectShowSampleScheduler::GetAllocator(IMemAllocator **ppAllocator) +{ + if (!ppAllocator) { + return E_POINTER; + } else { + QMutexLocker locker(&m_mutex); + + if (!m_allocator) { + return VFW_E_NO_ALLOCATOR; + } else { + *ppAllocator = m_allocator; + + return S_OK; + } + } +} + +HRESULT DirectShowSampleScheduler::NotifyAllocator(IMemAllocator *pAllocator, BOOL bReadOnly) +{ + Q_UNUSED(bReadOnly); + + HRESULT hr; + ALLOCATOR_PROPERTIES properties; + + if (!pAllocator) { + if (m_allocator) + m_allocator->Release(); + + m_allocator = 0; + + return S_OK; + } else if ((hr = pAllocator->GetProperties(&properties)) != S_OK) { + return hr; + } else { + if (properties.cBuffers == 1) { + ALLOCATOR_PROPERTIES actual; + + properties.cBuffers = 2; + if ((hr = pAllocator->SetProperties(&properties, &actual)) != S_OK) + return hr; + } + + QMutexLocker locker(&m_mutex); + + if (m_allocator) + m_allocator->Release(); + + m_allocator = pAllocator; + m_allocator->AddRef(); + + return S_OK; + } +} + +HRESULT DirectShowSampleScheduler::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps) +{ + if (!pProps) + return E_POINTER; + + pProps->cBuffers = 2; + + return S_OK; +} + +HRESULT DirectShowSampleScheduler::Receive(IMediaSample *pSample) +{ + if (!pSample) + return E_POINTER; + + m_semaphore.acquire(1); + + QMutexLocker locker(&m_mutex); + + if (m_state & Flushing) { + m_semaphore.release(1); + + return S_FALSE; + } else if (m_state == Stopped) { + m_semaphore.release(); + + return VFW_E_WRONG_STATE; + } else { + DirectShowTimedSample *timedSample = new DirectShowTimedSample(pSample); + + if (m_tail) + m_tail->setNextSample(timedSample); + else + m_head = timedSample; + + m_tail = timedSample; + + if (m_state == Running) { + if (!timedSample->schedule(m_clock, m_startTime, m_timeoutEvent)) { + // Timing information is unavailable, so schedule frames immediately. + QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); + } else { + locker.unlock(); + HANDLE handles[] = { m_flushEvent, m_timeoutEvent }; + DWORD result = ::WaitForMultipleObjects(2, handles, FALSE, INFINITE); + locker.relock(); + + if (result == WAIT_OBJECT_0 + 1) + QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); + } + } else if (m_tail == m_head) { + // If this is the first frame make it available. + QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); + + if (m_state == Paused) { + ::ResetEvent(m_timeoutEvent); + + locker.unlock(); + HANDLE handles[] = { m_flushEvent, m_timeoutEvent }; + ::WaitForMultipleObjects(2, handles, FALSE, INFINITE); + locker.relock(); + } + } + + return S_OK; + } +} + +HRESULT DirectShowSampleScheduler::ReceiveMultiple( + IMediaSample **pSamples, long nSamples, long *nSamplesProcessed) +{ + if (!pSamples || !nSamplesProcessed) + return E_POINTER; + + for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; ++(*nSamplesProcessed)) { + HRESULT hr = Receive(pSamples[*nSamplesProcessed]); + + if (hr != S_OK) + return hr; + } + return S_OK; +} + +HRESULT DirectShowSampleScheduler::ReceiveCanBlock() +{ + return S_OK; +} + +void DirectShowSampleScheduler::run(REFERENCE_TIME startTime) +{ + QMutexLocker locker(&m_mutex); + + m_state = (m_state & Flushing) | Running; + m_startTime = startTime; + + for (DirectShowTimedSample *sample = m_head; sample; sample = sample->nextSample()) { + sample->schedule(m_clock, m_startTime, m_timeoutEvent); + } + + if (!(m_state & Flushing)) + ::ResetEvent(m_flushEvent); + + if (!m_head) + ::SetEvent(m_timeoutEvent); + +} + +void DirectShowSampleScheduler::pause() +{ + QMutexLocker locker(&m_mutex); + + m_state = (m_state & Flushing) | Paused; + + for (DirectShowTimedSample *sample = m_head; sample; sample = sample->nextSample()) + sample->unschedule(m_clock); + + if (!(m_state & Flushing)) + ::ResetEvent(m_flushEvent); +} + +void DirectShowSampleScheduler::stop() +{ + QMutexLocker locker(&m_mutex); + + m_state = m_state & Flushing; + + for (DirectShowTimedSample *sample = m_head; sample; sample = sample->remove()) { + sample->unschedule(m_clock); + + m_semaphore.release(1); + } + + m_head = 0; + m_tail = 0; + + ::SetEvent(m_flushEvent); +} + +void DirectShowSampleScheduler::setFlushing(bool flushing) +{ + QMutexLocker locker(&m_mutex); + + const bool isFlushing = m_state & Flushing; + + if (isFlushing != flushing) { + if (flushing) { + m_state |= Flushing; + + for (DirectShowTimedSample *sample = m_head; sample; sample = sample->remove()) { + sample->unschedule(m_clock); + + m_semaphore.release(1); + } + m_head = 0; + m_tail = 0; + + ::SetEvent(m_flushEvent); + } else { + m_state &= ~Flushing; + + if (m_state != Stopped) + ::ResetEvent(m_flushEvent); + } + } +} + +void DirectShowSampleScheduler::setClock(IReferenceClock *clock) +{ + QMutexLocker locker(&m_mutex); + + if (m_clock) + m_clock->Release(); + + m_clock = clock; + + if (m_clock) + m_clock->AddRef(); +} + +IMediaSample *DirectShowSampleScheduler::takeSample(bool *eos) +{ + QMutexLocker locker(&m_mutex); + + if (m_head && m_head->isReady(m_clock)) { + IMediaSample *sample = m_head->sample(); + sample->AddRef(); + + *eos = m_head->isLast(); + + m_head = m_head->remove(); + + if (!m_head) + m_tail = 0; + + m_semaphore.release(1); + + return sample; + } else { + return 0; + } +} + +bool DirectShowSampleScheduler::scheduleEndOfStream() +{ + QMutexLocker locker(&m_mutex); + + if (m_tail) { + m_tail->setLast(); + + return true; + } else { + return false; + } +} + +bool DirectShowSampleScheduler::event(QEvent *event) +{ + if (event->type() == QEvent::UpdateRequest) { + emit sampleReady(); + + return true; + } else { + return QObject::event(event); + } +} diff --git a/src/plugins/directshow/player/directshowsamplescheduler.h b/src/plugins/directshow/player/directshowsamplescheduler.h new file mode 100644 index 000000000..bea833ef9 --- /dev/null +++ b/src/plugins/directshow/player/directshowsamplescheduler.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DIRECTSHOWSAMPLESCHEDULER_H +#define DIRECTSHOWSAMPLESCHEDULER_H + +#include +#include +#include + +#include + +class DirectShowTimedSample; + +class DirectShowSampleScheduler : public QObject, public IMemInputPin +{ + Q_OBJECT +public: + + enum State + { + Stopped = 0x00, + Running = 0x01, + Paused = 0x02, + RunMask = 0x03, + Flushing = 0x04 + }; + + DirectShowSampleScheduler(IUnknown *pin, QObject *parent = 0); + ~DirectShowSampleScheduler(); + + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + // IMemInputPin + HRESULT STDMETHODCALLTYPE GetAllocator(IMemAllocator **ppAllocator); + HRESULT STDMETHODCALLTYPE NotifyAllocator(IMemAllocator *pAllocator, BOOL bReadOnly); + HRESULT STDMETHODCALLTYPE GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps); + + HRESULT STDMETHODCALLTYPE Receive(IMediaSample *pSample); + HRESULT STDMETHODCALLTYPE ReceiveMultiple(IMediaSample **pSamples, long nSamples, long *nSamplesProcessed); + HRESULT STDMETHODCALLTYPE ReceiveCanBlock(); + + void run(REFERENCE_TIME startTime); + void pause(); + void stop(); + void setFlushing(bool flushing); + + IReferenceClock *clock() const { return m_clock; } + void setClock(IReferenceClock *clock); + + bool schedule(IMediaSample *sample); + bool scheduleEndOfStream(); + + IMediaSample *takeSample(bool *eos); + + bool event(QEvent *event); + +Q_SIGNALS: + void sampleReady(); + +private: + IUnknown *m_pin; + IReferenceClock *m_clock; + IMemAllocator *m_allocator; + DirectShowTimedSample *m_head; + DirectShowTimedSample *m_tail; + int m_maximumSamples; + int m_state; + REFERENCE_TIME m_startTime; + HANDLE m_timeoutEvent; + HANDLE m_flushEvent; + QSemaphore m_semaphore; + QMutex m_mutex; +}; + +#endif diff --git a/src/plugins/directshow/player/directshowvideorenderercontrol.cpp b/src/plugins/directshow/player/directshowvideorenderercontrol.cpp new file mode 100644 index 000000000..429d5e1ec --- /dev/null +++ b/src/plugins/directshow/player/directshowvideorenderercontrol.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "directshowvideorenderercontrol.h" + +#include "videosurfacefilter.h" + +DirectShowVideoRendererControl::DirectShowVideoRendererControl(DirectShowEventLoop *loop, QObject *parent) + : QVideoRendererControl(parent) + , m_loop(loop) + , m_surface(0) + , m_filter(0) +{ +} + +DirectShowVideoRendererControl::~DirectShowVideoRendererControl() +{ + delete m_filter; +} + +QAbstractVideoSurface *DirectShowVideoRendererControl::surface() const +{ + return m_surface; +} + +void DirectShowVideoRendererControl::setSurface(QAbstractVideoSurface *surface) +{ + if (surface != m_surface) { + m_surface = surface; + + VideoSurfaceFilter *existingFilter = m_filter; + + if (surface) { + m_filter = new VideoSurfaceFilter(surface, m_loop); + } else { + m_filter = 0; + } + + emit filterChanged(); + + delete existingFilter; + } +} + +IBaseFilter *DirectShowVideoRendererControl::filter() +{ + return m_filter; +} diff --git a/src/plugins/directshow/player/directshowvideorenderercontrol.h b/src/plugins/directshow/player/directshowvideorenderercontrol.h new file mode 100644 index 000000000..5057a94e0 --- /dev/null +++ b/src/plugins/directshow/player/directshowvideorenderercontrol.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DIRECTSHOWVIDEORENDERERCONTROL_H +#define DIRECTSHOWVIDEORENDERERCONTROL_H + +#include "qvideorenderercontrol.h" + +#include + +class DirectShowEventLoop; +class VideoSurfaceFilter; + +QT_USE_NAMESPACE + +class DirectShowVideoRendererControl : public QVideoRendererControl +{ + Q_OBJECT +public: + DirectShowVideoRendererControl(DirectShowEventLoop *loop, QObject *parent = 0); + ~DirectShowVideoRendererControl(); + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + + IBaseFilter *filter(); + +Q_SIGNALS: + void filterChanged(); + +private: + DirectShowEventLoop *m_loop; + QAbstractVideoSurface *m_surface; + VideoSurfaceFilter *m_filter; +}; + +#endif diff --git a/src/plugins/directshow/player/mediasamplevideobuffer.cpp b/src/plugins/directshow/player/mediasamplevideobuffer.cpp new file mode 100644 index 000000000..a2d1d7cee --- /dev/null +++ b/src/plugins/directshow/player/mediasamplevideobuffer.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mediasamplevideobuffer.h" + +MediaSampleVideoBuffer::MediaSampleVideoBuffer(IMediaSample *sample, int bytesPerLine) + : QAbstractVideoBuffer(NoHandle) + , m_sample(sample) + , m_bytesPerLine(bytesPerLine) + , m_mapMode(NotMapped) +{ + m_sample->AddRef(); +} + +MediaSampleVideoBuffer::~MediaSampleVideoBuffer() +{ + m_sample->Release(); +} + +uchar *MediaSampleVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine) +{ + if (m_mapMode == NotMapped && mode != NotMapped) { + if (numBytes) + *numBytes = m_sample->GetActualDataLength(); + + if (bytesPerLine) + *bytesPerLine = m_bytesPerLine; + + BYTE *bytes = 0; + + if (m_sample->GetPointer(&bytes) == S_OK) { + m_mapMode = mode; + + return reinterpret_cast(bytes); + } + } + return 0; +} + +void MediaSampleVideoBuffer::unmap() +{ + m_mapMode = NotMapped; +} + +QAbstractVideoBuffer::MapMode MediaSampleVideoBuffer::mapMode() const +{ + return m_mapMode; +} diff --git a/src/plugins/directshow/player/mediasamplevideobuffer.h b/src/plugins/directshow/player/mediasamplevideobuffer.h new file mode 100644 index 000000000..0d44e7a1f --- /dev/null +++ b/src/plugins/directshow/player/mediasamplevideobuffer.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MEDIASAMPLEVIDEOBUFFER_H +#define MEDIASAMPLEVIDEOBUFFER_H + +#include + +#include + +class MediaSampleVideoBuffer : public QAbstractVideoBuffer +{ +public: + MediaSampleVideoBuffer(IMediaSample *sample, int bytesPerLine); + ~MediaSampleVideoBuffer(); + + IMediaSample *sample() { return m_sample; } + + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine); + void unmap(); + + MapMode mapMode() const; + +private: + IMediaSample *m_sample; + int m_bytesPerLine; + MapMode m_mapMode; +}; + + +#endif diff --git a/src/plugins/directshow/player/player.pri b/src/plugins/directshow/player/player.pri new file mode 100644 index 000000000..a058b0659 --- /dev/null +++ b/src/plugins/directshow/player/player.pri @@ -0,0 +1,47 @@ +INCLUDEPATH += $$PWD + +DEFINES += QMEDIA_DIRECTSHOW_PLAYER + +HEADERS += \ + $$PWD/directshowaudioendpointcontrol.h \ + $$PWD/directshoweventloop.h \ + $$PWD/directshowglobal.h \ + $$PWD/directshowioreader.h \ + $$PWD/directshowiosource.h \ + $$PWD/directshowmediatype.h \ + $$PWD/directshowmediatypelist.h \ + $$PWD/directshowmetadatacontrol.h \ + $$PWD/directshowpinenum.h \ + $$PWD/directshowplayercontrol.h \ + $$PWD/directshowplayerservice.h \ + $$PWD/directshowsamplescheduler.h \ + $$PWD/directshowvideorenderercontrol.h \ + $$PWD/mediasamplevideobuffer.h \ + $$PWD/videosurfacefilter.h + +SOURCES += \ + $$PWD/directshowaudioendpointcontrol.cpp \ + $$PWD/directshoweventloop.cpp \ + $$PWD/directshowioreader.cpp \ + $$PWD/directshowiosource.cpp \ + $$PWD/directshowmediatype.cpp \ + $$PWD/directshowmediatypelist.cpp \ + $$PWD/directshowmetadatacontrol.cpp \ + $$PWD/directshowpinenum.cpp \ + $$PWD/directshowplayercontrol.cpp \ + $$PWD/directshowplayerservice.cpp \ + $$PWD/directshowsamplescheduler.cpp \ + $$PWD/directshowvideorenderercontrol.cpp \ + $$PWD/mediasamplevideobuffer.cpp \ + $$PWD/videosurfacefilter.cpp + +!simulator { +HEADERS += \ + $$PWD/vmr9videowindowcontrol.h + +SOURCES += \ + $$PWD/vmr9videowindowcontrol.cpp +} + +LIBS += -lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32 -lgdi32 + diff --git a/src/plugins/directshow/player/videosurfacefilter.cpp b/src/plugins/directshow/player/videosurfacefilter.cpp new file mode 100644 index 000000000..a6a3c1b4f --- /dev/null +++ b/src/plugins/directshow/player/videosurfacefilter.cpp @@ -0,0 +1,631 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "videosurfacefilter.h" + +#include "directshoweventloop.h" +#include "directshowglobal.h" +#include "directshowpinenum.h" +#include "mediasamplevideobuffer.h" + +#include +#include +#include +#include + +#include + +// { e23cad72-153d-406c-bf3f-4c4b523d96f2 } +DEFINE_GUID(CLSID_VideoSurfaceFilter, +0xe23cad72, 0x153d, 0x406c, 0xbf, 0x3f, 0x4c, 0x4b, 0x52, 0x3d, 0x96, 0xf2); + +VideoSurfaceFilter::VideoSurfaceFilter( + QAbstractVideoSurface *surface, DirectShowEventLoop *loop, QObject *parent) + : QObject(parent) + , m_ref(1) + , m_state(State_Stopped) + , m_surface(surface) + , m_loop(loop) + , m_graph(0) + , m_peerPin(0) + , m_bytesPerLine(0) + , m_startResult(S_OK) + , m_pinId(QString::fromLatin1("reference")) + , m_sampleScheduler(static_cast(this)) +{ + connect(surface, SIGNAL(supportedFormatsChanged()), this, SLOT(supportedFormatsChanged())); + connect(&m_sampleScheduler, SIGNAL(sampleReady()), this, SLOT(sampleReady())); +} + +VideoSurfaceFilter::~VideoSurfaceFilter() +{ + Q_ASSERT(m_ref == 1); +} + +HRESULT VideoSurfaceFilter::QueryInterface(REFIID riid, void **ppvObject) +{ + // 2dd74950-a890-11d1-abe8-00a0c905f375 + static const GUID iid_IAmFilterMiscFlags = { + 0x2dd74950, 0xa890, 0x11d1, {0xab, 0xe8, 0x00, 0xa0, 0xc9, 0x05, 0xf3, 0x75} }; + + if (!ppvObject) { + return E_POINTER; + } else if (riid == IID_IUnknown + || riid == IID_IPersist + || riid == IID_IMediaFilter + || riid == IID_IBaseFilter) { + *ppvObject = static_cast(this); + } else if (riid == iid_IAmFilterMiscFlags) { + *ppvObject = static_cast(this); + } else if (riid == IID_IPin) { + *ppvObject = static_cast(this); + } else if (riid == IID_IMemInputPin) { + *ppvObject = static_cast(&m_sampleScheduler); + } else { + *ppvObject = 0; + + return E_NOINTERFACE; + } + + AddRef(); + + return S_OK; +} + +ULONG VideoSurfaceFilter::AddRef() +{ + return InterlockedIncrement(&m_ref); +} + +ULONG VideoSurfaceFilter::Release() +{ + ULONG ref = InterlockedDecrement(&m_ref); + + Q_ASSERT(ref != 0); + + return ref; +} + +HRESULT VideoSurfaceFilter::GetClassID(CLSID *pClassID) +{ + *pClassID = CLSID_VideoSurfaceFilter; + + return S_OK; +} + +HRESULT VideoSurfaceFilter::Run(REFERENCE_TIME tStart) +{ + m_state = State_Running; + + m_sampleScheduler.run(tStart); + + return S_OK; +} + +HRESULT VideoSurfaceFilter::Pause() +{ + m_state = State_Paused; + + m_sampleScheduler.pause(); + + return S_OK; +} + +HRESULT VideoSurfaceFilter::Stop() +{ + m_state = State_Stopped; + + m_sampleScheduler.stop(); + + return S_OK; +} + +HRESULT VideoSurfaceFilter::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *pState) +{ + if (!pState) + return E_POINTER; + + *pState = m_state; + + return S_OK; +} + +HRESULT VideoSurfaceFilter::SetSyncSource(IReferenceClock *pClock) +{ + + m_sampleScheduler.setClock(pClock); + + return S_OK; +} + +HRESULT VideoSurfaceFilter::GetSyncSource(IReferenceClock **ppClock) +{ + if (!ppClock) { + return E_POINTER; + } else { + *ppClock = m_sampleScheduler.clock(); + + if (*ppClock) { + (*ppClock)->AddRef(); + + return S_OK; + } else { + return S_FALSE; + } + } +} + +HRESULT VideoSurfaceFilter::EnumPins(IEnumPins **ppEnum) +{ + if (ppEnum) { + *ppEnum = new DirectShowPinEnum(QList() << this); + + return S_OK; + } else { + return E_POINTER; + } +} + +HRESULT VideoSurfaceFilter::FindPin(LPCWSTR pId, IPin **ppPin) +{ + if (!ppPin || !pId) { + return E_POINTER; + } else if (QString::fromWCharArray(pId) == m_pinId) { + AddRef(); + + *ppPin = this; + + return S_OK; + } else { + return VFW_E_NOT_FOUND; + } +} + +HRESULT VideoSurfaceFilter::JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName) +{ + m_graph = pGraph; + m_name = QString::fromWCharArray(pName); + + return S_OK; +} + +HRESULT VideoSurfaceFilter::QueryFilterInfo(FILTER_INFO *pInfo) +{ + if (pInfo) { + QString name = m_name; + + if (name.length() >= MAX_FILTER_NAME) + name.truncate(MAX_FILTER_NAME - 1); + + int length = name.toWCharArray(pInfo->achName); + pInfo->achName[length] = '\0'; + + if (m_graph) + m_graph->AddRef(); + + pInfo->pGraph = m_graph; + + return S_OK; + } else { + return E_POINTER; + } +} + +HRESULT VideoSurfaceFilter::QueryVendorInfo(LPWSTR *pVendorInfo) +{ + Q_UNUSED(pVendorInfo); + + return E_NOTIMPL; +} + +ULONG VideoSurfaceFilter::GetMiscFlags() +{ + return AM_FILTER_MISC_FLAGS_IS_RENDERER; +} + + +HRESULT VideoSurfaceFilter::Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt) +{ + // This is an input pin, you shouldn't be calling Connect on it. + return E_POINTER; +} + +HRESULT VideoSurfaceFilter::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt) +{ + if (!pConnector) { + return E_POINTER; + } else if (!pmt) { + return E_POINTER; + } else { + HRESULT hr; + QMutexLocker locker(&m_mutex); + + if (m_peerPin) { + hr = VFW_E_ALREADY_CONNECTED; + } else if (pmt->majortype != MEDIATYPE_Video) { + hr = VFW_E_TYPE_NOT_ACCEPTED; + } else { + m_surfaceFormat = DirectShowMediaType::formatFromType(*pmt); + m_bytesPerLine = DirectShowMediaType::bytesPerLine(m_surfaceFormat); + + if (thread() == QThread::currentThread()) { + hr = start(); + } else { + m_loop->postEvent(this, new QEvent(QEvent::Type(StartSurface))); + + m_wait.wait(&m_mutex); + + hr = m_startResult; + } + } + if (hr == S_OK) { + m_peerPin = pConnector; + m_peerPin->AddRef(); + + DirectShowMediaType::copy(&m_mediaType, *pmt); + } + return hr; + } +} + +HRESULT VideoSurfaceFilter::start() +{ + if (!m_surface->isFormatSupported(m_surfaceFormat)) { + return VFW_E_TYPE_NOT_ACCEPTED; + } + if (!m_surface->start(m_surfaceFormat)) { + return VFW_E_TYPE_NOT_ACCEPTED; + } else { + return S_OK; + } +} + +HRESULT VideoSurfaceFilter::Disconnect() +{ + QMutexLocker locker(&m_mutex); + + if (!m_peerPin) + return S_FALSE; + + if (thread() == QThread::currentThread()) { + stop(); + } else { + m_loop->postEvent(this, new QEvent(QEvent::Type(StopSurface))); + + m_wait.wait(&m_mutex); + } + + m_mediaType.clear(); + + m_sampleScheduler.NotifyAllocator(0, FALSE); + + m_peerPin->Release(); + m_peerPin = 0; + + return S_OK; +} + +void VideoSurfaceFilter::stop() +{ + m_surface->stop(); +} + +HRESULT VideoSurfaceFilter::ConnectedTo(IPin **ppPin) +{ + if (!ppPin) { + return E_POINTER; + } else { + QMutexLocker locker(&m_mutex); + + if (!m_peerPin) { + return VFW_E_NOT_CONNECTED; + } else { + m_peerPin->AddRef(); + + *ppPin = m_peerPin; + + return S_OK; + } + } +} + +HRESULT VideoSurfaceFilter::ConnectionMediaType(AM_MEDIA_TYPE *pmt) +{ + if (!pmt) { + return E_POINTER; + } else { + QMutexLocker locker(&m_mutex); + + if (!m_peerPin) { + return VFW_E_NOT_CONNECTED; + } else { + DirectShowMediaType::copy(pmt, m_mediaType); + + return S_OK; + } + } +} + +HRESULT VideoSurfaceFilter::QueryPinInfo(PIN_INFO *pInfo) +{ + if (!pInfo) { + return E_POINTER; + } else { + AddRef(); + + pInfo->pFilter = this; + pInfo->dir = PINDIR_INPUT; + + const int bytes = qMin(MAX_FILTER_NAME, (m_pinId.length() + 1) * 2); + + qMemCopy(pInfo->achName, m_pinId.utf16(), bytes); + + return S_OK; + } +} + +HRESULT VideoSurfaceFilter::QueryId(LPWSTR *Id) +{ + if (!Id) { + return E_POINTER; + } else { + const int bytes = (m_pinId.length() + 1) * 2; + + *Id = static_cast(::CoTaskMemAlloc(bytes)); + + qMemCopy(*Id, m_pinId.utf16(), bytes); + + return S_OK; + } +} + +HRESULT VideoSurfaceFilter::QueryAccept(const AM_MEDIA_TYPE *pmt) +{ + return !m_surface->isFormatSupported(DirectShowMediaType::formatFromType(*pmt)) + ? S_OK + : S_FALSE; +} + +HRESULT VideoSurfaceFilter::EnumMediaTypes(IEnumMediaTypes **ppEnum) +{ + if (!ppEnum) { + return E_POINTER; + } else { + QMutexLocker locker(&m_mutex); + + *ppEnum = createMediaTypeEnum(); + + return S_OK; + } +} + +HRESULT VideoSurfaceFilter::QueryInternalConnections(IPin **apPin, ULONG *nPin) +{ + Q_UNUSED(apPin); + Q_UNUSED(nPin); + + return E_NOTIMPL; +} + +HRESULT VideoSurfaceFilter::EndOfStream() +{ + QMutexLocker locker(&m_mutex); + + if (!m_sampleScheduler.scheduleEndOfStream()) { + if (IMediaEventSink *sink = com_cast(m_graph, IID_IMediaEventSink)) { + sink->Notify( + EC_COMPLETE, + S_OK, + reinterpret_cast(static_cast(this))); + sink->Release(); + } + } + + return S_OK; +} + +HRESULT VideoSurfaceFilter::BeginFlush() +{ + QMutexLocker locker(&m_mutex); + + m_sampleScheduler.setFlushing(true); + + if (thread() == QThread::currentThread()) { + flush(); + } else { + m_loop->postEvent(this, new QEvent(QEvent::Type(FlushSurface))); + + m_wait.wait(&m_mutex); + } + + return S_OK; +} + +HRESULT VideoSurfaceFilter::EndFlush() +{ + QMutexLocker locker(&m_mutex); + + m_sampleScheduler.setFlushing(false); + + return S_OK; +} + +void VideoSurfaceFilter::flush() +{ + m_surface->present(QVideoFrame()); + + m_wait.wakeAll(); +} + +HRESULT VideoSurfaceFilter::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + Q_UNUSED(tStart); + Q_UNUSED(tStop); + Q_UNUSED(dRate); + + return S_OK; +} + +HRESULT VideoSurfaceFilter::QueryDirection(PIN_DIRECTION *pPinDir) +{ + if (!pPinDir) { + return E_POINTER; + } else { + *pPinDir = PINDIR_INPUT; + + return S_OK; + } +} + +int VideoSurfaceFilter::currentMediaTypeToken() +{ + QMutexLocker locker(&m_mutex); + + return DirectShowMediaTypeList::currentMediaTypeToken(); +} + +HRESULT VideoSurfaceFilter::nextMediaType( + int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount) +{ + QMutexLocker locker(&m_mutex); + + return DirectShowMediaTypeList::nextMediaType(token, index, count, types, fetchedCount); + +} + +HRESULT VideoSurfaceFilter::skipMediaType(int token, int *index, ULONG count) +{ + QMutexLocker locker(&m_mutex); + + return DirectShowMediaTypeList::skipMediaType(token, index, count); +} + +HRESULT VideoSurfaceFilter::cloneMediaType(int token, int index, IEnumMediaTypes **enumeration) +{ + QMutexLocker locker(&m_mutex); + + return DirectShowMediaTypeList::cloneMediaType(token, index, enumeration); +} + +void VideoSurfaceFilter::customEvent(QEvent *event) +{ + if (event->type() == StartSurface) { + QMutexLocker locker(&m_mutex); + + m_startResult = start(); + + m_wait.wakeAll(); + } else if (event->type() == StopSurface) { + QMutexLocker locker(&m_mutex); + + stop(); + + m_wait.wakeAll(); + } else if (event->type() == FlushSurface) { + QMutexLocker locker(&m_mutex); + + flush(); + + m_wait.wakeAll(); + } else { + QObject::customEvent(event); + } +} + +void VideoSurfaceFilter::supportedFormatsChanged() +{ + QMutexLocker locker(&m_mutex); + + // MEDIASUBTYPE_None; + static const GUID none = { + 0xe436eb8e, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70} }; + + QList formats = m_surface->supportedPixelFormats(); + + QVector mediaTypes; + mediaTypes.reserve(formats.count()); + + AM_MEDIA_TYPE type; + type.majortype = MEDIATYPE_Video; + type.bFixedSizeSamples = TRUE; + type.bTemporalCompression = FALSE; + type.lSampleSize = 0; + type.formattype = GUID_NULL; + type.pUnk = 0; + type.cbFormat = 0; + type.pbFormat = 0; + + foreach (QVideoFrame::PixelFormat format, formats) { + type.subtype = DirectShowMediaType::convertPixelFormat(format); + + if (type.subtype != none) + mediaTypes.append(type); + } + + setMediaTypes(mediaTypes); +} + +void VideoSurfaceFilter::sampleReady() +{ + bool eos = false; + + IMediaSample *sample = m_sampleScheduler.takeSample(&eos); + + if (sample) { + m_surface->present(QVideoFrame( + new MediaSampleVideoBuffer(sample, m_bytesPerLine), + m_surfaceFormat.frameSize(), + m_surfaceFormat.pixelFormat())); + + sample->Release(); + + if (eos) { + if (IMediaEventSink *sink = com_cast(m_graph, IID_IMediaEventSink)) { + sink->Notify( + EC_COMPLETE, + S_OK, + reinterpret_cast(static_cast(this))); + sink->Release(); + } + } + } +} + diff --git a/src/plugins/directshow/player/videosurfacefilter.h b/src/plugins/directshow/player/videosurfacefilter.h new file mode 100644 index 000000000..a58971630 --- /dev/null +++ b/src/plugins/directshow/player/videosurfacefilter.h @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef VIDEOSURFACEFILTER_H +#define VIDEOSURFACEFILTER_H + +#include "directshowglobal.h" +#include "directshowmediatypelist.h" +#include "directshowsamplescheduler.h" +#include "directshowmediatype.h" + +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE +class QAbstractVideoSurface; +QT_END_NAMESPACE + +class DirectShowEventLoop; + +class VideoSurfaceFilter + : public QObject + , public DirectShowMediaTypeList + , public IBaseFilter + , public IAMFilterMiscFlags + , public IPin +{ + Q_OBJECT +public: + VideoSurfaceFilter( + QAbstractVideoSurface *surface, DirectShowEventLoop *loop, QObject *parent = 0); + ~VideoSurfaceFilter(); + + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + // IPersist + HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID); + + // IMediaFilter + HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart); + HRESULT STDMETHODCALLTYPE Pause(); + HRESULT STDMETHODCALLTYPE Stop(); + + HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *pState); + + HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock *pClock); + HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock **ppClock); + + // IBaseFilter + HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins **ppEnum); + HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, IPin **ppPin); + + HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName); + + HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO *pInfo); + HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR *pVendorInfo); + + // IAMFilterMiscFlags + ULONG STDMETHODCALLTYPE GetMiscFlags(); + + // IPin + HRESULT STDMETHODCALLTYPE Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt); + HRESULT STDMETHODCALLTYPE ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt); + HRESULT STDMETHODCALLTYPE Disconnect(); + HRESULT STDMETHODCALLTYPE ConnectedTo(IPin **ppPin); + + HRESULT STDMETHODCALLTYPE ConnectionMediaType(AM_MEDIA_TYPE *pmt); + + HRESULT STDMETHODCALLTYPE QueryPinInfo(PIN_INFO *pInfo); + HRESULT STDMETHODCALLTYPE QueryId(LPWSTR *Id); + + HRESULT STDMETHODCALLTYPE QueryAccept(const AM_MEDIA_TYPE *pmt); + + HRESULT STDMETHODCALLTYPE EnumMediaTypes(IEnumMediaTypes **ppEnum); + + HRESULT STDMETHODCALLTYPE QueryInternalConnections(IPin **apPin, ULONG *nPin); + + HRESULT STDMETHODCALLTYPE EndOfStream(); + + HRESULT STDMETHODCALLTYPE BeginFlush(); + HRESULT STDMETHODCALLTYPE EndFlush(); + + HRESULT STDMETHODCALLTYPE NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + + HRESULT STDMETHODCALLTYPE QueryDirection(PIN_DIRECTION *pPinDir); + + int currentMediaTypeToken(); + HRESULT nextMediaType( + int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount); + HRESULT skipMediaType(int token, int *index, ULONG count); + HRESULT cloneMediaType(int token, int index, IEnumMediaTypes **enumeration); + +protected: + void customEvent(QEvent *event); + +private Q_SLOTS: + void supportedFormatsChanged(); + void sampleReady(); + +private: + HRESULT start(); + void stop(); + void flush(); + + enum + { + StartSurface = QEvent::User, + StopSurface, + FlushSurface + }; + + LONG m_ref; + FILTER_STATE m_state; + QAbstractVideoSurface *m_surface; + DirectShowEventLoop *m_loop; + IFilterGraph *m_graph; + IPin *m_peerPin; + int m_bytesPerLine; + HRESULT m_startResult; + QString m_name; + QString m_pinId; + DirectShowMediaType m_mediaType; + QVideoSurfaceFormat m_surfaceFormat; + QMutex m_mutex; + QWaitCondition m_wait; + DirectShowSampleScheduler m_sampleScheduler; +}; + +#endif diff --git a/src/plugins/directshow/player/vmr9videowindowcontrol.cpp b/src/plugins/directshow/player/vmr9videowindowcontrol.cpp new file mode 100644 index 000000000..5e729844b --- /dev/null +++ b/src/plugins/directshow/player/vmr9videowindowcontrol.cpp @@ -0,0 +1,329 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "vmr9videowindowcontrol.h" + +#include "directshowglobal.h" + +Vmr9VideoWindowControl::Vmr9VideoWindowControl(QObject *parent) + : QVideoWindowControl(parent) + , m_filter(com_new(CLSID_VideoMixingRenderer9, IID_IBaseFilter)) + , m_windowId(0) + , m_dirtyValues(0) + , m_aspectRatioMode(Qt::KeepAspectRatio) + , m_brightness(0) + , m_contrast(0) + , m_hue(0) + , m_saturation(0) + , m_fullScreen(false) +{ + if (IVMRFilterConfig9 *config = com_cast(m_filter, IID_IVMRFilterConfig9)) { + config->SetRenderingMode(VMR9Mode_Windowless); + config->SetNumberOfStreams(1); + config->Release(); + } +} + +Vmr9VideoWindowControl::~Vmr9VideoWindowControl() +{ + if (m_filter) + m_filter->Release(); +} + + +WId Vmr9VideoWindowControl::winId() const +{ + return m_windowId; + +} + +void Vmr9VideoWindowControl::setWinId(WId id) +{ + m_windowId = id; + + if (QWidget *widget = QWidget::find(m_windowId)) { + const QColor color = widget->palette().color(QPalette::Window); + + m_windowColor = RGB(color.red(), color.green(), color.blue()); + } + + if (IVMRWindowlessControl9 *control = com_cast( + m_filter, IID_IVMRWindowlessControl9)) { + control->SetVideoClippingWindow(m_windowId); + control->SetBorderColor(m_windowColor); + control->Release(); + } +} + +QRect Vmr9VideoWindowControl::displayRect() const +{ + return m_displayRect; +} + +void Vmr9VideoWindowControl::setDisplayRect(const QRect &rect) +{ + m_displayRect = rect; + + if (IVMRWindowlessControl9 *control = com_cast( + m_filter, IID_IVMRWindowlessControl9)) { + RECT sourceRect = { 0, 0, 0, 0 }; + RECT displayRect = { rect.left(), rect.top(), rect.right() + 1, rect.bottom() + 1 }; + + control->GetNativeVideoSize(&sourceRect.right, &sourceRect.bottom, 0, 0); + + if (m_aspectRatioMode == Qt::KeepAspectRatioByExpanding) { + QSize clippedSize = rect.size(); + clippedSize.scale(sourceRect.right, sourceRect.bottom, Qt::KeepAspectRatio); + + sourceRect.left = (sourceRect.right - clippedSize.width()) / 2; + sourceRect.top = (sourceRect.bottom - clippedSize.height()) / 2; + sourceRect.right = sourceRect.left + clippedSize.width(); + sourceRect.bottom = sourceRect.top + clippedSize.height(); + } + + control->SetVideoPosition(&sourceRect, &displayRect); + control->Release(); + } +} + +bool Vmr9VideoWindowControl::isFullScreen() const +{ + return m_fullScreen; +} + +void Vmr9VideoWindowControl::setFullScreen(bool fullScreen) +{ + emit fullScreenChanged(m_fullScreen = fullScreen); +} + +void Vmr9VideoWindowControl::repaint() +{ + PAINTSTRUCT paint; + + if (HDC dc = ::BeginPaint(m_windowId, &paint)) { + HRESULT hr = E_FAIL; + + if (IVMRWindowlessControl9 *control = com_cast( + m_filter, IID_IVMRWindowlessControl9)) { + hr = control->RepaintVideo(m_windowId, dc); + control->Release(); + } + + if (!SUCCEEDED(hr)) { + HPEN pen = ::CreatePen(PS_SOLID, 1, m_windowColor); + HBRUSH brush = ::CreateSolidBrush(m_windowColor); + ::SelectObject(dc, pen); + ::SelectObject(dc, brush); + + ::Rectangle( + dc, + m_displayRect.left(), + m_displayRect.top(), + m_displayRect.right() + 1, + m_displayRect.bottom() + 1); + + ::DeleteObject(pen); + ::DeleteObject(brush); + } + ::EndPaint(m_windowId, &paint); + } +} + +QSize Vmr9VideoWindowControl::nativeSize() const +{ + QSize size; + + if (IVMRWindowlessControl9 *control = com_cast( + m_filter, IID_IVMRWindowlessControl9)) { + LONG width; + LONG height; + + if (control->GetNativeVideoSize(&width, &height, 0, 0) == S_OK) + size = QSize(width, height); + control->Release(); + } + return size; +} + +Qt::AspectRatioMode Vmr9VideoWindowControl::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void Vmr9VideoWindowControl::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + m_aspectRatioMode = mode; + + if (IVMRWindowlessControl9 *control = com_cast( + m_filter, IID_IVMRWindowlessControl9)) { + switch (mode) { + case Qt::IgnoreAspectRatio: + control->SetAspectRatioMode(VMR9ARMode_None); + break; + case Qt::KeepAspectRatio: + control->SetAspectRatioMode(VMR9ARMode_LetterBox); + break; + case Qt::KeepAspectRatioByExpanding: + control->SetAspectRatioMode(VMR9ARMode_LetterBox); + setDisplayRect(m_displayRect); + break; + default: + break; + } + control->Release(); + } +} + +int Vmr9VideoWindowControl::brightness() const +{ + return m_brightness; +} + +void Vmr9VideoWindowControl::setBrightness(int brightness) +{ + m_brightness = brightness; + + m_dirtyValues |= ProcAmpControl9_Brightness; + + setProcAmpValues(); + + emit brightnessChanged(brightness); +} + +int Vmr9VideoWindowControl::contrast() const +{ + return m_contrast; +} + +void Vmr9VideoWindowControl::setContrast(int contrast) +{ + m_contrast = contrast; + + m_dirtyValues |= ProcAmpControl9_Contrast; + + setProcAmpValues(); + + emit contrastChanged(contrast); +} + +int Vmr9VideoWindowControl::hue() const +{ + return m_hue; +} + +void Vmr9VideoWindowControl::setHue(int hue) +{ + m_hue = hue; + + m_dirtyValues |= ProcAmpControl9_Hue; + + setProcAmpValues(); + + emit hueChanged(hue); +} + +int Vmr9VideoWindowControl::saturation() const +{ + return m_saturation; +} + +void Vmr9VideoWindowControl::setSaturation(int saturation) +{ + m_saturation = saturation; + + m_dirtyValues |= ProcAmpControl9_Saturation; + + setProcAmpValues(); + + emit saturationChanged(saturation); +} + +void Vmr9VideoWindowControl::setProcAmpValues() +{ + if (IVMRMixerControl9 *control = com_cast(m_filter, IID_IVMRMixerControl9)) { + VMR9ProcAmpControl procAmp; + procAmp.dwSize = sizeof(VMR9ProcAmpControl); + procAmp.dwFlags = m_dirtyValues; + + if (m_dirtyValues & ProcAmpControl9_Brightness) { + procAmp.Brightness = scaleProcAmpValue( + control, ProcAmpControl9_Brightness, m_brightness); + } + if (m_dirtyValues & ProcAmpControl9_Contrast) { + procAmp.Contrast = scaleProcAmpValue( + control, ProcAmpControl9_Contrast, m_contrast); + } + if (m_dirtyValues & ProcAmpControl9_Hue) { + procAmp.Hue = scaleProcAmpValue( + control, ProcAmpControl9_Hue, m_hue); + } + if (m_dirtyValues & ProcAmpControl9_Saturation) { + procAmp.Saturation = scaleProcAmpValue( + control, ProcAmpControl9_Saturation, m_saturation); + } + + if (SUCCEEDED(control->SetProcAmpControl(0, &procAmp))) { + m_dirtyValues = 0; + } + + control->Release(); + } +} + +float Vmr9VideoWindowControl::scaleProcAmpValue( + IVMRMixerControl9 *control, VMR9ProcAmpControlFlags property, int value) const +{ + float scaledValue = 0.0; + + VMR9ProcAmpControlRange range; + range.dwSize = sizeof(VMR9ProcAmpControlRange); + range.dwProperty = property; + + if (SUCCEEDED(control->GetProcAmpControlRange(0, &range))) { + scaledValue = range.DefaultValue; + if (value > 0) + scaledValue += float(value) * (range.MaxValue - range.DefaultValue) / 100; + else if (value < 0) + scaledValue -= float(value) * (range.MinValue - range.DefaultValue) / 100; + } + + return scaledValue; +} diff --git a/src/plugins/directshow/player/vmr9videowindowcontrol.h b/src/plugins/directshow/player/vmr9videowindowcontrol.h new file mode 100644 index 000000000..b4e39a7fd --- /dev/null +++ b/src/plugins/directshow/player/vmr9videowindowcontrol.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef VMR9VIDEOWINDOWCONTROL_H +#define VMR9VIDEOWINDOWCONTROL_H + +#include "qvideowindowcontrol.h" + +#include +#include +#include + +QT_USE_NAMESPACE + +class Vmr9VideoWindowControl : public QVideoWindowControl +{ + Q_OBJECT +public: + Vmr9VideoWindowControl(QObject *parent = 0); + ~Vmr9VideoWindowControl(); + + IBaseFilter *filter() const { return m_filter; } + + WId winId() const; + void setWinId(WId id); + + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + void repaint(); + + QSize nativeSize() const; + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + +private: + void setProcAmpValues(); + float scaleProcAmpValue( + IVMRMixerControl9 *control, VMR9ProcAmpControlFlags property, int value) const; + + IBaseFilter *m_filter; + WId m_windowId; + COLORREF m_windowColor; + DWORD m_dirtyValues; + Qt::AspectRatioMode m_aspectRatioMode; + QRect m_displayRect; + int m_brightness; + int m_contrast; + int m_hue; + int m_saturation; + bool m_fullScreen; +}; + +#endif diff --git a/src/plugins/gstreamer/camerabin/camerabin.pri b/src/plugins/gstreamer/camerabin/camerabin.pri new file mode 100644 index 000000000..5c266e784 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabin.pri @@ -0,0 +1,50 @@ +INCLUDEPATH += $$PWD \ + $${SOURCE_DIR}/src/multimedia + +INCLUDEPATH += camerabin + +DEFINES += QMEDIA_GSTREAMER_CAMERABIN + +LIBS += -lgstphotography-0.10 + +DEFINES += GST_USE_UNSTABLE_API #prevents warnings because of unstable photography API + +HEADERS += \ + $$PWD/camerabinservice.h \ + $$PWD/camerabinsession.h \ + $$PWD/camerabincontrol.h \ + $$PWD/camerabinaudioencoder.h \ + $$PWD/camerabinfocus.h \ + $$PWD/camerabinimageencoder.h \ + $$PWD/camerabinlocks.h \ + $$PWD/camerabinrecorder.h \ + $$PWD/camerabincontainer.h \ + $$PWD/camerabinexposure.h \ + $$PWD/camerabinflash.h \ + $$PWD/camerabinimagecapture.h \ + $$PWD/camerabinimageprocessing.h \ + $$PWD/camerabinmetadata.h \ + $$PWD/camerabinvideoencoder.h \ + $$PWD/camerabinresourcepolicy.h \ + $$PWD/camerabincapturedestination.h \ + $$PWD/camerabincapturebufferformat.h + +SOURCES += \ + $$PWD/camerabinservice.cpp \ + $$PWD/camerabinsession.cpp \ + $$PWD/camerabincontrol.cpp \ + $$PWD/camerabinaudioencoder.cpp \ + $$PWD/camerabincontainer.cpp \ + $$PWD/camerabinexposure.cpp \ + $$PWD/camerabinflash.cpp \ + $$PWD/camerabinfocus.cpp \ + $$PWD/camerabinimagecapture.cpp \ + $$PWD/camerabinimageencoder.cpp \ + $$PWD/camerabinimageprocessing.cpp \ + $$PWD/camerabinlocks.cpp \ + $$PWD/camerabinmetadata.cpp \ + $$PWD/camerabinrecorder.cpp \ + $$PWD/camerabinvideoencoder.cpp \ + $$PWD/camerabinresourcepolicy.cpp \ + $$PWD/camerabincapturedestination.cpp \ + $$PWD/camerabincapturebufferformat.cpp diff --git a/src/plugins/gstreamer/camerabin/camerabinaudioencoder.cpp b/src/plugins/gstreamer/camerabin/camerabinaudioencoder.cpp new file mode 100644 index 000000000..d028fb3e7 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinaudioencoder.cpp @@ -0,0 +1,293 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camerabinaudioencoder.h" +#include "camerabincontainer.h" + +#include + +CameraBinAudioEncoder::CameraBinAudioEncoder(QObject *parent) + :QAudioEncoderControl(parent) +{ + QList codecCandidates; + +#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) + codecCandidates << "audio/AAC" << "audio/PCM" << "audio/AMR" << "audio/AMR-WB" << "audio/speex" + << "audio/ADPCM" << "audio/iLBC" << "audio/vorbis" << "audio/mpeg" << "audio/FLAC"; + + m_elementNames["audio/AAC"] = "nokiaaacenc"; + m_elementNames["audio/speex"] = "speexenc"; + m_elementNames["audio/PCM"] = "audioresample"; + m_elementNames["audio/AMR"] = "nokiaamrnbenc"; + m_elementNames["audio/AMR-WB"] = "nokiaamrwbenc"; + m_elementNames["audio/ADPCM"] = "nokiaadpcmenc"; + m_elementNames["audio/iLBC"] = "nokiailbcenc"; + m_elementNames["audio/vorbis"] = "vorbisenc"; + m_elementNames["audio/FLAC"] = "flacenc"; + m_elementNames["audio/mpeg"] = "ffenc_mp2"; +#else + codecCandidates << "audio/mpeg" << "audio/vorbis" << "audio/speex" << "audio/GSM" + << "audio/PCM" << "audio/AMR" << "audio/AMR-WB"; + + m_elementNames["audio/mpeg"] = "lamemp3enc"; + m_elementNames["audio/vorbis"] = "vorbisenc"; + m_elementNames["audio/speex"] = "speexenc"; + m_elementNames["audio/GSM"] = "gsmenc"; + m_elementNames["audio/PCM"] = "audioresample"; + m_elementNames["audio/AMR"] = "amrnbenc"; + m_elementNames["audio/AMR-WB"] = "amrwbenc"; + + m_codecOptions["audio/vorbis"] = QStringList() << "min-bitrate" << "max-bitrate"; + m_codecOptions["audio/mpeg"] = QStringList() << "mode"; + m_codecOptions["audio/speex"] = QStringList() << "mode" << "vbr" << "vad" << "dtx"; + m_codecOptions["audio/GSM"] = QStringList(); + m_codecOptions["audio/PCM"] = QStringList(); + m_codecOptions["audio/AMR"] = QStringList(); + m_codecOptions["audio/AMR-WB"] = QStringList(); +#endif + + foreach( const QByteArray& codecName, codecCandidates ) { + QByteArray elementName = m_elementNames[codecName]; + GstElementFactory *factory = gst_element_factory_find(elementName.constData()); + + if (factory) { + m_codecs.append(codecName); + const gchar *descr = gst_element_factory_get_description(factory); + + if (codecName == QByteArray("audio/PCM")) + m_codecDescriptions.insert(codecName, tr("Raw PCM audio")); + else + m_codecDescriptions.insert(codecName, QString::fromUtf8(descr)); + + m_streamTypes.insert(codecName, + CameraBinContainer::supportedStreamTypes(factory, GST_PAD_SRC)); + + gst_object_unref(GST_OBJECT(factory)); + } + } +} + +CameraBinAudioEncoder::~CameraBinAudioEncoder() +{ +} + +QStringList CameraBinAudioEncoder::supportedAudioCodecs() const +{ + return m_codecs; +} + +QString CameraBinAudioEncoder::codecDescription(const QString &codecName) const +{ + return m_codecDescriptions.value(codecName); +} + +QStringList CameraBinAudioEncoder::supportedEncodingOptions(const QString &codec) const +{ + return m_codecOptions.value(codec); +} + +QVariant CameraBinAudioEncoder::encodingOption( + const QString &codec, const QString &name) const +{ + return m_options[codec].value(name); +} + +void CameraBinAudioEncoder::setEncodingOption( + const QString &codec, const QString &name, const QVariant &value) +{ + m_options[codec][name] = value; +} + +QList CameraBinAudioEncoder::supportedSampleRates(const QAudioEncoderSettings &, bool *) const +{ + //TODO check element caps to find actual values + + return QList(); +} + +QAudioEncoderSettings CameraBinAudioEncoder::audioSettings() const +{ + return m_audioSettings; +} + +void CameraBinAudioEncoder::setAudioSettings(const QAudioEncoderSettings &settings) +{ + m_userSettings = settings; + m_audioSettings = settings; + emit settingsChanged(); +} + +void CameraBinAudioEncoder::setActualAudioSettings(const QAudioEncoderSettings &settings) +{ + m_audioSettings = settings; +} + +void CameraBinAudioEncoder::resetActualSettings() +{ + m_audioSettings = m_userSettings; +} + +GstElement *CameraBinAudioEncoder::createEncoder() +{ + QString codec = m_audioSettings.codec(); + QByteArray encoderElementName = m_elementNames.value(codec); + GstElement *encoderElement = gst_element_factory_make(encoderElementName.constData(), NULL); + if (!encoderElement) + return 0; + + GstBin * encoderBin = GST_BIN(gst_bin_new("audio-encoder-bin")); + GstElement *capsFilter = gst_element_factory_make("capsfilter", NULL); + + gst_bin_add(encoderBin, capsFilter); + gst_bin_add(encoderBin, encoderElement); + gst_element_link(capsFilter, encoderElement); + + // add ghostpads + GstPad *pad = gst_element_get_static_pad(capsFilter, "sink"); + gst_element_add_pad(GST_ELEMENT(encoderBin), gst_ghost_pad_new("sink", pad)); + gst_object_unref(GST_OBJECT(pad)); + + pad = gst_element_get_static_pad(encoderElement, "src"); + gst_element_add_pad(GST_ELEMENT(encoderBin), gst_ghost_pad_new("src", pad)); + gst_object_unref(GST_OBJECT(pad)); + + if (m_audioSettings.sampleRate() > 0 || m_audioSettings.channelCount() > 0) { + GstCaps *caps = gst_caps_new_empty(); + GstStructure *structure = gst_structure_new("audio/x-raw-int", NULL); + + if (m_audioSettings.sampleRate() > 0) + gst_structure_set(structure, "rate", G_TYPE_INT, m_audioSettings.sampleRate(), NULL ); + + if (m_audioSettings.channelCount() > 0) + gst_structure_set(structure, "channels", G_TYPE_INT, m_audioSettings.channelCount(), NULL ); + + gst_caps_append_structure(caps,structure); + + g_object_set(G_OBJECT(capsFilter), "caps", caps, NULL); + } + + if (encoderElement) { + if (m_audioSettings.encodingMode() == QtMultimediaKit::ConstantQualityEncoding) { + QtMultimediaKit::EncodingQuality qualityValue = m_audioSettings.quality(); + + if (encoderElementName == "lamemp3enc") { + g_object_set(G_OBJECT(encoderElement), "target", 0, NULL); //constant quality mode + qreal quality[] = { + 10.0, //VeryLow + 6.0, //Low + 4.0, //Normal + 2.0, //High + 0.0 //VeryHigh + }; + g_object_set(G_OBJECT(encoderElement), "quality", quality[qualityValue], NULL); + } else if (encoderElementName == "ffenc_mp2") { + int quality[] = { + 8000, //VeryLow + 64000, //Low + 128000, //Normal + 192000, //High + 320000 //VeryHigh + }; + g_object_set(G_OBJECT(encoderElement), "bitrate", quality[qualityValue], NULL); + } else if (codec == QLatin1String("audio/speex")) { + //0-10 range with default 8 + double qualityTable[] = { + 2, //VeryLow + 5, //Low + 8, //Normal + 9, //High + 10 //VeryHigh + }; + g_object_set(G_OBJECT(encoderElement), "quality", qualityTable[qualityValue], NULL); + } else if (codec.startsWith("audio/AMR")) { + int band[] = { + 0, //VeryLow + 2, //Low + 4, //Normal + 6, //High + 7 //VeryHigh + }; + + g_object_set(G_OBJECT(encoderElement), "band-mode", band[qualityValue], NULL); + } + } else { + int bitrate = m_audioSettings.bitRate(); + if (bitrate > 0) { + g_object_set(G_OBJECT(encoderElement), "bitrate", bitrate, NULL); + } + } + + QMap options = m_options.value(codec); + QMapIterator it(options); + while (it.hasNext()) { + it.next(); + QString option = it.key(); + QVariant value = it.value(); + + switch (value.type()) { + case QVariant::Int: + g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toInt(), NULL); + break; + case QVariant::Bool: + g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toBool(), NULL); + break; + case QVariant::Double: + g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toDouble(), NULL); + break; + case QVariant::String: + g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toString().toUtf8().constData(), NULL); + break; + default: + qWarning() << "unsupported option type:" << option << value; + break; + } + } + } + + return GST_ELEMENT(encoderBin); + +} + + +QSet CameraBinAudioEncoder::supportedStreamTypes(const QString &codecName) const +{ + return m_streamTypes.value(codecName); +} diff --git a/src/plugins/gstreamer/camerabin/camerabinaudioencoder.h b/src/plugins/gstreamer/camerabin/camerabinaudioencoder.h new file mode 100644 index 000000000..1790fc37d --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinaudioencoder.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CAMERABINAUDIOENCODE_H +#define CAMERABINAUDIOENCODE_H + +#include +class CameraBinSession; + +#include +#include +#include + +#include + +#include + +QT_USE_NAMESPACE + +class CameraBinAudioEncoder : public QAudioEncoderControl +{ + Q_OBJECT +public: + CameraBinAudioEncoder(QObject *parent); + virtual ~CameraBinAudioEncoder(); + + QStringList supportedAudioCodecs() const; + QString codecDescription(const QString &codecName) const; + + QStringList supportedEncodingOptions(const QString &codec) const; + QVariant encodingOption(const QString &codec, const QString &name) const; + void setEncodingOption(const QString &codec, const QString &name, const QVariant &value); + + QList supportedSampleRates(const QAudioEncoderSettings &settings = QAudioEncoderSettings(), + bool *isContinuous = 0) const; + QList supportedChannelCounts(const QAudioEncoderSettings &settings = QAudioEncoderSettings()) const; + QList supportedSampleSizes(const QAudioEncoderSettings &settings = QAudioEncoderSettings()) const; + + QAudioEncoderSettings audioSettings() const; + void setAudioSettings(const QAudioEncoderSettings&); + + + GstElement *createEncoder(); + + QSet supportedStreamTypes(const QString &codecName) const; + + void setActualAudioSettings(const QAudioEncoderSettings&); + void resetActualSettings(); + +Q_SIGNALS: + void settingsChanged(); + +private: + QStringList m_codecs; + QMap m_elementNames; + QMap m_codecDescriptions; + QMap m_codecOptions; + + QMap > m_options; + + QMap > m_streamTypes; + + QAudioEncoderSettings m_audioSettings; + QAudioEncoderSettings m_userSettings; +}; + +#endif diff --git a/src/plugins/gstreamer/camerabin/camerabincapturebufferformat.cpp b/src/plugins/gstreamer/camerabin/camerabincapturebufferformat.cpp new file mode 100644 index 000000000..b99024f22 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabincapturebufferformat.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camerabincapturebufferformat.h" +#include "camerabinsession.h" + +CameraBinCaptureBufferFormat::CameraBinCaptureBufferFormat(CameraBinSession *session) + :QCameraCaptureBufferFormatControl(session) + , m_session(session) + , m_format(QVideoFrame::Format_Jpeg) +{ +} + +CameraBinCaptureBufferFormat::~CameraBinCaptureBufferFormat() +{ +} + +QList CameraBinCaptureBufferFormat::supportedBufferFormats() const +{ + //the exact YUV format is unknown with camerabin until the first capture is requested + return QList() + << QVideoFrame::Format_Jpeg +#ifdef Q_WS_MAEMO_6 + << QVideoFrame::Format_UYVY +#endif + ; +} + +QVideoFrame::PixelFormat CameraBinCaptureBufferFormat::bufferFormat() const +{ + return m_format; +} + +void CameraBinCaptureBufferFormat::setBufferFormat(QVideoFrame::PixelFormat format) +{ + if (m_format != format) { + m_format = format; + emit bufferFormatChanged(format); + } +} diff --git a/src/plugins/gstreamer/camerabin/camerabincapturebufferformat.h b/src/plugins/gstreamer/camerabin/camerabincapturebufferformat.h new file mode 100644 index 000000000..579ed239e --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabincapturebufferformat.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CAMERABINCAPTUREBUFFERFORMAT_H +#define CAMERABINCAPTUREBUFFERFORMAT_H + +#include +#include + +#include +#include + +class CameraBinSession; + +QT_USE_NAMESPACE + +class Q_MULTIMEDIA_EXPORT CameraBinCaptureBufferFormat : public QCameraCaptureBufferFormatControl +{ + Q_OBJECT +public: + CameraBinCaptureBufferFormat(CameraBinSession *session); + virtual ~CameraBinCaptureBufferFormat(); + + QList supportedBufferFormats() const; + + QVideoFrame::PixelFormat bufferFormat() const; + void setBufferFormat(QVideoFrame::PixelFormat format); + +private: + CameraBinSession *m_session; + QVideoFrame::PixelFormat m_format; +}; + +#endif diff --git a/src/plugins/gstreamer/camerabin/camerabincapturedestination.cpp b/src/plugins/gstreamer/camerabin/camerabincapturedestination.cpp new file mode 100644 index 000000000..2a83637b4 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabincapturedestination.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camerabincapturedestination.h" +#include "camerabinsession.h" + +CameraBinCaptureDestination::CameraBinCaptureDestination(CameraBinSession *session) + :QCameraCaptureDestinationControl(session) + , m_session(session) + , m_destination(QCameraImageCapture::CaptureToFile) +{ +} + +CameraBinCaptureDestination::~CameraBinCaptureDestination() +{ +} + + +bool CameraBinCaptureDestination::isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const +{ + //capture to buffer, file and both are supported. + return destination & (QCameraImageCapture::CaptureToFile | QCameraImageCapture::CaptureToBuffer); +} + +QCameraImageCapture::CaptureDestinations CameraBinCaptureDestination::captureDestination() const +{ + return m_destination; +} + +void CameraBinCaptureDestination::setCaptureDestination(QCameraImageCapture::CaptureDestinations destination) +{ + if (m_destination != destination) { + m_destination = destination; + emit captureDestinationChanged(m_destination); + } +} diff --git a/src/plugins/gstreamer/camerabin/camerabincapturedestination.h b/src/plugins/gstreamer/camerabin/camerabincapturedestination.h new file mode 100644 index 000000000..92c02f1b0 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabincapturedestination.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CAMERABINCAPTUREDESTINATION_H +#define CAMERABINCAPTUREDESTINATION_H + +#include +#include + + +class CameraBinSession; + +QT_USE_NAMESPACE + +class Q_MULTIMEDIA_EXPORT CameraBinCaptureDestination : public QCameraCaptureDestinationControl +{ + Q_OBJECT +public: + CameraBinCaptureDestination(CameraBinSession *session); + virtual ~CameraBinCaptureDestination(); + + bool isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const; + QCameraImageCapture::CaptureDestinations captureDestination() const; + void setCaptureDestination(QCameraImageCapture::CaptureDestinations destination); + +private: + CameraBinSession *m_session; + QCameraImageCapture::CaptureDestinations m_destination; +}; + +#endif // CAMERABINFLASHCONTROL_H diff --git a/src/plugins/gstreamer/camerabin/camerabincontainer.cpp b/src/plugins/gstreamer/camerabin/camerabincontainer.cpp new file mode 100644 index 000000000..97349204d --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabincontainer.cpp @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camerabincontainer.h" + + +#include + +CameraBinContainer::CameraBinContainer(QObject *parent) + :QMediaContainerControl(parent) +{ + QList formatCandidates; + formatCandidates << "mp4" << "ogg" << "wav" << "amr" << "mkv" + << "avi" << "3gp" << "3gp2" << "webm" << "mjpeg" << "asf" << "mov"; + + QMap elementNames; + + elementNames.insertMulti("mp4", "ffmux_mp4"); + elementNames.insertMulti("mp4", "hantromp4mux"); + elementNames.insertMulti("mp4", "mp4mux"); + elementNames.insert("ogg", "oggmux"); + elementNames["wav"] = "wavenc"; + elementNames["amr"] = "ffmux_amr"; + elementNames["mkv"] = "matroskamux"; + elementNames["avi"] = "avimux"; + elementNames["3gp"] = "ffmux_3gp"; + elementNames["3gp2"] = "ffmux_3g2"; + elementNames["webm"] = "webmmux"; + elementNames["mjpeg"] = "ffmux_mjpeg"; + elementNames["asf"] = "ffmux_asf"; + elementNames["mov"] = "qtmux"; + + QSet allTypes; + + foreach(const QByteArray &formatName, formatCandidates) { + foreach(const QByteArray &elementName, elementNames.values(formatName)) { + GstElementFactory *factory = gst_element_factory_find(elementName.constData()); + if (factory) { + m_supportedContainers.append(formatName); + const gchar *descr = gst_element_factory_get_description(factory); + m_containerDescriptions.insert(formatName, QString::fromUtf8(descr)); + + + if (formatName == QByteArray("raw")) { + m_streamTypes.insert(formatName, allTypes); + } else { + QSet types = supportedStreamTypes(factory, GST_PAD_SINK); + m_streamTypes.insert(formatName, types); + allTypes.unite(types); + } + + gst_object_unref(GST_OBJECT(factory)); + + m_elementNames.insert(formatName, elementName); + break; + } + } + } +} + +QSet CameraBinContainer::supportedStreamTypes(GstElementFactory *factory, GstPadDirection direction) +{ + QSet types; + const GList *pads = gst_element_factory_get_static_pad_templates(factory); + for (const GList *pad = pads; pad; pad = g_list_next(pad)) { + GstStaticPadTemplate *templ = (GstStaticPadTemplate*)pad->data; + if (templ->direction == direction) { + GstCaps *caps = gst_static_caps_get(&templ->static_caps); + for (uint i=0; i CameraBinContainer::supportedStreamTypes(const QString &container) const +{ + return m_streamTypes.value(container); +} diff --git a/src/plugins/gstreamer/camerabin/camerabincontainer.h b/src/plugins/gstreamer/camerabin/camerabincontainer.h new file mode 100644 index 000000000..3eac48342 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabincontainer.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef CAMERABINMEDIACONTAINERCONTROL_H +#define CAMERABINMEDIACONTAINERCONTROL_H + +#include +#include +#include + +#include + +QT_USE_NAMESPACE + +class CameraBinContainer : public QMediaContainerControl +{ +Q_OBJECT +public: + CameraBinContainer(QObject *parent); + virtual ~CameraBinContainer() {} + + virtual QStringList supportedContainers() const { return m_supportedContainers; } + virtual QString containerMimeType() const { return m_format; } + virtual void setContainerMimeType(const QString &formatMimeType) + { + m_format = formatMimeType; + + if (m_userFormat != formatMimeType) { + m_userFormat = formatMimeType; + emit settingsChanged(); + } + } + + void setActualContainer(const QString &formatMimeType) + { + m_format = formatMimeType; + } + + void resetActualContainer() + { + m_format = m_userFormat; + } + + virtual QString containerDescription(const QString &formatMimeType) const { return m_containerDescriptions.value(formatMimeType); } + + QByteArray formatElementName() const { return m_elementNames.value(containerMimeType()); } + + QSet supportedStreamTypes(const QString &container) const; + + static QSet supportedStreamTypes(GstElementFactory *factory, GstPadDirection direction); + +Q_SIGNALS: + void settingsChanged(); + +private: + QString m_format; // backend selected format, using m_userFormat + QString m_userFormat; + QStringList m_supportedContainers; + QMap m_elementNames; + QMap m_containerDescriptions; + QMap > m_streamTypes; +}; + +#endif // CAMERABINMEDIACONTAINERCONTROL_H diff --git a/src/plugins/gstreamer/camerabin/camerabincontrol.cpp b/src/plugins/gstreamer/camerabin/camerabincontrol.cpp new file mode 100644 index 000000000..2c30fd656 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabincontrol.cpp @@ -0,0 +1,356 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camerabincontrol.h" +#include "camerabincontainer.h" +#include "camerabinaudioencoder.h" +#include "camerabinvideoencoder.h" +#include "camerabinimageencoder.h" +#include "camerabinresourcepolicy.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define CAMEABIN_DEBUG 1 +#define ENUM_NAME(c,e,v) (c::staticMetaObject.enumerator(c::staticMetaObject.indexOfEnumerator(e)).valueToKey((v))) + +CameraBinControl::CameraBinControl(CameraBinSession *session) + :QCameraControl(session), + m_session(session), + m_state(QCamera::UnloadedState), + m_status(QCamera::UnloadedStatus), + m_reloadPending(false) +{ + connect(m_session, SIGNAL(stateChanged(QCamera::State)), + this, SLOT(updateStatus())); + + connect(m_session->audioEncodeControl(), SIGNAL(settingsChanged()), + SLOT(reloadLater())); + connect(m_session->videoEncodeControl(), SIGNAL(settingsChanged()), + SLOT(reloadLater())); + connect(m_session->mediaContainerControl(), SIGNAL(settingsChanged()), + SLOT(reloadLater())); + connect(m_session->imageEncodeControl(), SIGNAL(settingsChanged()), + SLOT(reloadLater())); + connect(m_session, SIGNAL(viewfinderChanged()), + SLOT(reloadLater())); + connect(m_session, SIGNAL(readyChanged(bool)), + SLOT(reloadLater())); + connect(m_session, SIGNAL(error(int,QString)), + SLOT(handleCameraError(int,QString))); + + m_resourcePolicy = new CamerabinResourcePolicy(this); + connect(m_resourcePolicy, SIGNAL(resourcesGranted()), + SLOT(handleResourcesGranted())); + connect(m_resourcePolicy, SIGNAL(resourcesDenied()), + SLOT(handleResourcesLost())); + connect(m_resourcePolicy, SIGNAL(resourcesLost()), + SLOT(handleResourcesLost())); + + connect(m_session, SIGNAL(busyChanged(bool)), + SLOT(handleBusyChanged(bool))); +} + +CameraBinControl::~CameraBinControl() +{ +} + +QCamera::CaptureMode CameraBinControl::captureMode() const +{ + return m_session->captureMode(); +} + +void CameraBinControl::setCaptureMode(QCamera::CaptureMode mode) +{ + if (m_session->captureMode() != mode) { + m_session->setCaptureMode(mode); + reloadLater(); + + if (m_state == QCamera::ActiveState) { + m_resourcePolicy->setResourceSet( + captureMode() == QCamera::CaptureStillImage ? + CamerabinResourcePolicy::ImageCaptureResources : + CamerabinResourcePolicy::VideoCaptureResources); + } + emit captureModeChanged(mode); + } +} + +bool CameraBinControl::isCaptureModeSupported(QCamera::CaptureMode mode) const +{ +#ifdef Q_WS_MAEMO_5 + //Front camera on N900 supports only video capture + if (m_session->cameraRole() == CameraBinSession::FrontCamera) + return mode == QCamera::CaptureVideo; +#endif + + return mode == QCamera::CaptureStillImage || mode == QCamera::CaptureVideo; +} + +void CameraBinControl::setState(QCamera::State state) +{ +#ifdef CAMEABIN_DEBUG + qDebug() << Q_FUNC_INFO << ENUM_NAME(QCamera, "State", state); +#endif + if (m_state != state) { + m_state = state; + + //special case for stopping the camera while it's busy, + //it should be delayed until the camera is idle + if (state == QCamera::LoadedState && + m_session->state() == QCamera::ActiveState && + m_session->isBusy()) { +#ifdef CAMEABIN_DEBUG + qDebug() << Q_FUNC_INFO << "Camera is busy, QCamera::stop() is delayed"; +#endif + emit stateChanged(m_state); + return; + } + + CamerabinResourcePolicy::ResourceSet resourceSet; + switch (state) { + case QCamera::UnloadedState: + resourceSet = CamerabinResourcePolicy::NoResources; + break; + case QCamera::LoadedState: + resourceSet = CamerabinResourcePolicy::LoadedResources; + break; + case QCamera::ActiveState: + resourceSet = captureMode() == QCamera::CaptureStillImage ? + CamerabinResourcePolicy::ImageCaptureResources : + CamerabinResourcePolicy::VideoCaptureResources; + break; + } + + m_resourcePolicy->setResourceSet(resourceSet); + + if (m_resourcePolicy->isResourcesGranted()) { + //postpone changing to Active if the session is nor ready yet + if (state == QCamera::ActiveState) { + if (m_session->isReady()) { + m_session->setState(state); + } else { +#ifdef CAMEABIN_DEBUG + qDebug() << "Camera session is not ready yet, postpone activating"; +#endif + } + } else + m_session->setState(state); + } + + emit stateChanged(m_state); + } +} + +QCamera::State CameraBinControl::state() const +{ + return m_state; +} + +void CameraBinControl::updateStatus() +{ + QCamera::State sessionState = m_session->state(); + QCamera::Status oldStatus = m_status; + + switch (m_state) { + case QCamera::UnloadedState: + m_status = QCamera::UnloadedStatus; + break; + case QCamera::LoadedState: + switch (sessionState) { + case QCamera::UnloadedState: + m_status = QCamera::LoadingStatus; + break; + case QCamera::LoadedState: + m_status = QCamera::LoadedStatus; + break; + case QCamera::ActiveState: + m_status = QCamera::ActiveStatus; + break; + } + break; + case QCamera::ActiveState: + switch (sessionState) { + case QCamera::UnloadedState: + m_status = QCamera::LoadingStatus; + break; + case QCamera::LoadedState: + m_status = QCamera::StartingStatus; + break; + case QCamera::ActiveState: + m_status = QCamera::ActiveStatus; + break; + } + } + + if (m_status != oldStatus) { +#ifdef CAMEABIN_DEBUG + qDebug() << "Camera status changed" << ENUM_NAME(QCamera, "Status", m_status); +#endif + emit statusChanged(m_status); + } +} + +void CameraBinControl::reloadLater() +{ +#ifdef CAMEABIN_DEBUG + qDebug() << "CameraBinControl: reload pipeline requested" << ENUM_NAME(QCamera, "State", m_state); +#endif + if (!m_reloadPending && m_state == QCamera::ActiveState) { + m_reloadPending = true; + + if (!m_session->isBusy()) { + m_session->setState(QCamera::LoadedState); + QMetaObject::invokeMethod(this, "delayedReload", Qt::QueuedConnection); + } + } +} + +void CameraBinControl::handleResourcesLost() +{ +#ifdef CAMEABIN_DEBUG + qDebug() << Q_FUNC_INFO << ENUM_NAME(QCamera, "State", m_state); +#endif + m_session->setState(QCamera::UnloadedState); +} + +void CameraBinControl::handleResourcesGranted() +{ +#ifdef CAMEABIN_DEBUG + qDebug() << Q_FUNC_INFO << ENUM_NAME(QCamera, "State", m_state); +#endif + + //camera will be started soon by delayedReload() + if (m_reloadPending && m_state == QCamera::ActiveState) + return; + + if (m_state == QCamera::ActiveState && m_session->isReady()) + m_session->setState(QCamera::ActiveState); + else if (m_state == QCamera::LoadedState) + m_session->setState(QCamera::LoadedState); +} + +void CameraBinControl::handleBusyChanged(bool busy) +{ + if (!busy && m_session->state() == QCamera::ActiveState) { + if (m_state == QCamera::LoadedState) { + //handle delayed stop() because of busy camera + m_resourcePolicy->setResourceSet(CamerabinResourcePolicy::LoadedResources); + m_session->setState(QCamera::LoadedState); + } else if (m_state == QCamera::ActiveState && m_reloadPending) { + //handle delayed reload because of busy camera + m_session->setState(QCamera::LoadedState); + QMetaObject::invokeMethod(this, "delayedReload", Qt::QueuedConnection); + } + } +} + +void CameraBinControl::handleCameraError(int errorCode, const QString &errorString) +{ + emit error(errorCode, errorString); + setState(QCamera::UnloadedState); +} + +void CameraBinControl::delayedReload() +{ +#ifdef CAMEABIN_DEBUG + qDebug() << "CameraBinControl: reload pipeline"; +#endif + if (m_reloadPending) { + m_reloadPending = false; + if (m_state == QCamera::ActiveState && + m_session->isReady() && + m_resourcePolicy->isResourcesGranted()) { + m_session->setState(QCamera::ActiveState); + } + } +} + +bool CameraBinControl::canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const +{ + Q_UNUSED(status); + + switch (changeType) { + case QCameraControl::CaptureMode: + case QCameraControl::ImageEncodingSettings: + case QCameraControl::VideoEncodingSettings: + case QCameraControl::Viewfinder: + return true; + default: + return false; + } +} + +#define VIEWFINDER_COLORSPACE_CONVERSION 0x00000004 + +bool CameraBinControl::viewfinderColorSpaceConversion() const +{ + gint flags = 0; + g_object_get(G_OBJECT(m_session->cameraBin()), "flags", &flags, NULL); + + return flags & VIEWFINDER_COLORSPACE_CONVERSION; +} + +void CameraBinControl::setViewfinderColorSpaceConversion(bool enabled) +{ + gint flags = 0; + g_object_get(G_OBJECT(m_session->cameraBin()), "flags", &flags, NULL); + + if (enabled) + flags |= VIEWFINDER_COLORSPACE_CONVERSION; + else + flags &= ~VIEWFINDER_COLORSPACE_CONVERSION; + + g_object_set(G_OBJECT(m_session->cameraBin()), "flags", flags, NULL); +} diff --git a/src/plugins/gstreamer/camerabin/camerabincontrol.h b/src/plugins/gstreamer/camerabin/camerabincontrol.h new file mode 100644 index 000000000..1e5f28e01 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabincontrol.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef CAMERABINCONTROL_H +#define CAMERABINCONTROL_H + +#include +#include +#include "camerabinsession.h" + +QT_USE_NAMESPACE + +class CamerabinResourcePolicy; + +class CameraBinControl : public QCameraControl +{ + Q_OBJECT + Q_PROPERTY(bool viewfinderColorSpaceConversion READ viewfinderColorSpaceConversion WRITE setViewfinderColorSpaceConversion) +public: + CameraBinControl( CameraBinSession *session ); + virtual ~CameraBinControl(); + + bool isValid() const { return true; } + + QCamera::State state() const; + void setState(QCamera::State state); + + QCamera::Status status() const { return m_status; } + + QCamera::CaptureMode captureMode() const; + void setCaptureMode(QCamera::CaptureMode mode); + + bool isCaptureModeSupported(QCamera::CaptureMode mode) const; + bool canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const; + bool viewfinderColorSpaceConversion() const; + +public slots: + void reloadLater(); + void setViewfinderColorSpaceConversion(bool enabled); + +private slots: + void updateStatus(); + void delayedReload(); + + void handleResourcesGranted(); + void handleResourcesLost(); + + void handleBusyChanged(bool); + void handleCameraError(int error, const QString &errorString); + +private: + void updateSupportedResolutions(const QString &device); + + CameraBinSession *m_session; + QCamera::State m_state; + QCamera::Status m_status; + CamerabinResourcePolicy *m_resourcePolicy; + + bool m_reloadPending; +}; + +#endif // CAMERABINCONTROL_H diff --git a/src/plugins/gstreamer/camerabin/camerabinexposure.cpp b/src/plugins/gstreamer/camerabin/camerabinexposure.cpp new file mode 100644 index 000000000..3401d07fc --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinexposure.cpp @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camerabinexposure.h" +#include "camerabinsession.h" +#include + +#include + +CameraBinExposure::CameraBinExposure(CameraBinSession *session) + :QCameraExposureControl(session), + m_session(session) +{ +} + +CameraBinExposure::~CameraBinExposure() +{ +} + +QCameraExposure::ExposureMode CameraBinExposure::exposureMode() const +{ + GstSceneMode sceneMode; + gst_photography_get_scene_mode(m_session->photography(), &sceneMode); + + switch (sceneMode) { + case GST_PHOTOGRAPHY_SCENE_MODE_PORTRAIT: return QCameraExposure::ExposurePortrait; + case GST_PHOTOGRAPHY_SCENE_MODE_SPORT: return QCameraExposure::ExposureSports; + case GST_PHOTOGRAPHY_SCENE_MODE_NIGHT: return QCameraExposure::ExposureNight; + case GST_PHOTOGRAPHY_SCENE_MODE_MANUAL: return QCameraExposure::ExposureManual; + case GST_PHOTOGRAPHY_SCENE_MODE_CLOSEUP: //no direct mapping available so mapping to auto mode + case GST_PHOTOGRAPHY_SCENE_MODE_LANDSCAPE: //no direct mapping available so mapping to auto mode + case GST_PHOTOGRAPHY_SCENE_MODE_AUTO: + default: + return QCameraExposure::ExposureAuto; + } +} + +void CameraBinExposure::setExposureMode(QCameraExposure::ExposureMode mode) +{ + GstSceneMode sceneMode; + gst_photography_get_scene_mode(m_session->photography(), &sceneMode); + + switch (mode) { + case QCameraExposure::ExposureManual: sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_MANUAL; break; + case QCameraExposure::ExposurePortrait: sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_PORTRAIT; break; + case QCameraExposure::ExposureSports: sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_SPORT; break; + case QCameraExposure::ExposureNight: sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_NIGHT; break; + case QCameraExposure::ExposureAuto: sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_AUTO; break; + default: + break; + } + + gst_photography_set_scene_mode(m_session->photography(), sceneMode); +} + +bool CameraBinExposure::isExposureModeSupported(QCameraExposure::ExposureMode mode) const +{ + //Similar mode names can be found in gst as GstSceneMode + return mode == QCameraExposure::ExposureAuto || + mode == QCameraExposure::ExposurePortrait || + mode == QCameraExposure::ExposureSports || + mode == QCameraExposure::ExposureNight; + + //No direct mapping available for GST_PHOTOGRAPHY_SCENE_MODE_CLOSEUP and + //GST_PHOTOGRAPHY_SCENE_MODE_LANDSCAPE +} + +QCameraExposure::MeteringMode CameraBinExposure::meteringMode() const +{ + return QCameraExposure::MeteringMatrix; +} + +void CameraBinExposure::setMeteringMode(QCameraExposure::MeteringMode mode) +{ + Q_UNUSED(mode); +} + +bool CameraBinExposure::isMeteringModeSupported(QCameraExposure::MeteringMode mode) const +{ + return mode == QCameraExposure::MeteringMatrix; +} + +bool CameraBinExposure::isParameterSupported(ExposureParameter parameter) const +{ + switch (parameter) { + case QCameraExposureControl::ExposureCompensation: + case QCameraExposureControl::ISO: + case QCameraExposureControl::Aperture: + case QCameraExposureControl::ShutterSpeed: + return true; + default: + return false; + } +} + +QVariant CameraBinExposure::exposureParameter(ExposureParameter parameter) const +{ + switch (parameter) { + case QCameraExposureControl::ExposureCompensation: + { + gfloat ev; + gst_photography_get_ev_compensation(m_session->photography(), &ev); + return QVariant(ev); + } + case QCameraExposureControl::ISO: + { + guint isoSpeed = 0; + gst_photography_get_iso_speed(m_session->photography(), &isoSpeed); + return QVariant(isoSpeed); + } + case QCameraExposureControl::Aperture: + return QVariant(2.8); + case QCameraExposureControl::ShutterSpeed: + { + guint32 shutterSpeed = 0; + gst_photography_get_exposure(m_session->photography(), &shutterSpeed); + + return QVariant(shutterSpeed/1000000.0); + } + default: + return QVariant(); + } +} + +QCameraExposureControl::ParameterFlags CameraBinExposure::exposureParameterFlags(ExposureParameter parameter) const +{ + QCameraExposureControl::ParameterFlags flags = 0; + + switch (parameter) { + case QCameraExposureControl::ExposureCompensation: + flags |= ContinuousRange; + break; + case QCameraExposureControl::Aperture: + flags |= ReadOnly; + break; + default: + break; + } + + return flags; +} + +QVariantList CameraBinExposure::supportedParameterRange(ExposureParameter parameter) const +{ + QVariantList res; + switch (parameter) { + case QCameraExposureControl::ExposureCompensation: + res << -2.0 << 2.0; + break; + case QCameraExposureControl::ISO: + res << 100 << 200 << 400; + break; + case QCameraExposureControl::Aperture: + res << 2.8; + break; + default: + break; + } + + return res; +} + +bool CameraBinExposure::setExposureParameter(ExposureParameter parameter, const QVariant& value) +{ + QVariant oldValue = exposureParameter(parameter); + + switch (parameter) { + case QCameraExposureControl::ExposureCompensation: + gst_photography_set_ev_compensation(m_session->photography(), value.toReal()); + break; + case QCameraExposureControl::ISO: + gst_photography_set_iso_speed(m_session->photography(), value.toInt()); + break; + case QCameraExposureControl::Aperture: + gst_photography_set_aperture(m_session->photography(), guint(value.toReal()*1000000)); + break; + case QCameraExposureControl::ShutterSpeed: + gst_photography_set_exposure(m_session->photography(), guint(value.toReal()*1000000)); + break; + default: + return false; + } + + QVariant newValue = exposureParameter(parameter); + if (!qFuzzyCompare(oldValue.toReal(), newValue.toReal())) + emit exposureParameterChanged(parameter); + + return true; +} + +QString CameraBinExposure::extendedParameterName(ExposureParameter) +{ + return QString(); +} diff --git a/src/plugins/gstreamer/camerabin/camerabinexposure.h b/src/plugins/gstreamer/camerabin/camerabinexposure.h new file mode 100644 index 000000000..44439253d --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinexposure.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CAMERABINEXPOSURECONTROL_MAEMO_H +#define CAMERABINEXPOSURECONTROL_MAEMO_H + +#include +#include + +#include +#include + +class CameraBinSession; + +QT_USE_NAMESPACE + +class Q_MULTIMEDIA_EXPORT CameraBinExposure : public QCameraExposureControl +{ + Q_OBJECT + +public: + CameraBinExposure(CameraBinSession *session); + virtual ~CameraBinExposure(); + + QCameraExposure::ExposureMode exposureMode() const; + void setExposureMode(QCameraExposure::ExposureMode mode); + bool isExposureModeSupported(QCameraExposure::ExposureMode mode) const; + + QCameraExposure::MeteringMode meteringMode() const; + void setMeteringMode(QCameraExposure::MeteringMode mode); + bool isMeteringModeSupported(QCameraExposure::MeteringMode mode) const; + + bool isParameterSupported(ExposureParameter parameter) const; + QVariant exposureParameter(ExposureParameter parameter) const; + ParameterFlags exposureParameterFlags(ExposureParameter parameter) const; + QVariantList supportedParameterRange(ExposureParameter parameter) const; + bool setExposureParameter(ExposureParameter parameter, const QVariant& value); + + QString extendedParameterName(ExposureParameter parameter); + +private: + CameraBinSession *m_session; +}; + +#endif // CAMERABINEXPOSURECONTROL_MAEMO_H diff --git a/src/plugins/gstreamer/camerabin/camerabinflash.cpp b/src/plugins/gstreamer/camerabin/camerabinflash.cpp new file mode 100644 index 000000000..f5b76524d --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinflash.cpp @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camerabinflash.h" +#include "camerabinsession.h" +#include + +#include + +CameraBinFlash::CameraBinFlash(CameraBinSession *session) + :QCameraFlashControl(session), + m_session(session) +{ +} + +CameraBinFlash::~CameraBinFlash() +{ +} + +QCameraExposure::FlashModes CameraBinFlash::flashMode() const +{ + GstFlashMode flashMode; + gst_photography_get_flash_mode(m_session->photography(), &flashMode); + + QCameraExposure::FlashModes modes; + switch (flashMode) { + case GST_PHOTOGRAPHY_FLASH_MODE_AUTO: modes |= QCameraExposure::FlashAuto; break; + case GST_PHOTOGRAPHY_FLASH_MODE_OFF: modes |= QCameraExposure::FlashOff; break; + case GST_PHOTOGRAPHY_FLASH_MODE_ON: modes |= QCameraExposure::FlashOn; break; + case GST_PHOTOGRAPHY_FLASH_MODE_FILL_IN: modes |= QCameraExposure::FlashFill; break; + case GST_PHOTOGRAPHY_FLASH_MODE_RED_EYE: modes |= QCameraExposure::FlashRedEyeReduction; break; + default: + modes |= QCameraExposure::FlashAuto; + break; + } + return modes; +} + +void CameraBinFlash::setFlashMode(QCameraExposure::FlashModes mode) +{ + GstFlashMode flashMode; + gst_photography_get_flash_mode(m_session->photography(), &flashMode); + + if (mode.testFlag(QCameraExposure::FlashAuto)) flashMode = GST_PHOTOGRAPHY_FLASH_MODE_AUTO; + else if (mode.testFlag(QCameraExposure::FlashOff)) flashMode = GST_PHOTOGRAPHY_FLASH_MODE_OFF; + else if (mode.testFlag(QCameraExposure::FlashOn)) flashMode = GST_PHOTOGRAPHY_FLASH_MODE_ON; + else if (mode.testFlag(QCameraExposure::FlashFill)) flashMode = GST_PHOTOGRAPHY_FLASH_MODE_FILL_IN; + else if (mode.testFlag(QCameraExposure::FlashRedEyeReduction)) flashMode = GST_PHOTOGRAPHY_FLASH_MODE_RED_EYE; + + gst_photography_set_flash_mode(m_session->photography(), flashMode); +} + +bool CameraBinFlash::isFlashModeSupported(QCameraExposure::FlashModes mode) const +{ + return mode == QCameraExposure::FlashOff || + mode == QCameraExposure::FlashOn || + mode == QCameraExposure::FlashAuto || + mode == QCameraExposure::FlashRedEyeReduction || + mode == QCameraExposure::FlashFill; +} + +bool CameraBinFlash::isFlashReady() const +{ + return true; +} + diff --git a/src/plugins/gstreamer/camerabin/camerabinflash.h b/src/plugins/gstreamer/camerabin/camerabinflash.h new file mode 100644 index 000000000..7c566becf --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinflash.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CAMERABINFLASHCONTROL_H +#define CAMERABINFLASHCONTROL_H + +#include +#include + +#include +#include + +class CameraBinSession; + +QT_USE_NAMESPACE + +class Q_MULTIMEDIA_EXPORT CameraBinFlash : public QCameraFlashControl +{ + Q_OBJECT +public: + CameraBinFlash(CameraBinSession *session); + virtual ~CameraBinFlash(); + + QCameraExposure::FlashModes flashMode() const; + void setFlashMode(QCameraExposure::FlashModes mode); + bool isFlashModeSupported(QCameraExposure::FlashModes mode) const; + + bool isFlashReady() const; + +private: + CameraBinSession *m_session; +}; + +#endif // CAMERABINFLASHCONTROL_H + diff --git a/src/plugins/gstreamer/camerabin/camerabinfocus.cpp b/src/plugins/gstreamer/camerabin/camerabinfocus.cpp new file mode 100644 index 000000000..cf7c9ecd8 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinfocus.cpp @@ -0,0 +1,245 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camerabinfocus.h" +#include "camerabinsession.h" + +#include + +#include +#include + +//#define CAMERABIN_DEBUG 1 +#define ENUM_NAME(c,e,v) (c::staticMetaObject.enumerator(c::staticMetaObject.indexOfEnumerator(e)).valueToKey((v))) + +CameraBinFocus::CameraBinFocus(CameraBinSession *session) + :QCameraFocusControl(session), + m_session(session), + m_focusMode(QCameraFocus::AutoFocus), + m_focusStatus(QCamera::Unlocked), + m_focusZoneStatus(QCameraFocusZone::Selected) +{ + connect(m_session, SIGNAL(stateChanged(QCamera::State)), + this, SLOT(_q_handleCameraStateChange(QCamera::State))); + connect(m_session, SIGNAL(imageCaptured(int,QImage)), + this, SLOT(_q_handleCapturedImage())); +} + +CameraBinFocus::~CameraBinFocus() +{ +} + +QCameraFocus::FocusMode CameraBinFocus::focusMode() const +{ + return m_focusMode; +} + +void CameraBinFocus::setFocusMode(QCameraFocus::FocusMode mode) +{ + if (isFocusModeSupported(mode)) { + m_focusMode = mode; + } +} + +bool CameraBinFocus::isFocusModeSupported(QCameraFocus::FocusMode mode) const +{ + return mode & QCameraFocus::AutoFocus; +} + +qreal CameraBinFocus::maximumOpticalZoom() const +{ + return 1.0; +} + +qreal CameraBinFocus::maximumDigitalZoom() const +{ + return 10; +} + +qreal CameraBinFocus::opticalZoom() const +{ + return 1.0; +} + +qreal CameraBinFocus::digitalZoom() const +{ +#ifdef Q_WS_MAEMO_5 + gint zoomFactor = 0; + g_object_get(GST_BIN(m_session->cameraBin()), "zoom", &zoomFactor, NULL); + return zoomFactor/100.0; +#else + gfloat zoomFactor = 1.0; + g_object_get(GST_BIN(m_session->cameraBin()), "zoom", &zoomFactor, NULL); + return zoomFactor; +#endif +} + +void CameraBinFocus::zoomTo(qreal optical, qreal digital) +{ + Q_UNUSED(optical); + digital = qBound(qreal(1.0), digital, qreal(10.0)); +#ifdef Q_WS_MAEMO_5 + g_object_set(GST_BIN(m_session->cameraBin()), "zoom", qRound(digital*100.0), NULL); +#else + g_object_set(GST_BIN(m_session->cameraBin()), "zoom", digital, NULL); +#endif + emit digitalZoomChanged(digital); +} + +QCameraFocus::FocusPointMode CameraBinFocus::focusPointMode() const +{ + return QCameraFocus::FocusPointAuto; +} + +void CameraBinFocus::setFocusPointMode(QCameraFocus::FocusPointMode mode) +{ + Q_UNUSED(mode); +} + +bool CameraBinFocus::isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const +{ + return mode == QCameraFocus::FocusPointAuto; +} + +QPointF CameraBinFocus::customFocusPoint() const +{ + return QPointF(0.5, 0.5); +} + +void CameraBinFocus::setCustomFocusPoint(const QPointF &point) +{ + Q_UNUSED(point); +} + +QCameraFocusZoneList CameraBinFocus::focusZones() const +{ + return QCameraFocusZoneList() << QCameraFocusZone(QRectF(0.35, 0.35, 0.3, 0.3), m_focusZoneStatus); +} + + +void CameraBinFocus::handleFocusMessage(GstMessage *gm) +{ + //it's a sync message, so it's called from non main thread + if (gst_structure_has_name(gm->structure, GST_PHOTOGRAPHY_AUTOFOCUS_DONE)) { + gint status = GST_PHOTOGRAPHY_FOCUS_STATUS_NONE; + gst_structure_get_int (gm->structure, "status", &status); + QCamera::LockStatus focusStatus = m_focusStatus; + QCamera::LockChangeReason reason = QCamera::UserRequest; + + switch (status) { + case GST_PHOTOGRAPHY_FOCUS_STATUS_FAIL: + focusStatus = QCamera::Unlocked; + reason = QCamera::LockFailed; + break; + case GST_PHOTOGRAPHY_FOCUS_STATUS_SUCCESS: + focusStatus = QCamera::Locked; + break; + case GST_PHOTOGRAPHY_FOCUS_STATUS_NONE: + break; + case GST_PHOTOGRAPHY_FOCUS_STATUS_RUNNING: + focusStatus = QCamera::Searching; + break; + default: + break; + } + + static int signalIndex = metaObject()->indexOfSlot( + "_q_setFocusStatus(QCamera::LockStatus,QCamera::LockChangeReason)"); + metaObject()->method(signalIndex).invoke(this, + Qt::QueuedConnection, + Q_ARG(QCamera::LockStatus,focusStatus), + Q_ARG(QCamera::LockChangeReason,reason)); + } +} + +void CameraBinFocus::_q_setFocusStatus(QCamera::LockStatus status, QCamera::LockChangeReason reason) +{ +#ifdef CAMERABIN_DEBUG + qDebug() << Q_FUNC_INFO << "Current:" + << ENUM_NAME(QCamera, "LockStatus", m_focusStatus) + << "New:" + << ENUM_NAME(QCamera, "LockStatus", status) << ENUM_NAME(QCamera, "LockChangeReason", reason); +#endif + + if (m_focusStatus != status) { + m_focusStatus = status; + + QCameraFocusZone::FocusZoneStatus zonesStatus = + m_focusStatus == QCamera::Locked ? + QCameraFocusZone::Focused : QCameraFocusZone::Selected; + + if (m_focusZoneStatus != zonesStatus) { + m_focusZoneStatus = zonesStatus; + emit focusZonesChanged(); + } + + emit _q_focusStatusChanged(m_focusStatus, reason); + } +} + +void CameraBinFocus::_q_handleCameraStateChange(QCamera::State state) +{ + if (state != QCamera::ActiveState) + _q_setFocusStatus(QCamera::Unlocked, QCamera::LockLost); +} + +void CameraBinFocus::_q_handleCapturedImage() +{ +#ifdef Q_WS_MAEMO_5 + //N900 lost focus after image capture + if (m_focusStatus != QCamera::Unlocked) { + m_focusStatus = QCamera::Unlocked; + emit _q_focusStatusChanged(QCamera::Unlocked, QCamera::LockLost); + } +#endif +} + +void CameraBinFocus::_q_startFocusing() +{ + _q_setFocusStatus(QCamera::Searching, QCamera::UserRequest); + gst_photography_set_autofocus(m_session->photography(), TRUE); +} + +void CameraBinFocus::_q_stopFocusing() +{ + gst_photography_set_autofocus(m_session->photography(), FALSE); + _q_setFocusStatus(QCamera::Unlocked, QCamera::UserRequest); +} diff --git a/src/plugins/gstreamer/camerabin/camerabinfocus.h b/src/plugins/gstreamer/camerabin/camerabinfocus.h new file mode 100644 index 000000000..e496d2e3b --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinfocus.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CAMERABINFOCUSCONTROL_H +#define CAMERABINFOCUSCONTROL_H + +#include +#include + +#include +#include + +class CameraBinSession; + +QT_USE_NAMESPACE + +class CameraBinFocus : public QCameraFocusControl +{ + Q_OBJECT + +public: + CameraBinFocus(CameraBinSession *session); + virtual ~CameraBinFocus(); + + QCameraFocus::FocusMode focusMode() const; + void setFocusMode(QCameraFocus::FocusMode mode); + bool isFocusModeSupported(QCameraFocus::FocusMode mode) const; + + qreal maximumOpticalZoom() const; + qreal maximumDigitalZoom() const; + qreal opticalZoom() const; + qreal digitalZoom() const; + + void zoomTo(qreal optical, qreal digital) ; + + QCameraFocus::FocusPointMode focusPointMode() const; + void setFocusPointMode(QCameraFocus::FocusPointMode mode) ; + bool isFocusPointModeSupported(QCameraFocus::FocusPointMode) const; + QPointF customFocusPoint() const; + void setCustomFocusPoint(const QPointF &point); + + QCameraFocusZoneList focusZones() const; + + void handleFocusMessage(GstMessage*); + QCamera::LockStatus focusStatus() const { return m_focusStatus; } + +Q_SIGNALS: + void _q_focusStatusChanged(QCamera::LockStatus status, QCamera::LockChangeReason reason); + +public Q_SLOTS: + void _q_startFocusing(); + void _q_stopFocusing(); + +private Q_SLOTS: + void _q_setFocusStatus(QCamera::LockStatus status, QCamera::LockChangeReason reason); + void _q_handleCameraStateChange(QCamera::State state); + void _q_handleCapturedImage(); + +private: + CameraBinSession *m_session; + QCameraFocus::FocusMode m_focusMode; + QCamera::LockStatus m_focusStatus; + QCameraFocusZone::FocusZoneStatus m_focusZoneStatus; +}; + +#endif // CAMERABINFOCUSCONTROL_H diff --git a/src/plugins/gstreamer/camerabin/camerabinimagecapture.cpp b/src/plugins/gstreamer/camerabin/camerabinimagecapture.cpp new file mode 100644 index 000000000..3df1105bc --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinimagecapture.cpp @@ -0,0 +1,347 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camerabinimagecapture.h" +#include "camerabincapturedestination.h" +#include "camerabincapturebufferformat.h" +#include "camerabinsession.h" +#include "qgstvideobuffer.h" +#include "qvideosurfacegstsink.h" +#include "qgstutils.h" +#include +#include +#include + +//#define DEBUG_CAPTURE + +#ifdef Q_WS_MAEMO_5 +#define IMAGE_DONE_SIGNAL "img-done" +#else +#define IMAGE_DONE_SIGNAL "image-done" +#endif + + +Q_DECLARE_METATYPE(QVideoFrame) +Q_DECLARE_METATYPE(QtMultimediaKit::MetaData) + +namespace +{ +class CameraRegisterMetaTypes +{ +public: + CameraRegisterMetaTypes() + { + qRegisterMetaType("QVideoFrame"); + qRegisterMetaType("QtMultimediaKit::MetaData"); + } +} _registerCameraMetaTypes; +} + + +CameraBinImageCapture::CameraBinImageCapture(CameraBinSession *session) + :QCameraImageCaptureControl(session) + , m_session(session) + , m_ready(false) + , m_requestId(0) + , m_jpegEncoderElement(0) + , m_metadataMuxerElement(0) +{ + connect(m_session, SIGNAL(stateChanged(QCamera::State)), SLOT(updateState())); + connect(m_session, SIGNAL(imageExposed(int)), this, SIGNAL(imageExposed(int))); + connect(m_session, SIGNAL(imageCaptured(int,QImage)), this, SIGNAL(imageCaptured(int,QImage))); + connect(m_session, SIGNAL(busMessage(QGstreamerMessage)), SLOT(handleBusMessage(QGstreamerMessage))); + + g_signal_connect(G_OBJECT(m_session->cameraBin()), IMAGE_DONE_SIGNAL, G_CALLBACK(handleImageSaved), this); +} + +CameraBinImageCapture::~CameraBinImageCapture() +{ +} + +bool CameraBinImageCapture::isReadyForCapture() const +{ + return m_ready; +} + +int CameraBinImageCapture::capture(const QString &fileName) +{ + m_requestId++; + + if (!m_ready) { + emit error(m_requestId, QCameraImageCapture::NotReadyError, tr("Camera not ready")); + return m_requestId; + } + +#ifdef DEBUG_CAPTURE + qDebug() << Q_FUNC_INFO << m_requestId << fileName; +#endif + m_session->captureImage(m_requestId, fileName); + return m_requestId; +} + +void CameraBinImageCapture::cancelCapture() +{ +} + +void CameraBinImageCapture::updateState() +{ + bool ready = m_session->state() == QCamera::ActiveState; + if (m_ready != ready) { +#ifdef DEBUG_CAPTURE + qDebug() << "readyForCaptureChanged" << ready; +#endif + emit readyForCaptureChanged(m_ready = ready); + } +} + +gboolean CameraBinImageCapture::handleImageSaved(GstElement *camera, + const gchar *filename, + CameraBinImageCapture *self) +{ +#ifdef DEBUG_CAPTURE + qDebug() << "Image saved" << filename; +#endif + + Q_UNUSED(camera); + + if (self->m_session->captureDestinationControl()->captureDestination() & QCameraImageCapture::CaptureToFile) { + QMetaObject::invokeMethod(self, "imageSaved", + Qt::QueuedConnection, + Q_ARG(int, self->m_requestId), + Q_ARG(QString, QString::fromUtf8(filename))); + } else { +#ifdef DEBUG_CAPTURE + qDebug() << Q_FUNC_INFO << "Dropped saving file" << filename; +#endif + //camerabin creates an empty file when captured buffer is dropped, + //let's remove it + QFileInfo info(QString::fromUtf8(filename)); + if (info.isFile() && + info.filePath().startsWith("/home") && + info.size() == 0) { + QFile(info.absoluteFilePath()).remove(); + } + } + return true; +} + +gboolean CameraBinImageCapture::metadataEventProbe(GstPad *pad, GstEvent *event, CameraBinImageCapture *self) +{ + + if (GST_EVENT_TYPE(event) == GST_EVENT_TAG) { + GstTagList *gstTags; + gst_event_parse_tag(event, &gstTags); + QMap extendedTags = QGstUtils::gstTagListToMap(gstTags); + +#ifdef DEBUG_CAPTURE + qDebug() << QString(gst_structure_to_string(gst_event_get_structure(event))).right(768); + qDebug() << "Capture event probe" << extendedTags; +#endif + + QMap tags; + tags[QtMultimediaKit::ISOSpeedRatings] = extendedTags.value("capturing-iso-speed"); + tags[QtMultimediaKit::DigitalZoomRatio] = extendedTags.value("capturing-digital-zoom-ratio"); + tags[QtMultimediaKit::ExposureTime] = extendedTags.value("capturing-shutter-speed"); + tags[QtMultimediaKit::WhiteBalance] = extendedTags.value("capturing-white-balance"); + tags[QtMultimediaKit::Flash] = extendedTags.value("capturing-flash-fired"); + tags[QtMultimediaKit::FocalLengthIn35mmFilm] = extendedTags.value("capturing-focal-length"); + tags[QtMultimediaKit::MeteringMode] = extendedTags.value("capturing-metering-mode"); + tags[QtMultimediaKit::ExposureMode] = extendedTags.value("capturing-exposure-mode"); + tags[QtMultimediaKit::FNumber] = extendedTags.value("capturing-focal-ratio"); + tags[QtMultimediaKit::ExposureMode] = extendedTags.value("capturing-exposure-mode"); + + QMapIterator i(tags); + while (i.hasNext()) { + i.next(); + if (i.value().isValid()) { + QMetaObject::invokeMethod(self, "imageMetadataAvailable", + Qt::QueuedConnection, + Q_ARG(int, self->m_requestId), + Q_ARG(QtMultimediaKit::MetaData, i.key()), + Q_ARG(QVariant, i.value())); + } + } + } + + return true; +} + +gboolean CameraBinImageCapture::uncompressedBufferProbe(GstPad *pad, GstBuffer *buffer, CameraBinImageCapture *self) +{ + Q_UNUSED(pad); + CameraBinSession *session = self->m_session; + +#ifdef DEBUG_CAPTURE + qDebug() << "Uncompressed buffer probe" << gst_caps_to_string(GST_BUFFER_CAPS(buffer)); +#endif + + QCameraImageCapture::CaptureDestinations destination = + session->captureDestinationControl()->captureDestination(); + QVideoFrame::PixelFormat format = session->captureBufferFormatControl()->bufferFormat(); + + if (destination & QCameraImageCapture::CaptureToBuffer) { + if (format != QVideoFrame::Format_Jpeg) { + GstCaps *caps = GST_BUFFER_CAPS(buffer); + int bytesPerLine = -1; + QVideoSurfaceFormat format = QVideoSurfaceGstSink::formatForCaps(caps, &bytesPerLine); +#ifdef DEBUG_CAPTURE + qDebug() << "imageAvailable(uncompressed):" << format; +#endif + QGstVideoBuffer *videoBuffer = new QGstVideoBuffer(buffer, bytesPerLine); + + QVideoFrame frame(videoBuffer, + format.frameSize(), + format.pixelFormat()); + + QMetaObject::invokeMethod(self, "imageAvailable", + Qt::QueuedConnection, + Q_ARG(int, self->m_requestId), + Q_ARG(QVideoFrame, frame)); + } + } + + //keep the buffer if capture to file or jpeg buffer capture was reuqsted + bool keepBuffer = (destination & QCameraImageCapture::CaptureToFile) || + ((destination & QCameraImageCapture::CaptureToBuffer) && + format == QVideoFrame::Format_Jpeg); + + return keepBuffer; +} + +gboolean CameraBinImageCapture::jpegBufferProbe(GstPad *pad, GstBuffer *buffer, CameraBinImageCapture *self) +{ + Q_UNUSED(pad); + CameraBinSession *session = self->m_session; + +#ifdef DEBUG_CAPTURE + qDebug() << "Jpeg buffer probe" << gst_caps_to_string(GST_BUFFER_CAPS(buffer)); +#endif + + QCameraImageCapture::CaptureDestinations destination = + session->captureDestinationControl()->captureDestination(); + + if ((destination & QCameraImageCapture::CaptureToBuffer) && + session->captureBufferFormatControl()->bufferFormat() == QVideoFrame::Format_Jpeg) { + QGstVideoBuffer *videoBuffer = new QGstVideoBuffer(buffer, + -1); //bytesPerLine is not available for jpegs + + QSize resolution = QGstUtils::capsCorrectedResolution(GST_BUFFER_CAPS(buffer)); + //if resolution is not presented in caps, try to find it from encoded jpeg data: + if (resolution.isEmpty()) { + QBuffer data; + data.setData(reinterpret_cast(GST_BUFFER_DATA(buffer)), GST_BUFFER_SIZE(buffer)); + QImageReader reader(&data, "JPEG"); + resolution = reader.size(); + } + + QVideoFrame frame(videoBuffer, + resolution, + QVideoFrame::Format_Jpeg); + + QMetaObject::invokeMethod(self, "imageAvailable", + Qt::QueuedConnection, + Q_ARG(int, self->m_requestId), + Q_ARG(QVideoFrame, frame)); + } + + //drop the buffer if capture to file was disabled + return destination & QCameraImageCapture::CaptureToFile; +} + +void CameraBinImageCapture::handleBusMessage(const QGstreamerMessage &message) +{ + //Install metadata event and buffer probes + + //The image capture pipiline is built dynamically, + //it's necessary to wait until jpeg encoder is added to pipeline + + GstMessage *gm = message.rawMessage(); + if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_STATE_CHANGED) { + GstState oldState; + GstState newState; + GstState pending; + gst_message_parse_state_changed(gm, &oldState, &newState, &pending); + + if (newState == GST_STATE_READY) { + GstElement *element = GST_ELEMENT(GST_MESSAGE_SRC(gm)); + if (!element) + return; + + QString elementName = QString::fromLatin1(gst_element_get_name(element)); + if (elementName.contains("jpegenc") && element != m_jpegEncoderElement) { + m_jpegEncoderElement = element; + GstPad *sinkpad = gst_element_get_static_pad(element, "sink"); + + //metadata event probe is installed before jpeg encoder + //to emit metadata available signal as soon as possible. +#ifdef DEBUG_CAPTURE + qDebug() << "install metadata probe"; +#endif + gst_pad_add_event_probe(sinkpad, + G_CALLBACK(CameraBinImageCapture::metadataEventProbe), + this); + +#ifdef DEBUG_CAPTURE + qDebug() << "install uncompressed buffer probe"; +#endif + gst_pad_add_buffer_probe(sinkpad, + G_CALLBACK(CameraBinImageCapture::uncompressedBufferProbe), + this); + + gst_object_unref(sinkpad); + } else if ((elementName.contains("jifmux") || elementName.startsWith("metadatamux")) + && element != m_metadataMuxerElement) { + //Jpeg encoded buffer probe is added after jifmux/metadatamux + //element to ensure the resulting jpeg buffer contains capture metadata + m_metadataMuxerElement = element; + + GstPad *srcpad = gst_element_get_static_pad(element, "src"); +#ifdef DEBUG_CAPTURE + qDebug() << "install jpeg buffer probe"; +#endif + gst_pad_add_buffer_probe(srcpad, + G_CALLBACK(CameraBinImageCapture::jpegBufferProbe), + this); + gst_object_unref(srcpad); + } + } + } +} diff --git a/src/plugins/gstreamer/camerabin/camerabinimagecapture.h b/src/plugins/gstreamer/camerabin/camerabinimagecapture.h new file mode 100644 index 000000000..4aa5e998f --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinimagecapture.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef CAMERABINIMAGECAPTURECONTROL_H +#define CAMERABINIMAGECAPTURECONTROL_H + +#include +#include "camerabinsession.h" + +QT_USE_NAMESPACE + +class CameraBinImageCapture : public QCameraImageCaptureControl +{ + Q_OBJECT +public: + CameraBinImageCapture(CameraBinSession *session); + virtual ~CameraBinImageCapture(); + + QCameraImageCapture::DriveMode driveMode() const { return QCameraImageCapture::SingleImageCapture; } + void setDriveMode(QCameraImageCapture::DriveMode) {} + + bool isReadyForCapture() const; + int capture(const QString &fileName); + void cancelCapture(); + +private slots: + void updateState(); + void handleBusMessage(const QGstreamerMessage &message); + +private: + static gboolean metadataEventProbe(GstPad *pad, GstEvent *event, CameraBinImageCapture *); + static gboolean uncompressedBufferProbe(GstPad *pad, GstBuffer *buffer, CameraBinImageCapture *); + static gboolean jpegBufferProbe(GstPad *pad, GstBuffer *buffer, CameraBinImageCapture *); + static gboolean handleImageSaved(GstElement *camera, const gchar *filename, CameraBinImageCapture *); + + CameraBinSession *m_session; + bool m_ready; + int m_requestId; + GstElement *m_jpegEncoderElement; + GstElement *m_metadataMuxerElement; +}; + +#endif // CAMERABINCAPTURECORNTROL_H diff --git a/src/plugins/gstreamer/camerabin/camerabinimageencoder.cpp b/src/plugins/gstreamer/camerabin/camerabinimageencoder.cpp new file mode 100644 index 000000000..2def12666 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinimageencoder.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camerabinimageencoder.h" +#include "camerabinsession.h" + +#include + +CameraBinImageEncoder::CameraBinImageEncoder(CameraBinSession *session) + :QImageEncoderControl(session), m_session(session) +{ +} + +CameraBinImageEncoder::~CameraBinImageEncoder() +{ +} + +QList CameraBinImageEncoder::supportedResolutions(const QImageEncoderSettings &, bool *continuous) const +{ + qDebug() << "CameraBinImageEncoder::supportedResolutions()"; + if (continuous) + *continuous = false; + + return m_session->supportedResolutions(qMakePair(0,0), continuous, QCamera::CaptureStillImage); +} + +QStringList CameraBinImageEncoder::supportedImageCodecs() const +{ + return QStringList() << "jpeg"; +} + +QString CameraBinImageEncoder::imageCodecDescription(const QString &codecName) const +{ + if (codecName == "jpeg") + return tr("JPEG image"); + + return QString(); +} + +QImageEncoderSettings CameraBinImageEncoder::imageSettings() const +{ + return m_settings; +} + +void CameraBinImageEncoder::setImageSettings(const QImageEncoderSettings &settings) +{ + m_settings = settings; + emit settingsChanged(); +} diff --git a/src/plugins/gstreamer/camerabin/camerabinimageencoder.h b/src/plugins/gstreamer/camerabin/camerabinimageencoder.h new file mode 100644 index 000000000..ddb06a668 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinimageencoder.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CAMERABINIMAGEENCODE_H +#define CAMERABINIMAGEENCODE_H + +class CameraBinSession; + +#include + +#include +#include + +#include +QT_USE_NAMESPACE + +class CameraBinImageEncoder : public QImageEncoderControl +{ + Q_OBJECT +public: + CameraBinImageEncoder(CameraBinSession *session); + virtual ~CameraBinImageEncoder(); + + QList supportedResolutions(const QImageEncoderSettings &settings = QImageEncoderSettings(), + bool *continuous = 0) const; + + QStringList supportedImageCodecs() const; + QString imageCodecDescription(const QString &formatName) const; + + QImageEncoderSettings imageSettings() const; + void setImageSettings(const QImageEncoderSettings &settings); + +Q_SIGNALS: + void settingsChanged(); + +private: + QImageEncoderSettings m_settings; + + CameraBinSession *m_session; + + // Added + QStringList m_codecs; + QMap m_elementNames; + QMap m_codecDescriptions; + QMap m_codecOptions; +}; + +#endif diff --git a/src/plugins/gstreamer/camerabin/camerabinimageprocessing.cpp b/src/plugins/gstreamer/camerabin/camerabinimageprocessing.cpp new file mode 100644 index 000000000..075ff2a67 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinimageprocessing.cpp @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camerabinimageprocessing.h" +#include "camerabinsession.h" + +CameraBinImageProcessing::CameraBinImageProcessing(CameraBinSession *session) + :QCameraImageProcessingControl(session), + m_session(session) +{ + m_mappedWbValues[GST_PHOTOGRAPHY_WB_MODE_AUTO] = QCameraImageProcessing::WhiteBalanceAuto; + m_mappedWbValues[GST_PHOTOGRAPHY_WB_MODE_DAYLIGHT] = QCameraImageProcessing::WhiteBalanceSunlight; + m_mappedWbValues[GST_PHOTOGRAPHY_WB_MODE_CLOUDY] = QCameraImageProcessing::WhiteBalanceCloudy; + m_mappedWbValues[GST_PHOTOGRAPHY_WB_MODE_SUNSET] = QCameraImageProcessing::WhiteBalanceSunset; + m_mappedWbValues[GST_PHOTOGRAPHY_WB_MODE_TUNGSTEN] = QCameraImageProcessing::WhiteBalanceTungsten; + m_mappedWbValues[GST_PHOTOGRAPHY_WB_MODE_FLUORESCENT] = QCameraImageProcessing::WhiteBalanceFluorescent; + + updateColorBalanceValues(); +} + +CameraBinImageProcessing::~CameraBinImageProcessing() +{ +} + +void CameraBinImageProcessing::updateColorBalanceValues() +{ + if (!GST_IS_COLOR_BALANCE(m_session->cameraBin())) { + // Camerabin doesn't implement gstcolorbalance interface + return; + } + + GstColorBalance *balance = GST_COLOR_BALANCE(m_session->cameraBin()); + const GList *controls = gst_color_balance_list_channels(balance); + + const GList *item; + GstColorBalanceChannel *channel; + gint cur_value; + + for (item = controls; item; item = g_list_next (item)) { + channel = (GstColorBalanceChannel *)item->data; + cur_value = gst_color_balance_get_value (balance, channel); + + if (!g_ascii_strcasecmp (channel->label, "brightness")) { + m_values[QCameraImageProcessingControl::Brightness] = cur_value; + } else if (!g_ascii_strcasecmp (channel->label, "contrast")) { + m_values[QCameraImageProcessingControl::Contrast] = cur_value; + } else if (!g_ascii_strcasecmp (channel->label, "saturation")) { + m_values[QCameraImageProcessingControl::Saturation] = cur_value; + } + } +} + +bool CameraBinImageProcessing::setColorBalanceValue(const QString& channel, int value) +{ + + if (!GST_IS_COLOR_BALANCE(m_session->cameraBin())) { + // Camerabin doesn't implement gstcolorbalance interface + return false; + } + + GstColorBalance *balance = GST_COLOR_BALANCE(m_session->cameraBin()); + const GList *controls = gst_color_balance_list_channels(balance); + + const GList *item; + GstColorBalanceChannel *colorBalanceChannel; + + for (item = controls; item; item = g_list_next (item)) { + colorBalanceChannel = (GstColorBalanceChannel *)item->data; + + if (!g_ascii_strcasecmp (colorBalanceChannel->label, channel.toAscii())) { + gst_color_balance_set_value (balance, colorBalanceChannel, value); + return true; + } + } + + return false; +} + +QCameraImageProcessing::WhiteBalanceMode CameraBinImageProcessing::whiteBalanceMode() const +{ + GstWhiteBalanceMode wbMode; + gst_photography_get_white_balance_mode(m_session->photography(), &wbMode); + return m_mappedWbValues[wbMode]; +} + +void CameraBinImageProcessing::setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode) +{ + if (isWhiteBalanceModeSupported(mode)) + gst_photography_set_white_balance_mode(m_session->photography(), m_mappedWbValues.key(mode)); +} + +bool CameraBinImageProcessing::isWhiteBalanceModeSupported(QCameraImageProcessing::WhiteBalanceMode mode) const +{ + return m_mappedWbValues.values().contains(mode); +} + +bool CameraBinImageProcessing::isProcessingParameterSupported(QCameraImageProcessingControl::ProcessingParameter parameter) const +{ + return parameter == QCameraImageProcessingControl::Contrast + || parameter == QCameraImageProcessingControl::Brightness + || parameter == QCameraImageProcessingControl::Saturation; +} + +QVariant CameraBinImageProcessing::processingParameter( + QCameraImageProcessingControl::ProcessingParameter parameter) const +{ + if (m_values.contains(parameter)) + return m_values.value(parameter); + else + return QVariant(); +} + +void CameraBinImageProcessing::setProcessingParameter( + QCameraImageProcessingControl::ProcessingParameter parameter, + QVariant value) +{ + switch (parameter) { + case Contrast: + setColorBalanceValue("contrast", value.toInt()); + break; + case Brightness: + setColorBalanceValue("brightness", value.toInt()); + break; + case Saturation: + setColorBalanceValue("saturation", value.toInt()); + break; + default: + break; + } + + updateColorBalanceValues(); +} + diff --git a/src/plugins/gstreamer/camerabin/camerabinimageprocessing.h b/src/plugins/gstreamer/camerabin/camerabinimageprocessing.h new file mode 100644 index 000000000..661d0d9d4 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinimageprocessing.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CAMERABINIMAGEPROCESSINGCONTROL_H +#define CAMERABINIMAGEPROCESSINGCONTROL_H + +#include +#include + +#include +#include + +#include +#include + +class CameraBinSession; + +QT_USE_NAMESPACE + +class CameraBinImageProcessing : public QCameraImageProcessingControl +{ + Q_OBJECT + +public: + CameraBinImageProcessing(CameraBinSession *session); + virtual ~CameraBinImageProcessing(); + + QCameraImageProcessing::WhiteBalanceMode whiteBalanceMode() const; + void setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode); + bool isWhiteBalanceModeSupported(QCameraImageProcessing::WhiteBalanceMode mode) const; + + bool isProcessingParameterSupported(ProcessingParameter) const; + QVariant processingParameter(ProcessingParameter parameter) const; + void setProcessingParameter(ProcessingParameter parameter, QVariant value); + +private: + bool setColorBalanceValue(const QString& channel, int value); + void updateColorBalanceValues(); + +private: + CameraBinSession *m_session; + QMap m_values; + QMap m_mappedWbValues; +}; + +#endif // CAMERABINIMAGEPROCESSINGCONTROL_H diff --git a/src/plugins/gstreamer/camerabin/camerabinlocks.cpp b/src/plugins/gstreamer/camerabin/camerabinlocks.cpp new file mode 100644 index 000000000..66da126f8 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinlocks.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camerabinlocks.h" +#include "camerabinsession.h" +#include "camerabinfocus.h" + +#include + +#include + +CameraBinLocks::CameraBinLocks(CameraBinSession *session) + :QCameraLocksControl(session), + m_session(session), + m_focus(m_session->cameraFocusControl()) +{ + connect(m_focus, SIGNAL(_q_focusStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason)), + this, SLOT(updateFocusStatus(QCamera::LockStatus, QCamera::LockChangeReason))); +} + +CameraBinLocks::~CameraBinLocks() +{ +} + +QCamera::LockTypes CameraBinLocks::supportedLocks() const +{ + return QCamera::LockFocus; +} + +QCamera::LockStatus CameraBinLocks::lockStatus(QCamera::LockType lock) const +{ + return lock == QCamera::LockFocus ? m_focus->focusStatus() : QCamera::Unlocked; +} + +void CameraBinLocks::searchAndLock(QCamera::LockTypes locks) +{ + if (locks & QCamera::LockFocus) + m_focus->_q_startFocusing(); +} + +void CameraBinLocks::unlock(QCamera::LockTypes locks) +{ + if (locks & QCamera::LockFocus) + m_focus->_q_stopFocusing(); +} + +void CameraBinLocks::updateFocusStatus(QCamera::LockStatus status, QCamera::LockChangeReason reason) +{ + emit lockStatusChanged(QCamera::LockFocus, status, reason); +} diff --git a/src/plugins/gstreamer/camerabin/camerabinlocks.h b/src/plugins/gstreamer/camerabin/camerabinlocks.h new file mode 100644 index 000000000..29c4f2ece --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinlocks.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CAMERABINLOCKSCONTROL_H +#define CAMERABINLOCKSCONTROL_H + +#include +#include + +#include +#include + +class CameraBinSession; +class CameraBinFocus; + +QT_USE_NAMESPACE + +class CameraBinLocks : public QCameraLocksControl +{ + Q_OBJECT + +public: + CameraBinLocks(CameraBinSession *session); + virtual ~CameraBinLocks(); + + QCamera::LockTypes supportedLocks() const; + + QCamera::LockStatus lockStatus(QCamera::LockType lock) const; + + void searchAndLock(QCamera::LockTypes locks); + void unlock(QCamera::LockTypes locks); + +private slots: + void updateFocusStatus(QCamera::LockStatus status, QCamera::LockChangeReason reason); + +private: + CameraBinSession *m_session; + CameraBinFocus *m_focus; +}; + +#endif diff --git a/src/plugins/gstreamer/camerabin/camerabinmetadata.cpp b/src/plugins/gstreamer/camerabin/camerabinmetadata.cpp new file mode 100644 index 000000000..d7036ebc2 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinmetadata.cpp @@ -0,0 +1,198 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camerabinmetadata.h" + +#include +#include + +struct QGstreamerMetaDataKeyLookup +{ + QtMultimediaKit::MetaData key; + const char *token; +}; + +static const QGstreamerMetaDataKeyLookup qt_gstreamerMetaDataKeys[] = +{ + { QtMultimediaKit::Title, GST_TAG_TITLE }, + //{ QtMultimediaKit::SubTitle, 0 }, + //{ QtMultimediaKit::Author, 0 }, + { QtMultimediaKit::Comment, GST_TAG_COMMENT }, + { QtMultimediaKit::Description, GST_TAG_DESCRIPTION }, + //{ QtMultimediaKit::Category, 0 }, + { QtMultimediaKit::Genre, GST_TAG_GENRE }, + //{ QtMultimediaKit::Year, 0 }, + //{ QtMultimediaKit::UserRating, 0 }, + + { QtMultimediaKit::Language, GST_TAG_LANGUAGE_CODE }, + + { QtMultimediaKit::Publisher, GST_TAG_ORGANIZATION }, + { QtMultimediaKit::Copyright, GST_TAG_COPYRIGHT }, + //{ QtMultimediaKit::ParentalRating, 0 }, + //{ QtMultimediaKit::RatingOrganisation, 0 }, + + // Media + //{ QtMultimediaKit::Size, 0 }, + //{ QtMultimediaKit::MediaType, 0 }, + { QtMultimediaKit::Duration, GST_TAG_DURATION }, + + // Audio + { QtMultimediaKit::AudioBitRate, GST_TAG_BITRATE }, + { QtMultimediaKit::AudioCodec, GST_TAG_AUDIO_CODEC }, + //{ QtMultimediaKit::ChannelCount, 0 }, + //{ QtMultimediaKit::SampleRate, 0 }, + + // Music + { QtMultimediaKit::AlbumTitle, GST_TAG_ALBUM }, + { QtMultimediaKit::AlbumArtist, GST_TAG_ARTIST}, + { QtMultimediaKit::ContributingArtist, GST_TAG_PERFORMER }, +#if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 19) + { QtMultimediaKit::Composer, GST_TAG_COMPOSER }, +#endif + //{ QtMultimediaKit::Conductor, 0 }, + //{ QtMultimediaKit::Lyrics, 0 }, + //{ QtMultimediaKit::Mood, 0 }, + { QtMultimediaKit::TrackNumber, GST_TAG_TRACK_NUMBER }, + + //{ QtMultimediaKit::CoverArtUrlSmall, 0 }, + //{ QtMultimediaKit::CoverArtUrlLarge, 0 }, + + // Image/Video + //{ QtMultimediaKit::Resolution, 0 }, + //{ QtMultimediaKit::PixelAspectRatio, 0 }, + + // Video + //{ QtMultimediaKit::VideoFrameRate, 0 }, + //{ QtMultimediaKit::VideoBitRate, 0 }, + { QtMultimediaKit::VideoCodec, GST_TAG_VIDEO_CODEC }, + + //{ QtMultimediaKit::PosterUrl, 0 }, + + // Movie + //{ QtMultimediaKit::ChapterNumber, 0 }, + //{ QtMultimediaKit::Director, 0 }, + { QtMultimediaKit::LeadPerformer, GST_TAG_PERFORMER }, + //{ QtMultimediaKit::Writer, 0 }, + + // Photos + //{ QtMultimediaKit::CameraManufacturer, 0 }, + //{ QtMultimediaKit::CameraModel, 0 }, + //{ QtMultimediaKit::Event, 0 }, + //{ QtMultimediaKit::Subject, 0 } +}; + +CameraBinMetaData::CameraBinMetaData(QObject *parent) + :QMetaDataWriterControl(parent) +{ +} + +QVariant CameraBinMetaData::metaData(QtMultimediaKit::MetaData key) const +{ + static const int count = sizeof(qt_gstreamerMetaDataKeys) / sizeof(QGstreamerMetaDataKeyLookup); + + for (int i = 0; i < count; ++i) { + if (qt_gstreamerMetaDataKeys[i].key == key) { + const char *name = qt_gstreamerMetaDataKeys[i].token; + + return m_values.value(QByteArray::fromRawData(name, qstrlen(name))); + } + } + return QVariant(); +} + +void CameraBinMetaData::setMetaData(QtMultimediaKit::MetaData key, const QVariant &value) +{ + static const int count = sizeof(qt_gstreamerMetaDataKeys) / sizeof(QGstreamerMetaDataKeyLookup); + + for (int i = 0; i < count; ++i) { + if (qt_gstreamerMetaDataKeys[i].key == key) { + const char *name = qt_gstreamerMetaDataKeys[i].token; + + m_values.insert(QByteArray::fromRawData(name, qstrlen(name)), value); + + emit QMetaDataWriterControl::metaDataChanged(); + emit metaDataChanged(m_values); + + return; + } + } +} + +QList CameraBinMetaData::availableMetaData() const +{ + static QMap keysMap; + if (keysMap.isEmpty()) { + const int count = sizeof(qt_gstreamerMetaDataKeys) / sizeof(QGstreamerMetaDataKeyLookup); + for (int i = 0; i < count; ++i) { + keysMap[QByteArray(qt_gstreamerMetaDataKeys[i].token)] = qt_gstreamerMetaDataKeys[i].key; + } + } + + QList res; + foreach (const QByteArray &key, m_values.keys()) { + QtMultimediaKit::MetaData tag = keysMap.value(key, QtMultimediaKit::MetaData(-1)); + if (tag != -1) + res.append(tag); + } + + return res; +} + +QVariant CameraBinMetaData::extendedMetaData(QString const &name) const +{ + return m_values.value(name.toLatin1()); +} + +void CameraBinMetaData::setExtendedMetaData(QString const &name, QVariant const &value) +{ + m_values.insert(name.toLatin1(), value); + emit QMetaDataWriterControl::metaDataChanged(); + emit metaDataChanged(m_values); +} + +QStringList CameraBinMetaData::availableExtendedMetaData() const +{ + QStringList res; + foreach (const QByteArray &key, m_values.keys()) + res.append(QString(key)); + + return res; +} diff --git a/src/plugins/gstreamer/camerabin/camerabinmetadata.h b/src/plugins/gstreamer/camerabin/camerabinmetadata.h new file mode 100644 index 000000000..be00da839 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinmetadata.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CAMERABINCAPTUREMETADATACONTROL_H +#define CAMERABINCAPTUREMETADATACONTROL_H + +#include + +QT_USE_NAMESPACE + +class CameraBinMetaData : public QMetaDataWriterControl +{ + Q_OBJECT +public: + CameraBinMetaData(QObject *parent); + virtual ~CameraBinMetaData() {} + + + bool isMetaDataAvailable() const { return true; } + bool isWritable() const { return true; } + + QVariant metaData(QtMultimediaKit::MetaData key) const; + void setMetaData(QtMultimediaKit::MetaData key, const QVariant &value); + QList availableMetaData() const; + + QVariant extendedMetaData(QString const &name) const; + void setExtendedMetaData(QString const &name, QVariant const &value); + QStringList availableExtendedMetaData() const; + +Q_SIGNALS: + void metaDataChanged(const QMap&); + +private: + QMap m_values; +}; + +#endif // CAMERABINCAPTUREMETADATACONTROL_H diff --git a/src/plugins/gstreamer/camerabin/camerabinrecorder.cpp b/src/plugins/gstreamer/camerabin/camerabinrecorder.cpp new file mode 100644 index 000000000..0cd8a5aaf --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinrecorder.cpp @@ -0,0 +1,225 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camerabinrecorder.h" +#include "camerabinaudioencoder.h" +#include "camerabinvideoencoder.h" +#include "camerabincontainer.h" +#include + +CameraBinRecorder::CameraBinRecorder(CameraBinSession *session) + :QMediaRecorderControl(session), + m_session(session), + m_state(QMediaRecorder::StoppedState) +{ + connect(m_session, SIGNAL(stateChanged(QCamera::State)), SLOT(updateState())); + connect(m_session, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged(qint64))); + connect(m_session, SIGNAL(mutedChanged(bool)), this, SIGNAL(mutedChanged(bool))); +} + +CameraBinRecorder::~CameraBinRecorder() +{ +} + +QUrl CameraBinRecorder::outputLocation() const +{ + return m_session->outputLocation(); +} + +bool CameraBinRecorder::setOutputLocation(const QUrl &sink) +{ + m_session->setOutputLocation(sink); + return true; +} + +QMediaRecorder::State CameraBinRecorder::state() const +{ + return m_state; +} + +void CameraBinRecorder::updateState() +{ + if (m_session->state() != QCamera::ActiveState && + m_state != QMediaRecorder::StoppedState) { + m_session->stopVideoRecording(); + emit stateChanged(m_state = QMediaRecorder::StoppedState); + } +} + +qint64 CameraBinRecorder::duration() const +{ + return m_session->duration(); +} + +void CameraBinRecorder::record() +{ + if (m_session->state() == QCamera::ActiveState) { + if (m_state == QMediaRecorder::PausedState) + m_session->resumeVideoRecording(); + else + m_session->recordVideo(); + emit stateChanged(m_state = QMediaRecorder::RecordingState); + } else + emit error(QMediaRecorder::ResourceError, tr("Service has not been started")); +} + +void CameraBinRecorder::pause() +{ + if (m_session->state() == QCamera::ActiveState) { + m_session->pauseVideoRecording(); + emit stateChanged(m_state = QMediaRecorder::PausedState); + } else + emit error(QMediaRecorder::ResourceError, tr("Service has not been started")); +} + +void CameraBinRecorder::stop() +{ + if (m_session->state() == QCamera::ActiveState) { + m_session->stopVideoRecording(); + emit stateChanged(m_state = QMediaRecorder::StoppedState); + } +} + +bool CameraBinRecorder::findCodecs() +{ + //Check the codecs are compatible with container, + //and choose the compatible codecs/container if omitted + CameraBinAudioEncoder *audioEncodeControl = m_session->audioEncodeControl(); + CameraBinVideoEncoder *videoEncodeControl = m_session->videoEncodeControl(); + CameraBinContainer *mediaContainerControl = m_session->mediaContainerControl(); + + audioEncodeControl->resetActualSettings(); + videoEncodeControl->resetActualSettings(); + mediaContainerControl->resetActualContainer(); + + QStringList containerCandidates; + if (mediaContainerControl->containerMimeType().isEmpty()) + containerCandidates = mediaContainerControl->supportedContainers(); + else + containerCandidates << mediaContainerControl->containerMimeType(); + + + QStringList audioCandidates; + QAudioEncoderSettings audioSettings = audioEncodeControl->audioSettings(); + if (audioSettings.codec().isEmpty()) + audioCandidates = audioEncodeControl->supportedAudioCodecs(); + else + audioCandidates << audioSettings.codec(); + + QStringList videoCandidates; + QVideoEncoderSettings videoSettings = videoEncodeControl->videoSettings(); + if (videoSettings.codec().isEmpty()) + videoCandidates = videoEncodeControl->supportedVideoCodecs(); + else + videoCandidates << videoSettings.codec(); + + QString container; + QString audioCodec; + QString videoCodec; + + foreach (const QString &containerCandidate, containerCandidates) { + QSet supportedTypes = mediaContainerControl->supportedStreamTypes(containerCandidate); + + audioCodec.clear(); + videoCodec.clear(); + + bool found = false; + foreach (const QString &audioCandidate, audioCandidates) { + QSet audioTypes = audioEncodeControl->supportedStreamTypes(audioCandidate); + if (!audioTypes.intersect(supportedTypes).isEmpty()) { + found = true; + audioCodec = audioCandidate; + break; + } + } + if (!found) + continue; + + found = false; + foreach (const QString &videoCandidate, videoCandidates) { + QSet videoTypes = videoEncodeControl->supportedStreamTypes(videoCandidate); + if (!videoTypes.intersect(supportedTypes).isEmpty()) { + found = true; + videoCodec = videoCandidate; + break; + } + } + if (!found) + continue; + + + container = containerCandidate; + break; + } + + if (container.isEmpty()) { + qWarning() << "Camera error: Not compatible codecs and container format."; + emit error(QMediaRecorder::FormatError, tr("Not compatible codecs and container format.")); + return false; + } else { + mediaContainerControl->setActualContainer(container); + + QAudioEncoderSettings audioSettings = audioEncodeControl->audioSettings(); + audioSettings.setCodec(audioCodec); + audioEncodeControl->setActualAudioSettings(audioSettings); + + QVideoEncoderSettings videoSettings = videoEncodeControl->videoSettings(); + videoSettings.setCodec(videoCodec); + videoEncodeControl->setActualVideoSettings(videoSettings); + } + + return true; +} + +void CameraBinRecorder::applySettings() +{ + findCodecs(); +} + +bool CameraBinRecorder::isMuted() const +{ + return m_session->isMuted(); +} + +void CameraBinRecorder::setMuted(bool muted) +{ + m_session->setMuted(muted); +} diff --git a/src/plugins/gstreamer/camerabin/camerabinrecorder.h b/src/plugins/gstreamer/camerabin/camerabinrecorder.h new file mode 100644 index 000000000..a6faf9b64 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinrecorder.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef CAMERABINRECORDERCONTROL_H +#define CAMERABINRECORDERCONTROL_H + +#include +#include "camerabinsession.h" +QT_USE_NAMESPACE + +class CameraBinRecorder : public QMediaRecorderControl +{ + Q_OBJECT + +public: + CameraBinRecorder(CameraBinSession *session); + virtual ~CameraBinRecorder(); + + QUrl outputLocation() const; + bool setOutputLocation(const QUrl &sink); + + QMediaRecorder::State state() const; + + qint64 duration() const; + + bool isMuted() const; + + bool findCodecs(); + + void applySettings(); + +public slots: + void record(); + void pause(); + void stop(); + void setMuted(bool); + +private slots: + void updateState(); + +private: + CameraBinSession *m_session; + QMediaRecorder::State m_state; +}; + +#endif // CAMERABINCAPTURECORNTROL_H diff --git a/src/plugins/gstreamer/camerabin/camerabinresourcepolicy.cpp b/src/plugins/gstreamer/camerabin/camerabinresourcepolicy.cpp new file mode 100644 index 000000000..db9218c4a --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinresourcepolicy.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camerabinresourcepolicy.h" + +#ifdef Q_WS_MAEMO_6 +#define HAVE_RESOURCE_POLICY +#endif + +//#define DEBUG_RESOURCE_POLICY +#include +#include + +#ifdef HAVE_RESOURCE_POLICY +#include +#include +#include +#endif + +CamerabinResourcePolicy::CamerabinResourcePolicy(QObject *parent) : + QObject(parent), + m_resourceSet(NoResources), + m_releasingResources(false) +{ +#ifdef HAVE_RESOURCE_POLICY + //loaded resource set is also kept requested for image and video capture sets + m_resource = new ResourcePolicy::ResourceSet("camera"); + m_resource->setAlwaysReply(); + m_resource->initAndConnect(); + + connect(m_resource, SIGNAL(resourcesGranted(const QList)), + SIGNAL(resourcesGranted())); + connect(m_resource, SIGNAL(resourcesDenied()), SIGNAL(resourcesDenied())); + connect(m_resource, SIGNAL(lostResources()), SIGNAL(resourcesLost())); + connect(m_resource, SIGNAL(resourcesReleased()), SLOT(handleResourcesReleased())); +#endif +} + +CamerabinResourcePolicy::~CamerabinResourcePolicy() +{ +#ifdef HAVE_RESOURCE_POLICY + //ensure the resources are released + if (m_resourceSet != NoResources) + setResourceSet(NoResources); + + //don't delete the resource set until resources are released + if (m_releasingResources) { + m_resource->connect(m_resource, SIGNAL(resourcesReleased()), + SLOT(deleteLater())); + } else { + delete m_resource; + m_resource = 0; + } +#endif +} + +CamerabinResourcePolicy::ResourceSet CamerabinResourcePolicy::resourceSet() const +{ + return m_resourceSet; +} + +void CamerabinResourcePolicy::setResourceSet(CamerabinResourcePolicy::ResourceSet set) +{ + CamerabinResourcePolicy::ResourceSet oldSet = m_resourceSet; + m_resourceSet = set; + +#ifdef DEBUG_RESOURCE_POLICY + qDebug() << Q_FUNC_INFO << set; +#endif + +#ifdef HAVE_RESOURCE_POLICY + QSet requestedTypes; + + switch (set) { + case NoResources: + break; + case LoadedResources: + requestedTypes << ResourcePolicy::LensCoverType //to detect lens cover is opened/closed + << ResourcePolicy::VideoRecorderType //to open camera device + << ResourcePolicy::SnapButtonType; //to detect capture button events + break; + case ImageCaptureResources: + requestedTypes << ResourcePolicy::LensCoverType + << ResourcePolicy::VideoPlaybackType + << ResourcePolicy::VideoRecorderType + << ResourcePolicy::AudioPlaybackType + << ResourcePolicy::ScaleButtonType + << ResourcePolicy::LedsType + << ResourcePolicy::SnapButtonType; + break; + case VideoCaptureResources: + requestedTypes << ResourcePolicy::LensCoverType + << ResourcePolicy::VideoPlaybackType + << ResourcePolicy::VideoRecorderType + << ResourcePolicy::AudioPlaybackType + << ResourcePolicy::AudioRecorderType + << ResourcePolicy::ScaleButtonType + << ResourcePolicy::LedsType + << ResourcePolicy::SnapButtonType; + break; + } + + QSet currentTypes; + foreach (ResourcePolicy::Resource *resource, m_resource->resources()) + currentTypes << resource->type(); + + foreach (ResourcePolicy::ResourceType resourceType, currentTypes - requestedTypes) + m_resource->deleteResource(resourceType); + + foreach (ResourcePolicy::ResourceType resourceType, requestedTypes - currentTypes) { + if (resourceType == ResourcePolicy::LensCoverType) { + ResourcePolicy::LensCoverResource *lensCoverResource = new ResourcePolicy::LensCoverResource; + lensCoverResource->setOptional(true); + m_resource->addResourceObject(lensCoverResource); + } else { + m_resource->addResource(resourceType); + } + } + + m_resource->update(); + if (set != NoResources) { + m_resource->acquire(); + } else { + if (oldSet != NoResources) { + m_releasingResources = true; + m_resource->release(); + } + } +#endif +} + +bool CamerabinResourcePolicy::isResourcesGranted() const +{ +#ifdef HAVE_RESOURCE_POLICY + foreach (ResourcePolicy::Resource *resource, m_resource->resources()) + if (!resource->isOptional() && !resource->isGranted()) + return false; +#endif + return true; +} + +void CamerabinResourcePolicy::handleResourcesReleased() +{ +#ifdef HAVE_RESOURCE_POLICY +#ifdef DEBUG_RESOURCE_POLICY + qDebug() << Q_FUNC_INFO; +#endif + m_releasingResources = false; +#endif +} diff --git a/src/plugins/gstreamer/camerabin/camerabinresourcepolicy.h b/src/plugins/gstreamer/camerabin/camerabinresourcepolicy.h new file mode 100644 index 000000000..cd2d84688 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinresourcepolicy.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CAMERARESOURCEPOLICY_H +#define CAMERARESOURCEPOLICY_H + +#include + +namespace ResourcePolicy { +class ResourceSet; +}; + +class CamerabinResourcePolicy : public QObject +{ + Q_OBJECT +public: + enum ResourceSet { + NoResources, + LoadedResources, + ImageCaptureResources, + VideoCaptureResources + }; + + CamerabinResourcePolicy(QObject *parent); + ~CamerabinResourcePolicy(); + + ResourceSet resourceSet() const; + void setResourceSet(ResourceSet set); + + bool isResourcesGranted() const; + +Q_SIGNALS: + void resourcesDenied(); + void resourcesGranted(); + void resourcesLost(); + +private Q_SLOTS: + void handleResourcesReleased(); + +private: + ResourceSet m_resourceSet; + ResourcePolicy::ResourceSet *m_resource; + bool m_releasingResources; +}; + +#endif diff --git a/src/plugins/gstreamer/camerabin/camerabinservice.cpp b/src/plugins/gstreamer/camerabin/camerabinservice.cpp new file mode 100644 index 000000000..261a9c308 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinservice.cpp @@ -0,0 +1,261 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camerabinservice.h" +#include "camerabinsession.h" +#include "camerabinrecorder.h" +#include "camerabincontainer.h" +#include "camerabinaudioencoder.h" +#include "camerabinvideoencoder.h" +#include "camerabinimageencoder.h" +#include "qgstreamerbushelper.h" +#include "camerabincontrol.h" +#include "camerabinlocks.h" +#include "camerabinmetadata.h" +#include "camerabinexposure.h" +#include "camerabinflash.h" +#include "camerabinfocus.h" +#include "camerabinimagecapture.h" +#include "camerabinimageprocessing.h" +#include "camerabincapturebufferformat.h" +#include "camerabincapturedestination.h" + +#include "qgstreameraudioinputendpointselector.h" +#include "qgstreamervideoinputdevicecontrol.h" + +#include "qgstreamervideooverlay.h" +#include "qgstreamervideowindow.h" +#include "qgstreamervideorenderer.h" + +#if defined(Q_WS_MAEMO_6) && defined(__arm__) +#include "qgstreamergltexturerenderer.h" +#endif + +#include "qgstreamervideowidget.h" + +#include + +#include +#include + +#if defined(Q_WS_MAEMO_5) +#include "camerabuttonlistener_maemo.h" +#endif + +#if defined(Q_WS_MAEMO_6) +#include "camerabuttonlistener_meego.h" +#endif + +CameraBinService::CameraBinService(const QString &service, QObject *parent): + QMediaService(parent) +{ + m_captureSession = 0; + m_cameraControl = 0; + m_metaDataControl = 0; + + m_audioInputEndpointSelector = 0; + m_videoInputDevice = 0; + + m_videoOutput = 0; + m_videoRenderer = 0; + m_videoWindow = 0; + m_videoWidgetControl = 0; + m_imageCaptureControl = 0; + + if (service == Q_MEDIASERVICE_CAMERA) { + m_captureSession = new CameraBinSession(this); + m_cameraControl = new CameraBinControl(m_captureSession); + m_videoInputDevice = new QGstreamerVideoInputDeviceControl(m_captureSession); + m_imageCaptureControl = new CameraBinImageCapture(m_captureSession); + + connect(m_videoInputDevice, SIGNAL(selectedDeviceChanged(QString)), + m_captureSession, SLOT(setDevice(QString))); + + if (m_videoInputDevice->deviceCount()) + m_captureSession->setDevice(m_videoInputDevice->deviceName(m_videoInputDevice->selectedDevice())); + +#if defined(Q_WS_MAEMO_6) && defined(__arm__) + m_videoRenderer = new QGstreamerGLTextureRenderer(this); +#else + m_videoRenderer = new QGstreamerVideoRenderer(this); +#endif + + +#ifdef Q_WS_MAEMO_6 + m_videoWindow = new QGstreamerVideoWindow(this, "omapxvsink"); + //m_videoWindow = new QGstreamerVideoWindow(this); +#else + m_videoWindow = new QGstreamerVideoOverlay(this); +#endif + + m_videoWidgetControl = new QGstreamerVideoWidgetControl(this); + + } + + if (!m_captureSession) { + qWarning() << Q_FUNC_INFO << "Service type is not supported:" << service; + return; + } + + m_audioInputEndpointSelector = new QGstreamerAudioInputEndpointSelector(this); + connect(m_audioInputEndpointSelector, SIGNAL(activeEndpointChanged(QString)), m_captureSession, SLOT(setCaptureDevice(QString))); + + if (m_captureSession && m_audioInputEndpointSelector->availableEndpoints().size() > 0) + m_captureSession->setCaptureDevice(m_audioInputEndpointSelector->defaultEndpoint()); + + m_metaDataControl = new CameraBinMetaData(this); + connect(m_metaDataControl, SIGNAL(metaDataChanged(QMap)), + m_captureSession, SLOT(setMetaData(QMap))); + +#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) + new CameraButtonListener(this); +#endif + +#if defined(Q_WS_MAEMO_5) + //disable the system camera application + QProcess::execute("/usr/sbin/dsmetool -k /usr/bin/camera-ui"); +#endif +} + +CameraBinService::~CameraBinService() +{ +#if defined(Q_WS_MAEMO_5) + //restore the system camera application + QProcess::execute("/usr/sbin/dsmetool -U user -o /usr/bin/camera-ui"); +#endif +} + +QMediaControl *CameraBinService::requestControl(const char *name) +{ + if (!m_captureSession) + return 0; + + //qDebug() << "Request control" << name; + + if (!m_videoOutput) { + if (qstrcmp(name, QVideoRendererControl_iid) == 0) { + m_videoOutput = m_videoRenderer; + m_captureSession->setViewfinder(m_videoRenderer); + } else if (qstrcmp(name, QVideoWindowControl_iid) == 0) { + m_videoOutput = m_videoWindow; + m_captureSession->setViewfinder(m_videoWindow); + } else if (qstrcmp(name, QVideoWidgetControl_iid) == 0) { + m_captureSession->setViewfinder(m_videoWidgetControl); + m_videoOutput = m_videoWidgetControl; + } + + if (m_videoOutput) + return m_videoOutput; + } + + if (qstrcmp(name,QAudioEndpointSelector_iid) == 0) + return m_audioInputEndpointSelector; + + if (qstrcmp(name,QVideoDeviceControl_iid) == 0) + return m_videoInputDevice; + + if (qstrcmp(name,QMediaRecorderControl_iid) == 0) + return m_captureSession->recorderControl(); + + if (qstrcmp(name,QAudioEncoderControl_iid) == 0) + return m_captureSession->audioEncodeControl(); + + if (qstrcmp(name,QVideoEncoderControl_iid) == 0) + return m_captureSession->videoEncodeControl(); + + if (qstrcmp(name,QImageEncoderControl_iid) == 0) + return m_captureSession->imageEncodeControl(); + + + if (qstrcmp(name,QMediaContainerControl_iid) == 0) + return m_captureSession->mediaContainerControl(); + + if (qstrcmp(name,QCameraControl_iid) == 0) + return m_cameraControl; + + if (qstrcmp(name,QMetaDataWriterControl_iid) == 0) + return m_metaDataControl; + + if (qstrcmp(name, QCameraImageCaptureControl_iid) == 0) + return m_imageCaptureControl; + + if (qstrcmp(name, QCameraExposureControl_iid) == 0) + return m_captureSession->cameraExposureControl(); + + if (qstrcmp(name, QCameraFlashControl_iid) == 0) + return m_captureSession->cameraFlashControl(); + + if (qstrcmp(name, QCameraFocusControl_iid) == 0) + return m_captureSession->cameraFocusControl(); + + if (qstrcmp(name, QCameraImageProcessingControl_iid) == 0) + return m_captureSession->imageProcessingControl(); + + if (qstrcmp(name, QCameraLocksControl_iid) == 0) + return m_captureSession->cameraLocksControl(); + + if (qstrcmp(name, QCameraCaptureDestinationControl_iid) == 0) + return m_captureSession->captureDestinationControl(); + + if (qstrcmp(name, QCameraCaptureBufferFormatControl_iid) == 0) + return m_captureSession->captureBufferFormatControl(); + + return 0; +} + +void CameraBinService::releaseControl(QMediaControl *control) +{ + if (control && control == m_videoOutput) { + m_videoOutput = 0; + m_captureSession->setViewfinder(0); + } +} + +bool CameraBinService::isCameraBinAvailable() +{ + GstElementFactory *factory = gst_element_factory_find("camerabin"); + if (factory) { + gst_object_unref(GST_OBJECT(factory)); + return true; + } + + return false; +} diff --git a/src/plugins/gstreamer/camerabin/camerabinservice.h b/src/plugins/gstreamer/camerabin/camerabinservice.h new file mode 100644 index 000000000..11c5aeadf --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinservice.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CAMERABINCAPTURESERVICE_H +#define CAMERABINCAPTURESERVICE_H + +#include + +#include +QT_BEGIN_NAMESPACE +class QAudioEndpointSelector; +class QVideoDeviceControl; +QT_END_NAMESPACE + +class CameraBinSession; +class CameraBinControl; +class QGstreamerMessage; +class QGstreamerBusHelper; +class QGstreamerVideoRenderer; +class QGstreamerVideoOverlay; +class QGstreamerVideoWidgetControl; +class QGstreamerElementFactory; +class CameraBinMetaData; +class CameraBinImageCapture; +class CameraBinMetaData; + +class CameraBinService : public QMediaService +{ + Q_OBJECT + +public: + CameraBinService(const QString &service, QObject *parent = 0); + virtual ~CameraBinService(); + + QMediaControl *requestControl(const char *name); + void releaseControl(QMediaControl *); + + static bool isCameraBinAvailable(); + +private: + void setAudioPreview(GstElement*); + + CameraBinSession *m_captureSession; + CameraBinControl *m_cameraControl; + CameraBinMetaData *m_metaDataControl; + + QAudioEndpointSelector *m_audioInputEndpointSelector; + QVideoDeviceControl *m_videoInputDevice; + + QMediaControl *m_videoOutput; + + QMediaControl *m_videoRenderer; + QMediaControl *m_videoWindow; + QGstreamerVideoWidgetControl *m_videoWidgetControl; + CameraBinImageCapture *m_imageCaptureControl; +}; + +#endif // CAMERABINCAPTURESERVICE_H diff --git a/src/plugins/gstreamer/camerabin/camerabinsession.cpp b/src/plugins/gstreamer/camerabin/camerabinsession.cpp new file mode 100644 index 000000000..e84a5af24 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinsession.cpp @@ -0,0 +1,1267 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "camerabinsession.h" +#include "camerabinrecorder.h" +#include "camerabincontainer.h" +#include "camerabinaudioencoder.h" +#include "camerabinvideoencoder.h" +#include "camerabinimageencoder.h" +#include "camerabinexposure.h" +#include "camerabinflash.h" +#include "camerabinfocus.h" +#include "camerabinimageprocessing.h" +#include "camerabinlocks.h" +#include "camerabincapturedestination.h" +#include "camerabincapturebufferformat.h" +#include "qgstreamerbushelper.h" +#include "qgstreamervideorendererinterface.h" +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +//#define CAMERABIN_DEBUG 1 +#define ENUM_NAME(c,e,v) (c::staticMetaObject.enumerator(c::staticMetaObject.indexOfEnumerator(e)).valueToKey((v))) + +#ifdef Q_WS_MAEMO_5 +#define FILENAME_PROPERTY "filename" +#define MODE_PROPERTY "mode" +#define MUTE_PROPERTY "mute" +#define ZOOM_PROPERTY "zoom" +#define IMAGE_PP_PROPERTY "imagepp" +#define IMAGE_ENCODER_PROPERTY "imageenc" +#define VIDEO_PP_PROPERTY "videopp" +#define VIDEO_ENCODER_PROPERTY "videoenc" +#define AUDIO_ENCODER_PROPERTY "audioenc" +#define VIDEO_MUXER_PROPERTY "videomux" +#define VIEWFINDER_SINK_PROPERTY "vfsink" +#define VIDEO_SOURCE_PROPERTY "videosrc" +#define AUDIO_SOURCE_PROPERTY "audiosrc" +#define VIDEO_SOURCE_CAPS_PROPERTY "inputcaps" +#define FILTER_CAPS_PROPERTY "filter-caps" +#define PREVIEW_CAPS_PROPERTY "preview-caps" + +#define IMAGE_DONE_SIGNAL "img-done" +#define CAPTURE_START "user-start" +#define CAPTURE_STOP "user-stop" +#define CAPTURE_PAUSE "user-pause" +#define SET_VIDEO_RESOLUTION_FPS "user-res-fps" +#define SET_IMAGE_RESOLUTION "user-image-res" + +#else + +#define FILENAME_PROPERTY "filename" +#define MODE_PROPERTY "mode" +#define MUTE_PROPERTY "mute" +#define ZOOM_PROPERTY "zoom" +#define IMAGE_PP_PROPERTY "image-post-processing" +#define IMAGE_ENCODER_PROPERTY "image-encoder" +#define VIDEO_PP_PROPERTY "video-post-processing" +#define VIDEO_ENCODER_PROPERTY "video-encoder" +#define AUDIO_ENCODER_PROPERTY "audio-encoder" +#define VIDEO_MUXER_PROPERTY "video-muxer" +#define VIEWFINDER_SINK_PROPERTY "viewfinder-sink" +#define VIDEO_SOURCE_PROPERTY "video-source" +#define AUDIO_SOURCE_PROPERTY "audio-source" +#define VIDEO_SOURCE_CAPS_PROPERTY "video-source-caps" +#define FILTER_CAPS_PROPERTY "filter-caps" +#define PREVIEW_CAPS_PROPERTY "preview-caps" + +#define IMAGE_DONE_SIGNAL "image-done" +#define CAPTURE_START "capture-start" +#define CAPTURE_STOP "capture-stop" +#define CAPTURE_PAUSE "capture-pause" +#define SET_VIDEO_RESOLUTION_FPS "set-video-resolution-fps" +#define SET_IMAGE_RESOLUTION "set-image-resolution" +#endif + +#define CAMERABIN_IMAGE_MODE 0 +#define CAMERABIN_VIDEO_MODE 1 + +#define gstRef(element) { gst_object_ref(GST_OBJECT(element)); gst_object_sink(GST_OBJECT(element)); } +#define gstUnref(element) { if (element) { gst_object_unref(GST_OBJECT(element)); element = 0; } } + +#define PREVIEW_CAPS_4_3 \ + "video/x-raw-rgb, width = (int) 640, height = (int) 480" + +#define VIEWFINDER_RESOLUTION_4x3 QSize(640, 480) +#define VIEWFINDER_RESOLUTION_3x2 QSize(720, 480) +#define VIEWFINDER_RESOLUTION_16x9 QSize(800, 450) + +//using GST_STATE_READY for QCamera::LoadedState +//doesn't work reliably at least with some webcams. +#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) +#define USE_READY_STATE_ON_LOADED +#endif + +CameraBinSession::CameraBinSession(QObject *parent) + :QObject(parent), + m_state(QCamera::UnloadedState), + m_pendingState(QCamera::UnloadedState), + m_recordingActive(false), + m_pendingResolutionUpdate(false), + m_muted(false), + m_busy(false), + m_captureMode(QCamera::CaptureStillImage), + m_audioInputFactory(0), + m_videoInputFactory(0), + m_viewfinder(0), + m_viewfinderInterface(0), + m_pipeline(0), + m_videoSrc(0), + m_viewfinderElement(0), + m_viewfinderHasChanged(true), + m_videoInputHasChanged(true), + m_sourceCaps(0), + m_audioSrc(0), + m_audioConvert(0), + m_capsFilter(0), + m_fileSink(0), + m_audioEncoder(0), + m_muxer(0) +{ + m_pipeline = gst_element_factory_make("camerabin", "camerabin"); + g_signal_connect(G_OBJECT(m_pipeline), "notify::idle", G_CALLBACK(updateBusyStatus), this); + + gstRef(m_pipeline); + + m_bus = gst_element_get_bus(m_pipeline); + + m_busHelper = new QGstreamerBusHelper(m_bus, this); + m_busHelper->installSyncEventFilter(this); + connect(m_busHelper, SIGNAL(message(QGstreamerMessage)), SLOT(handleBusMessage(QGstreamerMessage))); + m_audioEncodeControl = new CameraBinAudioEncoder(this); + m_videoEncodeControl = new CameraBinVideoEncoder(this); + m_imageEncodeControl = new CameraBinImageEncoder(this); + m_recorderControl = new CameraBinRecorder(this); + m_mediaContainerControl = new CameraBinContainer(this); + m_cameraExposureControl = new CameraBinExposure(this); + m_cameraFlashControl = new CameraBinFlash(this); + m_cameraFocusControl = new CameraBinFocus(this); + m_imageProcessingControl = new CameraBinImageProcessing(this); + m_cameraLocksControl = new CameraBinLocks(this); + m_captureDestinationControl = new CameraBinCaptureDestination(this); + m_captureBufferFormatControl = new CameraBinCaptureBufferFormat(this); +} + +CameraBinSession::~CameraBinSession() +{ + if (m_pipeline) { + if (m_viewfinderInterface) + m_viewfinderInterface->stopRenderer(); + + gst_element_set_state(m_pipeline, GST_STATE_NULL); + gst_element_get_state(m_pipeline, NULL, NULL, GST_CLOCK_TIME_NONE); + gstUnref(m_pipeline); + gstUnref(m_viewfinderElement); + } +} + +GstPhotography *CameraBinSession::photography() +{ + if (GST_IS_PHOTOGRAPHY(m_pipeline)) { + return GST_PHOTOGRAPHY(m_pipeline); + } + + if (!m_videoSrc) { + m_videoSrc = buildVideoSrc(); + + if (m_videoSrc) + g_object_set(m_pipeline, VIDEO_SOURCE_PROPERTY, m_videoSrc, NULL); + else + g_object_get(m_pipeline, VIDEO_SOURCE_PROPERTY, &m_videoSrc, NULL); + + updateVideoSourceCaps(); + m_videoInputHasChanged = false; + } + + if (m_videoSrc && GST_IS_PHOTOGRAPHY(m_videoSrc)) + return GST_PHOTOGRAPHY(m_videoSrc); + + return 0; +} + +CameraBinSession::CameraRole CameraBinSession::cameraRole() const +{ +#ifdef Q_WS_MAEMO_5 + return m_inputDevice == QLatin1String("/dev/video1") ? + FrontCamera : BackCamera; +#endif + + return BackCamera; +} + +bool CameraBinSession::setupCameraBin() +{ + if (m_captureMode == QCamera::CaptureStillImage) { + g_object_set(m_pipeline, MODE_PROPERTY, CAMERABIN_IMAGE_MODE, NULL); + } + + if (m_captureMode == QCamera::CaptureVideo) { + g_object_set(m_pipeline, MODE_PROPERTY, CAMERABIN_VIDEO_MODE, NULL); + + if (!m_recorderControl->findCodecs()) + return false; + + g_object_set(m_pipeline, VIDEO_ENCODER_PROPERTY, m_videoEncodeControl->createEncoder(), NULL); + g_object_set(m_pipeline, AUDIO_ENCODER_PROPERTY, m_audioEncodeControl->createEncoder(), NULL); + g_object_set(m_pipeline, VIDEO_MUXER_PROPERTY, + gst_element_factory_make(m_mediaContainerControl->formatElementName().constData(), NULL), NULL); + } + + if (m_videoInputHasChanged) { + m_videoSrc = buildVideoSrc(); + + if (m_videoSrc) + g_object_set(m_pipeline, VIDEO_SOURCE_PROPERTY, m_videoSrc, NULL); + else + g_object_get(m_pipeline, VIDEO_SOURCE_PROPERTY, &m_videoSrc, NULL); + + updateVideoSourceCaps(); + m_videoInputHasChanged = false; + } + + + if (m_viewfinderHasChanged) { + if (m_viewfinderElement) + gst_object_unref(GST_OBJECT(m_viewfinderElement)); + + m_viewfinderElement = m_viewfinderInterface ? m_viewfinderInterface->videoSink() : 0; +#if CAMERABIN_DEBUG + qDebug() << Q_FUNC_INFO << "Viewfinder changed, reconfigure."; +#endif + m_viewfinderHasChanged = false; + if (!m_viewfinderElement) { + qWarning() << "Staring camera without viewfinder available"; + m_viewfinderElement = gst_element_factory_make("fakesink", NULL); + } + gst_object_ref(GST_OBJECT(m_viewfinderElement)); + gst_element_set_state(m_pipeline, GST_STATE_NULL); + g_object_set(G_OBJECT(m_pipeline), VIEWFINDER_SINK_PROPERTY, m_viewfinderElement, NULL); + } + + GstCaps *previewCaps = gst_caps_from_string(PREVIEW_CAPS_4_3); + g_object_set(G_OBJECT(m_pipeline), PREVIEW_CAPS_PROPERTY, previewCaps, NULL); + gst_caps_unref(previewCaps); + + return true; +} + +void CameraBinSession::updateVideoSourceCaps() +{ + if (m_sourceCaps) { + gst_caps_unref(m_sourceCaps); + m_sourceCaps = 0; + } + + g_object_get(G_OBJECT(m_pipeline), VIDEO_SOURCE_CAPS_PROPERTY, &m_sourceCaps, NULL); +} + +void CameraBinSession::setupCaptureResolution() +{ + if (m_captureMode == QCamera::CaptureStillImage) { + QSize resolution = m_imageEncodeControl->imageSettings().resolution(); + + //by default select the maximum supported resolution + if (resolution.isEmpty()) { + updateVideoSourceCaps(); + bool continuous = false; + QList resolutions = supportedResolutions(qMakePair(0,0), + &continuous, + QCamera::CaptureStillImage); + if (!resolutions.isEmpty()) + resolution = resolutions.last(); + } + + QString previewCapsString = PREVIEW_CAPS_4_3; + QSize viewfinderResolution = VIEWFINDER_RESOLUTION_4x3; + + if (!resolution.isEmpty()) { +#if CAMERABIN_DEBUG + qDebug() << Q_FUNC_INFO << "set image resolution" << resolution; +#endif + g_signal_emit_by_name(G_OBJECT(m_pipeline), SET_IMAGE_RESOLUTION, resolution.width(), resolution.height(), NULL); + + previewCapsString = QString("video/x-raw-rgb, width = (int) %1, height = (int) 480") + .arg(resolution.width()*480/resolution.height()); + + if (!resolution.isEmpty()) { + qreal aspectRatio = qreal(resolution.width()) / resolution.height(); + if (aspectRatio < 1.4) + viewfinderResolution = VIEWFINDER_RESOLUTION_4x3; + else if (aspectRatio > 1.7) + viewfinderResolution = VIEWFINDER_RESOLUTION_16x9; + else + viewfinderResolution = VIEWFINDER_RESOLUTION_3x2; + } + } + + GstCaps *previewCaps = gst_caps_from_string(previewCapsString.toLatin1()); + g_object_set(G_OBJECT(m_pipeline), PREVIEW_CAPS_PROPERTY, previewCaps, NULL); + gst_caps_unref(previewCaps); + + //on low res cameras the viewfinder resolution should not be bigger + //then capture resolution + if (viewfinderResolution.width() > resolution.width()) + viewfinderResolution = resolution; + +#if CAMERABIN_DEBUG + qDebug() << Q_FUNC_INFO << "set viewfinder resolution" << viewfinderResolution; +#endif + g_signal_emit_by_name(G_OBJECT(m_pipeline), + SET_VIDEO_RESOLUTION_FPS, + viewfinderResolution.width(), + viewfinderResolution.height(), + 0, // maximum framerate + 1, // framerate denom + NULL); + } + + if (m_captureMode == QCamera::CaptureVideo) { + QSize resolution = m_videoEncodeControl->videoSettings().resolution(); + qreal framerate = m_videoEncodeControl->videoSettings().frameRate(); + + if (resolution.isEmpty()) { + //select the hightest supported resolution + + updateVideoSourceCaps(); + bool continuous = false; + QList resolutions = supportedResolutions(qMakePair(0,0), + &continuous, + QCamera::CaptureVideo); + if (!resolutions.isEmpty()) + resolution = resolutions.last(); + } + + if (!resolution.isEmpty() || framerate > 0) { +#if CAMERABIN_DEBUG + qDebug() << Q_FUNC_INFO << "set video resolution" << resolution; +#endif + g_signal_emit_by_name(G_OBJECT(m_pipeline), + SET_VIDEO_RESOLUTION_FPS, + resolution.width(), + resolution.height(), + 0, //framerate nom == max rate + 1, // framerate denom == max rate + NULL); + } + } +} + +GstElement *CameraBinSession::buildVideoSrc() +{ + GstElement *videoSrc = 0; + if (m_videoInputFactory) { + videoSrc = m_videoInputFactory->buildElement(); + } else { + QList candidates; + candidates << "subdevsrc" + << "v4l2camsrc" + << "v4l2src" + << "autovideosrc"; + QByteArray sourceElementName; + + foreach(sourceElementName, candidates) { + videoSrc = gst_element_factory_make(sourceElementName.constData(), "camera_source"); + if (videoSrc) + break; + } + + if (videoSrc && !m_inputDevice.isEmpty()) { +#if CAMERABIN_DEBUG + qDebug() << "set camera device" << m_inputDevice; +#endif + if (sourceElementName == "subdevsrc") { + if (m_inputDevice == QLatin1String("secondary")) + g_object_set(G_OBJECT(videoSrc), "camera-device", 1, NULL); + else + g_object_set(G_OBJECT(videoSrc), "camera-device", 0, NULL); + } else { + g_object_set(G_OBJECT(videoSrc), "device", m_inputDevice.toLocal8Bit().constData(), NULL); + } + } + } + + return videoSrc; +} + +void CameraBinSession::captureImage(int requestId, const QString &fileName) +{ + QString actualFileName = fileName; + if (actualFileName.isEmpty()) + actualFileName = generateFileName("img_", defaultDir(QCamera::CaptureStillImage), "jpg"); + + m_requestId = requestId; + + g_object_set(G_OBJECT(m_pipeline), FILENAME_PROPERTY, actualFileName.toLocal8Bit().constData(), NULL); + + g_signal_emit_by_name(G_OBJECT(m_pipeline), CAPTURE_START, NULL); + + m_imageFileName = actualFileName; +} + +void CameraBinSession::setCaptureMode(QCamera::CaptureMode mode) +{ + m_captureMode = mode; + + switch (m_captureMode) { + case QCamera::CaptureStillImage: + g_object_set(m_pipeline, MODE_PROPERTY, CAMERABIN_IMAGE_MODE, NULL); + break; + case QCamera::CaptureVideo: + g_object_set(m_pipeline, MODE_PROPERTY, CAMERABIN_VIDEO_MODE, NULL); + break; + } +} + +QUrl CameraBinSession::outputLocation() const +{ + //return the location service wrote data to, not one set by user, it can be empty. + return m_actualSink; +} + +bool CameraBinSession::setOutputLocation(const QUrl& sink) +{ + m_sink = m_actualSink = sink; + return true; +} + +QDir CameraBinSession::defaultDir(QCamera::CaptureMode mode) const +{ + QStringList dirCandidates; + +#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) + dirCandidates << QLatin1String("/home/user/MyDocs/DCIM"); + dirCandidates << QLatin1String("/home/user/MyDocs/"); +#endif + + if (mode == QCamera::CaptureVideo) { + dirCandidates << QDesktopServices::storageLocation(QDesktopServices::MoviesLocation); + dirCandidates << QDir::home().filePath("Documents/Video"); + dirCandidates << QDir::home().filePath("Documents/Videos"); + } else { + dirCandidates << QDesktopServices::storageLocation(QDesktopServices::PicturesLocation); + dirCandidates << QDir::home().filePath("Documents/Photo"); + dirCandidates << QDir::home().filePath("Documents/Photos"); + dirCandidates << QDir::home().filePath("Documents/photo"); + dirCandidates << QDir::home().filePath("Documents/photos"); + dirCandidates << QDir::home().filePath("Documents/Images"); + } + + dirCandidates << QDir::home().filePath("Documents"); + dirCandidates << QDir::home().filePath("My Documents"); + dirCandidates << QDir::homePath(); + dirCandidates << QDir::currentPath(); + dirCandidates << QDir::tempPath(); + + foreach (const QString &path, dirCandidates) { + if (QFileInfo(path).isWritable()) + return QDir(path); + } + + return QDir(); +} + +QString CameraBinSession::generateFileName(const QString &prefix, const QDir &dir, const QString &ext) const +{ + int lastClip = 0; + foreach(QString fileName, dir.entryList(QStringList() << QString("%1*.%2").arg(prefix).arg(ext))) { + int imgNumber = fileName.mid(prefix.length(), fileName.size()-prefix.length()-ext.length()-1).toInt(); + lastClip = qMax(lastClip, imgNumber); + } + + QString name = QString("%1%2.%3").arg(prefix) + .arg(lastClip+1, + 4, //fieldWidth + 10, + QLatin1Char('0')) + .arg(ext); + + return dir.absoluteFilePath(name); +} + +void CameraBinSession::setDevice(const QString &device) +{ + if (m_inputDevice != device) { + m_inputDevice = device; + m_videoInputHasChanged = true; + } +} + +void CameraBinSession::setAudioInput(QGstreamerElementFactory *audioInput) +{ + m_audioInputFactory = audioInput; +} + +void CameraBinSession::setVideoInput(QGstreamerElementFactory *videoInput) +{ + m_videoInputFactory = videoInput; + m_videoInputHasChanged = true; +} + +bool CameraBinSession::isReady() const +{ + //it's possible to use QCamera without any viewfinder attached + return !m_viewfinderInterface || m_viewfinderInterface->isReady(); +} + +void CameraBinSession::setViewfinder(QObject *viewfinder) +{ + if (m_viewfinderInterface) + m_viewfinderInterface->stopRenderer(); + + m_viewfinderInterface = qobject_cast(viewfinder); + if (!m_viewfinderInterface) + viewfinder = 0; + + if (m_viewfinder != viewfinder) { + bool oldReady = isReady(); + + if (m_viewfinder) { + disconnect(m_viewfinder, SIGNAL(sinkChanged()), + this, SLOT(handleViewfinderChange())); + disconnect(m_viewfinder, SIGNAL(readyChanged(bool)), + this, SIGNAL(readyChanged(bool))); + } + + m_viewfinder = viewfinder; + m_viewfinderHasChanged = true; + + if (m_viewfinder) { + connect(m_viewfinder, SIGNAL(sinkChanged()), + this, SLOT(handleViewfinderChange())); + connect(m_viewfinder, SIGNAL(readyChanged(bool)), + this, SIGNAL(readyChanged(bool))); + } + + emit viewfinderChanged(); + if (oldReady != isReady()) + emit readyChanged(isReady()); + } +} + +void CameraBinSession::handleViewfinderChange() +{ + //the viewfinder will be reloaded + //shortly when the pipeline is started + m_viewfinderHasChanged = true; + emit viewfinderChanged(); +} + +QCamera::State CameraBinSession::state() const +{ + return m_state; +} + +void CameraBinSession::setState(QCamera::State newState) +{ + if (newState == m_pendingState) + return; + + m_pendingState = newState; + +#if CAMERABIN_DEBUG + qDebug() << Q_FUNC_INFO << ENUM_NAME(QCamera, "State", newState); +#endif + + switch (newState) { + case QCamera::UnloadedState: + if (m_recordingActive) + stopVideoRecording(); + + if (m_viewfinderInterface) + m_viewfinderInterface->stopRenderer(); + + gst_element_set_state(m_pipeline, GST_STATE_NULL); + m_state = newState; + if (m_busy) + emit busyChanged(m_busy = false); + + emit stateChanged(m_state); + break; + case QCamera::LoadedState: + if (m_recordingActive) + stopVideoRecording(); + + if (m_videoInputHasChanged) { + if (m_viewfinderInterface) + m_viewfinderInterface->stopRenderer(); + + gst_element_set_state(m_pipeline, GST_STATE_NULL); + m_videoSrc = buildVideoSrc(); + g_object_set(m_pipeline, VIDEO_SOURCE_PROPERTY, m_videoSrc, NULL); + updateVideoSourceCaps(); + m_videoInputHasChanged = false; + } +#ifdef USE_READY_STATE_ON_LOADED + gst_element_set_state(m_pipeline, GST_STATE_READY); +#else + m_state = QCamera::LoadedState; + if (m_viewfinderInterface) + m_viewfinderInterface->stopRenderer(); + gst_element_set_state(m_pipeline, GST_STATE_NULL); + emit stateChanged(m_state); +#endif + break; + case QCamera::ActiveState: + if (setupCameraBin()) { + GstState binState = GST_STATE_NULL; + GstState pending = GST_STATE_NULL; + gst_element_get_state(m_pipeline, &binState, &pending, 0); + + if (pending == GST_STATE_VOID_PENDING && binState == GST_STATE_READY) { + m_pendingResolutionUpdate = false; + setupCaptureResolution(); + gst_element_set_state(m_pipeline, GST_STATE_PLAYING); + } else { + m_pendingResolutionUpdate = true; + gst_element_set_state(m_pipeline, GST_STATE_READY); + } + } + } +} + +bool CameraBinSession::isBusy() const +{ + return m_busy; +} + +void CameraBinSession::updateBusyStatus(GObject *o, GParamSpec *p, gpointer d) +{ + Q_UNUSED(p); + CameraBinSession *session = reinterpret_cast(d); + + bool idle = false; + g_object_get(o, "idle", &idle, NULL); + bool busy = !idle; + + if (session->m_busy != busy) { + session->m_busy = busy; + QMetaObject::invokeMethod(session, "busyChanged", + Qt::QueuedConnection, + Q_ARG(bool, busy)); + } +} + +qint64 CameraBinSession::duration() const +{ + GstFormat format = GST_FORMAT_TIME; + gint64 duration = 0; + + if ( m_pipeline && gst_element_query_position(m_pipeline, &format, &duration)) + return duration / 1000000; + else + return 0; +} + +bool CameraBinSession::isMuted() const +{ + return m_muted; +} + +void CameraBinSession::setMuted(bool muted) +{ + if (m_muted != muted) { + m_muted = muted; + + if (m_pipeline) + g_object_set(G_OBJECT(m_pipeline), MUTE_PROPERTY, m_muted, NULL); + emit mutedChanged(m_muted); + } +} + +void CameraBinSession::setCaptureDevice(const QString &deviceName) +{ + m_captureDevice = deviceName; +} + +void CameraBinSession::setMetaData(const QMap &data) +{ + m_metaData = data; + + if (m_pipeline) { + GstIterator *elements = gst_bin_iterate_all_by_interface(GST_BIN(m_pipeline), GST_TYPE_TAG_SETTER); + GstElement *element = 0; + while (gst_iterator_next(elements, (void**)&element) == GST_ITERATOR_OK) { + QMapIterator it(data); + while (it.hasNext()) { + it.next(); + const QString tagName = it.key(); + const QVariant tagValue = it.value(); + + switch(tagValue.type()) { + case QVariant::String: + gst_tag_setter_add_tags(GST_TAG_SETTER(element), + GST_TAG_MERGE_REPLACE_ALL, + tagName.toUtf8().constData(), + tagValue.toString().toUtf8().constData(), + NULL); + break; + case QVariant::Int: + case QVariant::LongLong: + gst_tag_setter_add_tags(GST_TAG_SETTER(element), + GST_TAG_MERGE_REPLACE_ALL, + tagName.toUtf8().constData(), + tagValue.toInt(), + NULL); + break; + case QVariant::Double: + gst_tag_setter_add_tags(GST_TAG_SETTER(element), + GST_TAG_MERGE_REPLACE_ALL, + tagName.toUtf8().constData(), + tagValue.toDouble(), + NULL); + break; + default: + break; + } + } + } + } +} + +bool CameraBinSession::processSyncMessage(const QGstreamerMessage &message) +{ + GstMessage* gm = message.rawMessage(); + const GstStructure *st; + const GValue *image; + GstBuffer *buffer = NULL; + + if (gm && GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ELEMENT) { + if (m_captureMode == QCamera::CaptureStillImage && + gst_structure_has_name(gm->structure, "preview-image")) { + st = gst_message_get_structure(gm); + if (gst_structure_has_field_typed(st, "buffer", GST_TYPE_BUFFER)) { + image = gst_structure_get_value(st, "buffer"); + if (image) { + buffer = gst_value_get_buffer(image); + + QImage img; + + GstCaps *caps = gst_buffer_get_caps(buffer); + if (caps) { + GstStructure *structure = gst_caps_get_structure(caps, 0); + gint width = 0; + gint height = 0; + + if (structure && + gst_structure_get_int(structure, "width", &width) && + gst_structure_get_int(structure, "height", &height) && + width > 0 && height > 0) { + if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-rgb") == 0) { + QImage::Format format = QImage::Format_Invalid; + int bpp = 0; + gst_structure_get_int(structure, "bpp", &bpp); + + if (bpp == 24) + format = QImage::Format_RGB888; + else if (bpp == 32) + format = QImage::Format_RGB32; + + if (format != QImage::Format_Invalid) { + img = QImage((const uchar *)buffer->data, width, height, format); + img.bits(); //detach + } + } + } + gst_caps_unref(caps); + + static int exposedSignalIndex = metaObject()->indexOfSignal("imageExposed(int)"); + metaObject()->method(exposedSignalIndex).invoke(this, + Qt::QueuedConnection, + Q_ARG(int,m_requestId)); + + static int signalIndex = metaObject()->indexOfSignal("imageCaptured(int,QImage)"); + metaObject()->method(signalIndex).invoke(this, + Qt::QueuedConnection, + Q_ARG(int,m_requestId), + Q_ARG(QImage,img)); + } + + } + return true; + } + } + + if (gst_structure_has_name(gm->structure, "prepare-xwindow-id")) { + if (m_viewfinderInterface) + m_viewfinderInterface->precessNewStream(); + + return true; + } + + if (gst_structure_has_name(gm->structure, GST_PHOTOGRAPHY_AUTOFOCUS_DONE)) + m_cameraFocusControl->handleFocusMessage(gm); + + if (m_viewfinderInterface && GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_viewfinderElement)) + m_viewfinderInterface->handleSyncMessage(gm); + } + + return false; +} + +void CameraBinSession::handleBusMessage(const QGstreamerMessage &message) +{ + GstMessage* gm = message.rawMessage(); + + if (gm) { + if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ERROR) { + GError *err; + gchar *debug; + gst_message_parse_error (gm, &err, &debug); + + QString message; + + if (err && err->message) { + message = QString::fromUtf8(err->message); + qWarning() << "CameraBin error:" << message; + } + + //only report error messager from camerabin + if (GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_pipeline)) { + if (message.isEmpty()) + message = tr("Camera error"); + + emit error(int(QMediaRecorder::ResourceError), message); + } + + if (err) + g_error_free (err); + + if (debug) + g_free (debug); + } + + if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_WARNING) { + GError *err; + gchar *debug; + gst_message_parse_warning (gm, &err, &debug); + + if (err && err->message) + qWarning() << "CameraBin warning:" << QString::fromUtf8(err->message); + + if (err) + g_error_free (err); + if (debug) + g_free (debug); + } + + if (GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_pipeline)) { + switch (GST_MESSAGE_TYPE(gm)) { + case GST_MESSAGE_DURATION: + break; + + case GST_MESSAGE_STATE_CHANGED: + { + + GstState oldState; + GstState newState; + GstState pending; + + gst_message_parse_state_changed(gm, &oldState, &newState, &pending); + + +#if CAMERABIN_DEBUG + QStringList states; + states << "GST_STATE_VOID_PENDING" << "GST_STATE_NULL" << "GST_STATE_READY" << "GST_STATE_PAUSED" << "GST_STATE_PLAYING"; + + + qDebug() << QString("state changed: old: %1 new: %2 pending: %3") \ + .arg(states[oldState]) \ + .arg(states[newState]) \ + .arg(states[pending]); +#endif + + switch (newState) { + case GST_STATE_VOID_PENDING: + case GST_STATE_NULL: + if (m_state != QCamera::UnloadedState) + emit stateChanged(m_state = QCamera::UnloadedState); + break; + case GST_STATE_READY: + if (m_pendingResolutionUpdate) { + m_pendingResolutionUpdate = false; + setupCaptureResolution(); + gst_element_set_state(m_pipeline, GST_STATE_PLAYING); + } + if (m_state != QCamera::LoadedState) + emit stateChanged(m_state = QCamera::LoadedState); + break; + case GST_STATE_PAUSED: + case GST_STATE_PLAYING: + emit stateChanged(m_state = QCamera::ActiveState); + break; + } + } + break; + default: + break; + } + //qDebug() << "New session state:" << ENUM_NAME(CameraBinSession,"State",m_state); + } + + if (m_viewfinderInterface && GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_viewfinderElement)) + m_viewfinderInterface->handleBusMessage(gm); + + emit busMessage(message); + } +} + +void CameraBinSession::recordVideo() +{ + m_recordingActive = true; + m_actualSink = m_sink; + if (m_actualSink.isEmpty()) { + QString ext = m_mediaContainerControl->containerMimeType(); + m_actualSink = generateFileName("clip_", defaultDir(QCamera::CaptureVideo), ext); + } + + g_object_set(G_OBJECT(m_pipeline), FILENAME_PROPERTY, m_actualSink.toEncoded().constData(), NULL); + + g_signal_emit_by_name(G_OBJECT(m_pipeline), CAPTURE_START, NULL); +} + +void CameraBinSession::resumeVideoRecording() +{ + m_recordingActive = true; + g_signal_emit_by_name(G_OBJECT(m_pipeline), CAPTURE_START, NULL); +} + + +void CameraBinSession::pauseVideoRecording() +{ + g_signal_emit_by_name(G_OBJECT(m_pipeline), CAPTURE_PAUSE, NULL); +} + +void CameraBinSession::stopVideoRecording() +{ + m_recordingActive = false; + g_signal_emit_by_name(G_OBJECT(m_pipeline), CAPTURE_STOP, NULL); +} + +//internal, only used by CameraBinSession::supportedFrameRates. +//recursively fills the list of framerates res from value data. +static void readValue(const GValue *value, QList< QPair > *res, bool *continuous) +{ + if (GST_VALUE_HOLDS_FRACTION(value)) { + int num = gst_value_get_fraction_numerator(value); + int denum = gst_value_get_fraction_denominator(value); + + *res << QPair(num, denum); + } else if (GST_VALUE_HOLDS_FRACTION_RANGE(value)) { + const GValue *rateValueMin = gst_value_get_fraction_range_min(value); + const GValue *rateValueMax = gst_value_get_fraction_range_max(value); + + if (continuous) + *continuous = true; + + readValue(rateValueMin, res, continuous); + readValue(rateValueMax, res, continuous); + } else if (GST_VALUE_HOLDS_LIST(value)) { + for (uint i=0; i &r1, const QPair &r2) +{ + return r1.first*r2.second < r2.first*r1.second; +} + +QList< QPair > CameraBinSession::supportedFrameRates(const QSize &frameSize, bool *continuous) const +{ + QList< QPair > res; + + if (!m_sourceCaps) + return res; + + GstCaps *caps = 0; + + if (frameSize.isEmpty()) { + caps = gst_caps_copy(m_sourceCaps); + } else { + GstCaps *filter = gst_caps_new_full( + gst_structure_new( + "video/x-raw-rgb", + "width" , G_TYPE_INT , frameSize.width(), + "height" , G_TYPE_INT, frameSize.height(), NULL), + gst_structure_new( + "video/x-raw-yuv", + "width" , G_TYPE_INT, frameSize.width(), + "height" , G_TYPE_INT, frameSize.height(), NULL), + gst_structure_new( + "image/jpeg", + "width" , G_TYPE_INT, frameSize.width(), + "height" , G_TYPE_INT, frameSize.height(), NULL), + NULL); + + caps = gst_caps_intersect(m_sourceCaps, filter); + gst_caps_unref(filter); + } + + //simplify to the list of rates only: + gst_caps_make_writable(caps); + for (uint i=0; i valueRange(const GValue *value, bool *continuous) +{ + int minValue = 0; + int maxValue = 0; + + if (g_value_type_compatible(G_VALUE_TYPE(value), G_TYPE_INT)) { + minValue = maxValue = g_value_get_int(value); + } else if (GST_VALUE_HOLDS_INT_RANGE(value)) { + minValue = gst_value_get_int_range_min(value); + maxValue = gst_value_get_int_range_max(value); + *continuous = true; + } else if (GST_VALUE_HOLDS_LIST(value)) { + for (uint i=0; i res = valueRange(gst_value_list_get_value(value, i), continuous); + + if (res.first > 0 && minValue > 0) + minValue = qMin(minValue, res.first); + else //select non 0 valid value + minValue = qMax(minValue, res.first); + + maxValue = qMax(maxValue, res.second); + } + } + + return QPair(minValue, maxValue); +} + +static bool resolutionLessThan(const QSize &r1, const QSize &r2) +{ + return r1.width()*r1.height() < r2.width()*r2.height(); +} + + +QList CameraBinSession::supportedResolutions(QPair rate, + bool *continuous, + QCamera::CaptureMode mode) const +{ + QList res; + + if (continuous) + *continuous = false; + + if (!m_sourceCaps) + return res; + +#if CAMERABIN_DEBUG + qDebug() << "Source caps:" << gst_caps_to_string(m_sourceCaps); +#endif + + GstCaps *caps = 0; + bool isContinuous = false; + + if (rate.first <= 0 || rate.second <= 0) { + caps = gst_caps_copy(m_sourceCaps); + } else { + GstCaps *filter = gst_caps_new_full( + gst_structure_new( + "video/x-raw-rgb", + "framerate" , GST_TYPE_FRACTION , rate.first, rate.second, NULL), + gst_structure_new( + "video/x-raw-yuv", + "framerate" , GST_TYPE_FRACTION , rate.first, rate.second, NULL), + gst_structure_new( + "image/jpeg", + "framerate" , GST_TYPE_FRACTION , rate.first, rate.second, NULL), + NULL); + + caps = gst_caps_intersect(m_sourceCaps, filter); + gst_caps_unref(filter); + } + + //simplify to the list of resolutions only: + gst_caps_make_writable(caps); + for (uint i=0; i wRange = valueRange(wValue, &isContinuous); + QPair hRange = valueRange(hValue, &isContinuous); + + QSize minSize(wRange.first, hRange.first); + QSize maxSize(wRange.second, hRange.second); + + if (!minSize.isEmpty()) + res << minSize; + + if (minSize != maxSize && !maxSize.isEmpty()) + res << maxSize; + } + + + qSort(res.begin(), res.end(), resolutionLessThan); + + //if the range is continuos, populate is with the common rates + if (isContinuous && res.size() >= 2) { + //fill the ragne with common value + static QList commonSizes = + QList() << QSize(128, 96) + << QSize(160,120) + << QSize(176, 144) + << QSize(320, 240) + << QSize(352, 288) + << QSize(640, 480) + << QSize(848, 480) + << QSize(854, 480) + << QSize(1024, 768) + << QSize(1280, 720) // HD 720 + << QSize(1280, 1024) + << QSize(1600, 1200) + << QSize(1920, 1080) // HD + << QSize(1920, 1200) + << QSize(2048, 1536) + << QSize(2560, 1600) + << QSize(2580, 1936); + QSize minSize = res.first(); + QSize maxSize = res.last(); + +#ifdef Q_WS_MAEMO_5 + if (mode == QCamera::CaptureVideo && cameraRole() == BackCamera) + maxSize = QSize(848, 480); + if (mode == QCamera::CaptureStillImage) + minSize = QSize(640, 480); +#elif defined(Q_WS_MAEMO_6) + if (cameraRole() == FrontCamera && maxSize.width() > 640) + maxSize = QSize(640, 480); + else if (mode == QCamera::CaptureVideo && maxSize.width() > 1280) + maxSize = QSize(1280, 720); +#else + Q_UNUSED(mode); +#endif + + res.clear(); + + foreach (const QSize &candidate, commonSizes) { + int w = candidate.width(); + int h = candidate.height(); + + if (w > maxSize.width() && h > maxSize.height()) + break; + + if (w >= minSize.width() && h >= minSize.height() && + w <= maxSize.width() && h <= maxSize.height()) + res << candidate; + } + + if (res.isEmpty() || res.first() != minSize) + res.prepend(minSize); + + if (res.last() != maxSize) + res.append(maxSize); + } + +#if CAMERABIN_DEBUG + qDebug() << "Supported resolutions:" << gst_caps_to_string(caps); + qDebug() << res; +#endif + + gst_caps_unref(caps); + + if (continuous) + *continuous = isContinuous; + + return res; +} diff --git a/src/plugins/gstreamer/camerabin/camerabinsession.h b/src/plugins/gstreamer/camerabin/camerabinsession.h new file mode 100644 index 000000000..9597ea873 --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinsession.h @@ -0,0 +1,234 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CAMERABINCAPTURESESSION_MAEMO_H +#define CAMERABINCAPTURESESSION_MAEMO_H + +#include + +#include +#include + +#include +#include + +#include "qgstreamerbushelper.h" +#include "qcamera.h" + + +class QGstreamerMessage; +class QGstreamerBusHelper; +class CameraBinAudioEncoder; +class CameraBinVideoEncoder; +class CameraBinImageEncoder; +class CameraBinRecorder; +class CameraBinContainer; +class CameraBinExposure; +class CameraBinFlash; +class CameraBinFocus; +class CameraBinImageProcessing; +class CameraBinLocks; +class CameraBinCaptureDestination; +class CameraBinCaptureBufferFormat; +class QGstreamerVideoRendererInterface; + +class QGstreamerElementFactory +{ +public: + virtual GstElement *buildElement() = 0; +}; + +class CameraBinSession : public QObject, public QGstreamerSyncEventFilter +{ + Q_OBJECT + Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged) +public: + enum CameraRole { + FrontCamera, // Secondary camera + BackCamera // Main photo camera + }; + + CameraBinSession(QObject *parent); + ~CameraBinSession(); + + GstPhotography *photography(); + GstElement *cameraBin() { return m_pipeline; } + + CameraRole cameraRole() const; + + QList< QPair > supportedFrameRates(const QSize &frameSize, bool *continuous) const; + QList supportedResolutions( QPair rate, bool *continuous, QCamera::CaptureMode mode) const; + + QCamera::CaptureMode captureMode() { return m_captureMode; } + void setCaptureMode(QCamera::CaptureMode mode); + + QUrl outputLocation() const; + bool setOutputLocation(const QUrl& sink); + + QDir defaultDir(QCamera::CaptureMode mode) const; + QString generateFileName(const QString &prefix, const QDir &dir, const QString &ext) const; + + CameraBinAudioEncoder *audioEncodeControl() const { return m_audioEncodeControl; } + CameraBinVideoEncoder *videoEncodeControl() const { return m_videoEncodeControl; } + CameraBinImageEncoder *imageEncodeControl() const { return m_imageEncodeControl; } + CameraBinExposure *cameraExposureControl() const { return m_cameraExposureControl; } + CameraBinFlash *cameraFlashControl() const { return m_cameraFlashControl; } + CameraBinFocus *cameraFocusControl() const { return m_cameraFocusControl; } + CameraBinImageProcessing *imageProcessingControl() const { return m_imageProcessingControl; } + CameraBinLocks *cameraLocksControl() const { return m_cameraLocksControl; } + CameraBinCaptureDestination *captureDestinationControl() const { return m_captureDestinationControl; } + CameraBinCaptureBufferFormat *captureBufferFormatControl() const { return m_captureBufferFormatControl; } + + + CameraBinRecorder *recorderControl() const { return m_recorderControl; } + CameraBinContainer *mediaContainerControl() const { return m_mediaContainerControl; } + + QGstreamerElementFactory *audioInput() const { return m_audioInputFactory; } + void setAudioInput(QGstreamerElementFactory *audioInput); + + QGstreamerElementFactory *videoInput() const { return m_videoInputFactory; } + void setVideoInput(QGstreamerElementFactory *videoInput); + bool isReady() const; + + QObject *viewfinder() const { return m_viewfinder; } + void setViewfinder(QObject *viewfinder); + + void captureImage(int requestId, const QString &fileName); + + QCamera::State state() const; + bool isBusy() const; + + qint64 duration() const; + + void recordVideo(); + void pauseVideoRecording(); + void resumeVideoRecording(); + void stopVideoRecording(); + + bool isMuted() const; + + bool processSyncMessage(const QGstreamerMessage &message); + +signals: + void stateChanged(QCamera::State state); + void durationChanged(qint64 duration); + void error(int error, const QString &errorString); + void imageExposed(int requestId); + void imageCaptured(int requestId, const QImage &img); + void mutedChanged(bool); + void viewfinderChanged(); + void readyChanged(bool); + void busyChanged(bool); + void busMessage(const QGstreamerMessage &message); + +public slots: + void setDevice(const QString &device); + void setState(QCamera::State); + void setCaptureDevice(const QString &deviceName); + void setMetaData(const QMap&); + void setMuted(bool); + +private slots: + void handleBusMessage(const QGstreamerMessage &message); + void handleViewfinderChange(); + +private: + bool setupCameraBin(); + void setupCaptureResolution(); + void updateVideoSourceCaps(); + GstElement *buildVideoSrc(); + static void updateBusyStatus(GObject *o, GParamSpec *p, gpointer d); + + QUrl m_sink; + QUrl m_actualSink; + bool m_recordingActive; + QString m_captureDevice; + QCamera::State m_state; + QCamera::State m_pendingState; + QString m_inputDevice; + bool m_pendingResolutionUpdate; + bool m_muted; + bool m_busy; + + QCamera::CaptureMode m_captureMode; + QMap m_metaData; + + QGstreamerElementFactory *m_audioInputFactory; + QGstreamerElementFactory *m_videoInputFactory; + QObject *m_viewfinder; + QGstreamerVideoRendererInterface *m_viewfinderInterface; + + CameraBinAudioEncoder *m_audioEncodeControl; + CameraBinVideoEncoder *m_videoEncodeControl; + CameraBinImageEncoder *m_imageEncodeControl; + CameraBinRecorder *m_recorderControl; + CameraBinContainer *m_mediaContainerControl; + CameraBinExposure *m_cameraExposureControl; + CameraBinFlash *m_cameraFlashControl; + CameraBinFocus *m_cameraFocusControl; + CameraBinImageProcessing *m_imageProcessingControl; + CameraBinLocks *m_cameraLocksControl; + CameraBinCaptureDestination *m_captureDestinationControl; + CameraBinCaptureBufferFormat *m_captureBufferFormatControl; + + QGstreamerBusHelper *m_busHelper; + GstBus* m_bus; + GstElement *m_pipeline; + GstElement *m_videoSrc; + GstElement *m_viewfinderElement; + bool m_viewfinderHasChanged; + bool m_videoInputHasChanged; + + GstCaps *m_sourceCaps; + + GstElement *m_audioSrc; + GstElement *m_audioConvert; + GstElement *m_capsFilter; + GstElement *m_fileSink; + GstElement *m_audioEncoder; + GstElement *m_muxer; + +public: + QString m_imageFileName; + int m_requestId; +}; + +#endif // CAMERABINCAPTURESESSION_MAEMO_H diff --git a/src/plugins/gstreamer/camerabin/camerabinvideoencoder.cpp b/src/plugins/gstreamer/camerabin/camerabinvideoencoder.cpp new file mode 100644 index 000000000..b1809abcb --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinvideoencoder.cpp @@ -0,0 +1,346 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camerabinvideoencoder.h" +#include "camerabinsession.h" +#include "camerabincontainer.h" + +#include + +CameraBinVideoEncoder::CameraBinVideoEncoder(CameraBinSession *session) + :QVideoEncoderControl(session), m_session(session) +{ + QList codecCandidates; +#if defined(Q_WS_MAEMO_5) + codecCandidates << "video/mpeg4" << "video/h264" << "video/h263" << "video/theora" + << "video/mpeg2" << "video/mpeg1" << "video/mjpeg" << "video/VP8" << "video/h261"; + + m_elementNames["video/h264"] = "dsph264enc"; + m_elementNames["video/mpeg4"] = "dspmp4venc"; + m_elementNames["video/h263"] = "dsph263enc"; + m_elementNames["video/theora"] = "theoraenc"; + m_elementNames["video/mpeg2"] = "ffenc_mpeg2video"; + m_elementNames["video/mpeg1"] = "ffenc_mpeg1video"; + m_elementNames["video/mjpeg"] = "ffenc_mjpeg"; + m_elementNames["video/VP8"] = "vp8enc"; + m_elementNames["video/h261"] = "ffenc_h261"; + + m_codecOptions["video/mpeg4"] = QStringList() << "mode" << "keyframe-interval"; +#elif defined(Q_WS_MAEMO_6) + codecCandidates << "video/mpeg4" << "video/h264" << "video/h263"; + + m_elementNames["video/h264"] = "dsph264enc"; + m_elementNames["video/mpeg4"] = "dsphdmp4venc"; + m_elementNames["video/h263"] = "dsph263enc"; + + QStringList options = QStringList() << "mode" << "keyframe-interval" << "max-bitrate" << "intra-refresh"; + m_codecOptions["video/h264"] = options; + m_codecOptions["video/mpeg4"] = options; + m_codecOptions["video/h263"] = options; +#else + codecCandidates << "video/h264" << "video/xvid" << "video/mpeg4" + << "video/mpeg1" << "video/mpeg2" << "video/theora" + << "video/VP8" << "video/h261" << "video/mjpeg"; + + m_elementNames["video/h264"] = "x264enc"; + m_elementNames["video/xvid"] = "xvidenc"; + m_elementNames["video/mpeg4"] = "ffenc_mpeg4"; + m_elementNames["video/mpeg1"] = "ffenc_mpeg1video"; + m_elementNames["video/mpeg2"] = "ffenc_mpeg2video"; + m_elementNames["video/theora"] = "theoraenc"; + m_elementNames["video/mjpeg"] = "ffenc_mjpeg"; + m_elementNames["video/VP8"] = "vp8enc"; + m_elementNames["video/h261"] = "ffenc_h261"; + + m_codecOptions["video/h264"] = QStringList() << "quantizer"; + m_codecOptions["video/xvid"] = QStringList() << "quantizer" << "profile"; + m_codecOptions["video/mpeg4"] = QStringList() << "quantizer"; + m_codecOptions["video/mpeg1"] = QStringList() << "quantizer"; + m_codecOptions["video/mpeg2"] = QStringList() << "quantizer"; + m_codecOptions["video/theora"] = QStringList(); + +#endif + + foreach( const QByteArray& codecName, codecCandidates ) { + QByteArray elementName = m_elementNames[codecName]; + GstElementFactory *factory = gst_element_factory_find(elementName.constData()); + if (factory) { + m_codecs.append(codecName); + const gchar *descr = gst_element_factory_get_description(factory); + m_codecDescriptions.insert(codecName, QString::fromUtf8(descr)); + + m_streamTypes.insert(codecName, + CameraBinContainer::supportedStreamTypes(factory, GST_PAD_SRC)); + + gst_object_unref(GST_OBJECT(factory)); + } + } +} + +CameraBinVideoEncoder::~CameraBinVideoEncoder() +{ +} + +QList CameraBinVideoEncoder::supportedResolutions(const QVideoEncoderSettings &settings, bool *continuous) const +{ + if (continuous) + *continuous = false; + + QPair rate = rateAsRational(settings.frameRate()); + + //select the closest supported rational rate to settings.frameRate() + + return m_session->supportedResolutions(rate, continuous, QCamera::CaptureVideo); +} + +QList< qreal > CameraBinVideoEncoder::supportedFrameRates(const QVideoEncoderSettings &settings, bool *continuous) const +{ + if (continuous) + *continuous = false; + + QList< qreal > res; + QPair rate; + + foreach(rate, m_session->supportedFrameRates(settings.resolution(), continuous)) { + if (rate.second > 0) + res << qreal(rate.first)/rate.second; + } + + return res; +} + +QStringList CameraBinVideoEncoder::supportedVideoCodecs() const +{ + return m_codecs; +} + +QString CameraBinVideoEncoder::videoCodecDescription(const QString &codecName) const +{ + return m_codecDescriptions.value(codecName); +} + +QStringList CameraBinVideoEncoder::supportedEncodingOptions(const QString &codec) const +{ + return m_codecOptions.value(codec); +} + +QVariant CameraBinVideoEncoder::encodingOption(const QString &codec, const QString &name) const +{ + return m_options[codec].value(name); +} + +void CameraBinVideoEncoder::setEncodingOption( + const QString &codec, const QString &name, const QVariant &value) +{ + m_options[codec][name] = value; +} + +QVideoEncoderSettings CameraBinVideoEncoder::videoSettings() const +{ + return m_videoSettings; +} + +void CameraBinVideoEncoder::setVideoSettings(const QVideoEncoderSettings &settings) +{ + m_videoSettings = settings; + m_userSettings = settings; + emit settingsChanged(); +} + +void CameraBinVideoEncoder::setActualVideoSettings(const QVideoEncoderSettings &settings) +{ + m_videoSettings = settings; +} + +void CameraBinVideoEncoder::resetActualSettings() +{ + m_videoSettings = m_userSettings; +} + +GstElement *CameraBinVideoEncoder::createEncoder() +{ + QString codec = m_videoSettings.codec(); + QByteArray elementName = m_elementNames.value(codec); + + GstElement *encoderElement = gst_element_factory_make( elementName.constData(), "video-encoder"); + + if (encoderElement) { + if (m_videoSettings.encodingMode() == QtMultimediaKit::ConstantQualityEncoding) { + QtMultimediaKit::EncodingQuality qualityValue = m_videoSettings.quality(); + + if (elementName == "x264enc") { + //constant quantizer mode + g_object_set(G_OBJECT(encoderElement), "pass", 4, NULL); + int qualityTable[] = { + 50, //VeryLow + 35, //Low + 21, //Normal + 15, //High + 8 //VeryHigh + }; + g_object_set(G_OBJECT(encoderElement), "quantizer", qualityTable[qualityValue], NULL); + } else if (elementName == "xvidenc") { + //constant quantizer mode + g_object_set(G_OBJECT(encoderElement), "pass", 3, NULL); + int qualityTable[] = { + 32, //VeryLow + 12, //Low + 5, //Normal + 3, //High + 2 //VeryHigh + }; + int quant = qualityTable[qualityValue]; + g_object_set(G_OBJECT(encoderElement), "quantizer", quant, NULL); + } else if (elementName == "ffenc_mpeg4" || + elementName == "ffenc_mpeg1video" || + elementName == "ffenc_mpeg2video" ) { + //constant quantizer mode + g_object_set(G_OBJECT(encoderElement), "pass", 2, NULL); + //quant from 1 to 30, default ~3 + double qualityTable[] = { + 20, //VeryLow + 8.0, //Low + 3.0, //Normal + 2.5, //High + 2.0 //VeryHigh + }; + double quant = qualityTable[qualityValue]; + g_object_set(G_OBJECT(encoderElement), "quantizer", quant, NULL); + } else if (elementName == "theoraenc") { + int qualityTable[] = { + 8, //VeryLow + 16, //Low + 32, //Normal + 45, //High + 60 //VeryHigh + }; + //quality from 0 to 63 + int quality = qualityTable[qualityValue]; + g_object_set(G_OBJECT(encoderElement), "quality", quality, NULL); + } else if (elementName == "dsph264enc" || + elementName == "dspmp4venc" || + elementName == "dsphdmp4venc" || + elementName == "dsph263enc") { + //only bitrate parameter is supported + int qualityTable[] = { + 1000000, //VeryLow + 2000000, //Low + 4000000, //Normal + 8000000, //High + 16000000 //VeryHigh + }; + int bitrate = qualityTable[qualityValue]; + g_object_set(G_OBJECT(encoderElement), "bitrate", bitrate, NULL); + } + } else { + int bitrate = m_videoSettings.bitRate(); + if (bitrate > 0) { + g_object_set(G_OBJECT(encoderElement), "bitrate", bitrate, NULL); + } + } + + QMap options = m_options.value(codec); + QMapIterator it(options); + while (it.hasNext()) { + it.next(); + QString option = it.key(); + QVariant value = it.value(); + + switch (value.type()) { + case QVariant::Int: + g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toInt(), NULL); + break; + case QVariant::Bool: + g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toBool(), NULL); + break; + case QVariant::Double: + g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toDouble(), NULL); + break; + case QVariant::String: + g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toString().toUtf8().constData(), NULL); + break; + default: + qWarning() << "unsupported option type:" << option << value; + break; + } + + } + } + + return encoderElement; +} + +QPair CameraBinVideoEncoder::rateAsRational(qreal frameRate) const +{ + if (frameRate > 0.001) { + //convert to rational number + QList denumCandidates; + denumCandidates << 1 << 2 << 3 << 5 << 10 << 25 << 30 << 50 << 100 << 1001 << 1000; + + qreal error = 1.0; + int num = 1; + int denum = 1; + + foreach (int curDenum, denumCandidates) { + int curNum = qRound(frameRate*curDenum); + qreal curError = qAbs(qreal(curNum)/curDenum - frameRate); + + if (curError < error) { + error = curError; + num = curNum; + denum = curDenum; + } + + if (curError < 1e-8) + break; + } + + return QPair(num,denum); + } + + return QPair(); +} + + +QSet CameraBinVideoEncoder::supportedStreamTypes(const QString &codecName) const +{ + return m_streamTypes.value(codecName); +} diff --git a/src/plugins/gstreamer/camerabin/camerabinvideoencoder.h b/src/plugins/gstreamer/camerabin/camerabinvideoencoder.h new file mode 100644 index 000000000..0dd9ffbad --- /dev/null +++ b/src/plugins/gstreamer/camerabin/camerabinvideoencoder.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CAMERABINVIDEOENCODE_H +#define CAMERABINVIDEOENCODE_H + +#include +class CameraBinSession; + +#include +#include +#include + +#include + +QT_USE_NAMESPACE + +class CameraBinVideoEncoder : public QVideoEncoderControl +{ + Q_OBJECT +public: + CameraBinVideoEncoder(CameraBinSession *session); + virtual ~CameraBinVideoEncoder(); + + QList supportedResolutions(const QVideoEncoderSettings &settings = QVideoEncoderSettings(), + bool *continuous = 0) const; + + QList< qreal > supportedFrameRates(const QVideoEncoderSettings &settings = QVideoEncoderSettings(), + bool *continuous = 0) const; + + QPair rateAsRational(qreal) const; + + QStringList supportedVideoCodecs() const; + QString videoCodecDescription(const QString &codecName) const; + + QVideoEncoderSettings videoSettings() const; + void setVideoSettings(const QVideoEncoderSettings &settings); + + QStringList supportedEncodingOptions(const QString &codec) const; + QVariant encodingOption(const QString &codec, const QString &name) const; + void setEncodingOption(const QString &codec, const QString &name, const QVariant &value); + + GstElement *createEncoder(); + + QSet supportedStreamTypes(const QString &codecName) const; + + void setActualVideoSettings(const QVideoEncoderSettings&); + void resetActualSettings(); + +Q_SIGNALS: + void settingsChanged(); + +private: + CameraBinSession *m_session; + + QStringList m_codecs; + QMap m_codecDescriptions; + QMap m_elementNames; + QMap m_codecOptions; + + QVideoEncoderSettings m_videoSettings; // backend selected settings, using m_userSettings + QVideoEncoderSettings m_userSettings; + + QMap > m_options; + QMap > m_streamTypes; +}; + +#endif diff --git a/src/plugins/gstreamer/camerabuttonlistener_maemo.cpp b/src/plugins/gstreamer/camerabuttonlistener_maemo.cpp new file mode 100644 index 000000000..c10156d7a --- /dev/null +++ b/src/plugins/gstreamer/camerabuttonlistener_maemo.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camerabuttonlistener_maemo.h" + +#include +#include + +#include +#include +#include + + +CameraButtonListener::CameraButtonListener(QObject *parent) : + QObject(parent), + m_focusPressed(false), + m_shutterPressed(false) +{ + QDBusConnection::systemBus().connect( + QString(), + "/org/freedesktop/Hal/devices/platform_cam_launch", + "org.freedesktop.Hal.Device", + "PropertyModified", + this, + SLOT(updateShuterButtonState())); + + QDBusConnection::systemBus().connect( + QString(), + "/org/freedesktop/Hal/devices/platform_cam_focus", + "org.freedesktop.Hal.Device", + "PropertyModified", + this, + SLOT(updateFocusButtonState())); +} + + +CameraButtonListener::~CameraButtonListener() +{ +} + +void CameraButtonListener::updateFocusButtonState() +{ + QDBusInterface propertyInterface("org.freedesktop.Hal", + "/org/freedesktop/Hal/devices/platform_cam_focus", + "org.freedesktop.Hal.Device", + QDBusConnection::systemBus()); + + bool pressed = propertyInterface.call("GetProperty", "button.state.value").arguments().at(0).toBool(); + + if (m_focusPressed != pressed) { + m_focusPressed = pressed; + QWidget *window = QApplication::focusWidget(); + + if (window) { + QApplication::postEvent(window, + new QKeyEvent(pressed ? QEvent::KeyPress : QEvent::KeyRelease, + 0x01100021, //Qt::Key_CameraFocus since Qt 4.7.0 + Qt::NoModifier)); + } + } +} + +void CameraButtonListener::updateShuterButtonState() +{ + QDBusInterface propertyInterface("org.freedesktop.Hal", + "/org/freedesktop/Hal/devices/platform_cam_launch", + "org.freedesktop.Hal.Device", + QDBusConnection::systemBus()); + + bool pressed = propertyInterface.call("GetProperty", "button.state.value").arguments().at(0).toBool(); + + if (m_shutterPressed != pressed) { + m_shutterPressed = pressed; + QWidget *window = QApplication::focusWidget(); + + if (window) { + QApplication::postEvent(window, + new QKeyEvent(pressed ? QEvent::KeyPress : QEvent::KeyRelease, + 0x01100020, //Qt::Key_Camera since Qt 4.7.0 + Qt::NoModifier)); + } + } +} diff --git a/src/plugins/gstreamer/camerabuttonlistener_maemo.h b/src/plugins/gstreamer/camerabuttonlistener_maemo.h new file mode 100644 index 000000000..a4d0153ad --- /dev/null +++ b/src/plugins/gstreamer/camerabuttonlistener_maemo.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef CAMERABUTTONLISTENER_MAEMO_H +#define CAMERABUTTONLISTENER_MAEMO_H + +#include + +class CameraButtonListener : public QObject +{ + Q_OBJECT +public: + CameraButtonListener(QObject *parent = 0); + virtual ~CameraButtonListener(); + +private slots: + void updateFocusButtonState(); + void updateShuterButtonState(); + +private: + bool m_focusPressed; + bool m_shutterPressed; +}; + +#endif // CAMERABUTTONLISTENER_MAEMO_H diff --git a/src/plugins/gstreamer/camerabuttonlistener_meego.cpp b/src/plugins/gstreamer/camerabuttonlistener_meego.cpp new file mode 100644 index 000000000..8be24ba2a --- /dev/null +++ b/src/plugins/gstreamer/camerabuttonlistener_meego.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camerabuttonlistener_meego.h" + +#include +#include +#include +#include + +CameraButtonListener::CameraButtonListener(QObject *parent) : + QObject(parent), + m_focusPressed(false), + m_shutterPressed(false) +{ + m_keys = new MeeGo::QmKeys(this); + connect(m_keys, SIGNAL(keyEvent(MeeGo::QmKeys::Key, MeeGo::QmKeys::State)), + this, SLOT(handleQmKeyEvent(MeeGo::QmKeys::Key,MeeGo::QmKeys::State))); +} + +CameraButtonListener::~CameraButtonListener() +{ +} + +void CameraButtonListener::handleQmKeyEvent(MeeGo::QmKeys::Key key, MeeGo::QmKeys::State state) +{ + if (key == MeeGo::QmKeys::Camera) { + QWidget *window = QApplication::focusWidget(); + + bool focusPressed = (state == MeeGo::QmKeys::KeyHalfDown) || + (state == MeeGo::QmKeys::KeyDown); + + if (m_focusPressed != focusPressed) { + m_focusPressed = focusPressed; + if (window) { + QApplication::postEvent(window, + new QKeyEvent(focusPressed ? QEvent::KeyPress : QEvent::KeyRelease, + Qt::Key_CameraFocus, + Qt::NoModifier)); + } + } + + bool shutterPressed = (state == MeeGo::QmKeys::KeyDown); + if (m_shutterPressed != shutterPressed) { + m_shutterPressed = shutterPressed; + if (window) { + QApplication::postEvent(window, + new QKeyEvent(shutterPressed ? QEvent::KeyPress : QEvent::KeyRelease, + Qt::Key_Camera, + Qt::NoModifier)); + } + } + } +} diff --git a/src/plugins/gstreamer/camerabuttonlistener_meego.h b/src/plugins/gstreamer/camerabuttonlistener_meego.h new file mode 100644 index 000000000..88ca26788 --- /dev/null +++ b/src/plugins/gstreamer/camerabuttonlistener_meego.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef CAMERABUTTONLISTENER_MEEGO_H +#define CAMERABUTTONLISTENER_MEEGO_H + +#include +#include + +class CameraButtonListener : public QObject +{ + Q_OBJECT +public: + CameraButtonListener(QObject *parent = 0); + ~CameraButtonListener(); + +private slots: + void handleQmKeyEvent(MeeGo::QmKeys::Key key, MeeGo::QmKeys::State state); + +private: + MeeGo::QmKeys *m_keys; + bool m_focusPressed; + bool m_shutterPressed; +}; + +#endif // CAMERABUTTONLISTENER_MEEGO_H diff --git a/src/plugins/gstreamer/gstreamer.pro b/src/plugins/gstreamer/gstreamer.pro new file mode 100644 index 000000000..681fac4e2 --- /dev/null +++ b/src/plugins/gstreamer/gstreamer.pro @@ -0,0 +1,101 @@ + +load(qt_module) + +TARGET = qgstengine +QT += multimediakit-private network +PLUGIN_TYPE=mediaservice + +load(qt_plugin) +DESTDIR = $$QT.multimediakit.plugins/$${PLUGIN_TYPE} + +unix:contains(QT_CONFIG, alsa) { +DEFINES += HAVE_ALSA +LIBS += \ + -lasound +} + +CONFIG += link_pkgconfig + +PKGCONFIG += \ + gstreamer-0.10 \ + gstreamer-base-0.10 \ + gstreamer-interfaces-0.10 \ + gstreamer-audio-0.10 \ + gstreamer-video-0.10 + +maemo*:PKGCONFIG +=gstreamer-plugins-bad-0.10 +contains(gstreamer-appsrc_enabled, yes): PKGCONFIG += gstreamer-app-0.10 + +maemo5 { + HEADERS += camerabuttonlistener_maemo.h + SOURCES += camerabuttonlistener_maemo.cpp + + QT += dbus +} + +maemo6 { + HEADERS += camerabuttonlistener_meego.h + SOURCES += camerabuttonlistener_meego.cpp + + PKGCONFIG += qmsystem2 libresourceqt1 + + isEqual(QT_ARCH,armv6) { + HEADERS += qgstreamergltexturerenderer.h + SOURCES += qgstreamergltexturerenderer.cpp + QT += opengl + LIBS += -lEGL -lgstmeegointerfaces-0.10 + } +} + +# Input +HEADERS += \ + qgstreamermessage.h \ + qgstreamerbushelper.h \ + qgstreamervideorendererinterface.h \ + qgstreamerserviceplugin.h \ + qgstreameraudioinputendpointselector.h \ + qgstreamervideorenderer.h \ + qgstvideobuffer.h \ + qvideosurfacegstsink.h \ + qgstreamervideoinputdevicecontrol.h \ + gstvideoconnector.h \ + qabstractgstbufferpool.h \ + qgstutils.h + +SOURCES += \ + qgstreamermessage.cpp \ + qgstreamerbushelper.cpp \ + qgstreamervideorendererinterface.cpp \ + qgstreamerserviceplugin.cpp \ + qgstreameraudioinputendpointselector.cpp \ + qgstreamervideorenderer.cpp \ + qgstvideobuffer.cpp \ + qvideosurfacegstsink.cpp \ + qgstreamervideoinputdevicecontrol.cpp \ + gstvideoconnector.c \ + qgstutils.cpp + + +!win32:!contains(QT_CONFIG,embedded):!mac:!symbian:!simulator:!contains(QT_CONFIG, qpa) { + LIBS += -lXv -lX11 -lXext + + HEADERS += \ + qgstreamervideooverlay.h \ + qgstreamervideowindow.h \ + qgstreamervideowidget.h \ + qx11videosurface.h \ + qgstxvimagebuffer.h + + SOURCES += \ + qgstreamervideooverlay.cpp \ + qgstreamervideowindow.cpp \ + qgstreamervideowidget.cpp \ + qx11videosurface.cpp \ + qgstxvimagebuffer.cpp +} +include(mediaplayer/mediaplayer.pri) +include(mediacapture/mediacapture.pri) + +contains(gstreamer-photography_enabled, yes) { + include(camerabin/camerabin.pri) +} diff --git a/src/plugins/gstreamer/gstvideoconnector.c b/src/plugins/gstreamer/gstvideoconnector.c new file mode 100644 index 000000000..55570873e --- /dev/null +++ b/src/plugins/gstreamer/gstvideoconnector.c @@ -0,0 +1,421 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "gstvideoconnector.h" + +/* signals */ +enum +{ + SIGNAL_RESEND_NEW_SEGMENT, + SIGNAL_CONNECTION_FAILED, + LAST_SIGNAL +}; +static guint gst_video_connector_signals[LAST_SIGNAL] = { 0 }; + + +GST_DEBUG_CATEGORY_STATIC (video_connector_debug); +#define GST_CAT_DEFAULT video_connector_debug + +static GstStaticPadTemplate gst_video_connector_sink_factory = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +static GstStaticPadTemplate gst_video_connector_src_factory = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +#define _do_init(bla) \ + GST_DEBUG_CATEGORY_INIT (video_connector_debug, \ + "video-connector", 0, "An identity like element for reconnecting video stream"); + +GST_BOILERPLATE_FULL (GstVideoConnector, gst_video_connector, GstElement, + GST_TYPE_ELEMENT, _do_init); + +static void gst_video_connector_dispose (GObject * object); +static GstFlowReturn gst_video_connector_chain (GstPad * pad, GstBuffer * buf); +static GstFlowReturn gst_video_connector_buffer_alloc (GstPad * pad, + guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf); +static GstStateChangeReturn gst_video_connector_change_state (GstElement * + element, GstStateChange transition); +static gboolean gst_video_connector_handle_sink_event (GstPad * pad, + GstEvent * event); +static gboolean gst_video_connector_new_buffer_probe(GstObject *pad, GstBuffer *buffer, guint * object); +static void gst_video_connector_resend_new_segment(GstElement * element, gboolean emitFailedSignal); +static gboolean gst_video_connector_setcaps (GstPad *pad, GstCaps *caps); +static GstCaps *gst_video_connector_getcaps (GstPad * pad); +static gboolean gst_video_connector_acceptcaps (GstPad * pad, GstCaps * caps); + +static void +gst_video_connector_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_set_details_simple (element_class, "Video Connector", + "Generic", + "An identity like element used for reconnecting video stream", + "Dmytro Poplavskiy "); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_video_connector_sink_factory)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_video_connector_src_factory)); +} + +static void +gst_video_connector_class_init (GstVideoConnectorClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->dispose = gst_video_connector_dispose; + gstelement_class->change_state = gst_video_connector_change_state; + klass->resend_new_segment = gst_video_connector_resend_new_segment; + + gst_video_connector_signals[SIGNAL_RESEND_NEW_SEGMENT] = + g_signal_new ("resend-new-segment", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GstVideoConnectorClass, resend_new_segment), NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + + gst_video_connector_signals[SIGNAL_CONNECTION_FAILED] = + g_signal_new ("connection-failed", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); +} + +static void +gst_video_connector_init (GstVideoConnector *element, + GstVideoConnectorClass *g_class) +{ + element->sinkpad = + gst_pad_new_from_static_template (&gst_video_connector_sink_factory, + "sink"); + gst_pad_set_chain_function(element->sinkpad, + GST_DEBUG_FUNCPTR (gst_video_connector_chain)); + gst_pad_set_event_function(element->sinkpad, + GST_DEBUG_FUNCPTR (gst_video_connector_handle_sink_event)); + gst_pad_set_bufferalloc_function(element->sinkpad, + GST_DEBUG_FUNCPTR (gst_video_connector_buffer_alloc)); + gst_pad_set_setcaps_function(element->sinkpad, + GST_DEBUG_FUNCPTR (gst_video_connector_setcaps)); + gst_pad_set_getcaps_function(element->sinkpad, + GST_DEBUG_FUNCPTR(gst_video_connector_getcaps)); + gst_pad_set_acceptcaps_function(element->sinkpad, + GST_DEBUG_FUNCPTR(gst_video_connector_acceptcaps)); + + gst_element_add_pad (GST_ELEMENT (element), element->sinkpad); + + element->srcpad = + gst_pad_new_from_static_template (&gst_video_connector_src_factory, + "src"); + gst_pad_add_buffer_probe(element->srcpad, + G_CALLBACK(gst_video_connector_new_buffer_probe), element); + gst_element_add_pad (GST_ELEMENT (element), element->srcpad); + + element->relinked = FALSE; + element->failedSignalEmited = FALSE; + gst_segment_init (&element->segment, GST_FORMAT_TIME); + element->latest_buffer = NULL; +} + +static void +gst_video_connector_reset (GstVideoConnector * element) +{ + element->relinked = FALSE; + element->failedSignalEmited = FALSE; + if (element->latest_buffer != NULL) { + gst_buffer_unref (element->latest_buffer); + element->latest_buffer = NULL; + } + gst_segment_init (&element->segment, GST_FORMAT_UNDEFINED); +} + +static void +gst_video_connector_dispose (GObject * object) +{ + GstVideoConnector *element = GST_VIDEO_CONNECTOR (object); + + gst_video_connector_reset (element); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static GstFlowReturn +gst_video_connector_buffer_alloc (GstPad * pad, guint64 offset, guint size, + GstCaps * caps, GstBuffer ** buf) +{ + GstVideoConnector *element; + GstFlowReturn res = GST_FLOW_OK; + element = GST_VIDEO_CONNECTOR (GST_PAD_PARENT (pad)); + + if (!buf) + return GST_FLOW_ERROR; + *buf = NULL; + + GST_OBJECT_LOCK (element); + gst_object_ref(element->srcpad); + GST_OBJECT_UNLOCK (element); + + res = gst_pad_alloc_buffer(element->srcpad, offset, size, caps, buf); + gst_object_unref (element->srcpad); + + GST_DEBUG_OBJECT (element, "buffer alloc finished: %s", gst_flow_get_name (res)); + + return res; +} + +static gboolean +gst_video_connector_setcaps (GstPad *pad, GstCaps *caps) +{ + GstVideoConnector *element; + element = GST_VIDEO_CONNECTOR (GST_PAD_PARENT (pad)); + + /* forward-negotiate */ + gboolean res = gst_pad_set_caps(element->srcpad, caps); + + GST_DEBUG_OBJECT(element, "gst_video_connector_setcaps %s %i", gst_caps_to_string(caps), res); + + if (!res) { + //if set_caps failed, emit "connection-failed" signal + //so colorspace transformation elemnt can be inserted + GST_INFO_OBJECT(element, "gst_video_connector_setcaps failed, emit connection-failed signal"); + g_signal_emit(G_OBJECT(element), gst_video_connector_signals[SIGNAL_CONNECTION_FAILED], 0); + + return gst_pad_set_caps(element->srcpad, caps); + } + + return TRUE; +} + +static GstCaps *gst_video_connector_getcaps (GstPad * pad) +{ + GstVideoConnector *element; + element = GST_VIDEO_CONNECTOR (GST_PAD_PARENT (pad)); + +#if (GST_VERSION_MICRO > 25) + GstCaps *caps = gst_pad_peer_get_caps_reffed(element->srcpad); +#else + GstCaps *caps = gst_pad_peer_get_caps(element->srcpad); +#endif + + if (!caps) + caps = gst_caps_new_any(); + + return caps; +} + +static gboolean gst_video_connector_acceptcaps (GstPad * pad, GstCaps * caps) +{ + GstVideoConnector *element; + element = GST_VIDEO_CONNECTOR (GST_PAD_PARENT (pad)); + + return gst_pad_peer_accept_caps(element->srcpad, caps); +} + +static void +gst_video_connector_resend_new_segment(GstElement * element, gboolean emitFailedSignal) +{ + GST_INFO_OBJECT(element, "New segment requested, failed signal enabled: %i", emitFailedSignal); + GstVideoConnector *connector = GST_VIDEO_CONNECTOR(element); + connector->relinked = TRUE; + if (emitFailedSignal) + connector->failedSignalEmited = FALSE; +} + + +static gboolean gst_video_connector_new_buffer_probe(GstObject *pad, GstBuffer *buffer, guint * object) +{ + GstVideoConnector *element = GST_VIDEO_CONNECTOR (object); + + /* + If relinking is requested, the current buffer should be rejected and + the new segment + previous buffer should be pushed first + */ + + if (element->relinked) + GST_LOG_OBJECT(element, "rejected buffer because of new segment request"); + + return !element->relinked; +} + + +static GstFlowReturn +gst_video_connector_chain (GstPad * pad, GstBuffer * buf) +{ + GstFlowReturn res; + GstVideoConnector *element; + + element = GST_VIDEO_CONNECTOR (gst_pad_get_parent (pad)); + + do { + /* + Resend the segment message and last buffer to preroll the new sink. + Sinks can be changed multiple times while paused, + while loop allows to send the segment message and preroll + all of them with the same buffer. + */ + while (element->relinked) { + element->relinked = FALSE; + + gint64 pos = element->segment.last_stop; + + if (element->latest_buffer && GST_BUFFER_TIMESTAMP_IS_VALID(element->latest_buffer)) { + pos = GST_BUFFER_TIMESTAMP (element->latest_buffer); + } + + //push a new segment and last buffer + GstEvent *ev = gst_event_new_new_segment (TRUE, + element->segment.rate, + element->segment.format, + pos, //start + element->segment.stop, + pos); + + GST_DEBUG_OBJECT (element, "Pushing new segment event"); + if (!gst_pad_push_event (element->srcpad, ev)) { + GST_WARNING_OBJECT (element, + "Newsegment handling failed in %" GST_PTR_FORMAT, + element->srcpad); + } + + if (element->latest_buffer) { + GST_DEBUG_OBJECT (element, "Pushing latest buffer..."); + gst_buffer_ref(element->latest_buffer); + gst_pad_push(element->srcpad, element->latest_buffer); + } + } + + gst_buffer_ref(buf); + + //it's possible video sink is changed during gst_pad_push blocked by + //pad lock, in this case ( element->relinked == TRUE ) + //the buffer should be rejected by the buffer probe and + //the new segment + prev buffer should be sent before + + GST_LOG_OBJECT (element, "Pushing buffer..."); + res = gst_pad_push (element->srcpad, buf); + GST_LOG_OBJECT (element, "Pushed buffer: %s", gst_flow_get_name (res)); + + //if gst_pad_push failed give the service another chance, + //it may still work with the colorspace element added + if (!element->failedSignalEmited && res == GST_FLOW_NOT_NEGOTIATED) { + element->failedSignalEmited = TRUE; + GST_INFO_OBJECT(element, "gst_pad_push failed, emit connection-failed signal"); + g_signal_emit(G_OBJECT(element), gst_video_connector_signals[SIGNAL_CONNECTION_FAILED], 0); + } + + } while (element->relinked); + + + if (element->latest_buffer) { + gst_buffer_unref (element->latest_buffer); + element->latest_buffer = NULL; + } + + //don't save the last video buffer on maemo6 because of buffers shortage + //with omapxvsink +#ifndef Q_WS_MAEMO_6 + element->latest_buffer = gst_buffer_ref(buf); +#endif + + gst_buffer_unref(buf); + gst_object_unref (element); + + return res; +} + +static GstStateChangeReturn +gst_video_connector_change_state (GstElement * element, + GstStateChange transition) +{ + GstVideoConnector *connector; + GstStateChangeReturn result; + + connector = GST_VIDEO_CONNECTOR(element); + result = GST_ELEMENT_CLASS (parent_class)->change_state(element, transition); + + switch (transition) { + case GST_STATE_CHANGE_PAUSED_TO_READY: + gst_video_connector_reset (connector); + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + connector->relinked = FALSE; + break; + default: + break; + } + + return result; +} + +static gboolean +gst_video_connector_handle_sink_event (GstPad * pad, GstEvent * event) +{ + if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) { + GstVideoConnector *element = GST_VIDEO_CONNECTOR (gst_pad_get_parent (pad)); + + gboolean update; + GstFormat format; + gdouble rate, arate; + gint64 start, stop, time; + + gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, + &start, &stop, &time); + + GST_LOG_OBJECT (element, + "NEWSEGMENT update %d, rate %lf, applied rate %lf, " + "format %d, " "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %" + G_GINT64_FORMAT, update, rate, arate, format, start, stop, time); + + gst_segment_set_newsegment_full (&element->segment, update, + rate, arate, format, start, stop, time); + + gst_object_unref (element); + } + + return gst_pad_event_default (pad, event); +} diff --git a/src/plugins/gstreamer/gstvideoconnector.h b/src/plugins/gstreamer/gstvideoconnector.h new file mode 100644 index 000000000..00d057e06 --- /dev/null +++ b/src/plugins/gstreamer/gstvideoconnector.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTVIDEOCONNECTOR_H +#define QGSTVIDEOCONNECTOR_H + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VIDEO_CONNECTOR \ + (gst_video_connector_get_type()) +#define GST_VIDEO_CONNECTOR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VIDEO_CONNECTOR, GstVideoConnector)) +#define GST_VIDEO_CONNECTOR_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VIDEO_CONNECTOR, GstVideoConnectorClass)) +#define GST_IS_VIDEO_CONNECTOR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VIDEO_CONNECTOR)) +#define GST_IS_VIDEO_CONNECTOR_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VIDEO_CONNECTOR)) + +typedef struct _GstVideoConnector GstVideoConnector; +typedef struct _GstVideoConnectorClass GstVideoConnectorClass; + +struct _GstVideoConnector { + GstElement element; + + GstPad *srcpad; + GstPad *sinkpad; + + gboolean relinked; + gboolean failedSignalEmited; + GstSegment segment; + GstBuffer *latest_buffer; +}; + +struct _GstVideoConnectorClass { + GstElementClass parent_class; + + /* action signal to resend new segment */ + void (*resend_new_segment) (GstElement * element, gboolean emitFailedSignal); +}; + +GType gst_video_connector_get_type (void); + +G_END_DECLS + +#endif + diff --git a/src/plugins/gstreamer/mediacapture/mediacapture.pri b/src/plugins/gstreamer/mediacapture/mediacapture.pri new file mode 100644 index 000000000..b7f7794f9 --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/mediacapture.pri @@ -0,0 +1,27 @@ +INCLUDEPATH += $$PWD + +DEFINES += QMEDIA_GSTREAMER_CAPTURE + +HEADERS += $$PWD/qgstreamercaptureservice.h \ + $$PWD/qgstreamercapturesession.h \ + $$PWD/qgstreameraudioencode.h \ + $$PWD/qgstreamervideoencode.h \ + $$PWD/qgstreamerrecordercontrol.h \ + $$PWD/qgstreamermediacontainercontrol.h \ + $$PWD/qgstreamercameracontrol.h \ + $$PWD/qgstreamerv4l2input.h \ + $$PWD/qgstreamercapturemetadatacontrol.h \ + $$PWD/qgstreamerimagecapturecontrol.h \ + $$PWD/qgstreamerimageencode.h + +SOURCES += $$PWD/qgstreamercaptureservice.cpp \ + $$PWD/qgstreamercapturesession.cpp \ + $$PWD/qgstreameraudioencode.cpp \ + $$PWD/qgstreamervideoencode.cpp \ + $$PWD/qgstreamerrecordercontrol.cpp \ + $$PWD/qgstreamermediacontainercontrol.cpp \ + $$PWD/qgstreamercameracontrol.cpp \ + $$PWD/qgstreamerv4l2input.cpp \ + $$PWD/qgstreamercapturemetadatacontrol.cpp \ + $$PWD/qgstreamerimagecapturecontrol.cpp \ + $$PWD/qgstreamerimageencode.cpp diff --git a/src/plugins/gstreamer/mediacapture/qgstreameraudioencode.cpp b/src/plugins/gstreamer/mediacapture/qgstreameraudioencode.cpp new file mode 100644 index 000000000..e548393eb --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreameraudioencode.cpp @@ -0,0 +1,292 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreameraudioencode.h" +#include "qgstreamercapturesession.h" +#include "qgstreamermediacontainercontrol.h" + +#include + +#include + +QGstreamerAudioEncode::QGstreamerAudioEncode(QObject *parent) + :QAudioEncoderControl(parent) +{ + QList codecCandidates; + +#if defined(Q_WS_MAEMO_5) + codecCandidates << "audio/PCM"; //<< "audio/AMR" << "audio/AMR-WB" << "audio/speex"; +#elif defined(Q_WS_MAEMO_6) + codecCandidates << "audio/AAC" << "audio/mpeg" << "audio/vorbis" << "audio/speex" << "audio/GSM" + << "audio/PCM" << "audio/AMR" << "audio/AMR-WB" << "audio/FLAC"; +#else + codecCandidates << "audio/mpeg" << "audio/vorbis" << "audio/speex" << "audio/GSM" + << "audio/PCM" << "audio/AMR" << "audio/AMR-WB" << "audio/FLAC"; +#endif + +#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) + m_elementNames["audio/AMR"] = "nokiaamrnbenc"; + m_elementNames["audio/AMR-WB"] = "nokiaamrwbenc"; + m_elementNames["audio/AAC"] = "nokiaaacenc"; +#else + m_elementNames["audio/mpeg"] = "lamemp3enc"; + m_elementNames["audio/AMR"] = "amrnbenc"; + m_elementNames["audio/AMR-WB"] = "amrwbenc"; +#endif + + m_elementNames["audio/vorbis"] = "vorbisenc"; + m_elementNames["audio/speex"] = "speexenc"; + m_elementNames["audio/PCM"] = "audioresample"; + m_elementNames["audio/FLAC"] = "flacenc"; + m_elementNames["audio/GSM"] = "gsmenc"; + + m_codecOptions["audio/vorbis"] = QStringList() << "min-bitrate" << "max-bitrate"; + m_codecOptions["audio/mpeg"] = QStringList() << "mode"; + m_codecOptions["audio/speex"] = QStringList() << "mode" << "vbr" << "vad" << "dtx"; + m_codecOptions["audio/GSM"] = QStringList(); + m_codecOptions["audio/PCM"] = QStringList(); + m_codecOptions["audio/AMR"] = QStringList(); + m_codecOptions["audio/AMR-WB"] = QStringList(); + + foreach( const QByteArray& codecName, codecCandidates ) { + QByteArray elementName = m_elementNames[codecName]; + GstElementFactory *factory = gst_element_factory_find(elementName.constData()); + + if (factory) { + m_codecs.append(codecName); + const gchar *descr = gst_element_factory_get_description(factory); + + if (codecName == QByteArray("audio/PCM")) + m_codecDescriptions.insert(codecName, tr("Raw PCM audio")); + else + m_codecDescriptions.insert(codecName, QString::fromUtf8(descr)); + + m_streamTypes.insert(codecName, + QGstreamerMediaContainerControl::supportedStreamTypes(factory, GST_PAD_SRC)); + + gst_object_unref(GST_OBJECT(factory)); + } + } + + //if (!m_codecs.isEmpty()) + // m_audioSettings.setCodec(m_codecs[0]); +} + +QGstreamerAudioEncode::~QGstreamerAudioEncode() +{ +} + +QStringList QGstreamerAudioEncode::supportedAudioCodecs() const +{ + return m_codecs; +} + +QString QGstreamerAudioEncode::codecDescription(const QString &codecName) const +{ + return m_codecDescriptions.value(codecName); +} + +QStringList QGstreamerAudioEncode::supportedEncodingOptions(const QString &codec) const +{ + return m_codecOptions.value(codec); +} + +QVariant QGstreamerAudioEncode::encodingOption( + const QString &codec, const QString &name) const +{ + return m_options[codec].value(name); +} + +void QGstreamerAudioEncode::setEncodingOption( + const QString &codec, const QString &name, const QVariant &value) +{ + m_options[codec][name] = value; +} + +QList QGstreamerAudioEncode::supportedSampleRates(const QAudioEncoderSettings &, bool *) const +{ + //TODO check element caps to find actual values + + return QList(); +} + +QAudioEncoderSettings QGstreamerAudioEncode::audioSettings() const +{ + return m_audioSettings; +} + +void QGstreamerAudioEncode::setAudioSettings(const QAudioEncoderSettings &settings) +{ + m_audioSettings = settings; +} + + +GstElement *QGstreamerAudioEncode::createEncoder() +{ + QString codec = m_audioSettings.codec(); + GstElement *encoderElement = gst_element_factory_make(m_elementNames.value(codec).constData(), NULL); + if (!encoderElement) + return 0; + + GstBin * encoderBin = GST_BIN(gst_bin_new("audio-encoder-bin")); + + GstElement *capsFilter = gst_element_factory_make("capsfilter", NULL); + + gst_bin_add(encoderBin, capsFilter); + gst_bin_add(encoderBin, encoderElement); + gst_element_link(capsFilter, encoderElement); + + // add ghostpads + GstPad *pad = gst_element_get_static_pad(capsFilter, "sink"); + gst_element_add_pad(GST_ELEMENT(encoderBin), gst_ghost_pad_new("sink", pad)); + gst_object_unref(GST_OBJECT(pad)); + + pad = gst_element_get_static_pad(encoderElement, "src"); + gst_element_add_pad(GST_ELEMENT(encoderBin), gst_ghost_pad_new("src", pad)); + gst_object_unref(GST_OBJECT(pad)); + + if (m_audioSettings.sampleRate() > 0 || m_audioSettings.channelCount() > 0) { + GstCaps *caps = gst_caps_new_empty(); + GstStructure *structure = gst_structure_new("audio/x-raw-int", NULL); + + if (m_audioSettings.sampleRate() > 0) + gst_structure_set(structure, "rate", G_TYPE_INT, m_audioSettings.sampleRate(), NULL ); + + if (m_audioSettings.channelCount() > 0) + gst_structure_set(structure, "channels", G_TYPE_INT, m_audioSettings.channelCount(), NULL ); + + gst_caps_append_structure(caps,structure); + + //qDebug() << "set caps filter:" << gst_caps_to_string(caps); + + g_object_set(G_OBJECT(capsFilter), "caps", caps, NULL); + } + + if (encoderElement) { + if (m_audioSettings.encodingMode() == QtMultimediaKit::ConstantQualityEncoding) { + QtMultimediaKit::EncodingQuality qualityValue = m_audioSettings.quality(); + + if (codec == QLatin1String("audio/vorbis")) { + double qualityTable[] = { + 0.1, //VeryLow + 0.3, //Low + 0.5, //Normal + 0.7, //High + 1.0 //VeryHigh + }; + g_object_set(G_OBJECT(encoderElement), "quality", qualityTable[qualityValue], NULL); + } else if (codec == QLatin1String("audio/mpeg")) { + g_object_set(G_OBJECT(encoderElement), "target", 0, NULL); //constant quality mode + qreal quality[] = { + 1, //VeryLow + 3, //Low + 5, //Normal + 7, //High + 9 //VeryHigh + }; + g_object_set(G_OBJECT(encoderElement), "quality", quality[qualityValue], NULL); + } else if (codec == QLatin1String("audio/speex")) { + //0-10 range with default 8 + double qualityTable[] = { + 2, //VeryLow + 5, //Low + 8, //Normal + 9, //High + 10 //VeryHigh + }; + g_object_set(G_OBJECT(encoderElement), "quality", qualityTable[qualityValue], NULL); + } else if (codec.startsWith("audio/AMR")) { + int band[] = { + 0, //VeryLow + 2, //Low + 4, //Normal + 6, //High + 7 //VeryHigh + }; + + g_object_set(G_OBJECT(encoderElement), "band-mode", band[qualityValue], NULL); + } + } else { + int bitrate = m_audioSettings.bitRate(); + if (bitrate > 0) { + if (codec == QLatin1String("audio/mpeg")) { + g_object_set(G_OBJECT(encoderElement), "target", 1, NULL); //constant bitrate mode + } + g_object_set(G_OBJECT(encoderElement), "bitrate", bitrate, NULL); + } + } + + QMap options = m_options.value(codec); + QMapIterator it(options); + while (it.hasNext()) { + it.next(); + QString option = it.key(); + QVariant value = it.value(); + + switch (value.type()) { + case QVariant::Int: + g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toInt(), NULL); + break; + case QVariant::Bool: + g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toBool(), NULL); + break; + case QVariant::Double: + g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toDouble(), NULL); + break; + case QVariant::String: + g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toString().toUtf8().constData(), NULL); + break; + default: + qWarning() << "unsupported option type:" << option << value; + break; + } + + } + } + + return GST_ELEMENT(encoderBin); +} + + +QSet QGstreamerAudioEncode::supportedStreamTypes(const QString &codecName) const +{ + return m_streamTypes.value(codecName); +} diff --git a/src/plugins/gstreamer/mediacapture/qgstreameraudioencode.h b/src/plugins/gstreamer/mediacapture/qgstreameraudioencode.h new file mode 100644 index 000000000..e2c48234d --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreameraudioencode.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERAUDIOENCODE_H +#define QGSTREAMERAUDIOENCODE_H + +#include +class QGstreamerCaptureSession; + +#include +#include +#include + +#include + +#include + +QT_USE_NAMESPACE + +class QGstreamerAudioEncode : public QAudioEncoderControl +{ + Q_OBJECT +public: + QGstreamerAudioEncode(QObject *parent); + virtual ~QGstreamerAudioEncode(); + + QStringList supportedAudioCodecs() const; + QString codecDescription(const QString &codecName) const; + + QStringList supportedEncodingOptions(const QString &codec) const; + QVariant encodingOption(const QString &codec, const QString &name) const; + void setEncodingOption(const QString &codec, const QString &name, const QVariant &value); + + QList supportedSampleRates(const QAudioEncoderSettings &settings = QAudioEncoderSettings(), + bool *isContinuous = 0) const; + QList supportedChannelCounts(const QAudioEncoderSettings &settings = QAudioEncoderSettings()) const; + QList supportedSampleSizes(const QAudioEncoderSettings &settings = QAudioEncoderSettings()) const; + + QAudioEncoderSettings audioSettings() const; + void setAudioSettings(const QAudioEncoderSettings&); + + GstElement *createEncoder(); + + QSet supportedStreamTypes(const QString &codecName) const; + +private: + QStringList m_codecs; + QMap m_elementNames; + QMap m_codecDescriptions; + QMap m_codecOptions; + + QMap > m_options; + + QMap > m_streamTypes; + + QAudioEncoderSettings m_audioSettings; +}; + +#endif diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercameracontrol.cpp b/src/plugins/gstreamer/mediacapture/qgstreamercameracontrol.cpp new file mode 100644 index 000000000..927a827dd --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamercameracontrol.cpp @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamercameracontrol.h" +#include "qgstreamerimageencode.h" + +#include +#include + + +QGstreamerCameraControl::QGstreamerCameraControl(QGstreamerCaptureSession *session) + :QCameraControl(session), + m_captureMode(QCamera::CaptureStillImage), + m_session(session), + m_state(QCamera::UnloadedState), + m_status(QCamera::UnloadedStatus), + m_reloadPending(false) + +{ + connect(m_session, SIGNAL(stateChanged(QGstreamerCaptureSession::State)), + this, SLOT(updateStatus())); + + connect(m_session->imageEncodeControl(), SIGNAL(settingsChanged()), + SLOT(reloadLater())); + connect(m_session, SIGNAL(viewfinderChanged()), + SLOT(reloadLater())); + connect(m_session, SIGNAL(readyChanged(bool)), + SLOT(reloadLater())); +} + +QGstreamerCameraControl::~QGstreamerCameraControl() +{ +} + +void QGstreamerCameraControl::setCaptureMode(QCamera::CaptureMode mode) +{ + if (m_captureMode == mode) + return; + + switch (mode) { + case QCamera::CaptureStillImage: + m_session->setCaptureMode(QGstreamerCaptureSession::Image); + break; + case QCamera::CaptureVideo: + m_session->setCaptureMode(QGstreamerCaptureSession::AudioAndVideo); + break; + } + + emit captureModeChanged(mode); + updateStatus(); + reloadLater(); +} + +void QGstreamerCameraControl::setState(QCamera::State state) +{ + if (m_state == state) + return; + + m_state = state; + switch (state) { + case QCamera::UnloadedState: + case QCamera::LoadedState: + m_session->setState(QGstreamerCaptureSession::StoppedState); + break; + case QCamera::ActiveState: + //postpone changing to Active if the session is nor ready yet + if (m_session->isReady()) { + m_session->setState(QGstreamerCaptureSession::PreviewState); + } else { +#ifdef CAMEABIN_DEBUG + qDebug() << "Camera session is not ready yet, postpone activating"; +#endif + } + break; + default: + emit error(QCamera::NotSupportedFeatureError, tr("State not supported.")); + } + + updateStatus(); + emit stateChanged(m_state); +} + +QCamera::State QGstreamerCameraControl::state() const +{ + return m_state; +} + +void QGstreamerCameraControl::updateStatus() +{ + QCamera::Status oldStatus = m_status; + + switch (m_state) { + case QCamera::UnloadedState: + m_status = QCamera::UnloadedStatus; + break; + case QCamera::LoadedState: + m_status = QCamera::LoadedStatus; + break; + case QCamera::ActiveState: + if (m_session->state() == QGstreamerCaptureSession::StoppedState) + m_status = QCamera::StartingStatus; + else + m_status = QCamera::ActiveStatus; + break; + } + + if (oldStatus != m_status) { + //qDebug() << "Status changed:" << m_status; + emit statusChanged(m_status); + } +} + +void QGstreamerCameraControl::reloadLater() +{ + //qDebug() << "reload pipeline requested"; + if (!m_reloadPending && m_state == QCamera::ActiveState) { + m_reloadPending = true; + m_session->setState(QGstreamerCaptureSession::StoppedState); + QMetaObject::invokeMethod(this, "reloadPipeline", Qt::QueuedConnection); + } +} + +void QGstreamerCameraControl::reloadPipeline() +{ + //qDebug() << "reload pipeline"; + if (m_reloadPending) { + m_reloadPending = false; + if (m_state == QCamera::ActiveState && m_session->isReady()) { + m_session->setState(QGstreamerCaptureSession::PreviewState); + } + } +} + +bool QGstreamerCameraControl::canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const +{ + Q_UNUSED(status); + + switch (changeType) { + case QCameraControl::CaptureMode: + case QCameraControl::ImageEncodingSettings: + case QCameraControl::VideoEncodingSettings: + case QCameraControl::Viewfinder: + return true; + default: + return false; + } +} diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercameracontrol.h b/src/plugins/gstreamer/mediacapture/qgstreamercameracontrol.h new file mode 100644 index 000000000..c07ffcd19 --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamercameracontrol.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QGSTREAMERCAMERACONTROL_H +#define QGSTREAMERCAMERACONTROL_H + +#include +#include +#include "qgstreamercapturesession.h" + +QT_USE_NAMESPACE +QT_USE_NAMESPACE + +class QGstreamerCameraControl : public QCameraControl +{ + Q_OBJECT +public: + QGstreamerCameraControl( QGstreamerCaptureSession *session ); + virtual ~QGstreamerCameraControl(); + + bool isValid() const { return true; } + + QCamera::State state() const; + void setState(QCamera::State state); + + QCamera::Status status() const { return m_status; } + + QCamera::CaptureMode captureMode() const { return m_captureMode; } + void setCaptureMode(QCamera::CaptureMode mode); + + bool isCaptureModeSupported(QCamera::CaptureMode mode) const + { + return mode == QCamera::CaptureStillImage || mode == QCamera::CaptureVideo; + } + + QCamera::LockTypes supportedLocks() const + { + return QCamera::NoLock; + } + + bool canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const; + +public slots: + void reloadLater(); + +private slots: + void updateStatus(); + void reloadPipeline(); + + +private: + QCamera::CaptureMode m_captureMode; + QGstreamerCaptureSession *m_session; + QCamera::State m_state; + QCamera::Status m_status; + bool m_reloadPending; +}; + +#endif // QGSTREAMERCAMERACONTROL_H diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercapturemetadatacontrol.cpp b/src/plugins/gstreamer/mediacapture/qgstreamercapturemetadatacontrol.cpp new file mode 100644 index 000000000..b0e589dc8 --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamercapturemetadatacontrol.cpp @@ -0,0 +1,198 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamercapturemetadatacontrol.h" + +#include +#include + +struct QGstreamerMetaDataKeyLookup +{ + QtMultimediaKit::MetaData key; + const char *token; +}; + +static const QGstreamerMetaDataKeyLookup qt_gstreamerMetaDataKeys[] = +{ + { QtMultimediaKit::Title, GST_TAG_TITLE }, + //{ QtMultimediaKit::SubTitle, 0 }, + //{ QtMultimediaKit::Author, 0 }, + { QtMultimediaKit::Comment, GST_TAG_COMMENT }, + { QtMultimediaKit::Description, GST_TAG_DESCRIPTION }, + //{ QtMultimediaKit::Category, 0 }, + { QtMultimediaKit::Genre, GST_TAG_GENRE }, + //{ QtMultimediaKit::Year, 0 }, + //{ QtMultimediaKit::UserRating, 0 }, + + { QtMultimediaKit::Language, GST_TAG_LANGUAGE_CODE }, + + { QtMultimediaKit::Publisher, GST_TAG_ORGANIZATION }, + { QtMultimediaKit::Copyright, GST_TAG_COPYRIGHT }, + //{ QtMultimediaKit::ParentalRating, 0 }, + //{ QtMultimediaKit::RatingOrganisation, 0 }, + + // Media + //{ QtMultimediaKit::Size, 0 }, + //{ QtMultimediaKit::MediaType, 0 }, + { QtMultimediaKit::Duration, GST_TAG_DURATION }, + + // Audio + { QtMultimediaKit::AudioBitRate, GST_TAG_BITRATE }, + { QtMultimediaKit::AudioCodec, GST_TAG_AUDIO_CODEC }, + //{ QtMultimediaKit::ChannelCount, 0 }, + //{ QtMultimediaKit::SampleRate, 0 }, + + // Music + { QtMultimediaKit::AlbumTitle, GST_TAG_ALBUM }, + { QtMultimediaKit::AlbumArtist, GST_TAG_ARTIST}, + { QtMultimediaKit::ContributingArtist, GST_TAG_PERFORMER }, +#if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 19) + { QtMultimediaKit::Composer, GST_TAG_COMPOSER }, +#endif + //{ QtMultimediaKit::Conductor, 0 }, + //{ QtMultimediaKit::Lyrics, 0 }, + //{ QtMultimediaKit::Mood, 0 }, + { QtMultimediaKit::TrackNumber, GST_TAG_TRACK_NUMBER }, + + //{ QtMultimediaKit::CoverArtUrlSmall, 0 }, + //{ QtMultimediaKit::CoverArtUrlLarge, 0 }, + + // Image/Video + //{ QtMultimediaKit::Resolution, 0 }, + //{ QtMultimediaKit::PixelAspectRatio, 0 }, + + // Video + //{ QtMultimediaKit::VideoFrameRate, 0 }, + //{ QtMultimediaKit::VideoBitRate, 0 }, + { QtMultimediaKit::VideoCodec, GST_TAG_VIDEO_CODEC }, + + //{ QtMultimediaKit::PosterUrl, 0 }, + + // Movie + //{ QtMultimediaKit::ChapterNumber, 0 }, + //{ QtMultimediaKit::Director, 0 }, + { QtMultimediaKit::LeadPerformer, GST_TAG_PERFORMER }, + //{ QtMultimediaKit::Writer, 0 }, + + // Photos + //{ QtMultimediaKit::CameraManufacturer, 0 }, + //{ QtMultimediaKit::CameraModel, 0 }, + //{ QtMultimediaKit::Event, 0 }, + //{ QtMultimediaKit::Subject, 0 } +}; + +QGstreamerCaptureMetaDataControl::QGstreamerCaptureMetaDataControl(QObject *parent) + :QMetaDataWriterControl(parent) +{ +} + +QVariant QGstreamerCaptureMetaDataControl::metaData(QtMultimediaKit::MetaData key) const +{ + static const int count = sizeof(qt_gstreamerMetaDataKeys) / sizeof(QGstreamerMetaDataKeyLookup); + + for (int i = 0; i < count; ++i) { + if (qt_gstreamerMetaDataKeys[i].key == key) { + const char *name = qt_gstreamerMetaDataKeys[i].token; + + return m_values.value(QByteArray::fromRawData(name, qstrlen(name))); + } + } + return QVariant(); +} + +void QGstreamerCaptureMetaDataControl::setMetaData(QtMultimediaKit::MetaData key, const QVariant &value) +{ + static const int count = sizeof(qt_gstreamerMetaDataKeys) / sizeof(QGstreamerMetaDataKeyLookup); + + for (int i = 0; i < count; ++i) { + if (qt_gstreamerMetaDataKeys[i].key == key) { + const char *name = qt_gstreamerMetaDataKeys[i].token; + + m_values.insert(QByteArray::fromRawData(name, qstrlen(name)), value); + + emit QMetaDataWriterControl::metaDataChanged(); + emit metaDataChanged(m_values); + + return; + } + } +} + +QList QGstreamerCaptureMetaDataControl::availableMetaData() const +{ + static QMap keysMap; + if (keysMap.isEmpty()) { + const int count = sizeof(qt_gstreamerMetaDataKeys) / sizeof(QGstreamerMetaDataKeyLookup); + for (int i = 0; i < count; ++i) { + keysMap[QByteArray(qt_gstreamerMetaDataKeys[i].token)] = qt_gstreamerMetaDataKeys[i].key; + } + } + + QList res; + foreach (const QByteArray &key, m_values.keys()) { + QtMultimediaKit::MetaData tag = keysMap.value(key, QtMultimediaKit::MetaData(-1)); + if (tag != -1) + res.append(tag); + } + + return res; +} + +QVariant QGstreamerCaptureMetaDataControl::extendedMetaData(QString const &name) const +{ + return m_values.value(name.toLatin1()); +} + +void QGstreamerCaptureMetaDataControl::setExtendedMetaData(QString const &name, QVariant const &value) +{ + m_values.insert(name.toLatin1(), value); + emit QMetaDataWriterControl::metaDataChanged(); + emit metaDataChanged(m_values); +} + +QStringList QGstreamerCaptureMetaDataControl::availableExtendedMetaData() const +{ + QStringList res; + foreach (const QByteArray &key, m_values.keys()) + res.append(QString(key)); + + return res; +} diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercapturemetadatacontrol.h b/src/plugins/gstreamer/mediacapture/qgstreamercapturemetadatacontrol.h new file mode 100644 index 000000000..e859da486 --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamercapturemetadatacontrol.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERCAPTUREMETADATACONTROL_H +#define QGSTREAMERCAPTUREMETADATACONTROL_H + +#include + +QT_USE_NAMESPACE + +class QGstreamerCaptureMetaDataControl : public QMetaDataWriterControl +{ + Q_OBJECT +public: + QGstreamerCaptureMetaDataControl(QObject *parent); + virtual ~QGstreamerCaptureMetaDataControl() {}; + + + bool isMetaDataAvailable() const { return true; } + bool isWritable() const { return true; } + + QVariant metaData(QtMultimediaKit::MetaData key) const; + void setMetaData(QtMultimediaKit::MetaData key, const QVariant &value); + QList availableMetaData() const; + + QVariant extendedMetaData(QString const &name) const; + void setExtendedMetaData(QString const &name, QVariant const &value); + QStringList availableExtendedMetaData() const; + +Q_SIGNALS: + void metaDataChanged(const QMap&); + +private: + QMap m_values; +}; + +#endif // QGSTREAMERCAPTUREMETADATACONTROL_H diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.cpp b/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.cpp new file mode 100644 index 000000000..97310d199 --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.cpp @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamercaptureservice.h" +#include "qgstreamercapturesession.h" +#include "qgstreamerrecordercontrol.h" +#include "qgstreamermediacontainercontrol.h" +#include "qgstreameraudioencode.h" +#include "qgstreamervideoencode.h" +#include "qgstreamerimageencode.h" +#include "qgstreamerbushelper.h" +#include "qgstreamercameracontrol.h" +#include "qgstreamerv4l2input.h" +#include "qgstreamercapturemetadatacontrol.h" + +#include "qgstreameraudioinputendpointselector.h" +#include "qgstreamervideoinputdevicecontrol.h" +#include "qgstreamerimagecapturecontrol.h" + +#include "qgstreamervideooverlay.h" +#include "qgstreamervideorenderer.h" + +#include "qgstreamervideowidget.h" + +#include + + +QGstreamerCaptureService::QGstreamerCaptureService(const QString &service, QObject *parent): + QMediaService(parent) +{ + m_captureSession = 0; + m_cameraControl = 0; + m_metaDataControl = 0; + + m_videoInput = 0; + m_audioInputEndpointSelector = 0; + m_videoInputDevice = 0; + + m_videoOutput = 0; + m_videoRenderer = 0; + m_videoWindow = 0; + m_videoWidgetControl = 0; + m_imageCaptureControl = 0; + + if (service == Q_MEDIASERVICE_AUDIOSOURCE) { + m_captureSession = new QGstreamerCaptureSession(QGstreamerCaptureSession::Audio, this); + } + + if (service == Q_MEDIASERVICE_CAMERA) { + m_captureSession = new QGstreamerCaptureSession(QGstreamerCaptureSession::AudioAndVideo, this); + m_cameraControl = new QGstreamerCameraControl(m_captureSession); + m_videoInput = new QGstreamerV4L2Input(this); + m_captureSession->setVideoInput(m_videoInput); + m_videoInputDevice = new QGstreamerVideoInputDeviceControl(this); + + connect(m_videoInputDevice, SIGNAL(selectedDeviceChanged(QString)), + m_videoInput, SLOT(setDevice(QString))); + + if (m_videoInputDevice->deviceCount()) + m_videoInput->setDevice(m_videoInputDevice->deviceName(m_videoInputDevice->selectedDevice())); + + m_videoRenderer = new QGstreamerVideoRenderer(this); + +#if defined(Q_WS_X11) && !defined(QT_NO_XVIDEO) + m_videoWindow = new QGstreamerVideoOverlay(this); + m_videoWidgetControl = new QGstreamerVideoWidgetControl(this); +#endif + m_imageCaptureControl = new QGstreamerImageCaptureControl(m_captureSession); + } + + m_audioInputEndpointSelector = new QGstreamerAudioInputEndpointSelector(this); + connect(m_audioInputEndpointSelector, SIGNAL(activeEndpointChanged(QString)), m_captureSession, SLOT(setCaptureDevice(QString))); + + if (m_captureSession && m_audioInputEndpointSelector->availableEndpoints().size() > 0) + m_captureSession->setCaptureDevice(m_audioInputEndpointSelector->defaultEndpoint()); + + m_metaDataControl = new QGstreamerCaptureMetaDataControl(this); + connect(m_metaDataControl, SIGNAL(metaDataChanged(QMap)), + m_captureSession, SLOT(setMetaData(QMap))); +} + +QGstreamerCaptureService::~QGstreamerCaptureService() +{ +} + +QMediaControl *QGstreamerCaptureService::requestControl(const char *name) +{ + if (!m_captureSession) + return 0; + + if (qstrcmp(name,QAudioEndpointSelector_iid) == 0) + return m_audioInputEndpointSelector; + + if (qstrcmp(name,QVideoDeviceControl_iid) == 0) + return m_videoInputDevice; + + if (qstrcmp(name,QMediaRecorderControl_iid) == 0) + return m_captureSession->recorderControl(); + + if (qstrcmp(name,QAudioEncoderControl_iid) == 0) + return m_captureSession->audioEncodeControl(); + + if (qstrcmp(name,QVideoEncoderControl_iid) == 0) + return m_captureSession->videoEncodeControl(); + + if (qstrcmp(name,QImageEncoderControl_iid) == 0) + return m_captureSession->imageEncodeControl(); + + + if (qstrcmp(name,QMediaContainerControl_iid) == 0) + return m_captureSession->mediaContainerControl(); + + if (qstrcmp(name,QCameraControl_iid) == 0) + return m_cameraControl; + + if (qstrcmp(name,QMetaDataWriterControl_iid) == 0) + return m_metaDataControl; + + if (qstrcmp(name, QCameraImageCaptureControl_iid) == 0) + return m_imageCaptureControl; + + if (!m_videoOutput) { + if (qstrcmp(name, QVideoRendererControl_iid) == 0) { + m_videoOutput = m_videoRenderer; + m_captureSession->setVideoPreview(m_videoRenderer); + } else if (qstrcmp(name, QVideoWindowControl_iid) == 0) { + m_videoOutput = m_videoWindow; + m_captureSession->setVideoPreview(m_videoWindow); + } else if (qstrcmp(name, QVideoWidgetControl_iid) == 0) { + m_captureSession->setVideoPreview(m_videoWidgetControl); + m_videoOutput = m_videoWidgetControl; + } + + if (m_videoOutput) + return m_videoOutput; + } + + return 0; +} + +void QGstreamerCaptureService::releaseControl(QMediaControl *control) +{ + if (control && control == m_videoOutput) { + m_videoOutput = 0; + m_captureSession->setVideoPreview(0); + } +} diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.h b/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.h new file mode 100644 index 000000000..09b275c35 --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERCAPTURESERVICE_H +#define QGSTREAMERCAPTURESERVICE_H + +#include +#include + +#include +QT_BEGIN_NAMESPACE +class QAudioEndpointSelector; +class QVideoDeviceControl; +QT_END_NAMESPACE + +class QGstreamerCaptureSession; +class QGstreamerCameraControl; +class QGstreamerMessage; +class QGstreamerBusHelper; +class QGstreamerVideoRenderer; +class QGstreamerVideoOverlay; +class QGstreamerVideoWidgetControl; +class QGstreamerElementFactory; +class QGstreamerCaptureMetaDataControl; +class QGstreamerImageCaptureControl; +class QGstreamerV4L2Input; + +class QGstreamerCaptureService : public QMediaService +{ + Q_OBJECT + +public: + QGstreamerCaptureService(const QString &service, QObject *parent = 0); + virtual ~QGstreamerCaptureService(); + + QMediaControl *requestControl(const char *name); + void releaseControl(QMediaControl *); + +private: + void setAudioPreview(GstElement*); + + QGstreamerCaptureSession *m_captureSession; + QGstreamerCameraControl *m_cameraControl; + QGstreamerV4L2Input *m_videoInput; + QGstreamerCaptureMetaDataControl *m_metaDataControl; + + QAudioEndpointSelector *m_audioInputEndpointSelector; + QVideoDeviceControl *m_videoInputDevice; + + QMediaControl *m_videoOutput; + + QGstreamerVideoRenderer *m_videoRenderer; + QMediaControl *m_videoWindow; + QMediaControl *m_videoWidgetControl; + QGstreamerImageCaptureControl *m_imageCaptureControl; +}; + +#endif // QGSTREAMERCAPTURESERVICE_H diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp b/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp new file mode 100644 index 000000000..f8e73c7af --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp @@ -0,0 +1,1051 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamercapturesession.h" +#include "qgstreamerrecordercontrol.h" +#include "qgstreamermediacontainercontrol.h" +#include "qgstreamervideorendererinterface.h" +#include "qgstreameraudioencode.h" +#include "qgstreamervideoencode.h" +#include "qgstreamerimageencode.h" +#include "qgstreamerbushelper.h" +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#define gstRef(element) { gst_object_ref(GST_OBJECT(element)); gst_object_sink(GST_OBJECT(element)); } +#define gstUnref(element) { if (element) { gst_object_unref(GST_OBJECT(element)); element = 0; } } + +QGstreamerCaptureSession::QGstreamerCaptureSession(QGstreamerCaptureSession::CaptureMode captureMode, QObject *parent) + :QObject(parent), + m_state(StoppedState), + m_pendingState(StoppedState), + m_waitingForEos(false), + m_pipelineMode(EmptyPipeline), + m_captureMode(captureMode), + m_audioInputFactory(0), + m_audioPreviewFactory(0), + m_videoInputFactory(0), + m_viewfinder(0), + m_viewfinderInterface(0), + m_audioSrc(0), + m_audioTee(0), + m_audioPreviewQueue(0), + m_audioPreview(0), + m_audioVolume(0), + m_muted(false), + m_videoSrc(0), + m_videoTee(0), + m_videoPreviewQueue(0), + m_videoPreview(0), + m_imageCaptureBin(0), + m_encodeBin(0), + m_passImage(false), + m_passPrerollImage(false) +{ + m_pipeline = gst_pipeline_new("media-capture-pipeline"); + gstRef(m_pipeline); + + m_bus = gst_element_get_bus(m_pipeline); + m_busHelper = new QGstreamerBusHelper(m_bus, this); + m_busHelper->installSyncEventFilter(this); + connect(m_busHelper, SIGNAL(message(QGstreamerMessage)), SLOT(busMessage(QGstreamerMessage))); + m_audioEncodeControl = new QGstreamerAudioEncode(this); + m_videoEncodeControl = new QGstreamerVideoEncode(this); + m_imageEncodeControl = new QGstreamerImageEncode(this); + m_recorderControl = new QGstreamerRecorderControl(this); + m_mediaContainerControl = new QGstreamerMediaContainerControl(this); + + setState(StoppedState); +} + +QGstreamerCaptureSession::~QGstreamerCaptureSession() +{ + setState(StoppedState); + gst_element_set_state(m_pipeline, GST_STATE_NULL); + gst_object_unref(GST_OBJECT(m_pipeline)); +} + +void QGstreamerCaptureSession::setCaptureMode(CaptureMode mode) +{ + m_captureMode = mode; +} + +GstElement *QGstreamerCaptureSession::buildEncodeBin() +{ + GstElement *encodeBin = gst_bin_new("encode-bin"); + + GstElement *muxer = gst_element_factory_make( m_mediaContainerControl->formatElementName().constData(), "muxer"); + if (!muxer) { + qWarning() << "Could not create a media muxer element:" << m_mediaContainerControl->formatElementName(); + gst_object_unref(encodeBin); + return 0; + } + + GstElement *fileSink = gst_element_factory_make("filesink", "filesink"); + g_object_set(G_OBJECT(fileSink), "location", m_sink.toString().toLocal8Bit().constData(), NULL); + gst_bin_add_many(GST_BIN(encodeBin), muxer, fileSink, NULL); + + if (!gst_element_link(muxer, fileSink)) { + gst_object_unref(encodeBin); + return 0; + } + + if (m_captureMode & Audio) { + GstElement *audioConvert = gst_element_factory_make("audioconvert", "audioconvert"); + GstElement *audioQueue = gst_element_factory_make("queue", "audio-encode-queue"); + m_audioVolume = gst_element_factory_make("volume", "volume"); + gst_bin_add_many(GST_BIN(encodeBin), audioConvert, audioQueue, m_audioVolume, NULL); + + GstElement *audioEncoder = m_audioEncodeControl->createEncoder(); + if (!audioEncoder) { + gst_object_unref(encodeBin); + qWarning() << "Could not create an audio encoder element:" << m_audioEncodeControl->audioSettings().codec(); + return 0; + } + + gst_bin_add(GST_BIN(encodeBin), audioEncoder); + + if (!gst_element_link_many(audioConvert, audioQueue, m_audioVolume, audioEncoder, muxer, NULL)) { + gst_object_unref(encodeBin); + return 0; + } + + g_object_set(G_OBJECT(m_audioVolume), "volume", (m_muted ? 0.0 : 1.0), NULL); + + // add ghostpads + GstPad *pad = gst_element_get_static_pad(audioConvert, "sink"); + gst_element_add_pad(GST_ELEMENT(encodeBin), gst_ghost_pad_new("audiosink", pad)); + gst_object_unref(GST_OBJECT(pad)); + } + + if (m_captureMode & Video) { + GstElement *videoQueue = gst_element_factory_make("queue", "video-encode-queue"); + GstElement *colorspace = gst_element_factory_make("ffmpegcolorspace", "ffmpegcolorspace-encoder"); + GstElement *videoscale = gst_element_factory_make("videoscale","videoscale-encoder"); + gst_bin_add_many(GST_BIN(encodeBin), videoQueue, colorspace, videoscale, NULL); + + GstElement *videoEncoder = m_videoEncodeControl->createEncoder(); + if (!videoEncoder) { + gst_object_unref(encodeBin); + qWarning() << "Could not create a video encoder element:" << m_videoEncodeControl->videoSettings().codec(); + return 0; + } + + gst_bin_add(GST_BIN(encodeBin), videoEncoder); + + if (!gst_element_link_many(videoQueue, colorspace, videoscale, videoEncoder, muxer, NULL)) { + gst_object_unref(encodeBin); + return 0; + } + + // add ghostpads + GstPad *pad = gst_element_get_static_pad(videoQueue, "sink"); + gst_element_add_pad(GST_ELEMENT(encodeBin), gst_ghost_pad_new("videosink", pad)); + gst_object_unref(GST_OBJECT(pad)); + } + + return encodeBin; +} + +GstElement *QGstreamerCaptureSession::buildAudioSrc() +{ + GstElement *audioSrc = 0; + if (m_audioInputFactory) + audioSrc = m_audioInputFactory->buildElement(); + else { + +#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) + audioSrc = gst_element_factory_make("pulsesrc", "audio_src"); +#elif defined(QT_QWS_N810) + audioSrc = gst_element_factory_make("dsppcmsrc", "audio_src"); +#else + QString elementName = "alsasrc"; + QString device; + + if (m_captureDevice.startsWith("alsa:")) { + device = m_captureDevice.mid(QString("alsa:").length()); + } else if (m_captureDevice.startsWith("oss:")) { + elementName = "osssrc"; + device = m_captureDevice.mid(QString("oss:").length()); + } else if (m_captureDevice.startsWith("pulseaudio:")) { + elementName = "pulsesrc"; + } else { + elementName = "autoaudiosrc"; + } + + audioSrc = gst_element_factory_make(elementName.toAscii().constData(), "audio_src"); + if (audioSrc && !device.isEmpty()) + g_object_set(G_OBJECT(audioSrc), "device", device.toLocal8Bit().constData(), NULL); +#endif + } + + if (!audioSrc) { + emit error(int(QMediaRecorder::ResourceError), tr("Could not create an audio source element")); + audioSrc = gst_element_factory_make("fakesrc", NULL); + } + + return audioSrc; +} + +GstElement *QGstreamerCaptureSession::buildAudioPreview() +{ + GstElement *previewElement = 0; + + if (m_audioPreviewFactory) { + previewElement = m_audioPreviewFactory->buildElement(); + } else { + + +#if 1 + previewElement = gst_element_factory_make("fakesink", "audio-preview"); +#else + GstElement *bin = gst_bin_new("audio-preview-bin"); + GstElement *visual = gst_element_factory_make("libvisual_lv_scope", "audio-preview"); + GstElement *sink = gst_element_factory_make("ximagesink", NULL); + gst_bin_add_many(GST_BIN(bin), visual, sink, NULL); + gst_element_link_many(visual,sink, NULL); + + + // add ghostpads + GstPad *pad = gst_element_get_static_pad(visual, "sink"); + Q_ASSERT(pad); + gst_element_add_pad(GST_ELEMENT(bin), gst_ghost_pad_new("audiosink", pad)); + gst_object_unref(GST_OBJECT(pad)); + + previewElement = bin; +#endif + } + + return previewElement; +} + +GstElement *QGstreamerCaptureSession::buildVideoSrc() +{ + GstElement *videoSrc = 0; + if (m_videoInputFactory) { + videoSrc = m_videoInputFactory->buildElement(); + } else { + videoSrc = gst_element_factory_make("videotestsrc", "video_test_src"); + //videoSrc = gst_element_factory_make("v4l2src", "video_test_src"); + } + + return videoSrc; +} + +GstElement *QGstreamerCaptureSession::buildVideoPreview() +{ + GstElement *previewElement = 0; + + if (m_viewfinderInterface) { + GstElement *bin = gst_bin_new("video-preview-bin"); + GstElement *colorspace = gst_element_factory_make("ffmpegcolorspace", "ffmpegcolorspace-preview"); + GstElement *capsFilter = gst_element_factory_make("capsfilter", "capsfilter-video-preview"); + GstElement *preview = m_viewfinderInterface->videoSink(); + + gst_bin_add_many(GST_BIN(bin), colorspace, capsFilter, preview, NULL); + gst_element_link(colorspace,capsFilter); + gst_element_link(capsFilter,preview); + + QSize resolution; + qreal frameRate = 0; + + if (m_captureMode & Video) { + QVideoEncoderSettings videoSettings = m_videoEncodeControl->videoSettings(); + resolution = videoSettings.resolution(); + frameRate = videoSettings.frameRate(); + } else if (m_captureMode & Image) { + resolution = m_imageEncodeControl->imageSettings().resolution(); + } + + if (!resolution.isEmpty() || frameRate > 0.001) { + GstCaps *caps = gst_caps_new_empty(); + QStringList structureTypes; + structureTypes << "video/x-raw-yuv" << "video/x-raw-rgb"; + + foreach(const QString &structureType, structureTypes) { + GstStructure *structure = gst_structure_new(structureType.toAscii().constData(), NULL); + + if (!resolution.isEmpty()) { + gst_structure_set(structure, "width", G_TYPE_INT, resolution.width(), NULL); + gst_structure_set(structure, "height", G_TYPE_INT, resolution.height(), NULL); + } + + if (frameRate > 0.001) { + QPair rate = m_videoEncodeControl->rateAsRational(); + + //qDebug() << "frame rate:" << num << denum; + + gst_structure_set(structure, "framerate", GST_TYPE_FRACTION, rate.first, rate.second, NULL); + } + + gst_caps_append_structure(caps,structure); + } + + //qDebug() << "set video preview caps filter:" << gst_caps_to_string(caps); + + g_object_set(G_OBJECT(capsFilter), "caps", caps, NULL); + + } + + // add ghostpads + GstPad *pad = gst_element_get_static_pad(colorspace, "sink"); + Q_ASSERT(pad); + gst_element_add_pad(GST_ELEMENT(bin), gst_ghost_pad_new("videosink", pad)); + gst_object_unref(GST_OBJECT(pad)); + + previewElement = bin; + } else { +#if 1 + previewElement = gst_element_factory_make("fakesink", "video-preview"); +#else + GstElement *bin = gst_bin_new("video-preview-bin"); + GstElement *colorspace = gst_element_factory_make("ffmpegcolorspace", "ffmpegcolorspace-preview"); + GstElement *preview = gst_element_factory_make("ximagesink", "video-preview"); + gst_bin_add_many(GST_BIN(bin), colorspace, preview, NULL); + gst_element_link(colorspace,preview); + + // add ghostpads + GstPad *pad = gst_element_get_static_pad(colorspace, "sink"); + Q_ASSERT(pad); + gst_element_add_pad(GST_ELEMENT(bin), gst_ghost_pad_new("videosink", pad)); + gst_object_unref(GST_OBJECT(pad)); + + previewElement = bin; +#endif + } + + return previewElement; +} + + +static gboolean passImageFilter(GstElement *element, + GstBuffer *buffer, + void *appdata) +{ + Q_UNUSED(element); + Q_UNUSED(buffer); + + QGstreamerCaptureSession *session = (QGstreamerCaptureSession *)appdata; + if (session->m_passImage || session->m_passPrerollImage) { + session->m_passImage = false; + + if (session->m_passPrerollImage) { + session->m_passPrerollImage = false; + return TRUE; + } + session->m_passPrerollImage = false; + + QImage img; + + GstCaps *caps = gst_buffer_get_caps(buffer); + if (caps) { + GstStructure *structure = gst_caps_get_structure (caps, 0); + gint width = 0; + gint height = 0; + + if (structure && + gst_structure_get_int(structure, "width", &width) && + gst_structure_get_int(structure, "height", &height) && + width > 0 && height > 0) { + if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-yuv") == 0) { + guint32 fourcc = 0; + gst_structure_get_fourcc(structure, "format", &fourcc); + + if (fourcc == GST_MAKE_FOURCC('I','4','2','0')) { + img = QImage(width/2, height/2, QImage::Format_RGB32); + + const uchar *data = (const uchar *)buffer->data; + + for (int y=0; ydata, + width, + height, + format); + img.bits(); //detach + } + } + } + gst_caps_unref(caps); + } + + static int exposedSignalIndex = session->metaObject()->indexOfSignal("imageExposed(int)"); + session->metaObject()->method(exposedSignalIndex).invoke(session, + Qt::QueuedConnection, + Q_ARG(int,session->m_imageRequestId)); + + static int capturedSignalIndex = session->metaObject()->indexOfSignal("imageCaptured(int,QImage)"); + session->metaObject()->method(capturedSignalIndex).invoke(session, + Qt::QueuedConnection, + Q_ARG(int,session->m_imageRequestId), + Q_ARG(QImage,img)); + + return TRUE; + } else { + return FALSE; + } +} + +static gboolean saveImageFilter(GstElement *element, + GstBuffer *buffer, + GstPad *pad, + void *appdata) +{ + Q_UNUSED(element); + Q_UNUSED(pad); + QGstreamerCaptureSession *session = (QGstreamerCaptureSession *)appdata; + + QString fileName = session->m_imageFileName; + + if (!fileName.isEmpty()) { + QFile f(fileName); + if (f.open(QFile::WriteOnly)) { + f.write((const char *)buffer->data, buffer->size); + f.close(); + + static int signalIndex = session->metaObject()->indexOfSignal("imageSaved(int,QString)"); + session->metaObject()->method(signalIndex).invoke(session, + Qt::QueuedConnection, + Q_ARG(int,session->m_imageRequestId), + Q_ARG(QString,fileName)); + } + } + + return TRUE; +} + +GstElement *QGstreamerCaptureSession::buildImageCapture() +{ + GstElement *bin = gst_bin_new("image-capture-bin"); + GstElement *queue = gst_element_factory_make("queue", "queue-image-capture"); + GstElement *colorspace = gst_element_factory_make("ffmpegcolorspace", "ffmpegcolorspace-image-capture"); + GstElement *encoder = gst_element_factory_make("jpegenc", "image-encoder"); + GstElement *sink = gst_element_factory_make("fakesink","sink-image-capture"); + + GstPad *pad = gst_element_get_static_pad(queue, "src"); + Q_ASSERT(pad); + gst_pad_add_buffer_probe(pad, G_CALLBACK(passImageFilter), this); + + g_object_set(G_OBJECT(sink), "signal-handoffs", TRUE, NULL); + g_signal_connect(G_OBJECT(sink), "handoff", + G_CALLBACK(saveImageFilter), this); + + gst_bin_add_many(GST_BIN(bin), queue, colorspace, encoder, sink, NULL); + gst_element_link_many(queue, colorspace, encoder, sink, NULL); + + // add ghostpads + pad = gst_element_get_static_pad(queue, "sink"); + Q_ASSERT(pad); + gst_element_add_pad(GST_ELEMENT(bin), gst_ghost_pad_new("imagesink", pad)); + gst_object_unref(GST_OBJECT(pad)); + + m_passImage = false; + m_passPrerollImage = true; + m_imageFileName = QString(); + + return bin; +} + +void QGstreamerCaptureSession::captureImage(int requestId, const QString &fileName) +{ + m_imageRequestId = requestId; + m_imageFileName = fileName; + m_passImage = true; +} + + +#define REMOVE_ELEMENT(element) { if (element) {gst_bin_remove(GST_BIN(m_pipeline), element); element = 0;} } + +bool QGstreamerCaptureSession::rebuildGraph(QGstreamerCaptureSession::PipelineMode newMode) +{ + REMOVE_ELEMENT(m_audioSrc); + REMOVE_ELEMENT(m_audioPreview); + REMOVE_ELEMENT(m_audioPreviewQueue); + REMOVE_ELEMENT(m_audioTee); + REMOVE_ELEMENT(m_videoSrc); + REMOVE_ELEMENT(m_videoPreview); + REMOVE_ELEMENT(m_videoPreviewQueue); + REMOVE_ELEMENT(m_videoTee); + REMOVE_ELEMENT(m_encodeBin); + REMOVE_ELEMENT(m_imageCaptureBin); + m_audioVolume = 0; + + bool ok = true; + + switch (newMode) { + case EmptyPipeline: + break; + case PreviewPipeline: + if (m_captureMode & Audio) { + m_audioSrc = buildAudioSrc(); + m_audioPreview = buildAudioPreview(); + + ok &= m_audioSrc && m_audioPreview; + + if (ok) { + gst_bin_add_many(GST_BIN(m_pipeline), m_audioSrc, m_audioPreview, NULL); + ok &= gst_element_link(m_audioSrc, m_audioPreview); + } + } + if (m_captureMode & Video || m_captureMode & Image) { + m_videoSrc = buildVideoSrc(); + m_videoTee = gst_element_factory_make("tee", "video-preview-tee"); + m_videoPreviewQueue = gst_element_factory_make("queue", "video-preview-queue"); + m_videoPreview = buildVideoPreview(); + m_imageCaptureBin = buildImageCapture(); + + ok &= m_videoSrc && m_videoTee && m_videoPreviewQueue && m_videoPreview && m_imageCaptureBin; + + if (ok) { + gst_bin_add_many(GST_BIN(m_pipeline), m_videoSrc, m_videoTee, + m_videoPreviewQueue, m_videoPreview, + m_imageCaptureBin, NULL); + + ok &= gst_element_link(m_videoSrc, m_videoTee); + ok &= gst_element_link(m_videoTee, m_videoPreviewQueue); + ok &= gst_element_link(m_videoPreviewQueue, m_videoPreview); + ok &= gst_element_link(m_videoTee, m_imageCaptureBin); + } + } + break; + case RecordingPipeline: + m_encodeBin = buildEncodeBin(); + gst_bin_add(GST_BIN(m_pipeline), m_encodeBin); + + if (m_captureMode & Audio) { + m_audioSrc = buildAudioSrc(); + ok &= m_audioSrc != 0; + + gst_bin_add(GST_BIN(m_pipeline), m_audioSrc); + ok &= gst_element_link(m_audioSrc, m_encodeBin); + } + + if (m_captureMode & Video) { + m_videoSrc = buildVideoSrc(); + ok &= m_videoSrc != 0; + + gst_bin_add(GST_BIN(m_pipeline), m_videoSrc); + ok &= gst_element_link(m_videoSrc, m_encodeBin); + } + + if (!m_metaData.isEmpty()) + setMetaData(m_metaData); + + break; + case PreviewAndRecordingPipeline: + m_encodeBin = buildEncodeBin(); + if (m_encodeBin) + gst_bin_add(GST_BIN(m_pipeline), m_encodeBin); + + ok &= m_encodeBin != 0; + + if (ok && m_captureMode & Audio) { + m_audioSrc = buildAudioSrc(); + m_audioPreview = buildAudioPreview(); + m_audioTee = gst_element_factory_make("tee", NULL); + m_audioPreviewQueue = gst_element_factory_make("queue", NULL); + + ok &= m_audioSrc && m_audioPreview && m_audioTee && m_audioPreviewQueue; + + if (ok) { + gst_bin_add_many(GST_BIN(m_pipeline), m_audioSrc, m_audioTee, + m_audioPreviewQueue, m_audioPreview, NULL); + ok &= gst_element_link(m_audioSrc, m_audioTee); + ok &= gst_element_link(m_audioTee, m_audioPreviewQueue); + ok &= gst_element_link(m_audioPreviewQueue, m_audioPreview); + ok &= gst_element_link(m_audioTee, m_encodeBin); + } + } + + if (ok && (m_captureMode & Video || m_captureMode & Image)) { + m_videoSrc = buildVideoSrc(); + m_videoPreview = buildVideoPreview(); + m_videoTee = gst_element_factory_make("tee", NULL); + m_videoPreviewQueue = gst_element_factory_make("queue", NULL); + + ok &= m_videoSrc && m_videoPreview && m_videoTee && m_videoPreviewQueue; + + if (ok) { + gst_bin_add_many(GST_BIN(m_pipeline), m_videoSrc, m_videoTee, + m_videoPreviewQueue, m_videoPreview, NULL); + ok &= gst_element_link(m_videoSrc, m_videoTee); + ok &= gst_element_link(m_videoTee, m_videoPreviewQueue); + ok &= gst_element_link(m_videoPreviewQueue, m_videoPreview); + } + + if (ok && (m_captureMode & Video)) + ok &= gst_element_link(m_videoTee, m_encodeBin); + } + + if (!m_metaData.isEmpty()) + setMetaData(m_metaData); + + + break; + } + + if (!ok) { + emit error(int(QMediaRecorder::FormatError),tr("Failed to build media capture pipeline.")); + } + + dumpGraph( QString("rebuild_graph_%1_%2").arg(m_pipelineMode).arg(newMode) ); + if (m_encodeBin) { + QString fileName = QString("rebuild_graph_encode_%1_%2").arg(m_pipelineMode).arg(newMode); +#if !(GST_DISABLE_GST_DEBUG) && (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 19) + _gst_debug_bin_to_dot_file(GST_BIN(m_encodeBin), GST_DEBUG_GRAPH_SHOW_ALL, fileName.toAscii()); +#endif + } + + if (ok) { + m_pipelineMode = newMode; + } else { + m_pipelineMode = EmptyPipeline; + + REMOVE_ELEMENT(m_audioSrc); + REMOVE_ELEMENT(m_audioPreview); + REMOVE_ELEMENT(m_audioPreviewQueue); + REMOVE_ELEMENT(m_audioTee); + REMOVE_ELEMENT(m_videoSrc); + REMOVE_ELEMENT(m_videoPreview); + REMOVE_ELEMENT(m_videoPreviewQueue); + REMOVE_ELEMENT(m_videoTee); + REMOVE_ELEMENT(m_encodeBin); + } + + return ok; +} + +void QGstreamerCaptureSession::dumpGraph(const QString &fileName) +{ +#if !(GST_DISABLE_GST_DEBUG) && (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 19) + _gst_debug_bin_to_dot_file(GST_BIN(m_pipeline), + GstDebugGraphDetails(/*GST_DEBUG_GRAPH_SHOW_ALL |*/ GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE | GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES), + fileName.toAscii()); +#endif +} + +QUrl QGstreamerCaptureSession::outputLocation() const +{ + return m_sink; +} + +bool QGstreamerCaptureSession::setOutputLocation(const QUrl& sink) +{ + m_sink = sink; + return true; +} + +void QGstreamerCaptureSession::setAudioInput(QGstreamerElementFactory *audioInput) +{ + m_audioInputFactory = audioInput; +} + +void QGstreamerCaptureSession::setAudioPreview(QGstreamerElementFactory *audioPreview) +{ + m_audioPreviewFactory = audioPreview; +} + +void QGstreamerCaptureSession::setVideoInput(QGstreamerVideoInput *videoInput) +{ + m_videoInputFactory = videoInput; +} + +void QGstreamerCaptureSession::setVideoPreview(QObject *viewfinder) +{ + m_viewfinderInterface = qobject_cast(viewfinder); + if (!m_viewfinderInterface) + viewfinder = 0; + + if (m_viewfinder != viewfinder) { + bool oldReady = isReady(); + + if (m_viewfinder) { + disconnect(m_viewfinder, SIGNAL(sinkChanged()), + this, SIGNAL(viewfinderChanged())); + disconnect(m_viewfinder, SIGNAL(readyChanged(bool)), + this, SIGNAL(readyChanged(bool))); + } + + m_viewfinder = viewfinder; + //m_viewfinderHasChanged = true; + + if (m_viewfinder) { + connect(m_viewfinder, SIGNAL(sinkChanged()), + this, SIGNAL(viewfinderChanged())); + connect(m_viewfinder, SIGNAL(readyChanged(bool)), + this, SIGNAL(readyChanged(bool))); + } + + emit viewfinderChanged(); + if (oldReady != isReady()) + emit readyChanged(isReady()); + } +} + +bool QGstreamerCaptureSession::isReady() const +{ + return m_viewfinderInterface != 0 && m_viewfinderInterface->isReady(); +} + +QGstreamerCaptureSession::State QGstreamerCaptureSession::state() const +{ + return m_state; +} + +void QGstreamerCaptureSession::waitForStopped() +{ + GstState state = GST_STATE_PLAYING; + gst_element_get_state(m_pipeline, &state, 0, 0); + + while (state != GST_STATE_NULL) { + qApp->processEvents(); + gst_element_get_state(m_pipeline, &state, 0, 0); + } +} + +void QGstreamerCaptureSession::setState(QGstreamerCaptureSession::State newState) +{ + if (newState == m_pendingState && !m_waitingForEos) + return; + + m_pendingState = newState; + + PipelineMode newMode = EmptyPipeline; + + switch (newState) { + case PausedState: + case RecordingState: + newMode = PreviewAndRecordingPipeline; + break; + case PreviewState: + newMode = PreviewPipeline; + break; + case StoppedState: + newMode = EmptyPipeline; + break; + } + + if (newMode != m_pipelineMode) { + if (m_pipelineMode == PreviewAndRecordingPipeline) { + if (!m_waitingForEos) { + m_waitingForEos = true; + //qDebug() << "Waiting for EOS"; + //with live sources it's necessary to send EOS even to pipeline + //before going to STOPPED state + gst_element_send_event(m_pipeline, gst_event_new_eos()); + // Unless gstreamer is in GST_STATE_PLAYING our EOS message will not be received. + gst_element_set_state(m_pipeline, GST_STATE_PLAYING); + + return; + } else { + m_waitingForEos = false; + //qDebug() << "EOS received"; + } + } + + //select suitable default codecs/containers, if necessary + m_recorderControl->applySettings(); + + gst_element_set_state(m_pipeline, GST_STATE_NULL); + + //It would be better to do this async. but + //gstreamer doesn't notify about pipeline went to NULL state + waitForStopped(); + if (!rebuildGraph(newMode)) { + m_pendingState = StoppedState; + m_state = StoppedState; + emit stateChanged(StoppedState); + + return; + } + } + + switch (newState) { + case PausedState: + gst_element_set_state(m_pipeline, GST_STATE_PAUSED); + break; + case RecordingState: + case PreviewState: + gst_element_set_state(m_pipeline, GST_STATE_PLAYING); + break; + case StoppedState: + gst_element_set_state(m_pipeline, GST_STATE_NULL); + } + + //we have to do it here, since gstreamer will not emit bus messages any more + if (newState == StoppedState) { + m_state = StoppedState; + emit stateChanged(StoppedState); + } +} + + +qint64 QGstreamerCaptureSession::duration() const +{ + GstFormat format = GST_FORMAT_TIME; + gint64 duration = 0; + + if ( m_encodeBin && gst_element_query_position(m_encodeBin, &format, &duration)) + return duration / 1000000; + else + return 0; +} + +void QGstreamerCaptureSession::setCaptureDevice(const QString &deviceName) +{ + m_captureDevice = deviceName; +} + +void QGstreamerCaptureSession::setMetaData(const QMap &data) +{ + //qDebug() << "QGstreamerCaptureSession::setMetaData" << data; + m_metaData = data; + + if (m_encodeBin) { + GstIterator *elements = gst_bin_iterate_all_by_interface(GST_BIN(m_encodeBin), GST_TYPE_TAG_SETTER); + GstElement *element = 0; + while (gst_iterator_next(elements, (void**)&element) == GST_ITERATOR_OK) { + //qDebug() << "found element with tag setter interface:" << gst_element_get_name(element); + QMapIterator it(data); + while (it.hasNext()) { + it.next(); + const QString tagName = it.key(); + const QVariant tagValue = it.value(); + + + switch(tagValue.type()) { + case QVariant::String: + gst_tag_setter_add_tags(GST_TAG_SETTER(element), + GST_TAG_MERGE_REPLACE_ALL, + tagName.toUtf8().constData(), + tagValue.toString().toUtf8().constData(), + NULL); + break; + case QVariant::Int: + case QVariant::LongLong: + gst_tag_setter_add_tags(GST_TAG_SETTER(element), + GST_TAG_MERGE_REPLACE_ALL, + tagName.toUtf8().constData(), + tagValue.toInt(), + NULL); + break; + case QVariant::Double: + gst_tag_setter_add_tags(GST_TAG_SETTER(element), + GST_TAG_MERGE_REPLACE_ALL, + tagName.toUtf8().constData(), + tagValue.toDouble(), + NULL); + break; + default: + break; + } + + } + + } + } +} + +bool QGstreamerCaptureSession::processSyncMessage(const QGstreamerMessage &message) +{ + GstMessage* gm = message.rawMessage(); + + if (gm && GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ELEMENT) { + if (GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_videoPreview)) + m_viewfinderInterface->handleSyncMessage(gm); + + if (gst_structure_has_name(gm->structure, "prepare-xwindow-id")) { + if (m_audioPreviewFactory) + m_audioPreviewFactory->prepareWinId(); + + if (m_viewfinderInterface) + m_viewfinderInterface->precessNewStream(); + + return true; + } + } + + return false; +} + +void QGstreamerCaptureSession::busMessage(const QGstreamerMessage &message) +{ + GstMessage* gm = message.rawMessage(); + + if (gm) { + if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ERROR) { + GError *err; + gchar *debug; + gst_message_parse_error (gm, &err, &debug); + emit error(int(QMediaRecorder::ResourceError),QString::fromUtf8(err->message)); + g_error_free (err); + g_free (debug); + } + + if (GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_pipeline)) { + switch (GST_MESSAGE_TYPE(gm)) { + case GST_MESSAGE_DURATION: + break; + + case GST_MESSAGE_EOS: + if (m_waitingForEos) + setState(m_pendingState); + break; + + case GST_MESSAGE_STATE_CHANGED: + { + + GstState oldState; + GstState newState; + GstState pending; + + gst_message_parse_state_changed(gm, &oldState, &newState, &pending); + + QStringList states; + states << "GST_STATE_VOID_PENDING" << "GST_STATE_NULL" << "GST_STATE_READY" << "GST_STATE_PAUSED" << "GST_STATE_PLAYING"; + + /* + qDebug() << QString("state changed: old: %1 new: %2 pending: %3") \ + .arg(states[oldState]) \ + .arg(states[newState]) \ + .arg(states[pending]); + + #define ENUM_NAME(c,e,v) (c::staticMetaObject.enumerator(c::staticMetaObject.indexOfEnumerator(e)).valueToKey((v))) + + qDebug() << "Current session state:" << ENUM_NAME(QGstreamerCaptureSession,"State",m_state); + qDebug() << "Pending session state:" << ENUM_NAME(QGstreamerCaptureSession,"State",m_pendingState); + */ + + switch (newState) { + case GST_STATE_VOID_PENDING: + case GST_STATE_NULL: + case GST_STATE_READY: + if (m_state != StoppedState && m_pendingState == StoppedState) { + emit stateChanged(m_state = StoppedState); + dumpGraph("stopped"); + } + break; + case GST_STATE_PAUSED: + if (m_state != PausedState && m_pendingState == PausedState) + emit stateChanged(m_state = PausedState); + dumpGraph("paused"); + + if (m_pipelineMode == RecordingPipeline && !m_metaData.isEmpty()) + setMetaData(m_metaData); + break; + case GST_STATE_PLAYING: + { + if ((m_pendingState == PreviewState || m_pendingState == RecordingState) && + m_state != m_pendingState) + { + m_state = m_pendingState; + emit stateChanged(m_state); + } + + if (m_pipelineMode == PreviewPipeline) + dumpGraph("preview"); + else + dumpGraph("recording"); + } + break; + } + } + break; + default: + break; + } + //qDebug() << "New session state:" << ENUM_NAME(QGstreamerCaptureSession,"State",m_state); + } + + if (m_videoPreview && m_viewfinderInterface && + GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_videoPreview)) + m_viewfinderInterface->handleBusMessage(gm); + } +} + +void QGstreamerCaptureSession::setMuted(bool muted) +{ + if (m_muted != muted) { + m_muted = muted; + if (m_audioVolume) + g_object_set(G_OBJECT(m_audioVolume), "volume", (m_muted ? 0.0 : 1.0), NULL); + emit mutedChanged(muted); + } +} diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.h b/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.h new file mode 100644 index 000000000..f04a49be2 --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.h @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERCAPTURESESSION_H +#define QGSTREAMERCAPTURESESSION_H + +#include +#include + +#include + +#include + +#include "qgstreamerbushelper.h" + +QT_USE_NAMESPACE + +class QGstreamerMessage; +class QGstreamerBusHelper; +class QGstreamerAudioEncode; +class QGstreamerVideoEncode; +class QGstreamerImageEncode; +class QGstreamerRecorderControl; +class QGstreamerMediaContainerControl; +class QGstreamerVideoRendererInterface; + +class QGstreamerElementFactory +{ +public: + virtual GstElement *buildElement() = 0; + virtual void prepareWinId() {} +}; + +class QGstreamerVideoInput : public QGstreamerElementFactory +{ +public: + virtual QList supportedFrameRates(const QSize &frameSize = QSize()) const = 0; + virtual QList supportedResolutions(qreal frameRate = -1) const = 0; +}; + +class QGstreamerCaptureSession : public QObject, public QGstreamerSyncEventFilter +{ + Q_OBJECT + Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged) + Q_ENUMS(State) + Q_ENUMS(CaptureMode) +public: + enum CaptureMode { Audio = 1, Video = 2, Image=4, AudioAndVideo = Audio | Video }; + enum State { StoppedState, PreviewState, PausedState, RecordingState }; + + QGstreamerCaptureSession(CaptureMode captureMode, QObject *parent); + ~QGstreamerCaptureSession(); + + CaptureMode captureMode() const { return m_captureMode; } + void setCaptureMode(CaptureMode); + + QUrl outputLocation() const; + bool setOutputLocation(const QUrl& sink); + + QGstreamerAudioEncode *audioEncodeControl() const { return m_audioEncodeControl; } + QGstreamerVideoEncode *videoEncodeControl() const { return m_videoEncodeControl; } + QGstreamerImageEncode *imageEncodeControl() const { return m_imageEncodeControl; } + + QGstreamerRecorderControl *recorderControl() const { return m_recorderControl; } + QGstreamerMediaContainerControl *mediaContainerControl() const { return m_mediaContainerControl; } + + QGstreamerElementFactory *audioInput() const { return m_audioInputFactory; } + void setAudioInput(QGstreamerElementFactory *audioInput); + + QGstreamerElementFactory *audioPreview() const { return m_audioPreviewFactory; } + void setAudioPreview(QGstreamerElementFactory *audioPreview); + + QGstreamerVideoInput *videoInput() const { return m_videoInputFactory; } + void setVideoInput(QGstreamerVideoInput *videoInput); + + QObject *videoPreview() const { return m_viewfinder; } + void setVideoPreview(QObject *viewfinder); + + void captureImage(int requestId, const QString &fileName); + + State state() const; + qint64 duration() const; + bool isMuted() const { return m_muted; } + + bool isReady() const; + + bool processSyncMessage(const QGstreamerMessage &message); + +signals: + void stateChanged(QGstreamerCaptureSession::State state); + void durationChanged(qint64 duration); + void error(int error, const QString &errorString); + void imageExposed(int requestId); + void imageCaptured(int requestId, const QImage &img); + void imageSaved(int requestId, const QString &path); + void mutedChanged(bool); + void readyChanged(bool); + void viewfinderChanged(); + +public slots: + void setState(QGstreamerCaptureSession::State); + void setCaptureDevice(const QString &deviceName); + + void dumpGraph(const QString &fileName); + + void setMetaData(const QMap&); + void setMuted(bool); + +private slots: + void busMessage(const QGstreamerMessage &message); + +private: + enum PipelineMode { EmptyPipeline, PreviewPipeline, RecordingPipeline, PreviewAndRecordingPipeline }; + + GstElement *buildEncodeBin(); + GstElement *buildAudioSrc(); + GstElement *buildAudioPreview(); + GstElement *buildVideoSrc(); + GstElement *buildVideoPreview(); + GstElement *buildImageCapture(); + + void waitForStopped(); + bool rebuildGraph(QGstreamerCaptureSession::PipelineMode newMode); + + QUrl m_sink; + QString m_captureDevice; + State m_state; + State m_pendingState; + bool m_waitingForEos; + PipelineMode m_pipelineMode; + QGstreamerCaptureSession::CaptureMode m_captureMode; + QMap m_metaData; + + QGstreamerElementFactory *m_audioInputFactory; + QGstreamerElementFactory *m_audioPreviewFactory; + QGstreamerVideoInput *m_videoInputFactory; + QObject *m_viewfinder; + QGstreamerVideoRendererInterface *m_viewfinderInterface; + + QGstreamerAudioEncode *m_audioEncodeControl; + QGstreamerVideoEncode *m_videoEncodeControl; + QGstreamerImageEncode *m_imageEncodeControl; + QGstreamerRecorderControl *m_recorderControl; + QGstreamerMediaContainerControl *m_mediaContainerControl; + + QGstreamerBusHelper *m_busHelper; + GstBus* m_bus; + GstElement *m_pipeline; + + GstElement *m_audioSrc; + GstElement *m_audioTee; + GstElement *m_audioPreviewQueue; + GstElement *m_audioPreview; + GstElement *m_audioVolume; + bool m_muted; + + GstElement *m_videoSrc; + GstElement *m_videoTee; + GstElement *m_videoPreviewQueue; + GstElement *m_videoPreview; + + GstElement *m_imageCaptureBin; + + GstElement *m_encodeBin; + +public: + bool m_passImage; + bool m_passPrerollImage; + QString m_imageFileName; + int m_imageRequestId; +}; + +#endif // QGSTREAMERCAPTURESESSION_H diff --git a/src/plugins/gstreamer/mediacapture/qgstreamerimagecapturecontrol.cpp b/src/plugins/gstreamer/mediacapture/qgstreamerimagecapturecontrol.cpp new file mode 100644 index 000000000..99c3b1665 --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamerimagecapturecontrol.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamerimagecapturecontrol.h" +#include +#include + +QGstreamerImageCaptureControl::QGstreamerImageCaptureControl(QGstreamerCaptureSession *session) + :QCameraImageCaptureControl(session), m_session(session), m_ready(false), m_lastId(0) +{ + connect(m_session, SIGNAL(stateChanged(QGstreamerCaptureSession::State)), SLOT(updateState())); + connect(m_session, SIGNAL(imageExposed(int)), this, SIGNAL(imageExposed(int))); + connect(m_session, SIGNAL(imageCaptured(int,QImage)), this, SIGNAL(imageCaptured(int,QImage))); + connect(m_session, SIGNAL(imageSaved(int,QString)), this, SIGNAL(imageSaved(int,QString))); +} + +QGstreamerImageCaptureControl::~QGstreamerImageCaptureControl() +{ +} + +bool QGstreamerImageCaptureControl::isReadyForCapture() const +{ + return m_ready; +} + +int QGstreamerImageCaptureControl::capture(const QString &fileName) +{ + QString path = fileName; + if (path.isEmpty()) { + int lastImage = 0; + QDir outputDir = QDir::currentPath(); + foreach(QString fileName, outputDir.entryList(QStringList() << "img_*.jpg")) { + int imgNumber = fileName.mid(4, fileName.size()-8).toInt(); + lastImage = qMax(lastImage, imgNumber); + } + + path = QString("img_%1.jpg").arg(lastImage+1, + 4, //fieldWidth + 10, + QLatin1Char('0')); + } + m_lastId++; + + m_session->captureImage(m_lastId, path); + + return m_lastId; +} + +void QGstreamerImageCaptureControl::cancelCapture() +{ + +} + +void QGstreamerImageCaptureControl::updateState() +{ + bool ready = m_session->state() == QGstreamerCaptureSession::PreviewState; + if (m_ready != ready) { + emit readyForCaptureChanged(m_ready = ready); + } +} diff --git a/src/plugins/gstreamer/mediacapture/qgstreamerimagecapturecontrol.h b/src/plugins/gstreamer/mediacapture/qgstreamerimagecapturecontrol.h new file mode 100644 index 000000000..898162440 --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamerimagecapturecontrol.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QGSTREAMERIMAGECAPTURECONTROL_H +#define QGSTREAMERIMAGECAPTURECONTROL_H + +#include +#include "qgstreamercapturesession.h" +QT_USE_NAMESPACE + +class QGstreamerImageCaptureControl : public QCameraImageCaptureControl +{ + Q_OBJECT +public: + QGstreamerImageCaptureControl(QGstreamerCaptureSession *session); + virtual ~QGstreamerImageCaptureControl(); + + QCameraImageCapture::DriveMode driveMode() const { return QCameraImageCapture::SingleImageCapture; } + void setDriveMode(QCameraImageCapture::DriveMode) {} + + bool isReadyForCapture() const; + int capture(const QString &fileName); + void cancelCapture(); + +private slots: + void updateState(); + +private: + QGstreamerCaptureSession *m_session; + bool m_ready; + int m_lastId; +}; + +#endif // QGSTREAMERCAPTURECORNTROL_H diff --git a/src/plugins/gstreamer/mediacapture/qgstreamerimageencode.cpp b/src/plugins/gstreamer/mediacapture/qgstreamerimageencode.cpp new file mode 100644 index 000000000..5aef97794 --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamerimageencode.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamerimageencode.h" +#include "qgstreamercapturesession.h" + +#include + +#include + +QGstreamerImageEncode::QGstreamerImageEncode(QGstreamerCaptureSession *session) + :QImageEncoderControl(session), m_session(session) +{ +} + +QGstreamerImageEncode::~QGstreamerImageEncode() +{ +} + +QList QGstreamerImageEncode::supportedResolutions(const QImageEncoderSettings &, bool *continuous) const +{ + if (continuous) + *continuous = m_session->videoInput() != 0; + + return m_session->videoInput() ? m_session->videoInput()->supportedResolutions() : QList(); +} + +QStringList QGstreamerImageEncode::supportedImageCodecs() const +{ + return QStringList() << "jpeg"; +} + +QString QGstreamerImageEncode::imageCodecDescription(const QString &codecName) const +{ + if (codecName == "jpeg") + return tr("JPEG image encoder"); + + return QString(); +} + +QImageEncoderSettings QGstreamerImageEncode::imageSettings() const +{ + return m_settings; +} + +void QGstreamerImageEncode::setImageSettings(const QImageEncoderSettings &settings) +{ + if (m_settings != settings) { + m_settings = settings; + emit settingsChanged(); + } +} diff --git a/src/plugins/gstreamer/mediacapture/qgstreamerimageencode.h b/src/plugins/gstreamer/mediacapture/qgstreamerimageencode.h new file mode 100644 index 000000000..b66ba75f8 --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamerimageencode.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERIMAGEENCODE_H +#define QGSTREAMERIMAGEENCODE_H + +class QGstreamerCaptureSession; + +#include + +#include +#include + +#include +QT_USE_NAMESPACE + +class QGstreamerImageEncode : public QImageEncoderControl +{ + Q_OBJECT +public: + QGstreamerImageEncode(QGstreamerCaptureSession *session); + virtual ~QGstreamerImageEncode(); + + QList supportedResolutions(const QImageEncoderSettings &settings = QImageEncoderSettings(), + bool *continuous = 0) const; + + QStringList supportedImageCodecs() const; + QString imageCodecDescription(const QString &codecName) const; + + QImageEncoderSettings imageSettings() const; + void setImageSettings(const QImageEncoderSettings &settings); + +Q_SIGNALS: + void settingsChanged(); + +private: + QImageEncoderSettings m_settings; + + QGstreamerCaptureSession *m_session; +}; + +#endif diff --git a/src/plugins/gstreamer/mediacapture/qgstreamermediacontainercontrol.cpp b/src/plugins/gstreamer/mediacapture/qgstreamermediacontainercontrol.cpp new file mode 100644 index 000000000..34c43e3ac --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamermediacontainercontrol.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamermediacontainercontrol.h" + + +#include + +QGstreamerMediaContainerControl::QGstreamerMediaContainerControl(QObject *parent) + :QMediaContainerControl(parent) +{ + QList formatCandidates; + formatCandidates << "matroska" << "ogg" << "mp4" << "wav" << "quicktime" << "avi" << "3gpp"; + formatCandidates << "flv" << "amr" << "asf" << "dv" << "gif"; + formatCandidates << "mpeg" << "vob" << "mpegts" << "3g2" << "3gp"; + formatCandidates << "raw"; + + m_elementNames["matroska"] = "matroskamux"; + m_elementNames["ogg"] = "oggmux"; + m_elementNames["mp4"] = "ffmux_mp4"; + m_elementNames["quicktime"] = "ffmux_mov"; + m_elementNames["avi"] = "avimux"; + m_elementNames["3gpp"] = "gppmux"; + m_elementNames["flv"] = "flvmux"; + m_elementNames["wav"] = "wavenc"; + m_elementNames["amr"] = "ffmux_amr"; + m_elementNames["asf"] = "ffmux_asf"; + m_elementNames["dv"] = "ffmux_dv"; + m_elementNames["gif"] = "ffmux_gif"; + m_elementNames["mpeg"] = "ffmux_mpeg"; + m_elementNames["vob"] = "ffmux_vob"; + m_elementNames["mpegts"] = "ffmux_mpegts"; + m_elementNames["3g2"] = "ffmux_3g2"; + m_elementNames["3gp"] = "ffmux_3gp"; + m_elementNames["raw"] = "identity"; + + m_containerExtensions["matroska"] = "mkv"; + m_containerExtensions["quicktime"] = "mov"; + m_containerExtensions["mpegts"] = "m2t"; + m_containerExtensions["mpeg"] = "mpg"; + + QSet allTypes; + + foreach( const QByteArray& formatName, formatCandidates ) { + QByteArray elementName = m_elementNames[formatName]; + GstElementFactory *factory = gst_element_factory_find(elementName.constData()); + if (factory) { + m_supportedContainers.append(formatName); + const gchar *descr = gst_element_factory_get_description(factory); + m_containerDescriptions.insert(formatName, QString::fromUtf8(descr)); + + + if (formatName == QByteArray("raw")) { + m_streamTypes.insert(formatName, allTypes); + } else { + QSet types = supportedStreamTypes(factory, GST_PAD_SINK); + m_streamTypes.insert(formatName, types); + allTypes.unite(types); + } + + gst_object_unref(GST_OBJECT(factory)); + } + } + + //if (!m_supportedContainers.isEmpty()) + // setContainerMimeType(m_supportedContainers[0]); +} + +QSet QGstreamerMediaContainerControl::supportedStreamTypes(GstElementFactory *factory, GstPadDirection direction) +{ + QSet types; + const GList *pads = gst_element_factory_get_static_pad_templates(factory); + for (const GList *pad = pads; pad; pad = g_list_next(pad)) { + GstStaticPadTemplate *templ = (GstStaticPadTemplate*)pad->data; + if (templ->direction == direction) { + GstCaps *caps = gst_static_caps_get(&templ->static_caps); + for (uint i=0; i QGstreamerMediaContainerControl::supportedStreamTypes(const QString &container) const +{ + return m_streamTypes.value(container); +} + +QString QGstreamerMediaContainerControl::containerExtension() const +{ + return m_containerExtensions.value(m_format, m_format); +} diff --git a/src/plugins/gstreamer/mediacapture/qgstreamermediacontainercontrol.h b/src/plugins/gstreamer/mediacapture/qgstreamermediacontainercontrol.h new file mode 100644 index 000000000..57e0a5bf1 --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamermediacontainercontrol.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QGSTREAMERMEDIACONTAINERCONTROL_H +#define QGSTREAMERMEDIACONTAINERCONTROL_H + +#include +#include +#include + +#include + +QT_USE_NAMESPACE + +class QGstreamerMediaContainerControl : public QMediaContainerControl +{ +Q_OBJECT +public: + QGstreamerMediaContainerControl(QObject *parent); + virtual ~QGstreamerMediaContainerControl() {}; + + virtual QStringList supportedContainers() const { return m_supportedContainers; } + virtual QString containerMimeType() const { return m_format; } + virtual void setContainerMimeType(const QString &formatMimeType) { m_format = formatMimeType; } + + virtual QString containerDescription(const QString &formatMimeType) const { return m_containerDescriptions.value(formatMimeType); } + + QByteArray formatElementName() const { return m_elementNames.value(containerMimeType()); } + + QSet supportedStreamTypes(const QString &container) const; + + static QSet supportedStreamTypes(GstElementFactory *factory, GstPadDirection direction); + + QString containerExtension() const; + +private: + QString m_format; + QStringList m_supportedContainers; + QMap m_elementNames; + QMap m_containerDescriptions; + QMap m_containerExtensions; + QMap > m_streamTypes; +}; + +#endif // QGSTREAMERMEDIACONTAINERCONTROL_H diff --git a/src/plugins/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp b/src/plugins/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp new file mode 100644 index 000000000..24b28dead --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp @@ -0,0 +1,289 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamerrecordercontrol.h" +#include "qgstreameraudioencode.h" +#include "qgstreamervideoencode.h" +#include "qgstreamermediacontainercontrol.h" +#include + +QGstreamerRecorderControl::QGstreamerRecorderControl(QGstreamerCaptureSession *session) + :QMediaRecorderControl(session), m_session(session), m_state(QMediaRecorder::StoppedState) +{ + connect(m_session, SIGNAL(stateChanged(QGstreamerCaptureSession::State)), SLOT(updateState())); + connect(m_session, SIGNAL(error(int,QString)), SIGNAL(error(int,QString))); + connect(m_session, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged(qint64))); + connect(m_session, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged(bool))); + m_hasPreviewState = m_session->captureMode() != QGstreamerCaptureSession::Audio; +} + +QGstreamerRecorderControl::~QGstreamerRecorderControl() +{ +} + +QUrl QGstreamerRecorderControl::outputLocation() const +{ + return m_session->outputLocation(); +} + +bool QGstreamerRecorderControl::setOutputLocation(const QUrl &sink) +{ + m_outputLocation = sink; + m_session->setOutputLocation(sink); + return true; +} + + +QMediaRecorder::State QGstreamerRecorderControl::state() const +{ + switch ( m_session->state() ) { + case QGstreamerCaptureSession::RecordingState: + return QMediaRecorder::RecordingState; + case QGstreamerCaptureSession::PausedState: + return QMediaRecorder::PausedState; + case QGstreamerCaptureSession::PreviewState: + case QGstreamerCaptureSession::StoppedState: + return QMediaRecorder::StoppedState; + } + + return QMediaRecorder::StoppedState; + +} + +void QGstreamerRecorderControl::updateState() +{ + QMediaRecorder::State newState = state(); + if (m_state != newState) { + m_state = newState; + emit stateChanged(m_state); + } +} + +qint64 QGstreamerRecorderControl::duration() const +{ + return m_session->duration(); +} + +void QGstreamerRecorderControl::record() +{ + if (m_outputLocation.isEmpty()) { + QString container = m_session->mediaContainerControl()->containerExtension(); + if (container.isEmpty()) + container = "raw"; + + m_session->setOutputLocation(QUrl(generateFileName(defaultDir(), container))); + } + + m_session->dumpGraph("before-record"); + if (!m_hasPreviewState || m_session->state() != QGstreamerCaptureSession::StoppedState) { + m_session->setState(QGstreamerCaptureSession::RecordingState); + } else + emit error(QMediaRecorder::ResourceError, tr("Service has not been started")); + + m_session->dumpGraph("after-record"); +} + +void QGstreamerRecorderControl::pause() +{ + m_session->dumpGraph("before-pause"); + if (!m_hasPreviewState || m_session->state() != QGstreamerCaptureSession::StoppedState) { + m_session->setState(QGstreamerCaptureSession::PausedState); + } else + emit error(QMediaRecorder::ResourceError, tr("Service has not been started")); +} + +void QGstreamerRecorderControl::stop() +{ + if (!m_hasPreviewState) { + m_session->setState(QGstreamerCaptureSession::StoppedState); + } else { + if (m_session->state() != QGstreamerCaptureSession::StoppedState) + m_session->setState(QGstreamerCaptureSession::PreviewState); + } +} + +void QGstreamerRecorderControl::applySettings() +{ + //Check the codecs are compatible with container, + //and choose the compatible codecs/container if omitted + QGstreamerAudioEncode *audioEncodeControl = m_session->audioEncodeControl(); + QGstreamerVideoEncode *videoEncodeControl = m_session->videoEncodeControl(); + QGstreamerMediaContainerControl *mediaContainerControl = m_session->mediaContainerControl(); + + bool needAudio = m_session->captureMode() & QGstreamerCaptureSession::Audio; + bool needVideo = m_session->captureMode() & QGstreamerCaptureSession::Video; + + QStringList containerCandidates; + if (mediaContainerControl->containerMimeType().isEmpty()) + containerCandidates = mediaContainerControl->supportedContainers(); + else + containerCandidates << mediaContainerControl->containerMimeType(); + + + QStringList audioCandidates; + if (needAudio) { + QAudioEncoderSettings audioSettings = audioEncodeControl->audioSettings(); + if (audioSettings.codec().isEmpty()) + audioCandidates = audioEncodeControl->supportedAudioCodecs(); + else + audioCandidates << audioSettings.codec(); + } + + QStringList videoCandidates; + if (needVideo) { + QVideoEncoderSettings videoSettings = videoEncodeControl->videoSettings(); + if (videoSettings.codec().isEmpty()) + videoCandidates = videoEncodeControl->supportedVideoCodecs(); + else + videoCandidates << videoSettings.codec(); + } + + QString container; + QString audioCodec; + QString videoCodec; + + foreach (const QString &containerCandidate, containerCandidates) { + QSet supportedTypes = mediaContainerControl->supportedStreamTypes(containerCandidate); + + audioCodec.clear(); + videoCodec.clear(); + + if (needAudio) { + bool found = false; + foreach (const QString &audioCandidate, audioCandidates) { + QSet audioTypes = audioEncodeControl->supportedStreamTypes(audioCandidate); + if (!audioTypes.intersect(supportedTypes).isEmpty()) { + found = true; + audioCodec = audioCandidate; + break; + } + } + if (!found) + continue; + } + + if (needVideo) { + bool found = false; + foreach (const QString &videoCandidate, videoCandidates) { + QSet videoTypes = videoEncodeControl->supportedStreamTypes(videoCandidate); + if (!videoTypes.intersect(supportedTypes).isEmpty()) { + found = true; + videoCodec = videoCandidate; + break; + } + } + if (!found) + continue; + } + + container = containerCandidate; + break; + } + + if (container.isEmpty()) { + emit error(QMediaRecorder::FormatError, tr("Not compatible codecs and container format.")); + } else { + mediaContainerControl->setContainerMimeType(container); + + if (needAudio) { + QAudioEncoderSettings audioSettings = audioEncodeControl->audioSettings(); + audioSettings.setCodec(audioCodec); + audioEncodeControl->setAudioSettings(audioSettings); + } + + if (needVideo) { + QVideoEncoderSettings videoSettings = videoEncodeControl->videoSettings(); + videoSettings.setCodec(videoCodec); + videoEncodeControl->setVideoSettings(videoSettings); + } + } +} + + +bool QGstreamerRecorderControl::isMuted() const +{ + return m_session->isMuted(); +} + +void QGstreamerRecorderControl::setMuted(bool muted) +{ + m_session->setMuted(muted); +} + +QDir QGstreamerRecorderControl::defaultDir() const +{ + QStringList dirCandidates; + +#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) + dirCandidates << QLatin1String("/home/user/MyDocs"); +#endif + + dirCandidates << QDir::home().filePath("Documents"); + dirCandidates << QDir::home().filePath("My Documents"); + dirCandidates << QDir::homePath(); + dirCandidates << QDir::currentPath(); + dirCandidates << QDir::tempPath(); + + foreach (const QString &path, dirCandidates) { + QDir dir(path); + if (dir.exists() && QFileInfo(path).isWritable()) + return dir; + } + + return QDir(); +} + +QString QGstreamerRecorderControl::generateFileName(const QDir &dir, const QString &ext) const +{ + + int lastClip = 0; + foreach(QString fileName, dir.entryList(QStringList() << QString("clip_*.%1").arg(ext))) { + int imgNumber = fileName.mid(5, fileName.size()-6-ext.length()).toInt(); + lastClip = qMax(lastClip, imgNumber); + } + + QString name = QString("clip_%1.%2").arg(lastClip+1, + 4, //fieldWidth + 10, + QLatin1Char('0')).arg(ext); + + return dir.absoluteFilePath(name); +} diff --git a/src/plugins/gstreamer/mediacapture/qgstreamerrecordercontrol.h b/src/plugins/gstreamer/mediacapture/qgstreamerrecordercontrol.h new file mode 100644 index 000000000..c252f1543 --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamerrecordercontrol.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QGSTREAMERRECORDERCONTROL_H +#define QGSTREAMERRECORDERCONTROL_H + +#include + +#include +#include "qgstreamercapturesession.h" + +QT_USE_NAMESPACE + +class QGstreamerRecorderControl : public QMediaRecorderControl +{ + Q_OBJECT + +public: + QGstreamerRecorderControl(QGstreamerCaptureSession *session); + virtual ~QGstreamerRecorderControl(); + + QUrl outputLocation() const; + bool setOutputLocation(const QUrl &sink); + + QMediaRecorder::State state() const; + + qint64 duration() const; + + bool isMuted() const; + + void applySettings(); + +public slots: + void record(); + void pause(); + void stop(); + void setMuted(bool); + +private slots: + void updateState(); + +private: + QDir defaultDir() const; + QString generateFileName(const QDir &dir, const QString &ext) const; + + QUrl m_outputLocation; + QGstreamerCaptureSession *m_session; + QMediaRecorder::State m_state; + bool m_hasPreviewState; +}; + +#endif // QGSTREAMERCAPTURECORNTROL_H diff --git a/src/plugins/gstreamer/mediacapture/qgstreamerv4l2input.cpp b/src/plugins/gstreamer/mediacapture/qgstreamerv4l2input.cpp new file mode 100644 index 000000000..70907b2dd --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamerv4l2input.cpp @@ -0,0 +1,297 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamerv4l2input.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +static inline uint qHash(const QSize& key) { return uint(key.width()*256+key.height()); } + +static bool operator<(const QSize &s1, const QSize s2) +{ + return s1.width()*s1.height() < s2.width()*s2.height(); +} +QT_END_NAMESPACE + +QGstreamerV4L2Input::QGstreamerV4L2Input(QObject *parent) + :QObject(parent) +{ +} + +QGstreamerV4L2Input::~QGstreamerV4L2Input() +{ +} + +GstElement *QGstreamerV4L2Input::buildElement() +{ +#ifndef Q_WS_MAEMO_5 + GstElement *camera = gst_element_factory_make("v4l2src", "camera_source"); +#else + GstElement *camera = gst_element_factory_make("v4l2camsrc", "camera_source"); +#endif + if (camera && !m_device.isEmpty() ) + g_object_set(G_OBJECT(camera), "device", m_device.constData(), NULL); + + return camera; +} + +void QGstreamerV4L2Input::setDevice(const QByteArray &newDevice) +{ + if (m_device != newDevice) { + m_device = newDevice; + updateSupportedResolutions(newDevice); + } +} + +void QGstreamerV4L2Input::setDevice(const QString &device) +{ + setDevice(QFile::encodeName(device)); +} + +void QGstreamerV4L2Input::updateSupportedResolutions(const QByteArray &device) +{ + m_frameRates.clear(); + m_resolutions.clear(); + m_ratesByResolution.clear(); + + QSet allResolutions; + QSet allFrameRates; + + QFile f(device); + + if (!f.open(QFile::ReadOnly)) + return; + + int fd = f.handle(); + + //get the list of formats: + QList supportedFormats; + + { + v4l2_fmtdesc fmt; + memset(&fmt, 0, sizeof(v4l2_fmtdesc)); + + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + int sanity = 0; + + for (fmt.index = 0;; fmt.index++) { + if (sanity++ > 8) + break; + if( ::ioctl(fd, VIDIOC_ENUM_FMT, &fmt) == -1) { + if(errno == EINVAL) + break; + } + supportedFormats.append(fmt.pixelformat); + } + } + + QList commonSizes; + commonSizes << QSize(128, 96) + < commonRates; + commonRates << 05*1000 << 75*1000 << 10*1000 << 15*1000 << 20*1000 + << 24*1000 << 25*1000 << 30*1000 << 50*1000 << 60*1000; + + + //get the list of resolutions: + + foreach (quint32 format, supportedFormats) { + struct v4l2_frmsizeenum formatSize; + memset(&formatSize, 0, sizeof(formatSize)); + formatSize.pixel_format = format; + + QList sizeList; + + if (0) { + char formatStr[5]; + memcpy(formatStr, &format, 4); + formatStr[4] = 0; + //qDebug() << "trying format" << formatStr; + } + + for (int i=0;;i++) { + formatSize.index = i; + if (ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &formatSize) < 0) + break; + + if (formatSize.type == V4L2_FRMSIZE_TYPE_DISCRETE) { + sizeList.append(QSize(formatSize.discrete.width, formatSize.discrete.height)); + } else { + + foreach (const QSize& candidate, commonSizes) { + if (candidate.width() <= (int)formatSize.stepwise.max_width && + candidate.height() >= (int)formatSize.stepwise.min_width && + candidate.width() % formatSize.stepwise.step_width == 0 && + candidate.height() <= (int)formatSize.stepwise.max_height && + candidate.height() >= (int)formatSize.stepwise.min_height && + candidate.height() % formatSize.stepwise.step_height == 0) { + sizeList.append(candidate); + } + } + + if (!sizeList.contains(QSize(formatSize.stepwise.min_width, formatSize.stepwise.min_height))) + sizeList.prepend(QSize(formatSize.stepwise.min_width, formatSize.stepwise.min_height)); + + if (!sizeList.contains(QSize(formatSize.stepwise.max_width, formatSize.stepwise.max_height))) + sizeList.append(QSize(formatSize.stepwise.max_width, formatSize.stepwise.max_height)); + + break; //stepwise values are returned only for index 0 + } + + } + + //and frameRates for each resolution. + + foreach (const QSize &s, sizeList) { + allResolutions.insert(s); + + struct v4l2_frmivalenum formatInterval; + memset(&formatInterval, 0, sizeof(formatInterval)); + formatInterval.pixel_format = format; + formatInterval.width = s.width(); + formatInterval.height = s.height(); + + QList frameRates; //in 1/1000 of fps + + for (int i=0; ; i++) { + formatInterval.index = i; + + if (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &formatInterval) < 0) + break; + + if (formatInterval.type == V4L2_FRMIVAL_TYPE_DISCRETE) { + //converts seconds to fps*1000 + if (formatInterval.discrete.numerator) + frameRates.append(qRound(formatInterval.discrete.denominator*1000.0 / formatInterval.discrete.numerator)); + } else { + if (formatInterval.stepwise.min.numerator == 0 || + formatInterval.stepwise.max.numerator == 0) { + qWarning() << "received invalid frame interval"; + break; + } + + + int minRate = qRound(formatInterval.stepwise.min.denominator*1000.0 / + formatInterval.stepwise.min.numerator); + + int maxRate = qRound(formatInterval.stepwise.max.denominator*1000.0 / + formatInterval.stepwise.max.numerator); + + + foreach (int candidate, commonRates) { + if (candidate >= minRate && candidate <= maxRate) + frameRates.append(candidate); + } + + if (!frameRates.contains(minRate)) + frameRates.prepend(minRate); + + if (!frameRates.contains(maxRate)) + frameRates.append(maxRate); + + break; //stepwise values are returned only for index 0 + } + } + allFrameRates.unite(frameRates.toSet()); + m_ratesByResolution[s].unite(frameRates.toSet()); + } + } + + f.close(); + + foreach(int rate, allFrameRates) { + m_frameRates.append(rate/1000.0); + } + + qSort(m_frameRates); + + m_resolutions = allResolutions.toList(); + qSort(m_resolutions); + + //qDebug() << "frame rates:" << m_frameRates; + //qDebug() << "resolutions:" << m_resolutions; +} + + +QList QGstreamerV4L2Input::supportedFrameRates(const QSize &frameSize) const +{ + if (frameSize.isEmpty()) + return m_frameRates; + else { + QList res; + foreach(int rate, m_ratesByResolution[frameSize]) { + res.append(rate/1000.0); + } + return res; + } +} + +QList QGstreamerV4L2Input::supportedResolutions(qreal frameRate) const +{ + Q_UNUSED(frameRate); + return m_resolutions; +} diff --git a/src/plugins/gstreamer/mediacapture/qgstreamerv4l2input.h b/src/plugins/gstreamer/mediacapture/qgstreamerv4l2input.h new file mode 100644 index 000000000..5dbdd5453 --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamerv4l2input.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QGSTREAMERV4L2INPUT_H +#define QGSTREAMERV4L2INPUT_H + +#include +#include +#include +#include +#include "qgstreamercapturesession.h" + +QT_USE_NAMESPACE + +class QGstreamerV4L2Input : public QObject, public QGstreamerVideoInput +{ + Q_OBJECT +public: + QGstreamerV4L2Input(QObject *parent = 0); + virtual ~QGstreamerV4L2Input(); + + GstElement *buildElement(); + + QList supportedFrameRates(const QSize &frameSize = QSize()) const; + QList supportedResolutions(qreal frameRate = -1) const; + + QByteArray device() const; + +public slots: + void setDevice(const QByteArray &device); + void setDevice(const QString &device); + +private: + void updateSupportedResolutions(const QByteArray &device); + + QList m_frameRates; + QList m_resolutions; + + QHash > m_ratesByResolution; + + QByteArray m_device; +}; + +#endif // QGSTREAMERV4L2INPUT_H diff --git a/src/plugins/gstreamer/mediacapture/qgstreamervideoencode.cpp b/src/plugins/gstreamer/mediacapture/qgstreamervideoencode.cpp new file mode 100644 index 000000000..a491f14ae --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamervideoencode.cpp @@ -0,0 +1,331 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamervideoencode.h" +#include "qgstreamercapturesession.h" +#include "qgstreamermediacontainercontrol.h" + +#include + +#include + +QGstreamerVideoEncode::QGstreamerVideoEncode(QGstreamerCaptureSession *session) + :QVideoEncoderControl(session), m_session(session) +{ + QList codecCandidates; + codecCandidates << "video/h264" << "video/xvid" << "video/mpeg4" << "video/mpeg1" << "video/mpeg2" << "video/theora"; + + m_elementNames["video/h264"] = "x264enc"; + m_elementNames["video/xvid"] = "xvidenc"; + m_elementNames["video/mpeg4"] = "ffenc_mpeg4"; + m_elementNames["video/mpeg1"] = "ffenc_mpeg1video"; + m_elementNames["video/mpeg2"] = "ffenc_mpeg2video"; + m_elementNames["video/theora"] = "theoraenc"; + + m_codecOptions["video/h264"] = QStringList() << "quantizer"; + m_codecOptions["video/xvid"] = QStringList() << "quantizer" << "profile"; + m_codecOptions["video/mpeg4"] = QStringList() << "quantizer"; + m_codecOptions["video/mpeg1"] = QStringList() << "quantizer"; + m_codecOptions["video/mpeg2"] = QStringList() << "quantizer"; + m_codecOptions["video/theora"] = QStringList(); + + foreach( const QByteArray& codecName, codecCandidates ) { + QByteArray elementName = m_elementNames[codecName]; + GstElementFactory *factory = gst_element_factory_find(elementName.constData()); + if (factory) { + m_codecs.append(codecName); + const gchar *descr = gst_element_factory_get_description(factory); + m_codecDescriptions.insert(codecName, QString::fromUtf8(descr)); + + m_streamTypes.insert(codecName, + QGstreamerMediaContainerControl::supportedStreamTypes(factory, GST_PAD_SRC)); + + gst_object_unref(GST_OBJECT(factory)); + } + } + + //if (!m_codecs.isEmpty()) + // m_videoSettings.setCodec(m_codecs[0]); +} + +QGstreamerVideoEncode::~QGstreamerVideoEncode() +{ +} + +QList QGstreamerVideoEncode::supportedResolutions(const QVideoEncoderSettings &, bool *continuous) const +{ + if (continuous) + *continuous = m_session->videoInput() != 0; + + return m_session->videoInput() ? m_session->videoInput()->supportedResolutions() : QList(); +} + +QList< qreal > QGstreamerVideoEncode::supportedFrameRates(const QVideoEncoderSettings &, bool *continuous) const +{ + if (continuous) + *continuous = false; + + return m_session->videoInput() ? m_session->videoInput()->supportedFrameRates() : QList(); +} + +QStringList QGstreamerVideoEncode::supportedVideoCodecs() const +{ + return m_codecs; +} + +QString QGstreamerVideoEncode::videoCodecDescription(const QString &codecName) const +{ + return m_codecDescriptions.value(codecName); +} + +QStringList QGstreamerVideoEncode::supportedEncodingOptions(const QString &codec) const +{ + return m_codecOptions.value(codec); +} + +QVariant QGstreamerVideoEncode::encodingOption(const QString &codec, const QString &name) const +{ + return m_options[codec].value(name); +} + +void QGstreamerVideoEncode::setEncodingOption( + const QString &codec, const QString &name, const QVariant &value) +{ + m_options[codec][name] = value; +} + +QVideoEncoderSettings QGstreamerVideoEncode::videoSettings() const +{ + return m_videoSettings; +} + +void QGstreamerVideoEncode::setVideoSettings(const QVideoEncoderSettings &settings) +{ + m_videoSettings = settings; +} + +GstElement *QGstreamerVideoEncode::createEncoder() +{ + QString codec = m_videoSettings.codec(); + //qDebug() << "create encoder for video codec" << codec; + GstElement *encoderElement = gst_element_factory_make( m_elementNames.value(codec).constData(), "video-encoder"); + if (!encoderElement) + return 0; + + GstBin *encoderBin = GST_BIN(gst_bin_new("video-encoder-bin")); + + GstElement *capsFilter = gst_element_factory_make("capsfilter", "capsfilter-video"); + gst_bin_add(encoderBin, capsFilter); + + GstElement *colorspace = gst_element_factory_make("ffmpegcolorspace", NULL); + gst_bin_add(encoderBin, colorspace); + gst_bin_add(encoderBin, encoderElement); + + gst_element_link_many(capsFilter, colorspace, encoderElement, NULL); + + // add ghostpads + GstPad *pad = gst_element_get_static_pad(capsFilter, "sink"); + gst_element_add_pad(GST_ELEMENT(encoderBin), gst_ghost_pad_new("sink", pad)); + gst_object_unref(GST_OBJECT(pad)); + + pad = gst_element_get_static_pad(encoderElement, "src"); + gst_element_add_pad(GST_ELEMENT(encoderBin), gst_ghost_pad_new("src", pad)); + gst_object_unref(GST_OBJECT(pad)); + + if (encoderElement) { + if (m_videoSettings.encodingMode() == QtMultimediaKit::ConstantQualityEncoding) { + QtMultimediaKit::EncodingQuality qualityValue = m_videoSettings.quality(); + + if (codec == QLatin1String("video/h264")) { + //constant quantizer mode + g_object_set(G_OBJECT(encoderElement), "pass", 4, NULL); + int qualityTable[] = { + 50, //VeryLow + 35, //Low + 21, //Normal + 15, //High + 8 //VeryHigh + }; + g_object_set(G_OBJECT(encoderElement), "quantizer", qualityTable[qualityValue], NULL); + } else if (codec == QLatin1String("video/xvid")) { + //constant quantizer mode + g_object_set(G_OBJECT(encoderElement), "pass", 3, NULL); + int qualityTable[] = { + 32, //VeryLow + 12, //Low + 5, //Normal + 3, //High + 2 //VeryHigh + }; + int quant = qualityTable[qualityValue]; + g_object_set(G_OBJECT(encoderElement), "quantizer", quant, NULL); + } else if (codec == QLatin1String("video/mpeg4") || + codec == QLatin1String("video/mpeg1") || + codec == QLatin1String("video/mpeg2") ) { + //constant quantizer mode + g_object_set(G_OBJECT(encoderElement), "pass", 2, NULL); + //quant from 1 to 30, default ~3 + double qualityTable[] = { + 20, //VeryLow + 8.0, //Low + 3.0, //Normal + 2.5, //High + 2.0 //VeryHigh + }; + double quant = qualityTable[qualityValue]; + g_object_set(G_OBJECT(encoderElement), "quantizer", quant, NULL); + } else if (codec == QLatin1String("video/theora")) { + int qualityTable[] = { + 8, //VeryLow + 16, //Low + 32, //Normal + 45, //High + 60 //VeryHigh + }; + //quality from 0 to 63 + int quality = qualityTable[qualityValue]; + g_object_set(G_OBJECT(encoderElement), "quality", quality, NULL); + } + } else { + int bitrate = m_videoSettings.bitRate(); + if (bitrate > 0) { + g_object_set(G_OBJECT(encoderElement), "bitrate", bitrate, NULL); + } + } + + QMap options = m_options.value(codec); + QMapIterator it(options); + while (it.hasNext()) { + it.next(); + QString option = it.key(); + QVariant value = it.value(); + + switch (value.type()) { + case QVariant::Int: + g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toInt(), NULL); + break; + case QVariant::Bool: + g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toBool(), NULL); + break; + case QVariant::Double: + g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toDouble(), NULL); + break; + case QVariant::String: + g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toString().toUtf8().constData(), NULL); + break; + default: + qWarning() << "unsupported option type:" << option << value; + break; + } + + } + } + + if (!m_videoSettings.resolution().isEmpty() || m_videoSettings.frameRate() > 0.001) { + GstCaps *caps = gst_caps_new_empty(); + QStringList structureTypes; + structureTypes << "video/x-raw-yuv" << "video/x-raw-rgb"; + + foreach(const QString &structureType, structureTypes) { + GstStructure *structure = gst_structure_new(structureType.toAscii().constData(), NULL); + + if (!m_videoSettings.resolution().isEmpty()) { + gst_structure_set(structure, "width", G_TYPE_INT, m_videoSettings.resolution().width(), NULL); + gst_structure_set(structure, "height", G_TYPE_INT, m_videoSettings.resolution().height(), NULL); + } + + if (m_videoSettings.frameRate() > 0.001) { + QPair rate = rateAsRational(); + + //qDebug() << "frame rate:" << num << denum; + + gst_structure_set(structure, "framerate", GST_TYPE_FRACTION, rate.first, rate.second, NULL); + } + + gst_caps_append_structure(caps,structure); + } + + //qDebug() << "set video caps filter:" << gst_caps_to_string(caps); + + g_object_set(G_OBJECT(capsFilter), "caps", caps, NULL); + } + + return GST_ELEMENT(encoderBin); +} + +QPair QGstreamerVideoEncode::rateAsRational() const +{ + qreal frameRate = m_videoSettings.frameRate(); + + if (frameRate > 0.001) { + //convert to rational number + QList denumCandidates; + denumCandidates << 1 << 2 << 3 << 5 << 10 << 1001 << 1000; + + qreal error = 1.0; + int num = 1; + int denum = 1; + + foreach (int curDenum, denumCandidates) { + int curNum = qRound(frameRate*curDenum); + qreal curError = qAbs(qreal(curNum)/curDenum - frameRate); + + if (curError < error) { + error = curError; + num = curNum; + denum = curDenum; + } + + if (curError < 1e-8) + break; + } + + return QPair(num,denum); + } + + return QPair(); +} + + +QSet QGstreamerVideoEncode::supportedStreamTypes(const QString &codecName) const +{ + return m_streamTypes.value(codecName); +} diff --git a/src/plugins/gstreamer/mediacapture/qgstreamervideoencode.h b/src/plugins/gstreamer/mediacapture/qgstreamervideoencode.h new file mode 100644 index 000000000..c042efd25 --- /dev/null +++ b/src/plugins/gstreamer/mediacapture/qgstreamervideoencode.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERVIDEOENCODE_H +#define QGSTREAMERVIDEOENCODE_H + +#include +class QGstreamerCaptureSession; + +#include +#include +#include + +#include + +QT_USE_NAMESPACE + +class QGstreamerVideoEncode : public QVideoEncoderControl +{ + Q_OBJECT +public: + QGstreamerVideoEncode(QGstreamerCaptureSession *session); + virtual ~QGstreamerVideoEncode(); + + QList supportedResolutions(const QVideoEncoderSettings &settings = QVideoEncoderSettings(), + bool *continuous = 0) const; + + QList< qreal > supportedFrameRates(const QVideoEncoderSettings &settings = QVideoEncoderSettings(), + bool *continuous = 0) const; + + QPair rateAsRational() const; + + QStringList supportedVideoCodecs() const; + QString videoCodecDescription(const QString &codecName) const; + + QVideoEncoderSettings videoSettings() const; + void setVideoSettings(const QVideoEncoderSettings &settings); + + QStringList supportedEncodingOptions(const QString &codec) const; + QVariant encodingOption(const QString &codec, const QString &name) const; + void setEncodingOption(const QString &codec, const QString &name, const QVariant &value); + + GstElement *createEncoder(); + + QSet supportedStreamTypes(const QString &codecName) const; + +private: + QGstreamerCaptureSession *m_session; + + QStringList m_codecs; + QMap m_codecDescriptions; + QMap m_elementNames; + QMap m_codecOptions; + + QVideoEncoderSettings m_videoSettings; + QMap > m_options; + QMap > m_streamTypes; +}; + +#endif diff --git a/src/plugins/gstreamer/mediaplayer/mediaplayer.pri b/src/plugins/gstreamer/mediaplayer/mediaplayer.pri new file mode 100644 index 000000000..9045a80dd --- /dev/null +++ b/src/plugins/gstreamer/mediaplayer/mediaplayer.pri @@ -0,0 +1,30 @@ +INCLUDEPATH += $$PWD + +DEFINES += QMEDIA_GSTREAMER_PLAYER + +contains(gstreamer-appsrc_enabled, yes) { + HEADERS += $$PWD/qgstappsrc.h + SOURCES += $$PWD/qgstappsrc.cpp + + DEFINES += HAVE_GST_APPSRC + + LIBS += -lgstapp-0.10 +} + +HEADERS += \ + $$PWD/qgstreamerplayercontrol.h \ + $$PWD/qgstreamerplayerservice.h \ + $$PWD/qgstreamerplayersession.h \ + $$PWD/qgstreamerstreamscontrol.h \ + $$PWD/qgstreamermetadataprovider.h \ + $$PWD/playerresourcepolicy.h + +SOURCES += \ + $$PWD/qgstreamerplayercontrol.cpp \ + $$PWD/qgstreamerplayerservice.cpp \ + $$PWD/qgstreamerplayersession.cpp \ + $$PWD/qgstreamerstreamscontrol.cpp \ + $$PWD/qgstreamermetadataprovider.cpp \ + $$PWD/playerresourcepolicy.cpp + + diff --git a/src/plugins/gstreamer/mediaplayer/playerresourcepolicy.cpp b/src/plugins/gstreamer/mediaplayer/playerresourcepolicy.cpp new file mode 100644 index 000000000..b2cf3498d --- /dev/null +++ b/src/plugins/gstreamer/mediaplayer/playerresourcepolicy.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "playerresourcepolicy.h" + +#ifdef Q_WS_MAEMO_6 +#define HAVE_RESOURCE_POLICY +#endif + +//#define DEBUG_RESOURCE_POLICY +#include + +#ifdef HAVE_RESOURCE_POLICY +#include +#include +#include +#endif + +PlayerResourcePolicy::PlayerResourcePolicy(QObject *parent) : + QObject(parent), + m_videoEnabled(true), + m_resourceSet(0), + m_status(PlayerResourcePolicy::Initial) +{ +#ifdef HAVE_RESOURCE_POLICY + m_resourceSet = new ResourcePolicy::ResourceSet("player", this); + m_resourceSet->setAlwaysReply(); + + ResourcePolicy::AudioResource *audioResource = new ResourcePolicy::AudioResource("player"); + audioResource->setProcessID(QCoreApplication::applicationPid()); + audioResource->setStreamTag("media.name", "*"); + m_resourceSet->addResourceObject(audioResource); + + m_resourceSet->addResource(ResourcePolicy::VideoPlaybackType); + m_resourceSet->update(); + + connect(m_resourceSet, SIGNAL(resourcesGranted(const QList)), + this, SLOT(handleResourcesGranted())); + connect(m_resourceSet, SIGNAL(resourcesDenied()), + this, SLOT(handleResourcesDenied())); + connect(m_resourceSet, SIGNAL(lostResources()), + this, SLOT(handleResourcesLost())); + connect(m_resourceSet, SIGNAL(resourcesReleasedByManager()), + this, SLOT(handleResourcesLost())); +#endif +} + +PlayerResourcePolicy::~PlayerResourcePolicy() +{ +} + +bool PlayerResourcePolicy::isVideoEnabled() const +{ + return m_videoEnabled; +} + +void PlayerResourcePolicy::setVideoEnabled(bool enabled) +{ + if (m_videoEnabled != enabled) { + m_videoEnabled = enabled; + +#ifdef HAVE_RESOURCE_POLICY + if (enabled) + m_resourceSet->addResource(ResourcePolicy::VideoPlaybackType); + else + m_resourceSet->deleteResource(ResourcePolicy::VideoPlaybackType); + + m_resourceSet->update(); +#endif + } +} + +void PlayerResourcePolicy::acquire() +{ +#ifdef HAVE_RESOURCE_POLICY + +#ifdef DEBUG_RESOURCE_POLICY + qDebug() << Q_FUNC_INFO << "Acquire resource"; +#endif + m_status = RequestedResource; + m_resourceSet->acquire(); +#else + m_status = GrantedResource; +#endif +} + +void PlayerResourcePolicy::release() +{ +#ifdef HAVE_RESOURCE_POLICY + +#ifdef DEBUG_RESOURCE_POLICY + qDebug() << Q_FUNC_INFO << "Release resource"; +#endif + + m_resourceSet->release(); +#endif + m_status = Initial; + +} + +bool PlayerResourcePolicy::isGranted() const +{ + return m_status == GrantedResource; +} + +bool PlayerResourcePolicy::isRequested() const +{ + return m_status == RequestedResource; +} + +void PlayerResourcePolicy::handleResourcesGranted() +{ + m_status = GrantedResource; +#ifdef DEBUG_RESOURCE_POLICY + qDebug() << Q_FUNC_INFO << "Resource granted"; +#endif + emit resourcesGranted(); +} + +void PlayerResourcePolicy::handleResourcesDenied() +{ + m_status = Initial; +#ifdef DEBUG_RESOURCE_POLICY + qDebug() << Q_FUNC_INFO << "Resource denied"; +#endif + emit resourcesDenied(); +} + +void PlayerResourcePolicy::handleResourcesLost() +{ +#ifdef DEBUG_RESOURCE_POLICY + qDebug() << Q_FUNC_INFO << "Resource lost"; +#endif + if (m_status != Initial) { + m_status = Initial; + emit resourcesLost(); + } + +#ifdef HAVE_RESOURCE_POLICY + m_resourceSet->release(); +#endif +} diff --git a/src/plugins/gstreamer/mediaplayer/playerresourcepolicy.h b/src/plugins/gstreamer/mediaplayer/playerresourcepolicy.h new file mode 100644 index 000000000..fecf5fa80 --- /dev/null +++ b/src/plugins/gstreamer/mediaplayer/playerresourcepolicy.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PLAYERRESOURCEPOLICY_H +#define PLAYERRESOURCEPOLICY_H + +#include + +namespace ResourcePolicy { +class ResourceSet; +}; + +class PlayerResourcePolicy : public QObject +{ + Q_OBJECT +public: + PlayerResourcePolicy(QObject *parent = 0); + ~PlayerResourcePolicy(); + + bool isVideoEnabled() const; + bool isGranted() const; + bool isRequested() const; + +Q_SIGNALS: + void resourcesDenied(); + void resourcesGranted(); + void resourcesLost(); + +public Q_SLOTS: + void acquire(); + void release(); + + void setVideoEnabled(bool enabled); + +private Q_SLOTS: + void handleResourcesGranted(); + void handleResourcesDenied(); + void handleResourcesLost(); + +private: + enum ResourceStatus { + Initial = 0, + RequestedResource, + GrantedResource + }; + + bool m_videoEnabled; + ResourcePolicy::ResourceSet *m_resourceSet; + ResourceStatus m_status; +}; + +#endif diff --git a/src/plugins/gstreamer/mediaplayer/qgstappsrc.cpp b/src/plugins/gstreamer/mediaplayer/qgstappsrc.cpp new file mode 100644 index 000000000..cf814c462 --- /dev/null +++ b/src/plugins/gstreamer/mediaplayer/qgstappsrc.cpp @@ -0,0 +1,224 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "qgstappsrc.h" +#include + +QGstAppSrc::QGstAppSrc(QObject *parent) + :QObject(parent) + ,m_stream(0) + ,m_appSrc(0) + ,m_sequential(false) + ,m_maxBytes(0) + ,m_setup(false) + ,m_dataRequestSize(-1) + ,m_dataRequested(false) + ,m_enoughData(false) + ,m_forceData(false) +{ +} + +QGstAppSrc::~QGstAppSrc() +{ + if (m_appSrc) + gst_object_unref(G_OBJECT(m_appSrc)); +} + +bool QGstAppSrc::setup(GstElement* appsrc) +{ + if (m_setup || m_stream == 0 || appsrc == 0) + return false; + + m_appSrc = GST_APP_SRC(appsrc); + m_callbacks.need_data = &QGstAppSrc::on_need_data; + m_callbacks.enough_data = &QGstAppSrc::on_enough_data; + m_callbacks.seek_data = &QGstAppSrc::on_seek_data; + gst_app_src_set_callbacks(m_appSrc, (GstAppSrcCallbacks*)&m_callbacks, this, (GDestroyNotify)&QGstAppSrc::destroy_notify); + + g_object_get(G_OBJECT(m_appSrc), "max-bytes", &m_maxBytes, NULL); + + if (m_sequential) + m_streamType = GST_APP_STREAM_TYPE_STREAM; + else + m_streamType = GST_APP_STREAM_TYPE_RANDOM_ACCESS; + gst_app_src_set_stream_type(m_appSrc, m_streamType); + gst_app_src_set_size(m_appSrc, (m_sequential) ? -1 : m_stream->size()); + + return m_setup = true; +} + +void QGstAppSrc::setStream(QIODevice *stream) +{ + if (stream == 0) + return; + if (m_stream) { + disconnect(m_stream, SIGNAL(readyRead()), this, SLOT(onDataReady())); + disconnect(m_stream, SIGNAL(destroyed()), this, SLOT(streamDestroyed())); + } + if (m_appSrc) + gst_object_unref(G_OBJECT(m_appSrc)); + + m_dataRequestSize = -1; + m_dataRequested = false; + m_enoughData = false; + m_forceData = false; + m_maxBytes = 0; + + m_appSrc = 0; + m_stream = stream; + connect(m_stream, SIGNAL(destroyed()), SLOT(streamDestroyed())); + connect(m_stream, SIGNAL(readyRead()), this, SLOT(onDataReady())); + m_sequential = m_stream->isSequential(); + m_setup = false; +} + +QIODevice *QGstAppSrc::stream() const +{ + return m_stream; +} + +GstAppSrc *QGstAppSrc::element() +{ + return m_appSrc; +} + +void QGstAppSrc::onDataReady() +{ + if (!m_enoughData) { + m_dataRequested = true; + pushDataToAppSrc(); + } +} + +void QGstAppSrc::streamDestroyed() +{ + if (sender() == m_stream) { + m_stream = 0; + sendEOS(); + } +} + +void QGstAppSrc::pushDataToAppSrc() +{ + if (!isStreamValid() || !m_setup) + return; + + if (m_dataRequested && !m_enoughData) { + qint64 size; + if (m_dataRequestSize == (unsigned int)-1) + size = qMin(m_stream->bytesAvailable(), queueSize()); + else + size = qMin(m_stream->bytesAvailable(), (qint64)m_dataRequestSize); + void *data = g_malloc(size); + GstBuffer* buffer = gst_app_buffer_new(data, size, g_free, data); + buffer->offset = m_stream->pos(); + qint64 bytesRead = m_stream->read((char*)GST_BUFFER_DATA(buffer), size); + buffer->offset_end = buffer->offset + bytesRead - 1; + + if (bytesRead > 0) { + m_dataRequested = false; + m_enoughData = false; + GstFlowReturn ret = gst_app_src_push_buffer (GST_APP_SRC (element()), buffer); + if (ret == GST_FLOW_ERROR) { + qWarning()<<"appsrc: push buffer error"; + } else if (ret == GST_FLOW_WRONG_STATE) { + qWarning()<<"appsrc: push buffer wrong state"; + } else if (ret == GST_FLOW_RESEND) { + qWarning()<<"appsrc: push buffer resend"; + } + } + } else if (m_stream->atEnd()) { + sendEOS(); + } +} + +bool QGstAppSrc::doSeek(qint64 value) +{ + if (isStreamValid()) + return stream()->seek(value); + return false; +} + + +gboolean QGstAppSrc::on_seek_data(GstAppSrc *element, guint64 arg0, gpointer userdata) +{ + QGstAppSrc *self = reinterpret_cast(userdata); + if (self && self->isStreamValid()) { + if (!self->stream()->isSequential()) + QMetaObject::invokeMethod(self, "doSeek", Qt::AutoConnection, Q_ARG(qint64, arg0)); + } + else + return false; + + return true; +} + +void QGstAppSrc::on_enough_data(GstAppSrc *element, gpointer userdata) +{ + QGstAppSrc *self = reinterpret_cast(userdata); + if (self) + self->enoughData() = true; +} + +void QGstAppSrc::on_need_data(GstAppSrc *element, guint arg0, gpointer userdata) +{ + QGstAppSrc *self = reinterpret_cast(userdata); + if (self) { + self->dataRequested() = true; + self->enoughData() = false; + self->dataRequestSize()= arg0; + QMetaObject::invokeMethod(self, "pushDataToAppSrc", Qt::AutoConnection); + } +} + +void QGstAppSrc::destroy_notify(gpointer data) +{ + Q_UNUSED(data); +} + +void QGstAppSrc::sendEOS() +{ + gst_app_src_end_of_stream(GST_APP_SRC(m_appSrc)); + if (isStreamValid() && !stream()->isSequential()) + stream()->reset(); +} diff --git a/src/plugins/gstreamer/mediaplayer/qgstappsrc.h b/src/plugins/gstreamer/mediaplayer/qgstappsrc.h new file mode 100644 index 000000000..17ee2af72 --- /dev/null +++ b/src/plugins/gstreamer/mediaplayer/qgstappsrc.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTAPPSRC_H +#define QGSTAPPSRC_H + +#include +#include + +#include +#include +#include + +class QGstAppSrc : public QObject +{ + Q_OBJECT +public: + QGstAppSrc(QObject *parent = 0); + ~QGstAppSrc(); + + bool setup(GstElement *); + bool isReady() const { return m_setup; } + + void setStream(QIODevice *); + QIODevice *stream() const; + + GstAppSrc *element(); + + qint64 queueSize() const { return m_maxBytes; } + + bool& enoughData() { return m_enoughData; } + bool& dataRequested() { return m_dataRequested; } + unsigned int& dataRequestSize() { return m_dataRequestSize; } + + bool isStreamValid() const + { + return m_stream != 0 && + m_stream->isOpen(); + } + +private slots: + void pushDataToAppSrc(); + bool doSeek(qint64); + void onDataReady(); + + void streamDestroyed(); +private: + static gboolean on_seek_data(GstAppSrc *element, guint64 arg0, gpointer userdata); + static void on_enough_data(GstAppSrc *element, gpointer userdata); + static void on_need_data(GstAppSrc *element, uint arg0, gpointer userdata); + static void destroy_notify(gpointer data); + + void sendEOS(); + + QIODevice *m_stream; + GstAppSrc *m_appSrc; + bool m_sequential; + GstAppStreamType m_streamType; + GstAppSrcCallbacks m_callbacks; + qint64 m_maxBytes; + bool m_setup; + unsigned int m_dataRequestSize; + bool m_dataRequested; + bool m_enoughData; + bool m_forceData; +}; + +#endif diff --git a/src/plugins/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp b/src/plugins/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp new file mode 100644 index 000000000..cdd6d89b4 --- /dev/null +++ b/src/plugins/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamermetadataprovider.h" +#include "qgstreamerplayersession.h" +#include + +#include + +struct QGstreamerMetaDataKeyLookup +{ + QtMultimediaKit::MetaData key; + const char *token; +}; + +static const QGstreamerMetaDataKeyLookup qt_gstreamerMetaDataKeys[] = +{ + { QtMultimediaKit::Title, GST_TAG_TITLE }, + //{ QtMultimediaKit::SubTitle, 0 }, + //{ QtMultimediaKit::Author, 0 }, + { QtMultimediaKit::Comment, GST_TAG_COMMENT }, + { QtMultimediaKit::Description, GST_TAG_DESCRIPTION }, + //{ QtMultimediaKit::Category, 0 }, + { QtMultimediaKit::Genre, GST_TAG_GENRE }, + { QtMultimediaKit::Year, "year" }, + //{ QtMultimediaKit::UserRating, 0 }, + + { QtMultimediaKit::Language, GST_TAG_LANGUAGE_CODE }, + + { QtMultimediaKit::Publisher, GST_TAG_ORGANIZATION }, + { QtMultimediaKit::Copyright, GST_TAG_COPYRIGHT }, + //{ QtMultimediaKit::ParentalRating, 0 }, + //{ QtMultimediaKit::RatingOrganisation, 0 }, + + // Media + //{ QtMultimediaKit::Size, 0 }, + //{ QtMultimediaKit::MediaType, 0 }, + { QtMultimediaKit::Duration, GST_TAG_DURATION }, + + // Audio + { QtMultimediaKit::AudioBitRate, GST_TAG_BITRATE }, + { QtMultimediaKit::AudioCodec, GST_TAG_AUDIO_CODEC }, + //{ QtMultimediaKit::ChannelCount, 0 }, + //{ QtMultimediaKit::SampleRate, 0 }, + + // Music + { QtMultimediaKit::AlbumTitle, GST_TAG_ALBUM }, + { QtMultimediaKit::AlbumArtist, GST_TAG_ARTIST}, + { QtMultimediaKit::ContributingArtist, GST_TAG_PERFORMER }, +#if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 19) + { QtMultimediaKit::Composer, GST_TAG_COMPOSER }, +#endif + //{ QtMultimediaKit::Conductor, 0 }, + //{ QtMultimediaKit::Lyrics, 0 }, + //{ QtMultimediaKit::Mood, 0 }, + { QtMultimediaKit::TrackNumber, GST_TAG_TRACK_NUMBER }, + + //{ QtMultimediaKit::CoverArtUrlSmall, 0 }, + //{ QtMultimediaKit::CoverArtUrlLarge, 0 }, + + // Image/Video + { QtMultimediaKit::Resolution, "resolution" }, + { QtMultimediaKit::PixelAspectRatio, "pixel-aspect-ratio" }, + + // Video + //{ QtMultimediaKit::VideoFrameRate, 0 }, + //{ QtMultimediaKit::VideoBitRate, 0 }, + { QtMultimediaKit::VideoCodec, GST_TAG_VIDEO_CODEC }, + + //{ QtMultimediaKit::PosterUrl, 0 }, + + // Movie + //{ QtMultimediaKit::ChapterNumber, 0 }, + //{ QtMultimediaKit::Director, 0 }, + { QtMultimediaKit::LeadPerformer, GST_TAG_PERFORMER }, + //{ QtMultimediaKit::Writer, 0 }, + + // Photos + //{ QtMultimediaKit::CameraManufacturer, 0 }, + //{ QtMultimediaKit::CameraModel, 0 }, + //{ QtMultimediaKit::Event, 0 }, + //{ QtMultimediaKit::Subject, 0 } +}; + +QGstreamerMetaDataProvider::QGstreamerMetaDataProvider(QGstreamerPlayerSession *session, QObject *parent) + :QMetaDataReaderControl(parent), m_session(session) +{ + connect(m_session, SIGNAL(tagsChanged()), SLOT(updateTags())); +} + +QGstreamerMetaDataProvider::~QGstreamerMetaDataProvider() +{ +} + +bool QGstreamerMetaDataProvider::isMetaDataAvailable() const +{ + return !m_session->tags().isEmpty(); +} + +bool QGstreamerMetaDataProvider::isWritable() const +{ + return false; +} + +QVariant QGstreamerMetaDataProvider::metaData(QtMultimediaKit::MetaData key) const +{ + static const int count = sizeof(qt_gstreamerMetaDataKeys) / sizeof(QGstreamerMetaDataKeyLookup); + + for (int i = 0; i < count; ++i) { + if (qt_gstreamerMetaDataKeys[i].key == key) { + return m_session->tags().value(QByteArray(qt_gstreamerMetaDataKeys[i].token)); + } + } + return QVariant(); +} + +QList QGstreamerMetaDataProvider::availableMetaData() const +{ + static QMap keysMap; + if (keysMap.isEmpty()) { + const int count = sizeof(qt_gstreamerMetaDataKeys) / sizeof(QGstreamerMetaDataKeyLookup); + for (int i = 0; i < count; ++i) { + keysMap[QByteArray(qt_gstreamerMetaDataKeys[i].token)] = qt_gstreamerMetaDataKeys[i].key; + } + } + + QList res; + foreach (const QByteArray &key, m_session->tags().keys()) { + QtMultimediaKit::MetaData tag = keysMap.value(key, QtMultimediaKit::MetaData(-1)); + if (tag != -1) + res.append(tag); + } + + return res; +} + +QVariant QGstreamerMetaDataProvider::extendedMetaData(const QString &key) const +{ + return m_session->tags().value(key.toLatin1()); +} + +QStringList QGstreamerMetaDataProvider::availableExtendedMetaData() const +{ + QStringList res; + foreach (const QByteArray &key, m_session->tags().keys()) + res.append(QString(key)); + + return res; +} + +void QGstreamerMetaDataProvider::updateTags() +{ + emit metaDataChanged(); +} diff --git a/src/plugins/gstreamer/mediaplayer/qgstreamermetadataprovider.h b/src/plugins/gstreamer/mediaplayer/qgstreamermetadataprovider.h new file mode 100644 index 000000000..fa0c0243f --- /dev/null +++ b/src/plugins/gstreamer/mediaplayer/qgstreamermetadataprovider.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERMETADATAPROVIDER_H +#define QGSTREAMERMETADATAPROVIDER_H + +#include + +QT_USE_NAMESPACE + +class QGstreamerPlayerSession; + +class QGstreamerMetaDataProvider : public QMetaDataReaderControl +{ + Q_OBJECT +public: + QGstreamerMetaDataProvider( QGstreamerPlayerSession *session, QObject *parent ); + virtual ~QGstreamerMetaDataProvider(); + + bool isMetaDataAvailable() const; + bool isWritable() const; + + QVariant metaData(QtMultimediaKit::MetaData key) const; + QList availableMetaData() const; + + QVariant extendedMetaData(const QString &key) const ; + QStringList availableExtendedMetaData() const; + +private slots: + void updateTags(); + +private: + QGstreamerPlayerSession *m_session; +}; + +#endif // QGSTREAMERMETADATAPROVIDER_H diff --git a/src/plugins/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp b/src/plugins/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp new file mode 100644 index 000000000..f36dd08a3 --- /dev/null +++ b/src/plugins/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp @@ -0,0 +1,748 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamerplayercontrol.h" +#include "qgstreamerplayersession.h" +#include "playerresourcepolicy.h" + +#include + + +#include +#include +#include +#include + +#include +#include +#include +#include + +//#define DEBUG_PLAYBIN + +QGstreamerPlayerControl::QGstreamerPlayerControl(QGstreamerPlayerSession *session, QObject *parent) + : QMediaPlayerControl(parent) + , m_ownStream(false) + , m_session(session) + , m_state(QMediaPlayer::StoppedState) + , m_mediaStatus(QMediaPlayer::NoMedia) + , m_bufferProgress(-1) + , m_seekToStartPending(false) + , m_pendingSeekPosition(-1) + , m_stream(0) + , m_fifoNotifier(0) + , m_fifoCanWrite(false) + , m_bufferSize(0) + , m_bufferOffset(0) +{ + m_fifoFd[0] = -1; + m_fifoFd[1] = -1; + + m_resources = new PlayerResourcePolicy(this); + + connect(m_session, SIGNAL(positionChanged(qint64)), + this, SIGNAL(positionChanged(qint64))); + connect(m_session, SIGNAL(durationChanged(qint64)), + this, SIGNAL(durationChanged(qint64))); + connect(m_session, SIGNAL(mutedStateChanged(bool)), + this, SIGNAL(mutedChanged(bool))); + connect(m_session, SIGNAL(volumeChanged(int)), + this, SIGNAL(volumeChanged(int))); + connect(m_session, SIGNAL(stateChanged(QMediaPlayer::State)), + this, SLOT(updateSessionState(QMediaPlayer::State))); + connect(m_session,SIGNAL(bufferingProgressChanged(int)), + this, SLOT(setBufferProgress(int))); + connect(m_session, SIGNAL(playbackFinished()), + this, SLOT(processEOS())); + connect(m_session, SIGNAL(audioAvailableChanged(bool)), + this, SIGNAL(audioAvailableChanged(bool))); + connect(m_session, SIGNAL(videoAvailableChanged(bool)), + this, SIGNAL(videoAvailableChanged(bool))); + connect(m_session, SIGNAL(seekableChanged(bool)), + this, SIGNAL(seekableChanged(bool))); + connect(m_session, SIGNAL(error(int,QString)), + this, SIGNAL(error(int,QString))); + connect(m_session, SIGNAL(invalidMedia()), + this, SLOT(handleInvalidMedia())); + connect(m_session, SIGNAL(playbackRateChanged(qreal)), + this, SIGNAL(playbackRateChanged(qreal))); + connect(m_session, SIGNAL(seekableChanged(bool)), + this, SLOT(applyPendingSeek(bool))); + + connect(m_resources, SIGNAL(resourcesGranted()), SLOT(handleResourcesGranted())); + connect(m_resources, SIGNAL(resourcesDenied()), SLOT(handleResourcesLost())); + connect(m_resources, SIGNAL(resourcesLost()), SLOT(handleResourcesLost())); +} + +QGstreamerPlayerControl::~QGstreamerPlayerControl() +{ + if (m_fifoFd[0] >= 0) { + ::close(m_fifoFd[0]); + ::close(m_fifoFd[1]); + m_fifoFd[0] = -1; + m_fifoFd[1] = -1; + } +} + +qint64 QGstreamerPlayerControl::position() const +{ + return m_seekToStartPending ? 0 : m_session->position(); +} + +qint64 QGstreamerPlayerControl::duration() const +{ + return m_session->duration(); +} + +QMediaPlayer::State QGstreamerPlayerControl::state() const +{ + return m_state; +} + +QMediaPlayer::MediaStatus QGstreamerPlayerControl::mediaStatus() const +{ + return m_mediaStatus; +} + +int QGstreamerPlayerControl::bufferStatus() const +{ + if (m_bufferProgress == -1) { + return m_session->state() == QMediaPlayer::StoppedState ? 0 : 100; + } else + return m_bufferProgress; +} + +int QGstreamerPlayerControl::volume() const +{ + return m_session->volume(); +} + +bool QGstreamerPlayerControl::isMuted() const +{ + return m_session->isMuted(); +} + +bool QGstreamerPlayerControl::isSeekable() const +{ + return m_session->isSeekable(); +} + +QMediaTimeRange QGstreamerPlayerControl::availablePlaybackRanges() const +{ + return m_session->availablePlaybackRanges(); +} + +qreal QGstreamerPlayerControl::playbackRate() const +{ + return m_session->playbackRate(); +} + +void QGstreamerPlayerControl::setPlaybackRate(qreal rate) +{ + m_session->setPlaybackRate(rate); +} + +void QGstreamerPlayerControl::setPosition(qint64 pos) +{ +#ifdef DEBUG_PLAYBIN + qDebug() << Q_FUNC_INFO << pos/1000.0; +#endif + + pushState(); + + if (m_mediaStatus == QMediaPlayer::EndOfMedia) { + m_mediaStatus = QMediaPlayer::LoadedMedia; + m_seekToStartPending = true; + } + + if (m_session->isSeekable() && m_session->seek(pos)) { + m_seekToStartPending = false; + m_pendingSeekPosition = -1; + } else { + m_pendingSeekPosition = pos; + } + + popAndNotifyState(); +} + +void QGstreamerPlayerControl::play() +{ +#ifdef DEBUG_PLAYBIN + qDebug() << Q_FUNC_INFO; +#endif + + playOrPause(QMediaPlayer::PlayingState); +} + +void QGstreamerPlayerControl::pause() +{ +#ifdef DEBUG_PLAYBIN + qDebug() << Q_FUNC_INFO; +#endif + + playOrPause(QMediaPlayer::PausedState); +} + +void QGstreamerPlayerControl::playOrPause(QMediaPlayer::State newState) +{ + if (m_mediaStatus == QMediaPlayer::NoMedia) + return; + + pushState(); +#ifdef Q_WS_MAEMO_6 + //this is a work around for the gstreamer bug, + //should be remove once it get fixed + if (newState == QMediaPlayer::PlayingState && m_mediaStatus == QMediaPlayer::InvalidMedia) { + setMedia(m_currentResource, m_stream); + } +#endif + + if (m_mediaStatus == QMediaPlayer::EndOfMedia) { + m_mediaStatus = QMediaPlayer::BufferedMedia; + m_seekToStartPending = true; + } + + if (!m_resources->isGranted() && !m_resources->isRequested()) + m_resources->acquire(); + + if (m_resources->isGranted()) { + if (m_seekToStartPending) { + m_session->pause(); + if (!m_session->seek(0)) { + m_bufferProgress = -1; + m_session->stop(); + m_mediaStatus = QMediaPlayer::LoadingMedia; + } + m_seekToStartPending = false; + } + + bool ok = false; + + if (newState == QMediaPlayer::PlayingState) + ok = m_session->play(); + else + ok = m_session->pause(); + + if (!ok) + newState = QMediaPlayer::StoppedState; + } + + if (m_mediaStatus == QMediaPlayer::InvalidMedia) + m_mediaStatus = QMediaPlayer::LoadingMedia; + + m_state = newState; + + if (m_mediaStatus == QMediaPlayer::EndOfMedia || m_mediaStatus == QMediaPlayer::LoadedMedia) { + if (m_bufferProgress == -1 || m_bufferProgress == 100) + m_mediaStatus = QMediaPlayer::BufferedMedia; + else + m_mediaStatus = QMediaPlayer::BufferingMedia; + } + + popAndNotifyState(); + + emit positionChanged(position()); +} + +void QGstreamerPlayerControl::stop() +{ +#ifdef DEBUG_PLAYBIN + qDebug() << Q_FUNC_INFO; +#endif + + pushState(); + + if (m_state != QMediaPlayer::StoppedState) { + m_state = QMediaPlayer::StoppedState; + if (m_resources->isGranted()) + m_session->pause(); + + if (m_mediaStatus != QMediaPlayer::EndOfMedia) { + m_seekToStartPending = true; + emit positionChanged(position()); + } + } + + popAndNotifyState(); +} + +void QGstreamerPlayerControl::setVolume(int volume) +{ + m_session->setVolume(volume); +} + +void QGstreamerPlayerControl::setMuted(bool muted) +{ + m_session->setMuted(muted); +} + +QMediaContent QGstreamerPlayerControl::media() const +{ + return m_currentResource; +} + +const QIODevice *QGstreamerPlayerControl::mediaStream() const +{ + return m_stream; +} + +void QGstreamerPlayerControl::setMedia(const QMediaContent &content, QIODevice *stream) +{ +#ifdef DEBUG_PLAYBIN + qDebug() << Q_FUNC_INFO; +#endif + + pushState(); + + m_state = QMediaPlayer::StoppedState; + QMediaContent oldMedia = m_currentResource; + m_pendingSeekPosition = -1; + + if (!content.isNull() || stream) { + if (!m_resources->isRequested() && !m_resources->isGranted()) + m_resources->acquire(); + + if (!m_resources->isGranted()) { + m_currentResource = content; + m_stream = stream; + + m_state = QMediaPlayer::StoppedState; + m_mediaStatus = QMediaPlayer::LoadingMedia; + if (m_currentResource != oldMedia) + emit mediaChanged(m_currentResource); + popAndNotifyState(); + return; + } + } else { + m_resources->release(); + } + + m_session->stop(); + + bool userStreamValid = false; + + if (m_bufferProgress != -1) { + m_bufferProgress = -1; + emit bufferStatusChanged(0); + } + + if (m_stream) { +#if !defined(HAVE_GST_APPSRC) + closeFifo(); + + disconnect(m_stream, SIGNAL(readyRead()), this, SLOT(writeFifo())); +#endif + + if (m_ownStream) + delete m_stream; + m_stream = 0; + m_ownStream = false; + } + + // If the canonical URL refers to a Qt resource, open with QFile and use + // the stream playback capability to play. + if (stream == 0 && content.canonicalUrl().scheme() == QLatin1String("qrc")) { + stream = new QFile(QLatin1Char(':') + content.canonicalUrl().path(), this); + if (!stream->open(QIODevice::ReadOnly)) { + delete stream; + m_mediaStatus = QMediaPlayer::InvalidMedia; + m_currentResource = content; + emit mediaChanged(m_currentResource); + emit error(QMediaPlayer::FormatError, tr("Attempting to play invalid Qt resource")); + if (m_state != QMediaPlayer::PlayingState) + m_resources->release(); + popAndNotifyState(); + return; + } + m_ownStream = true; + } + + m_currentResource = content; + m_stream = stream; + m_seekToStartPending = false; + + QNetworkRequest request; + + if (m_stream) { +#if !defined(HAVE_GST_APPSRC) + if (m_stream->isReadable() && openFifo()) { + request = QNetworkRequest(QUrl(QString(QLatin1String("fd://%1")).arg(m_fifoFd[0]))); + } +#else + userStreamValid = stream->isOpen() && m_stream->isReadable(); + request = content.canonicalRequest(); +#endif + } else if (!content.isNull()) { + request = content.canonicalRequest(); + } + +#if !defined(HAVE_GST_APPSRC) + m_session->loadFromUri(request); +#else + if (m_stream) { + if (userStreamValid){ + m_session->loadFromStream(request, m_stream); + } else { + m_mediaStatus = QMediaPlayer::InvalidMedia; + emit error(QMediaPlayer::FormatError, tr("Attempting to play invalid user stream")); + if (m_state != QMediaPlayer::PlayingState) + m_resources->release(); + popAndNotifyState(); + return; + } + } else + m_session->loadFromUri(request); +#endif + +#if !defined(HAVE_GST_APPSRC) + if (m_fifoFd[1] >= 0) { + m_fifoCanWrite = true; + + writeFifo(); + } +#endif + +#if defined(HAVE_GST_APPSRC) + if (!request.url().isEmpty() || userStreamValid) { +#else + if (!request.url().isEmpty()) { +#endif + m_mediaStatus = QMediaPlayer::LoadingMedia; + m_session->pause(); + } else { + m_mediaStatus = QMediaPlayer::NoMedia; + setBufferProgress(0); + } + + if (m_currentResource != oldMedia) + emit mediaChanged(m_currentResource); + + emit positionChanged(position()); + + if (content.isNull() && !stream) + m_resources->release(); + + popAndNotifyState(); +} + +void QGstreamerPlayerControl::setVideoOutput(QObject *output) +{ + m_session->setVideoRenderer(output); +} + +bool QGstreamerPlayerControl::isAudioAvailable() const +{ + return m_session->isAudioAvailable(); +} + +bool QGstreamerPlayerControl::isVideoAvailable() const +{ + return m_session->isVideoAvailable(); +} + +void QGstreamerPlayerControl::updateSessionState(QMediaPlayer::State state) +{ + pushState(); + + if (state == QMediaPlayer::StoppedState) + m_state = QMediaPlayer::StoppedState; + + updateMediaStatus(); + + popAndNotifyState(); +} + +void QGstreamerPlayerControl::updateMediaStatus() +{ + pushState(); + QMediaPlayer::MediaStatus oldStatus = m_mediaStatus; + + switch (m_session->state()) { + case QMediaPlayer::StoppedState: + if (m_currentResource.isNull()) + m_mediaStatus = QMediaPlayer::NoMedia; + else if (oldStatus != QMediaPlayer::InvalidMedia) + m_mediaStatus = QMediaPlayer::LoadingMedia; + break; + + case QMediaPlayer::PlayingState: + case QMediaPlayer::PausedState: + if (m_state == QMediaPlayer::StoppedState) { + m_mediaStatus = QMediaPlayer::LoadedMedia; + } else { + if (m_bufferProgress == -1 || m_bufferProgress == 100) + m_mediaStatus = QMediaPlayer::BufferedMedia; + else + m_mediaStatus = QMediaPlayer::StalledMedia; + } + break; + } + + if (m_state == QMediaPlayer::PlayingState && !m_resources->isGranted()) + m_mediaStatus = QMediaPlayer::StalledMedia; + + //EndOfMedia status should be kept, until reset by pause, play or setMedia + if (oldStatus == QMediaPlayer::EndOfMedia) + m_mediaStatus = QMediaPlayer::EndOfMedia; + + popAndNotifyState(); +} + +void QGstreamerPlayerControl::processEOS() +{ + pushState(); + m_mediaStatus = QMediaPlayer::EndOfMedia; + emit positionChanged(position()); + stop(); + popAndNotifyState(); +} + +void QGstreamerPlayerControl::setBufferProgress(int progress) +{ + if (m_bufferProgress == progress || m_mediaStatus == QMediaPlayer::NoMedia) + return; + +#ifdef DEBUG_PLAYBIN + qDebug() << Q_FUNC_INFO << progress; +#endif + m_bufferProgress = progress; + + if (m_resources->isGranted()) { + if (m_state == QMediaPlayer::PlayingState && + m_bufferProgress == 100 && + m_session->state() != QMediaPlayer::PlayingState) + m_session->play(); + + if (m_bufferProgress < 100 && + (m_session->state() == QMediaPlayer::PlayingState || + m_session->pendingState() == QMediaPlayer::PlayingState)) + m_session->pause(); + } + + updateMediaStatus(); + + emit bufferStatusChanged(m_bufferProgress); +} + +void QGstreamerPlayerControl::writeFifo() +{ + if (m_fifoCanWrite) { + qint64 bytesToRead = qMin( + m_stream->bytesAvailable(), PIPE_BUF - m_bufferSize); + + if (bytesToRead > 0) { + int bytesRead = m_stream->read(&m_buffer[m_bufferOffset + m_bufferSize], bytesToRead); + + if (bytesRead > 0) + m_bufferSize += bytesRead; + } + + if (m_bufferSize > 0) { + int bytesWritten = ::write(m_fifoFd[1], &m_buffer[m_bufferOffset], size_t(m_bufferSize)); + + if (bytesWritten > 0) { + m_bufferOffset += bytesWritten; + m_bufferSize -= bytesWritten; + + if (m_bufferSize == 0) + m_bufferOffset = 0; + } else if (errno == EAGAIN) { + m_fifoCanWrite = false; + } else { + closeFifo(); + } + } + } + + m_fifoNotifier->setEnabled(m_stream->bytesAvailable() > 0); +} + +void QGstreamerPlayerControl::fifoReadyWrite(int socket) +{ + if (socket == m_fifoFd[1]) { + m_fifoCanWrite = true; + + writeFifo(); + } +} + +bool QGstreamerPlayerControl::openFifo() +{ + Q_ASSERT(m_fifoFd[0] < 0); + Q_ASSERT(m_fifoFd[1] < 0); + + if (::pipe(m_fifoFd) == 0) { + int flags = ::fcntl(m_fifoFd[1], F_GETFD); + + if (::fcntl(m_fifoFd[1], F_SETFD, flags | O_NONBLOCK) >= 0) { + m_fifoNotifier = new QSocketNotifier(m_fifoFd[1], QSocketNotifier::Write); + + connect(m_fifoNotifier, SIGNAL(activated(int)), this, SLOT(fifoReadyWrite(int))); + + return true; + } else { + qWarning("Failed to make pipe non blocking %d", errno); + + ::close(m_fifoFd[0]); + ::close(m_fifoFd[1]); + + m_fifoFd[0] = -1; + m_fifoFd[1] = -1; + + return false; + } + } else { + qWarning("Failed to create pipe %d", errno); + + return false; + } +} + +void QGstreamerPlayerControl::closeFifo() +{ + if (m_fifoFd[0] >= 0) { + delete m_fifoNotifier; + m_fifoNotifier = 0; + + ::close(m_fifoFd[0]); + ::close(m_fifoFd[1]); + m_fifoFd[0] = -1; + m_fifoFd[1] = -1; + + m_fifoCanWrite = false; + + m_bufferSize = 0; + m_bufferOffset = 0; + } +} + +void QGstreamerPlayerControl::applyPendingSeek(bool isSeekable) +{ + if (isSeekable && m_pendingSeekPosition != -1) + setPosition(m_pendingSeekPosition); +} + +void QGstreamerPlayerControl::handleInvalidMedia() +{ + pushState(); + m_mediaStatus = QMediaPlayer::InvalidMedia; + m_state = QMediaPlayer::StoppedState; + popAndNotifyState(); +} + +void QGstreamerPlayerControl::handleResourcesGranted() +{ + pushState(); + + QMediaPlayer::State state = m_state; + + //preserve m_pendingSeekPosition, it's reset on setMedia + qint64 pos = m_pendingSeekPosition; + setMedia(m_currentResource, m_stream); + + if (pos != -1) + setPosition(pos); + + if (state != QMediaPlayer::StoppedState) + playOrPause(state); + else + updateMediaStatus(); + + popAndNotifyState(); +} + +void QGstreamerPlayerControl::handleResourcesLost() +{ + //on resource lost the pipeline should be stopped + //player status is changed to paused + + pushState(); + QMediaPlayer::State oldState = m_state; + + qint64 pos = m_session->position(); + m_session->stop(); + m_pendingSeekPosition = pos; + + if (oldState != QMediaPlayer::StoppedState ) + m_state = QMediaPlayer::PausedState; + + popAndNotifyState(); +} + +bool QGstreamerPlayerControl::isMediaDownloadEnabled() const +{ + return m_session->property("mediaDownloadEnabled").toBool(); +} + +void QGstreamerPlayerControl::setMediaDownloadEnabled(bool enabled) +{ + m_session->setProperty("mediaDownloadEnabled", enabled); +} + +void QGstreamerPlayerControl::pushState() +{ + m_stateStack.push(m_state); + m_mediaStatusStack.push(m_mediaStatus); +} + +void QGstreamerPlayerControl::popAndNotifyState() +{ + Q_ASSERT(!m_stateStack.isEmpty()); + + QMediaPlayer::State oldState = m_stateStack.pop(); + QMediaPlayer::MediaStatus oldMediaStatus = m_mediaStatusStack.pop(); + + if (m_stateStack.isEmpty()) { + if (m_state != oldState) { +#ifdef DEBUG_PLAYBIN + qDebug() << "State changed:" << m_state; +#endif + emit stateChanged(m_state); + } + + if (m_mediaStatus != oldMediaStatus) { +#ifdef DEBUG_PLAYBIN + qDebug() << "Media status changed:" << m_mediaStatus; +#endif + emit mediaStatusChanged(m_mediaStatus); + } + } +} diff --git a/src/plugins/gstreamer/mediaplayer/qgstreamerplayercontrol.h b/src/plugins/gstreamer/mediaplayer/qgstreamerplayercontrol.h new file mode 100644 index 000000000..5a53a0713 --- /dev/null +++ b/src/plugins/gstreamer/mediaplayer/qgstreamerplayercontrol.h @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERPLAYERCONTROL_H +#define QGSTREAMERPLAYERCONTROL_H + +#include +#include + +#include +#include + +#include + +QT_BEGIN_NAMESPACE +class QMediaPlaylist; +class QMediaPlaylistNavigator; +class QSocketNotifier; +QT_END_NAMESPACE + +QT_USE_NAMESPACE + +class QGstreamerPlayerSession; +class QGstreamerPlayerService; +class PlayerResourcePolicy; + +class QGstreamerPlayerControl : public QMediaPlayerControl +{ + Q_OBJECT + Q_PROPERTY(bool mediaDownloadEnabled READ isMediaDownloadEnabled WRITE setMediaDownloadEnabled) + +public: + QGstreamerPlayerControl(QGstreamerPlayerSession *session, QObject *parent = 0); + ~QGstreamerPlayerControl(); + + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + + qint64 position() const; + qint64 duration() const; + + int bufferStatus() const; + + int volume() const; + bool isMuted() const; + + bool isAudioAvailable() const; + bool isVideoAvailable() const; + void setVideoOutput(QObject *output); + + bool isSeekable() const; + QMediaTimeRange availablePlaybackRanges() const; + + qreal playbackRate() const; + void setPlaybackRate(qreal rate); + + QMediaContent media() const; + const QIODevice *mediaStream() const; + void setMedia(const QMediaContent&, QIODevice *); + + bool isMediaDownloadEnabled() const; + void setMediaDownloadEnabled(bool enabled); + +public Q_SLOTS: + void setPosition(qint64 pos); + + void play(); + void pause(); + void stop(); + + void setVolume(int volume); + void setMuted(bool muted); + +private Q_SLOTS: + void writeFifo(); + void fifoReadyWrite(int socket); + + void updateSessionState(QMediaPlayer::State state); + void updateMediaStatus(); + void processEOS(); + void setBufferProgress(int progress); + void applyPendingSeek(bool isSeekable); + + void handleInvalidMedia(); + + void handleResourcesGranted(); + void handleResourcesLost(); + +private: + bool openFifo(); + void closeFifo(); + void playOrPause(QMediaPlayer::State state); + + void pushState(); + void popAndNotifyState(); + + bool m_ownStream; + QGstreamerPlayerSession *m_session; + QMediaPlayer::State m_state; + QMediaPlayer::MediaStatus m_mediaStatus; + QStack m_stateStack; + QStack m_mediaStatusStack; + + int m_bufferProgress; + bool m_seekToStartPending; + qint64 m_pendingSeekPosition; + QMediaContent m_currentResource; + QIODevice *m_stream; + QSocketNotifier *m_fifoNotifier; + int m_fifoFd[2]; + bool m_fifoCanWrite; + int m_bufferSize; + int m_bufferOffset; + char m_buffer[PIPE_BUF]; + + PlayerResourcePolicy *m_resources; +}; + +#endif diff --git a/src/plugins/gstreamer/mediaplayer/qgstreamerplayerservice.cpp b/src/plugins/gstreamer/mediaplayer/qgstreamerplayerservice.cpp new file mode 100644 index 000000000..6976c18ae --- /dev/null +++ b/src/plugins/gstreamer/mediaplayer/qgstreamerplayerservice.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +#include "qgstreamerplayerservice.h" +#include "qgstreamerplayercontrol.h" +#include "qgstreamerplayersession.h" +#include "qgstreamermetadataprovider.h" + +#include "qgstreamervideooverlay.h" +#include "qgstreamervideowindow.h" +#include "qgstreamervideorenderer.h" + +#if defined(Q_WS_MAEMO_6) && defined(__arm__) +#include "qgstreamergltexturerenderer.h" +#endif + +#include "qgstreamervideowidget.h" +#include "qgstreamerstreamscontrol.h" + +#include +#include + +QGstreamerPlayerService::QGstreamerPlayerService(QObject *parent): + QMediaService(parent), + m_videoOutput(0), + m_videoRenderer(0), + m_videoWindow(0), + m_videoWidget(0) +{ + m_session = new QGstreamerPlayerSession(this); + m_control = new QGstreamerPlayerControl(m_session, this); + m_metaData = new QGstreamerMetaDataProvider(m_session, this); + m_streamsControl = new QGstreamerStreamsControl(m_session,this); + +#if defined(Q_WS_MAEMO_6) && defined(__arm__) + m_videoRenderer = new QGstreamerGLTextureRenderer(this); +#else + m_videoRenderer = new QGstreamerVideoRenderer(this); +#endif + +#if defined(Q_WS_X11) && !defined(QT_NO_XVIDEO) + +#ifdef Q_WS_MAEMO_6 + m_videoWindow = new QGstreamerVideoWindow(this, "omapxvsink"); +#else + m_videoWindow = new QGstreamerVideoOverlay(this); +#endif + + m_videoWidget = new QGstreamerVideoWidgetControl(this); +#endif +} + +QGstreamerPlayerService::~QGstreamerPlayerService() +{ +} + +QMediaControl *QGstreamerPlayerService::requestControl(const char *name) +{ + if (qstrcmp(name,QMediaPlayerControl_iid) == 0) + return m_control; + + if (qstrcmp(name,QMetaDataReaderControl_iid) == 0) + return m_metaData; + + if (qstrcmp(name,QMediaStreamsControl_iid) == 0) + return m_streamsControl; + + if (!m_videoOutput) { + if (qstrcmp(name, QVideoWidgetControl_iid) == 0) + m_videoOutput = m_videoWidget; + else if (qstrcmp(name, QVideoRendererControl_iid) == 0) + m_videoOutput = m_videoRenderer; + else if (qstrcmp(name, QVideoWindowControl_iid) == 0) + m_videoOutput = m_videoWindow; + + if (m_videoOutput) { + m_control->setVideoOutput(m_videoOutput); + return m_videoOutput; + } + } + + return 0; +} + +void QGstreamerPlayerService::releaseControl(QMediaControl *control) +{ + if (control == m_videoOutput) { + m_videoOutput = 0; + m_control->setVideoOutput(0); + } +} + diff --git a/src/plugins/gstreamer/mediaplayer/qgstreamerplayerservice.h b/src/plugins/gstreamer/mediaplayer/qgstreamerplayerservice.h new file mode 100644 index 000000000..92ea9ffa4 --- /dev/null +++ b/src/plugins/gstreamer/mediaplayer/qgstreamerplayerservice.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERPLAYERSERVICE_H +#define QGSTREAMERPLAYERSERVICE_H + +#include +#include + +#include + +QT_BEGIN_NAMESPACE +class QMediaMetaData; +class QMediaPlayerControl; +class QMediaPlaylist; +class QMediaPlaylistNavigator; +QT_END_NAMESPACE + +class QGstreamerMetaData; +class QGstreamerPlayerControl; +class QGstreamerPlayerSession; +class QGstreamerMetaDataProvider; +class QGstreamerStreamsControl; +class QGstreamerVideoRenderer; +class QGstreamerVideoOverlay; +class QGstreamerVideoWidgetControl; + +QT_USE_NAMESPACE + +class QGstreamerPlayerService : public QMediaService +{ + Q_OBJECT +public: + QGstreamerPlayerService(QObject *parent = 0); + ~QGstreamerPlayerService(); + + QMediaControl *requestControl(const char *name); + void releaseControl(QMediaControl *control); + +private: + QGstreamerPlayerControl *m_control; + QGstreamerPlayerSession *m_session; + QGstreamerMetaDataProvider *m_metaData; + QGstreamerStreamsControl *m_streamsControl; + + QMediaControl *m_videoOutput; + QMediaControl *m_videoRenderer; + QMediaControl *m_videoWindow; + QMediaControl *m_videoWidget; +}; + +#endif diff --git a/src/plugins/gstreamer/mediaplayer/qgstreamerplayersession.cpp b/src/plugins/gstreamer/mediaplayer/qgstreamerplayersession.cpp new file mode 100644 index 000000000..d12bb2697 --- /dev/null +++ b/src/plugins/gstreamer/mediaplayer/qgstreamerplayersession.cpp @@ -0,0 +1,1537 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamerplayersession.h" +#include "qgstreamerbushelper.h" + +#include "qgstreamervideorendererinterface.h" +#include "gstvideoconnector.h" +#include "qgstutils.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) || (GST_VERSION_MICRO > 20) +#define USE_PLAYBIN2 +#endif + +//#define DEBUG_PLAYBIN +//#define DEBUG_VO_BIN_DUMP + +typedef enum { + GST_PLAY_FLAG_VIDEO = 0x00000001, + GST_PLAY_FLAG_AUDIO = 0x00000002, + GST_PLAY_FLAG_TEXT = 0x00000004, + GST_PLAY_FLAG_VIS = 0x00000008, + GST_PLAY_FLAG_SOFT_VOLUME = 0x00000010, + GST_PLAY_FLAG_NATIVE_AUDIO = 0x00000020, + GST_PLAY_FLAG_NATIVE_VIDEO = 0x00000040, + GST_PLAY_FLAG_DOWNLOAD = 0x00000080, + GST_PLAY_FLAG_BUFFERING = 0x000000100 +} GstPlayFlags; + +QGstreamerPlayerSession::QGstreamerPlayerSession(QObject *parent) + :QObject(parent), + m_state(QMediaPlayer::StoppedState), + m_pendingState(QMediaPlayer::StoppedState), + m_busHelper(0), + m_playbin(0), + m_usePlaybin2(false), + m_usingColorspaceElement(false), + m_videoSink(0), + m_pendingVideoSink(0), + m_nullVideoSink(0), + m_bus(0), + m_videoOutput(0), + m_renderer(0), + m_haveQueueElement(false), +#if defined(HAVE_GST_APPSRC) + m_appSrc(0), +#endif + m_volume(100), + m_playbackRate(1.0), + m_muted(false), + m_audioAvailable(false), + m_videoAvailable(false), + m_seekable(false), + m_lastPosition(0), + m_duration(-1), + m_durationQueries(0), + m_everPlayed(false) , + m_sourceType(UnknownSrc) +{ +#ifdef USE_PLAYBIN2 + m_playbin = gst_element_factory_make("playbin2", NULL); +#endif + + if (m_playbin) { + m_usePlaybin2 = true; + + //GST_PLAY_FLAG_NATIVE_VIDEO omits configuration of ffmpegcolorspace and videoscale, + //since those elements are included in the video output bin when necessary. +#ifdef Q_WS_MAEMO_6 + int flags = GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_AUDIO | + GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_NATIVE_AUDIO; +#else + int flags = 0; + g_object_get(G_OBJECT(m_playbin), "flags", &flags, NULL); + flags |= GST_PLAY_FLAG_NATIVE_VIDEO; +#endif + g_object_set(G_OBJECT(m_playbin), "flags", flags, NULL); + } else { + m_usePlaybin2 = false; + m_playbin = gst_element_factory_make("playbin", NULL); + } + + m_videoOutputBin = gst_bin_new("video-output-bin"); + gst_object_ref(GST_OBJECT(m_videoOutputBin)); + + m_videoIdentity = GST_ELEMENT(g_object_new(gst_video_connector_get_type(), 0)); + g_signal_connect(G_OBJECT(m_videoIdentity), "connection-failed", G_CALLBACK(insertColorSpaceElement), (gpointer)this); + m_colorSpace = gst_element_factory_make("ffmpegcolorspace", "ffmpegcolorspace-vo"); + gst_object_ref(GST_OBJECT(m_colorSpace)); + + m_nullVideoSink = gst_element_factory_make("fakesink", NULL); + g_object_set(G_OBJECT(m_nullVideoSink), "sync", true, NULL); + gst_object_ref(GST_OBJECT(m_nullVideoSink)); + gst_bin_add_many(GST_BIN(m_videoOutputBin), m_videoIdentity, m_nullVideoSink, NULL); + gst_element_link(m_videoIdentity, m_nullVideoSink); + + m_videoSink = m_nullVideoSink; + + // add ghostpads + GstPad *pad = gst_element_get_static_pad(m_videoIdentity,"sink"); + gst_element_add_pad(GST_ELEMENT(m_videoOutputBin), gst_ghost_pad_new("videosink", pad)); + gst_object_unref(GST_OBJECT(pad)); + + if (m_playbin != 0) { + // Sort out messages + m_bus = gst_element_get_bus(m_playbin); + m_busHelper = new QGstreamerBusHelper(m_bus, this); + connect(m_busHelper, SIGNAL(message(QGstreamerMessage)), SLOT(busMessage(QGstreamerMessage))); + m_busHelper->installSyncEventFilter(this); + + g_object_set(G_OBJECT(m_playbin), "video-sink", m_videoOutputBin, NULL); + + g_signal_connect(G_OBJECT(m_playbin), "notify::source", G_CALLBACK(playbinNotifySource), this); + g_signal_connect(G_OBJECT(m_playbin), "element-added", G_CALLBACK(handleElementAdded), this); + + // Initial volume + double volume = 1.0; + g_object_get(G_OBJECT(m_playbin), "volume", &volume, NULL); + m_volume = int(volume*100); + + g_signal_connect(G_OBJECT(m_playbin), "notify::volume", G_CALLBACK(handleVolumeChange), this); + if (m_usePlaybin2) + g_signal_connect(G_OBJECT(m_playbin), "notify::mute", G_CALLBACK(handleMutedChange), this); + } +} + +QGstreamerPlayerSession::~QGstreamerPlayerSession() +{ + if (m_playbin) { + stop(); + + delete m_busHelper; + gst_object_unref(GST_OBJECT(m_bus)); + gst_object_unref(GST_OBJECT(m_playbin)); + gst_object_unref(GST_OBJECT(m_colorSpace)); + gst_object_unref(GST_OBJECT(m_nullVideoSink)); + gst_object_unref(GST_OBJECT(m_videoOutputBin)); + } +} + +#if defined(HAVE_GST_APPSRC) +void QGstreamerPlayerSession::configureAppSrcElement(GObject* object, GObject *orig, GParamSpec *pspec, QGstreamerPlayerSession* self) +{ + if (self->appsrc()->isReady()) + return; + + GstElement *appsrc; + g_object_get(orig, "source", &appsrc, NULL); + + if (!self->appsrc()->setup(appsrc)) + qWarning()<<"Could not setup appsrc element"; +} +#endif + +void QGstreamerPlayerSession::loadFromStream(const QNetworkRequest &request, QIODevice *appSrcStream) +{ +#if defined(HAVE_GST_APPSRC) + m_request = request; + m_duration = -1; + m_lastPosition = 0; + m_haveQueueElement = false; + + if (m_appSrc) + m_appSrc->deleteLater(); + m_appSrc = new QGstAppSrc(this); + m_appSrc->setStream(appSrcStream); + + if (m_playbin) { + m_tags.clear(); + emit tagsChanged(); + + g_signal_connect(G_OBJECT(m_playbin), "deep-notify::source", (GCallback) &QGstreamerPlayerSession::configureAppSrcElement, (gpointer)this); + g_object_set(G_OBJECT(m_playbin), "uri", "appsrc://", NULL); + + if (!m_streamTypes.isEmpty()) { + m_streamProperties.clear(); + m_streamTypes.clear(); + + emit streamsChanged(); + } + } +#endif +} + +void QGstreamerPlayerSession::loadFromUri(const QNetworkRequest &request) +{ + m_request = request; + m_duration = -1; + m_lastPosition = 0; + m_haveQueueElement = false; + + if (m_playbin) { + m_tags.clear(); + emit tagsChanged(); + + g_object_set(G_OBJECT(m_playbin), "uri", m_request.url().toEncoded().constData(), NULL); + + if (!m_streamTypes.isEmpty()) { + m_streamProperties.clear(); + m_streamTypes.clear(); + + emit streamsChanged(); + } + } +} + +qint64 QGstreamerPlayerSession::duration() const +{ + return m_duration; +} + +qint64 QGstreamerPlayerSession::position() const +{ + GstFormat format = GST_FORMAT_TIME; + gint64 position = 0; + + if ( m_playbin && gst_element_query_position(m_playbin, &format, &position)) + m_lastPosition = position / 1000000; + + return m_lastPosition; +} + +qreal QGstreamerPlayerSession::playbackRate() const +{ + return m_playbackRate; +} + +void QGstreamerPlayerSession::setPlaybackRate(qreal rate) +{ + if (!qFuzzyCompare(m_playbackRate, rate)) { + m_playbackRate = rate; + if (m_playbin) { + gst_element_seek(m_playbin, rate, GST_FORMAT_TIME, + GstSeekFlags(GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH), + GST_SEEK_TYPE_NONE,0, + GST_SEEK_TYPE_NONE,0 ); + } + emit playbackRateChanged(m_playbackRate); + } +} + +QMediaTimeRange QGstreamerPlayerSession::availablePlaybackRanges() const +{ + QMediaTimeRange ranges; +#if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 31) + //GST_FORMAT_TIME would be more appropriate, but unfortunately it's not supported. + //with GST_FORMAT_PERCENT media is treated as encoded with constant bitrate. + GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT); + + if (gst_element_query(m_playbin, query)) { + for (guint index = 0; index < gst_query_get_n_buffering_ranges(query); index++) { + gint64 rangeStart = 0; + gint64 rangeStop = 0; + + //This query should return values in GST_FORMAT_PERCENT_MAX range, + //but queue2 returns values in 0..100 range instead + if (gst_query_parse_nth_buffering_range(query, index, &rangeStart, &rangeStop)) + ranges.addInterval(rangeStart * duration() / 100, + rangeStop * duration() / 100); + } + } + + gst_query_unref(query); +#endif + + //without queue2 element in pipeline all the media is considered available + if (ranges.isEmpty() && duration() > 0 && !m_haveQueueElement) + ranges.addInterval(0, duration()); + +#ifdef DEBUG_PLAYBIN + qDebug() << ranges; +#endif + + return ranges; +} + +int QGstreamerPlayerSession::activeStream(QMediaStreamsControl::StreamType streamType) const +{ + int streamNumber = -1; + if (m_playbin) { + switch (streamType) { + case QMediaStreamsControl::AudioStream: + g_object_get(G_OBJECT(m_playbin), "current-audio", streamNumber, NULL); + break; + case QMediaStreamsControl::VideoStream: + g_object_get(G_OBJECT(m_playbin), "current-video", streamNumber, NULL); + break; + case QMediaStreamsControl::SubPictureStream: + g_object_get(G_OBJECT(m_playbin), "current-text", streamNumber, NULL); + break; + default: + break; + } + } + + if (m_usePlaybin2 && streamNumber >= 0) + streamNumber += m_playbin2StreamOffset.value(streamType,0); + + return streamNumber; +} + +void QGstreamerPlayerSession::setActiveStream(QMediaStreamsControl::StreamType streamType, int streamNumber) +{ + + if (m_usePlaybin2 && streamNumber >= 0) + streamNumber -= m_playbin2StreamOffset.value(streamType,0); + + if (m_playbin) { + switch (streamType) { + case QMediaStreamsControl::AudioStream: + g_object_set(G_OBJECT(m_playbin), "current-audio", &streamNumber, NULL); + break; + case QMediaStreamsControl::VideoStream: + g_object_set(G_OBJECT(m_playbin), "current-video", &streamNumber, NULL); + break; + case QMediaStreamsControl::SubPictureStream: + g_object_set(G_OBJECT(m_playbin), "current-text", &streamNumber, NULL); + break; + default: + break; + } + } +} + + +bool QGstreamerPlayerSession::isBuffering() const +{ + return false; +} + +int QGstreamerPlayerSession::bufferingProgress() const +{ + return 0; +} + +int QGstreamerPlayerSession::volume() const +{ + return m_volume; +} + +bool QGstreamerPlayerSession::isMuted() const +{ + return m_muted; +} + +bool QGstreamerPlayerSession::isAudioAvailable() const +{ + return m_audioAvailable; +} + +static void block_pad_cb(GstPad *pad, gboolean blocked, gpointer user_data) +{ + Q_UNUSED(pad); +#ifdef DEBUG_PLAYBIN + qDebug() << "block_pad_cb, blocked:" << blocked; +#endif + + if (blocked && user_data) { + QGstreamerPlayerSession *session = reinterpret_cast(user_data); + QMetaObject::invokeMethod(session, "finishVideoOutputChange", Qt::QueuedConnection); + } +} + +void QGstreamerPlayerSession::updateVideoRenderer() +{ +#ifdef DEBUG_PLAYBIN + qDebug() << "Video sink has chaged, reload video output"; +#endif + + if (m_videoOutput) + setVideoRenderer(m_videoOutput); +} + +void QGstreamerPlayerSession::setVideoRenderer(QObject *videoOutput) +{ + if (m_videoOutput != videoOutput) { + if (m_videoOutput) { + disconnect(m_videoOutput, SIGNAL(sinkChanged()), + this, SLOT(updateVideoRenderer())); + disconnect(m_videoOutput, SIGNAL(readyChanged(bool)), + this, SLOT(updateVideoRenderer())); + } + + if (videoOutput) { + connect(videoOutput, SIGNAL(sinkChanged()), + this, SLOT(updateVideoRenderer())); + connect(videoOutput, SIGNAL(readyChanged(bool)), + this, SLOT(updateVideoRenderer())); + } + + m_videoOutput = videoOutput; + } + + QGstreamerVideoRendererInterface* renderer = qobject_cast(videoOutput); + + m_renderer = renderer; + +#ifdef DEBUG_VO_BIN_DUMP + _gst_debug_bin_to_dot_file_with_ts(GST_BIN(m_playbin), + GstDebugGraphDetails(GST_DEBUG_GRAPH_SHOW_ALL /* GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE | GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES*/), + "playbin_set"); +#endif + + GstElement *videoSink = 0; + if (m_renderer && m_renderer->isReady()) + videoSink = m_renderer->videoSink(); + + if (!videoSink) + videoSink = m_nullVideoSink; + +#ifdef DEBUG_PLAYBIN + qDebug() << "Set video output:" << videoOutput; + qDebug() << "Current sink:" << (m_videoSink ? GST_ELEMENT_NAME(m_videoSink) : "") << m_videoSink + << "pending:" << (m_pendingVideoSink ? GST_ELEMENT_NAME(m_pendingVideoSink) : "") << m_pendingVideoSink + << "new sink:" << (videoSink ? GST_ELEMENT_NAME(videoSink) : "") << videoSink; +#endif + + if (m_pendingVideoSink == videoSink || + (m_pendingVideoSink == 0 && m_videoSink == videoSink)) { +#ifdef DEBUG_PLAYBIN + qDebug() << "Video sink has not changed, skip video output reconfiguration"; +#endif + return; + } + +#ifdef DEBUG_PLAYBIN + qDebug() << "Reconfigure video output"; +#endif + + if (m_state == QMediaPlayer::StoppedState) { +#ifdef DEBUG_PLAYBIN + qDebug() << "The pipeline has not started yet, pending state:" << m_pendingState; +#endif + //the pipeline has not started yet + m_pendingVideoSink = 0; + gst_element_set_state(m_videoSink, GST_STATE_NULL); + gst_element_set_state(m_playbin, GST_STATE_NULL); + + if (m_usingColorspaceElement) { + gst_element_unlink(m_colorSpace, m_videoSink); + gst_bin_remove(GST_BIN(m_videoOutputBin), m_colorSpace); + } else { + gst_element_unlink(m_videoIdentity, m_videoSink); + } + + gst_bin_remove(GST_BIN(m_videoOutputBin), m_videoSink); + + m_videoSink = videoSink; + + gst_bin_add(GST_BIN(m_videoOutputBin), m_videoSink); + + m_usingColorspaceElement = false; + bool linked = gst_element_link(m_videoIdentity, m_videoSink); + if (!linked) { + m_usingColorspaceElement = true; +#ifdef DEBUG_PLAYBIN + qDebug() << "Failed to connect video output, inserting the colorspace element."; +#endif + gst_bin_add(GST_BIN(m_videoOutputBin), m_colorSpace); + linked = gst_element_link_many(m_videoIdentity, m_colorSpace, m_videoSink, NULL); + } + + switch (m_pendingState) { + case QMediaPlayer::PausedState: + gst_element_set_state(m_playbin, GST_STATE_PAUSED); + break; + case QMediaPlayer::PlayingState: + gst_element_set_state(m_playbin, GST_STATE_PLAYING); + break; + default: + break; + } + } else { + if (m_pendingVideoSink) { +#ifdef DEBUG_PLAYBIN + qDebug() << "already waiting for pad to be blocked, just change the pending sink"; +#endif + m_pendingVideoSink = videoSink; + return; + } + + m_pendingVideoSink = videoSink; + +#ifdef DEBUG_PLAYBIN + qDebug() << "Blocking the video output pad..."; +#endif + + //block pads, async to avoid locking in paused state + GstPad *srcPad = gst_element_get_static_pad(m_videoIdentity, "src"); + gst_pad_set_blocked_async(srcPad, true, &block_pad_cb, this); + gst_object_unref(GST_OBJECT(srcPad)); + + //Unpause the sink to avoid waiting until the buffer is processed + //while the sink is paused. The pad will be blocked as soon as the current + //buffer is processed. + if (m_state == QMediaPlayer::PausedState) { +#ifdef DEBUG_PLAYBIN + qDebug() << "Starting video output to avoid blocking in paused state..."; +#endif + gst_element_set_state(m_videoSink, GST_STATE_PLAYING); + } + } +} + +void QGstreamerPlayerSession::finishVideoOutputChange() +{ + if (!m_pendingVideoSink) + return; + +#ifdef DEBUG_PLAYBIN + qDebug() << "finishVideoOutputChange" << m_pendingVideoSink; +#endif + + GstPad *srcPad = gst_element_get_static_pad(m_videoIdentity, "src"); + + if (!gst_pad_is_blocked(srcPad)) { + //pad is not blocked, it's possible to swap outputs only in the null state + qWarning() << "Pad is not blocked yet, could not switch video sink"; + GstState identityElementState = GST_STATE_NULL; + gst_element_get_state(m_videoIdentity, &identityElementState, NULL, GST_CLOCK_TIME_NONE); + if (identityElementState != GST_STATE_NULL) { + gst_object_unref(GST_OBJECT(srcPad)); + return; //can't change vo yet, received async call from the previous change + } + } + + if (m_pendingVideoSink == m_videoSink) { + //video output was change back to the current one, + //no need to torment the pipeline, just unblock the pad + if (gst_pad_is_blocked(srcPad)) + gst_pad_set_blocked_async(srcPad, false, &block_pad_cb, 0); + + m_pendingVideoSink = 0; + gst_object_unref(GST_OBJECT(srcPad)); + return; + } + + if (m_usingColorspaceElement) { + gst_element_set_state(m_colorSpace, GST_STATE_NULL); + gst_element_set_state(m_videoSink, GST_STATE_NULL); + + gst_element_unlink(m_colorSpace, m_videoSink); + gst_bin_remove(GST_BIN(m_videoOutputBin), m_colorSpace); + } else { + gst_element_set_state(m_videoSink, GST_STATE_NULL); + gst_element_unlink(m_videoIdentity, m_videoSink); + } + + gst_bin_remove(GST_BIN(m_videoOutputBin), m_videoSink); + + m_videoSink = m_pendingVideoSink; + m_pendingVideoSink = 0; + + gst_bin_add(GST_BIN(m_videoOutputBin), m_videoSink); + + m_usingColorspaceElement = false; + bool linked = gst_element_link(m_videoIdentity, m_videoSink); + if (!linked) { + m_usingColorspaceElement = true; +#ifdef DEBUG_PLAYBIN + qDebug() << "Failed to connect video output, inserting the colorspace element."; +#endif + gst_bin_add(GST_BIN(m_videoOutputBin), m_colorSpace); + linked = gst_element_link_many(m_videoIdentity, m_colorSpace, m_videoSink, NULL); + } + + if (!linked) + qWarning() << "Linking video output element failed"; + +#ifdef DEBUG_PLAYBIN + qDebug() << "notify the video connector it has to emit a new segment message..."; +#endif + //it's necessary to send a new segment event just before + //the first buffer pushed to the new sink + g_signal_emit_by_name(m_videoIdentity, + "resend-new-segment", + true //emit connection-failed signal + //to have a chance to insert colorspace element + ); + + + GstState state; + + switch (m_pendingState) { + case QMediaPlayer::StoppedState: + state = GST_STATE_NULL; + break; + case QMediaPlayer::PausedState: + state = GST_STATE_PAUSED; + break; + case QMediaPlayer::PlayingState: + state = GST_STATE_PLAYING; + break; + } + + if (m_usingColorspaceElement) + gst_element_set_state(m_colorSpace, state); + + gst_element_set_state(m_videoSink, state); + + // Set state change that was deferred due the video output + // change being pending + gst_element_set_state(m_playbin, state); + + //don't have to wait here, it will unblock eventually + if (gst_pad_is_blocked(srcPad)) + gst_pad_set_blocked_async(srcPad, false, &block_pad_cb, 0); + gst_object_unref(GST_OBJECT(srcPad)); + +#ifdef DEBUG_VO_BIN_DUMP + _gst_debug_bin_to_dot_file_with_ts(GST_BIN(m_playbin), + GstDebugGraphDetails(GST_DEBUG_GRAPH_SHOW_ALL /* GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE | GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES*/), + "playbin_finish"); +#endif +} + +void QGstreamerPlayerSession::insertColorSpaceElement(GstElement *element, gpointer data) +{ + Q_UNUSED(element); + QGstreamerPlayerSession* session = reinterpret_cast(data); + + if (session->m_usingColorspaceElement) + return; + session->m_usingColorspaceElement = true; + +#ifdef DEBUG_PLAYBIN + qDebug() << "Failed to connect video output, inserting the colorspace elemnt."; + qDebug() << "notify the video connector it has to emit a new segment message..."; +#endif + //it's necessary to send a new segment event just before + //the first buffer pushed to the new sink + g_signal_emit_by_name(session->m_videoIdentity, + "resend-new-segment", + false // don't emit connection-failed signal + ); + + gst_element_unlink(session->m_videoIdentity, session->m_videoSink); + gst_bin_add(GST_BIN(session->m_videoOutputBin), session->m_colorSpace); + gst_element_link_many(session->m_videoIdentity, session->m_colorSpace, session->m_videoSink, NULL); + + GstState state; + + switch (session->m_pendingState) { + case QMediaPlayer::StoppedState: + state = GST_STATE_NULL; + break; + case QMediaPlayer::PausedState: + state = GST_STATE_PAUSED; + break; + case QMediaPlayer::PlayingState: + state = GST_STATE_PLAYING; + break; + } + + gst_element_set_state(session->m_colorSpace, state); +} + + +bool QGstreamerPlayerSession::isVideoAvailable() const +{ + return m_videoAvailable; +} + +bool QGstreamerPlayerSession::isSeekable() const +{ + return m_seekable; +} + +bool QGstreamerPlayerSession::play() +{ + m_everPlayed = false; + if (m_playbin) { + m_pendingState = QMediaPlayer::PlayingState; + if (gst_element_set_state(m_playbin, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { + qWarning() << "GStreamer; Unable to play -" << m_request.url().toString(); + m_pendingState = m_state = QMediaPlayer::StoppedState; + + emit stateChanged(m_state); + } else + return true; + } + + return false; +} + +bool QGstreamerPlayerSession::pause() +{ + if (m_playbin) { + m_pendingState = QMediaPlayer::PausedState; + if (m_pendingVideoSink != 0) + return true; + + if (gst_element_set_state(m_playbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) { + qWarning() << "GStreamer; Unable to pause -" << m_request.url().toString(); + m_pendingState = m_state = QMediaPlayer::StoppedState; + + emit stateChanged(m_state); + } else { + return true; + } + } + + return false; +} + +void QGstreamerPlayerSession::stop() +{ + m_everPlayed = false; + if (m_playbin) { + if (m_renderer) + m_renderer->stopRenderer(); + + gst_element_set_state(m_playbin, GST_STATE_NULL); + + m_lastPosition = 0; + QMediaPlayer::State oldState = m_state; + m_pendingState = m_state = QMediaPlayer::StoppedState; + + finishVideoOutputChange(); + + //we have to do it here, since gstreamer will not emit bus messages any more + setSeekable(false); + if (oldState != m_state) + emit stateChanged(m_state); + } +} + +bool QGstreamerPlayerSession::seek(qint64 ms) +{ + //seek locks when the video output sink is changing and pad is blocked + if (m_playbin && !m_pendingVideoSink && m_state != QMediaPlayer::StoppedState) { + ms = qMax(ms,qint64(0)); + gint64 position = ms * 1000000; + bool isSeeking = gst_element_seek(m_playbin, + m_playbackRate, + GST_FORMAT_TIME, + GstSeekFlags(GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH), + GST_SEEK_TYPE_SET, + position, + GST_SEEK_TYPE_NONE, + 0); + if (isSeeking) + m_lastPosition = ms; + + return isSeeking; + } + + return false; +} + +void QGstreamerPlayerSession::setVolume(int volume) +{ + if (m_volume != volume) { + m_volume = volume; + + if (m_playbin) { + //playbin2 allows to set volume and muted independently, + //with playbin1 it's necessary to keep volume at 0 while muted + if (!m_muted || m_usePlaybin2) + g_object_set(G_OBJECT(m_playbin), "volume", m_volume/100.0, NULL); + } + + emit volumeChanged(m_volume); + } +} + +void QGstreamerPlayerSession::setMuted(bool muted) +{ + if (m_muted != muted) { + m_muted = muted; + + if (m_usePlaybin2) + g_object_set(G_OBJECT(m_playbin), "mute", m_muted, NULL); + else + g_object_set(G_OBJECT(m_playbin), "volume", (m_muted ? 0 : m_volume/100.0), NULL); + + emit mutedStateChanged(m_muted); + } +} + + +void QGstreamerPlayerSession::setSeekable(bool seekable) +{ + if (seekable != m_seekable) { + m_seekable = seekable; + emit seekableChanged(m_seekable); + } +} + +bool QGstreamerPlayerSession::processSyncMessage(const QGstreamerMessage &message) +{ + GstMessage* gm = message.rawMessage(); + + if (gm && GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ELEMENT) { + if (m_renderer) { + if (GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_videoSink)) + m_renderer->handleSyncMessage(gm); + + if (gst_structure_has_name(gm->structure, "prepare-xwindow-id")) { + m_renderer->precessNewStream(); + return true; + } + } + } + + return false; +} + +void QGstreamerPlayerSession::busMessage(const QGstreamerMessage &message) +{ + GstMessage* gm = message.rawMessage(); + + if (gm) { + //tag message comes from elements inside playbin, not from playbin itself + if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_TAG) { + //qDebug() << "tag message"; + GstTagList *tag_list; + gst_message_parse_tag(gm, &tag_list); + m_tags.unite(QGstUtils::gstTagListToMap(tag_list)); + + //qDebug() << m_tags; + + emit tagsChanged(); + } else if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_DURATION) { + updateDuration(); + } + +#ifdef DEBUG_PLAYBIN + if (m_sourceType == MMSSrc && qstrcmp(GST_OBJECT_NAME(GST_MESSAGE_SRC(gm)), "source") == 0) { + qDebug() << "Message from MMSSrc: " << GST_MESSAGE_TYPE(gm); + } +#endif + + if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_BUFFERING) { + int progress = 0; + gst_message_parse_buffering(gm, &progress); + emit bufferingProgressChanged(progress); + } + + bool handlePlaybin2 = false; + if (GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_playbin)) { + switch (GST_MESSAGE_TYPE(gm)) { + case GST_MESSAGE_STATE_CHANGED: + { + GstState oldState; + GstState newState; + GstState pending; + + gst_message_parse_state_changed(gm, &oldState, &newState, &pending); + +#ifdef DEBUG_PLAYBIN + QStringList states; + states << "GST_STATE_VOID_PENDING" << "GST_STATE_NULL" << "GST_STATE_READY" << "GST_STATE_PAUSED" << "GST_STATE_PLAYING"; + + qDebug() << QString("state changed: old: %1 new: %2 pending: %3") \ + .arg(states[oldState]) \ + .arg(states[newState]) \ + .arg(states[pending]); +#endif + + switch (newState) { + case GST_STATE_VOID_PENDING: + case GST_STATE_NULL: + setSeekable(false); + finishVideoOutputChange(); + if (m_state != QMediaPlayer::StoppedState) + emit stateChanged(m_state = QMediaPlayer::StoppedState); + break; + case GST_STATE_READY: + setSeekable(false); + if (m_state != QMediaPlayer::StoppedState) + emit stateChanged(m_state = QMediaPlayer::StoppedState); + break; + case GST_STATE_PAUSED: + { + QMediaPlayer::State prevState = m_state; + m_state = QMediaPlayer::PausedState; + + //check for seekable + if (oldState == GST_STATE_READY) { + if (m_sourceType == SoupHTTPSrc || m_sourceType == MMSSrc) { + //since udpsrc is a live source, it is not applicable here + m_everPlayed = true; + } + + getStreamsInfo(); + updateVideoResolutionTag(); + + //gstreamer doesn't give a reliable indication the duration + //information is ready, GST_MESSAGE_DURATION is not sent by most elements + //the duration is queried up to 5 times with increasing delay + m_durationQueries = 5; + updateDuration(); + + /* + //gst_element_seek_simple doesn't work reliably here, have to find a better solution + + GstFormat format = GST_FORMAT_TIME; + gint64 position = 0; + bool seekable = false; + if (gst_element_query_position(m_playbin, &format, &position)) { + seekable = gst_element_seek_simple(m_playbin, format, GST_SEEK_FLAG_NONE, position); + } + + setSeekable(seekable); + */ + + setSeekable(true); + + if (!qFuzzyCompare(m_playbackRate, qreal(1.0))) { + qreal rate = m_playbackRate; + m_playbackRate = 1.0; + setPlaybackRate(rate); + } + } + + if (m_state != prevState) + emit stateChanged(m_state); + + break; + } + case GST_STATE_PLAYING: + m_everPlayed = true; + if (m_state != QMediaPlayer::PlayingState) + emit stateChanged(m_state = QMediaPlayer::PlayingState); + + break; + } + } + break; + + case GST_MESSAGE_EOS: + emit playbackFinished(); + break; + + case GST_MESSAGE_TAG: + case GST_MESSAGE_STREAM_STATUS: + case GST_MESSAGE_UNKNOWN: + break; + case GST_MESSAGE_ERROR: { + GError *err; + gchar *debug; + gst_message_parse_error(gm, &err, &debug); + if (err->domain == GST_STREAM_ERROR && err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND) + processInvalidMedia(QMediaPlayer::FormatError, tr("Cannot play stream of type: ")); + else + processInvalidMedia(QMediaPlayer::ResourceError, QString::fromUtf8(err->message)); + qWarning() << "Error:" << QString::fromUtf8(err->message); + g_error_free(err); + g_free(debug); + } + break; + case GST_MESSAGE_WARNING: + { + GError *err; + gchar *debug; + gst_message_parse_warning (gm, &err, &debug); + qWarning() << "Warning:" << QString::fromUtf8(err->message); + g_error_free (err); + g_free (debug); + } + break; + case GST_MESSAGE_INFO: +#ifdef DEBUG_PLAYBIN + { + GError *err; + gchar *debug; + gst_message_parse_info (gm, &err, &debug); + qDebug() << "Info:" << QString::fromUtf8(err->message); + g_error_free (err); + g_free (debug); + } +#endif + break; + case GST_MESSAGE_BUFFERING: + case GST_MESSAGE_STATE_DIRTY: + case GST_MESSAGE_STEP_DONE: + case GST_MESSAGE_CLOCK_PROVIDE: + case GST_MESSAGE_CLOCK_LOST: + case GST_MESSAGE_NEW_CLOCK: + case GST_MESSAGE_STRUCTURE_CHANGE: + case GST_MESSAGE_APPLICATION: + case GST_MESSAGE_ELEMENT: + break; + case GST_MESSAGE_SEGMENT_START: + { + const GstStructure *structure = gst_message_get_structure(gm); + qint64 position = g_value_get_int64(gst_structure_get_value(structure, "position")); + position /= 1000000; + m_lastPosition = position; + emit positionChanged(position); + } + break; + case GST_MESSAGE_SEGMENT_DONE: + break; + case GST_MESSAGE_LATENCY: +#if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 13) + case GST_MESSAGE_ASYNC_START: + break; + case GST_MESSAGE_ASYNC_DONE: + { + GstFormat format = GST_FORMAT_TIME; + gint64 position = 0; + if (gst_element_query_position(m_playbin, &format, &position)) { + position /= 1000000; + m_lastPosition = position; + emit positionChanged(position); + } + break; + } +#if GST_VERSION_MICRO >= 23 + case GST_MESSAGE_REQUEST_STATE: +#endif +#endif + case GST_MESSAGE_ANY: + break; + default: + break; + } + } else if (m_videoSink + && m_renderer + && GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_videoSink)) { + + m_renderer->handleBusMessage(gm); + if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_STATE_CHANGED) { + GstState oldState; + GstState newState; + gst_message_parse_state_changed(gm, &oldState, &newState, 0); + + if (oldState == GST_STATE_READY && newState == GST_STATE_PAUSED) + m_renderer->precessNewStream(); + } + } else if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ERROR) { + GError *err; + gchar *debug; + gst_message_parse_error(gm, &err, &debug); + // If the source has given up, so do we. + if (qstrcmp(GST_OBJECT_NAME(GST_MESSAGE_SRC(gm)), "source") == 0) { + bool everPlayed = m_everPlayed; + // Try and differentiate network related resource errors from the others + if (!m_request.url().isRelative() && m_request.url().scheme().compare(QLatin1String("file"), Qt::CaseInsensitive) != 0 ) { + if (everPlayed || + (err->domain == GST_RESOURCE_ERROR && ( + err->code == GST_RESOURCE_ERROR_BUSY || + err->code == GST_RESOURCE_ERROR_OPEN_READ || + err->code == GST_RESOURCE_ERROR_READ || + err->code == GST_RESOURCE_ERROR_SEEK || + err->code == GST_RESOURCE_ERROR_SYNC))) { + processInvalidMedia(QMediaPlayer::NetworkError, QString::fromUtf8(err->message)); + } else { + processInvalidMedia(QMediaPlayer::ResourceError, QString::fromUtf8(err->message)); + } + } + else + processInvalidMedia(QMediaPlayer::ResourceError, QString::fromUtf8(err->message)); + } else if (err->domain == GST_STREAM_ERROR + && (err->code == GST_STREAM_ERROR_DECRYPT || err->code == GST_STREAM_ERROR_DECRYPT_NOKEY)) { + processInvalidMedia(QMediaPlayer::AccessDeniedError, QString::fromUtf8(err->message)); + } else { + handlePlaybin2 = m_usePlaybin2; + } + if (!handlePlaybin2) + qWarning() << "Error:" << QString::fromUtf8(err->message); + g_error_free(err); + g_free(debug); + } else if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ELEMENT + && qstrcmp(GST_OBJECT_NAME(GST_MESSAGE_SRC(gm)), "source") == 0 + && m_sourceType == UDPSrc + && gst_structure_has_name(gst_message_get_structure(gm), "GstUDPSrcTimeout")) { + //since udpsrc will not generate an error for the timeout event, + //we need to process its element message here and treat it as an error. + processInvalidMedia(m_everPlayed ? QMediaPlayer::NetworkError : QMediaPlayer::ResourceError, + tr("UDP source timeout")); + } else { + handlePlaybin2 = m_usePlaybin2; + } + + if (handlePlaybin2) { + if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_WARNING) { + GError *err; + gchar *debug; + gst_message_parse_warning(gm, &err, &debug); + if (err->domain == GST_STREAM_ERROR && err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND) + emit error(int(QMediaPlayer::FormatError), tr("Cannot play stream of type: ")); + qWarning() << "Warning:" << QString::fromUtf8(err->message); + g_error_free(err); + g_free(debug); + } else if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ERROR) { + GError *err; + gchar *debug; + gst_message_parse_error(gm, &err, &debug); + if (qstrncmp(GST_OBJECT_NAME(GST_MESSAGE_SRC(gm)), "decodebin2", 10) == 0 + || qstrncmp(GST_OBJECT_NAME(GST_MESSAGE_SRC(gm)), "uridecodebin", 12) == 0) { + processInvalidMedia(QMediaPlayer::ResourceError, QString::fromUtf8(err->message)); + } else if (err->domain == GST_STREAM_ERROR + && (err->code == GST_STREAM_ERROR_DECRYPT || err->code == GST_STREAM_ERROR_DECRYPT_NOKEY)) { + processInvalidMedia(QMediaPlayer::AccessDeniedError, QString::fromUtf8(err->message)); + } + qWarning() << "Error:" << QString::fromUtf8(err->message); + g_error_free(err); + g_free(debug); + } + } + } +} + +void QGstreamerPlayerSession::getStreamsInfo() +{ + //check if video is available: + bool haveAudio = false; + bool haveVideo = false; + m_streamProperties.clear(); + m_streamTypes.clear(); + + if (m_usePlaybin2) { + gint audioStreamsCount = 0; + gint videoStreamsCount = 0; + gint textStreamsCount = 0; + + g_object_get(G_OBJECT(m_playbin), "n-audio", &audioStreamsCount, NULL); + g_object_get(G_OBJECT(m_playbin), "n-video", &videoStreamsCount, NULL); + g_object_get(G_OBJECT(m_playbin), "n-text", &textStreamsCount, NULL); + + haveAudio = audioStreamsCount > 0; + haveVideo = videoStreamsCount > 0; + + m_playbin2StreamOffset[QMediaStreamsControl::AudioStream] = 0; + m_playbin2StreamOffset[QMediaStreamsControl::VideoStream] = audioStreamsCount; + m_playbin2StreamOffset[QMediaStreamsControl::SubPictureStream] = audioStreamsCount+videoStreamsCount; + + for (int i=0; i streamProperties; + + int streamIndex = i - m_playbin2StreamOffset[streamType]; + + GstTagList *tags = 0; + switch (streamType) { + case QMediaStreamsControl::AudioStream: + g_signal_emit_by_name(G_OBJECT(m_playbin), "get-audio-tags", streamIndex, &tags); + break; + case QMediaStreamsControl::VideoStream: + g_signal_emit_by_name(G_OBJECT(m_playbin), "get-video-tags", streamIndex, &tags); + break; + case QMediaStreamsControl::SubPictureStream: + g_signal_emit_by_name(G_OBJECT(m_playbin), "get-text-tags", streamIndex, &tags); + break; + default: + break; + } + + if (tags && gst_is_tag_list(tags)) { + gchar *languageCode = 0; + if (gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &languageCode)) + streamProperties[QtMultimediaKit::Language] = QString::fromUtf8(languageCode); + + //qDebug() << "language for setream" << i << QString::fromUtf8(languageCode); + g_free (languageCode); + } + + m_streamProperties.append(streamProperties); + } + } else { // PlayBin 1 + enum { + GST_STREAM_TYPE_UNKNOWN, + GST_STREAM_TYPE_AUDIO, + GST_STREAM_TYPE_VIDEO, + GST_STREAM_TYPE_TEXT, + GST_STREAM_TYPE_SUBPICTURE, + GST_STREAM_TYPE_ELEMENT + }; + + GList* streamInfoList; + g_object_get(G_OBJECT(m_playbin), "stream-info", &streamInfoList, NULL); + + for (; streamInfoList != 0; streamInfoList = g_list_next(streamInfoList)) { + gint type; + gchar *languageCode = 0; + + GObject* streamInfo = G_OBJECT(streamInfoList->data); + + g_object_get(streamInfo, "type", &type, NULL); + g_object_get(streamInfo, "language-code", &languageCode, NULL); + + QMediaStreamsControl::StreamType streamType = QMediaStreamsControl::UnknownStream; + + switch (type) { + case GST_STREAM_TYPE_VIDEO: + streamType = QMediaStreamsControl::VideoStream; + haveVideo = true; + break; + case GST_STREAM_TYPE_AUDIO: + streamType = QMediaStreamsControl::AudioStream; + haveAudio = true; + break; + case GST_STREAM_TYPE_SUBPICTURE: + streamType = QMediaStreamsControl::SubPictureStream; + break; + case GST_STREAM_TYPE_UNKNOWN: { + GstCaps *caps = 0; + g_object_get(streamInfo, "caps", &caps, NULL); + const GstStructure *structure = gst_caps_get_structure(caps, 0); + const gchar *media_type = gst_structure_get_name(structure); + emit error(int(QMediaPlayer::FormatError), QString::fromLatin1("Cannot play stream of type: %1").arg(QString::fromUtf8(media_type))); +#ifdef DEBUG_PLAYBIN + qDebug() << "Encountered unknown stream type"; +#endif + gst_caps_unref(caps); + } + default: + streamType = QMediaStreamsControl::UnknownStream; + break; + } + + QMap streamProperties; + streamProperties[QtMultimediaKit::Language] = QString::fromUtf8(languageCode); + + m_streamProperties.append(streamProperties); + m_streamTypes.append(streamType); + } + } + + + if (haveAudio != m_audioAvailable) { + m_audioAvailable = haveAudio; + emit audioAvailableChanged(m_audioAvailable); + } + if (haveVideo != m_videoAvailable) { + m_videoAvailable = haveVideo; + emit videoAvailableChanged(m_videoAvailable); + } + + emit streamsChanged(); +} + +void QGstreamerPlayerSession::updateVideoResolutionTag() +{ + QSize size; + QSize aspectRatio; + + GstPad *pad = gst_element_get_static_pad(m_videoIdentity, "src"); + GstCaps *caps = gst_pad_get_negotiated_caps(pad); + + if (caps) { + const GstStructure *structure = gst_caps_get_structure(caps, 0); + gst_structure_get_int(structure, "width", &size.rwidth()); + gst_structure_get_int(structure, "height", &size.rheight()); + + gint aspectNum = 0; + gint aspectDenum = 0; + if (!size.isEmpty() && gst_structure_get_fraction( + structure, "pixel-aspect-ratio", &aspectNum, &aspectDenum)) { + if (aspectDenum > 0) + aspectRatio = QSize(aspectNum, aspectDenum); + } + gst_caps_unref(caps); + } + + gst_object_unref(GST_OBJECT(pad)); + + QSize currentSize = m_tags.value("resolution").toSize(); + QSize currentAspectRatio = m_tags.value("pixel-aspect-ratio").toSize(); + + if (currentSize != size || currentAspectRatio != aspectRatio) { + if (aspectRatio.isEmpty()) + m_tags.remove("pixel-aspect-ratio"); + + if (size.isEmpty()) { + m_tags.remove("resolution"); + } else { + m_tags.insert("resolution", QVariant(size)); + if (!aspectRatio.isEmpty()) + m_tags.insert("pixel-aspect-ratio", QVariant(aspectRatio)); + } + + emit tagsChanged(); + } +} + +void QGstreamerPlayerSession::updateDuration() +{ + GstFormat format = GST_FORMAT_TIME; + gint64 gstDuration = 0; + int duration = -1; + + if (m_playbin && gst_element_query_duration(m_playbin, &format, &gstDuration)) + duration = gstDuration / 1000000; + + if (m_duration != duration) { + m_duration = duration; + emit durationChanged(m_duration); + } + + if (m_duration > 0) + m_durationQueries = 0; + + if (m_durationQueries > 0) { + //increase delay between duration requests + int delay = 25 << (5 - m_durationQueries); + QTimer::singleShot(delay, this, SLOT(updateDuration())); + m_durationQueries--; + } +} + +void QGstreamerPlayerSession::playbinNotifySource(GObject *o, GParamSpec *p, gpointer d) +{ + Q_UNUSED(p); + + GstElement *source = 0; + g_object_get(o, "source", &source, NULL); + if (source == 0) + return; + +#ifdef DEBUG_PLAYBIN + qDebug() << "Playbin source added:" << G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(source)); +#endif + + // Turn off icecast metadata request, will be re-set if in QNetworkRequest + // (souphttpsrc docs say is false by default, but header appears in request + // @version 0.10.21) + if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), "iradio-mode") != 0) + g_object_set(G_OBJECT(source), "iradio-mode", FALSE, NULL); + + + // Set Headers + const QByteArray userAgentString("User-Agent"); + + QGstreamerPlayerSession *self = reinterpret_cast(d); + + // User-Agent - special case, souphhtpsrc will always set something, even if + // defined in extra-headers + if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), "user-agent") != 0) { + g_object_set(G_OBJECT(source), "user-agent", + self->m_request.rawHeader(userAgentString).constData(), NULL); + } + + // The rest + if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), "extra-headers") != 0) { + GstStructure *extras = gst_structure_empty_new("extras"); + + foreach (const QByteArray &rawHeader, self->m_request.rawHeaderList()) { + if (rawHeader == userAgentString) // Filter User-Agent + continue; + else { + GValue headerValue; + + memset(&headerValue, 0, sizeof(GValue)); + g_value_init(&headerValue, G_TYPE_STRING); + + g_value_set_string(&headerValue, + self->m_request.rawHeader(rawHeader).constData()); + + gst_structure_set_value(extras, rawHeader.constData(), &headerValue); + } + } + + if (gst_structure_n_fields(extras) > 0) + g_object_set(G_OBJECT(source), "extra-headers", extras, NULL); + + gst_structure_free(extras); + } + + //set timeout property to 5 seconds + if (qstrcmp(G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(source)), "GstUDPSrc") == 0) { + //udpsrc timeout unit = microsecond + g_object_set(G_OBJECT(source), "timeout", G_GUINT64_CONSTANT(5000000), NULL); + self->m_sourceType = UDPSrc; + } else if (qstrcmp(G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(source)), "GstSoupHTTPSrc") == 0) { + //souphttpsrc timeout unit = second + g_object_set(G_OBJECT(source), "timeout", guint(5), NULL); + self->m_sourceType = SoupHTTPSrc; + } else if (qstrcmp(G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(source)), "GstMMSSrc") == 0) { + self->m_sourceType = MMSSrc; + g_object_set(G_OBJECT(source), "tcp-timeout", G_GUINT64_CONSTANT(5000000), NULL); + } else { + self->m_sourceType = UnknownSrc; + } + + gst_object_unref(source); +} + +void QGstreamerPlayerSession::handleVolumeChange(GObject *o, GParamSpec *p, gpointer d) +{ + Q_UNUSED(o); + Q_UNUSED(p); + QGstreamerPlayerSession *session = reinterpret_cast(d); + QMetaObject::invokeMethod(session, "updateVolume", Qt::QueuedConnection); +} + +void QGstreamerPlayerSession::updateVolume() +{ + double volume = 1.0; + g_object_get(m_playbin, "volume", &volume, NULL); + + //special case for playbin1 volume changes in muted state + //playbin1 has no separate muted state, + //it's emulated with volume value saved and set to 0 + //this change should not be reported to user + if (!m_usePlaybin2 && m_muted) { + if (volume > 0.001) { + //volume is changed, player in not muted any more + m_muted = false; + emit mutedStateChanged(m_muted = false); + } else { + //don't emit volume changed to 0 when player is muted + return; + } + } + + if (m_volume != int(volume*100)) { + m_volume = int(volume*100); +#ifdef DEBUG_PLAYBIN + qDebug() << Q_FUNC_INFO << m_muted; +#endif + emit volumeChanged(m_volume); + } +} + +void QGstreamerPlayerSession::handleMutedChange(GObject *o, GParamSpec *p, gpointer d) +{ + Q_UNUSED(o); + Q_UNUSED(p); + QGstreamerPlayerSession *session = reinterpret_cast(d); + QMetaObject::invokeMethod(session, "updateMuted", Qt::QueuedConnection); +} + +void QGstreamerPlayerSession::updateMuted() +{ + gboolean muted = false; + g_object_get(G_OBJECT(m_playbin), "mute", &muted, NULL); + if (m_muted != muted) { + m_muted = muted; +#ifdef DEBUG_PLAYBIN + qDebug() << Q_FUNC_INFO << m_muted; +#endif + emit mutedStateChanged(muted); + } +} + + +void QGstreamerPlayerSession::handleElementAdded(GstBin *bin, GstElement *element, QGstreamerPlayerSession *session) +{ + Q_UNUSED(bin); + //we have to configure queue2 element to enable media downloading + //and reporting available ranges, + //but it's added dynamically to playbin2 + + gchar *elementName = gst_element_get_name(element); + + if (g_str_has_prefix(elementName, "queue2")) { + session->m_haveQueueElement = true; + + if (session->property("mediaDownloadEnabled").toBool()) { + QDir cacheDir(QDesktopServices::storageLocation(QDesktopServices::CacheLocation)); + QString cacheLocation = cacheDir.absoluteFilePath("gstmedia__XXXXXX"); +#ifdef DEBUG_PLAYBIN + qDebug() << "set queue2 temp-location" << cacheLocation; +#endif + g_object_set(G_OBJECT(element), "temp-template", cacheLocation.toUtf8().constData(), NULL); + } else { + g_object_set(G_OBJECT(element), "temp-template", NULL, NULL); + } + } else if (g_str_has_prefix(elementName, "uridecodebin") || + g_str_has_prefix(elementName, "decodebin2")) { + //listen for queue2 element added to uridecodebin/decodebin2 as well. + //Don't touch other bins since they may have unrelated queues + g_signal_connect(element, "element-added", + G_CALLBACK(handleElementAdded), session); + } + + g_free(elementName); +} + +//doing proper operations when detecting an invalidMedia: change media status before signal the erorr +void QGstreamerPlayerSession::processInvalidMedia(QMediaPlayer::Error errorCode, const QString& errorString) +{ + emit invalidMedia(); + stop(); + emit error(int(errorCode), errorString); +} diff --git a/src/plugins/gstreamer/mediaplayer/qgstreamerplayersession.h b/src/plugins/gstreamer/mediaplayer/qgstreamerplayersession.h new file mode 100644 index 000000000..e6fa996b0 --- /dev/null +++ b/src/plugins/gstreamer/mediaplayer/qgstreamerplayersession.h @@ -0,0 +1,217 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERPLAYERSESSION_H +#define QGSTREAMERPLAYERSESSION_H + +#include +#include +#include "qgstreamerplayercontrol.h" +#include "qgstreamerbushelper.h" +#include +#include + +#if defined(HAVE_GST_APPSRC) +#include "qgstappsrc.h" +#endif + +#include + +class QGstreamerBusHelper; +class QGstreamerMessage; + +class QGstreamerVideoRendererInterface; + +QT_USE_NAMESPACE + +class QGstreamerPlayerSession : public QObject, public QGstreamerSyncEventFilter +{ +Q_OBJECT + +public: + QGstreamerPlayerSession(QObject *parent); + virtual ~QGstreamerPlayerSession(); + + QNetworkRequest request() const; + + QMediaPlayer::State state() const { return m_state; } + QMediaPlayer::State pendingState() const { return m_pendingState; } + + qint64 duration() const; + qint64 position() const; + + bool isBuffering() const; + + int bufferingProgress() const; + + int volume() const; + bool isMuted() const; + + bool isAudioAvailable() const; + + void setVideoRenderer(QObject *renderer); + bool isVideoAvailable() const; + + bool isSeekable() const; + + qreal playbackRate() const; + void setPlaybackRate(qreal rate); + + QMediaTimeRange availablePlaybackRanges() const; + + QMap tags() const { return m_tags; } + QMap streamProperties(int streamNumber) const { return m_streamProperties[streamNumber]; } + int streamCount() const { return m_streamProperties.count(); } + QMediaStreamsControl::StreamType streamType(int streamNumber) { return m_streamTypes.value(streamNumber, QMediaStreamsControl::UnknownStream); } + + int activeStream(QMediaStreamsControl::StreamType streamType) const; + void setActiveStream(QMediaStreamsControl::StreamType streamType, int streamNumber); + + bool processSyncMessage(const QGstreamerMessage &message); + +#if defined(HAVE_GST_APPSRC) + QGstAppSrc *appsrc() const { return m_appSrc; } + static void configureAppSrcElement(GObject*, GObject*, GParamSpec*,QGstreamerPlayerSession* _this); +#endif + +public slots: + void loadFromUri(const QNetworkRequest &url); + void loadFromStream(const QNetworkRequest &url, QIODevice *stream); + bool play(); + bool pause(); + void stop(); + + bool seek(qint64 pos); + + void setVolume(int volume); + void setMuted(bool muted); + +signals: + void durationChanged(qint64 duration); + void positionChanged(qint64 position); + void stateChanged(QMediaPlayer::State state); + void volumeChanged(int volume); + void mutedStateChanged(bool muted); + void audioAvailableChanged(bool audioAvailable); + void videoAvailableChanged(bool videoAvailable); + void bufferingChanged(bool buffering); + void bufferingProgressChanged(int percentFilled); + void playbackFinished(); + void tagsChanged(); + void streamsChanged(); + void seekableChanged(bool); + void error(int error, const QString &errorString); + void invalidMedia(); + void playbackRateChanged(qreal); + +private slots: + void busMessage(const QGstreamerMessage &message); + void getStreamsInfo(); + void setSeekable(bool); + void finishVideoOutputChange(); + void updateVideoRenderer(); + void updateVideoResolutionTag(); + void updateVolume(); + void updateMuted(); + void updateDuration(); + +private: + static void playbinNotifySource(GObject *o, GParamSpec *p, gpointer d); + static void handleVolumeChange(GObject *o, GParamSpec *p, gpointer d); + static void handleMutedChange(GObject *o, GParamSpec *p, gpointer d); + static void insertColorSpaceElement(GstElement *element, gpointer data); + static void handleElementAdded(GstBin *bin, GstElement *element, QGstreamerPlayerSession *session); + void processInvalidMedia(QMediaPlayer::Error errorCode, const QString& errorString); + + QNetworkRequest m_request; + QMediaPlayer::State m_state; + QMediaPlayer::State m_pendingState; + QGstreamerBusHelper* m_busHelper; + GstElement* m_playbin; + bool m_usePlaybin2; + + GstElement* m_videoOutputBin; + GstElement* m_videoIdentity; + GstElement* m_colorSpace; + bool m_usingColorspaceElement; + GstElement* m_videoSink; + GstElement* m_pendingVideoSink; + GstElement* m_nullVideoSink; + + GstBus* m_bus; + QObject *m_videoOutput; + QGstreamerVideoRendererInterface *m_renderer; + + bool m_haveQueueElement; + +#if defined(HAVE_GST_APPSRC) + QGstAppSrc *m_appSrc; +#endif + + QMap m_tags; + QList< QMap > m_streamProperties; + QList m_streamTypes; + QMap m_playbin2StreamOffset; + + + int m_volume; + qreal m_playbackRate; + bool m_muted; + bool m_audioAvailable; + bool m_videoAvailable; + bool m_seekable; + + mutable qint64 m_lastPosition; + qint64 m_duration; + int m_durationQueries; + + enum SourceType + { + UnknownSrc, + SoupHTTPSrc, + UDPSrc, + MMSSrc + }; + SourceType m_sourceType; + bool m_everPlayed; +}; + +#endif // QGSTREAMERPLAYERSESSION_H diff --git a/src/plugins/gstreamer/mediaplayer/qgstreamerstreamscontrol.cpp b/src/plugins/gstreamer/mediaplayer/qgstreamerstreamscontrol.cpp new file mode 100644 index 000000000..0ab93022b --- /dev/null +++ b/src/plugins/gstreamer/mediaplayer/qgstreamerstreamscontrol.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamerstreamscontrol.h" +#include "qgstreamerplayersession.h" + +QGstreamerStreamsControl::QGstreamerStreamsControl(QGstreamerPlayerSession *session, QObject *parent) + :QMediaStreamsControl(parent), m_session(session) +{ + connect(m_session, SIGNAL(streamsChanged()), SIGNAL(streamsChanged())); +} + +QGstreamerStreamsControl::~QGstreamerStreamsControl() +{ +} + +int QGstreamerStreamsControl::streamCount() +{ + return m_session->streamCount(); +} + +QMediaStreamsControl::StreamType QGstreamerStreamsControl::streamType(int streamNumber) +{ + return m_session->streamType(streamNumber); +} + +QVariant QGstreamerStreamsControl::metaData(int streamNumber, QtMultimediaKit::MetaData key) +{ + return m_session->streamProperties(streamNumber).value(key); +} + +bool QGstreamerStreamsControl::isActive(int streamNumber) +{ + return streamNumber != -1 && streamNumber == m_session->activeStream(streamType(streamNumber)); +} + +void QGstreamerStreamsControl::setActive(int streamNumber, bool state) +{ + QMediaStreamsControl::StreamType type = m_session->streamType(streamNumber); + if (type == QMediaStreamsControl::UnknownStream) + return; + + if (state) + m_session->setActiveStream(type, streamNumber); + else { + //only one active stream of certain type is supported + if (m_session->activeStream(type) == streamNumber) + m_session->setActiveStream(type, -1); + } +} + diff --git a/src/plugins/gstreamer/mediaplayer/qgstreamerstreamscontrol.h b/src/plugins/gstreamer/mediaplayer/qgstreamerstreamscontrol.h new file mode 100644 index 000000000..1213455b9 --- /dev/null +++ b/src/plugins/gstreamer/mediaplayer/qgstreamerstreamscontrol.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERSTREAMSCONTROL_H +#define QGSTREAMERSTREAMSCONTROL_H + +#include + +QT_USE_NAMESPACE + +class QGstreamerPlayerSession; + +class QGstreamerStreamsControl : public QMediaStreamsControl +{ + Q_OBJECT +public: + QGstreamerStreamsControl(QGstreamerPlayerSession *session, QObject *parent); + virtual ~QGstreamerStreamsControl(); + + virtual int streamCount(); + virtual StreamType streamType(int streamNumber); + + virtual QVariant metaData(int streamNumber, QtMultimediaKit::MetaData key); + + virtual bool isActive(int streamNumber); + virtual void setActive(int streamNumber, bool state); + +private: + QGstreamerPlayerSession *m_session; +}; + +#endif // QGSTREAMERSTREAMSCONTROL_H + diff --git a/src/plugins/gstreamer/qabstractgstbufferpool.h b/src/plugins/gstreamer/qabstractgstbufferpool.h new file mode 100644 index 000000000..8681dac71 --- /dev/null +++ b/src/plugins/gstreamer/qabstractgstbufferpool.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTBUFFERPOOL_H +#define QGSTBUFFERPOOL_H + +#include +#include + +#include + +/*! + Abstract interface for video buffers allocation. +*/ +class QAbstractGstBufferPool +{ +public: + virtual ~QAbstractGstBufferPool() {} + + virtual bool isFormatSupported(const QVideoSurfaceFormat &format) const = 0; + + virtual GType bufferType() const = 0; + virtual GstBuffer *takeBuffer(const QVideoSurfaceFormat &format, GstCaps *caps) = 0; + virtual void clear() = 0; + + virtual QAbstractVideoBuffer::HandleType handleType() const = 0; + + /*! + Build an QAbstractVideoBuffer instance from compatible (mathcing gst buffer type) + GstBuffer. + + This method is called from gstreamer video sink thread. + */ + virtual QAbstractVideoBuffer *prepareVideoBuffer(GstBuffer *buffer, int bytesPerLine) = 0; +}; + +#endif diff --git a/src/plugins/gstreamer/qgstreameraudioinputendpointselector.cpp b/src/plugins/gstreamer/qgstreameraudioinputendpointselector.cpp new file mode 100644 index 000000000..606f06052 --- /dev/null +++ b/src/plugins/gstreamer/qgstreameraudioinputendpointselector.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreameraudioinputendpointselector.h" + +#include +#include +#include + +#include + +#ifdef HAVE_ALSA +#include +#endif + +QGstreamerAudioInputEndpointSelector::QGstreamerAudioInputEndpointSelector(QObject *parent) + :QAudioEndpointSelector(parent) +{ + update(); +} + +QGstreamerAudioInputEndpointSelector::~QGstreamerAudioInputEndpointSelector() +{ +} + +QList QGstreamerAudioInputEndpointSelector::availableEndpoints() const +{ + return m_names; +} + +QString QGstreamerAudioInputEndpointSelector::endpointDescription(const QString& name) const +{ + QString desc; + + for (int i = 0; i < m_names.size(); i++) { + if (m_names.at(i).compare(name) == 0) { + desc = m_descriptions.at(i); + break; + } + } + return desc; +} + +QString QGstreamerAudioInputEndpointSelector::defaultEndpoint() const +{ + if (m_names.size() > 0) + return m_names.at(0); + + return QString(); +} + +QString QGstreamerAudioInputEndpointSelector::activeEndpoint() const +{ + return m_audioInput; +} + +void QGstreamerAudioInputEndpointSelector::setActiveEndpoint(const QString& name) +{ + if (m_audioInput.compare(name) != 0) { + m_audioInput = name; + emit activeEndpointChanged(name); + } +} + +void QGstreamerAudioInputEndpointSelector::update() +{ + m_names.clear(); + m_descriptions.clear(); +#ifndef Q_WS_MAEMO_5 + updateAlsaDevices(); + updateOssDevices(); +#endif + updatePulseDevices(); + if (m_names.size() > 0) + m_audioInput = m_names.at(0); +} + +void QGstreamerAudioInputEndpointSelector::updateAlsaDevices() +{ +#ifdef HAVE_ALSA + void **hints, **n; + if (snd_device_name_hint(-1, "pcm", &hints) < 0) { + qWarning()<<"no alsa devices available"; + return; + } + n = hints; + + while (*n != NULL) { + char *name = snd_device_name_get_hint(*n, "NAME"); + char *descr = snd_device_name_get_hint(*n, "DESC"); + char *io = snd_device_name_get_hint(*n, "IOID"); + + if ((name != NULL) && (descr != NULL)) { + if ( io == NULL || qstrcmp(io,"Input") == 0 ) { + m_names.append(QLatin1String("alsa:")+QString::fromUtf8(name)); + m_descriptions.append(QString::fromUtf8(descr)); + } + } + + if (name != NULL) + free(name); + if (descr != NULL) + free(descr); + if (io != NULL) + free(io); + n++; + } + snd_device_name_free_hint(hints); +#endif +} + +void QGstreamerAudioInputEndpointSelector::updateOssDevices() +{ + QDir devDir("/dev"); + devDir.setFilter(QDir::System); +#ifndef QT_QWS_N810 + QFileInfoList entries = devDir.entryInfoList(QStringList() << "dsp*"); + foreach(const QFileInfo& entryInfo, entries) { + m_names.append(QLatin1String("oss:")+entryInfo.filePath()); + m_descriptions.append(QString("OSS device %1").arg(entryInfo.fileName())); + } +#else + m_names.append("dsppcm"); + m_descriptions.append("PCM audio input"); +#endif +} + +void QGstreamerAudioInputEndpointSelector::updatePulseDevices() +{ + GstElementFactory *factory = gst_element_factory_find("pulsesrc"); + if (factory) { + m_names.append("pulseaudio:"); + m_descriptions.append("PulseAudio device."); + gst_object_unref(GST_OBJECT(factory)); + } +} diff --git a/src/plugins/gstreamer/qgstreameraudioinputendpointselector.h b/src/plugins/gstreamer/qgstreameraudioinputendpointselector.h new file mode 100644 index 000000000..c9587fcb8 --- /dev/null +++ b/src/plugins/gstreamer/qgstreameraudioinputendpointselector.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERAUDIOINPUTENDPOINTSELECTOR_H +#define QGSTREAMERAUDIOINPUTENDPOINTSELECTOR_H + +#include +#include + +QT_USE_NAMESPACE + +class QGstreamerAudioInputEndpointSelector : public QAudioEndpointSelector +{ +Q_OBJECT +public: + QGstreamerAudioInputEndpointSelector(QObject *parent); + ~QGstreamerAudioInputEndpointSelector(); + + QList availableEndpoints() const; + QString endpointDescription(const QString& name) const; + QString defaultEndpoint() const; + QString activeEndpoint() const; + +public Q_SLOTS: + void setActiveEndpoint(const QString& name); + +private: + void update(); + void updateAlsaDevices(); + void updateOssDevices(); + void updatePulseDevices(); + + QString m_audioInput; + QList m_names; + QList m_descriptions; +}; + +#endif // QGSTREAMERAUDIOINPUTENDPOINTSELECTOR_H diff --git a/src/plugins/gstreamer/qgstreamerbushelper.cpp b/src/plugins/gstreamer/qgstreamerbushelper.cpp new file mode 100644 index 000000000..a60ec7fab --- /dev/null +++ b/src/plugins/gstreamer/qgstreamerbushelper.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +#include "qgstreamerbushelper.h" + + +#ifndef QT_NO_GLIB +class QGstreamerBusHelperPrivate : public QObject +{ + Q_OBJECT + +public: + void addWatch(GstBus* bus, QGstreamerBusHelper* helper) + { + setParent(helper); + m_tag = gst_bus_add_watch_full(bus, 0, busCallback, this, NULL); + m_helper = helper; + filter = 0; + } + + void removeWatch(QGstreamerBusHelper* helper) + { + Q_UNUSED(helper); + g_source_remove(m_tag); + } + + static QGstreamerBusHelperPrivate* instance() + { + return new QGstreamerBusHelperPrivate; + } + +private: + void processMessage(GstBus* bus, GstMessage* message) + { + Q_UNUSED(bus); + emit m_helper->message(message); + } + + static gboolean busCallback(GstBus *bus, GstMessage *message, gpointer data) + { + reinterpret_cast(data)->processMessage(bus, message); + return TRUE; + } + + guint m_tag; + QGstreamerBusHelper* m_helper; + +public: + GstBus* bus; + QGstreamerSyncEventFilter *filter; + QMutex filterMutex; +}; + +#else + +class QGstreamerBusHelperPrivate : public QObject +{ + Q_OBJECT + typedef QMap HelperMap; + +public: + void addWatch(GstBus* bus, QGstreamerBusHelper* helper) + { + m_helperMap.insert(helper, bus); + + if (m_helperMap.size() == 1) + m_intervalTimer->start(); + } + + void removeWatch(QGstreamerBusHelper* helper) + { + m_helperMap.remove(helper); + + if (m_helperMap.size() == 0) + m_intervalTimer->stop(); + } + + static QGstreamerBusHelperPrivate* instance() + { + static QGstreamerBusHelperPrivate self; + + return &self; + } + +private slots: + void interval() + { + for (HelperMap::iterator it = m_helperMap.begin(); it != m_helperMap.end(); ++it) { + GstMessage* message; + + while ((message = gst_bus_poll(it.value(), GST_MESSAGE_ANY, 0)) != 0) { + emit it.key()->message(message); + gst_message_unref(message); + } + + emit it.key()->message(QGstreamerMessage()); + } + } + +private: + QGstreamerBusHelperPrivate() + { + m_intervalTimer = new QTimer(this); + m_intervalTimer->setInterval(250); + + connect(m_intervalTimer, SIGNAL(timeout()), SLOT(interval())); + } + + HelperMap m_helperMap; + QTimer* m_intervalTimer; + +public: + GstBus* bus; + QGstreamerSyncEventFilter *filter; + QMutex filterMutex; +}; +#endif + + +static GstBusSyncReply syncGstBusFilter(GstBus* bus, GstMessage* message, QGstreamerBusHelperPrivate *d) +{ + Q_UNUSED(bus); + QMutexLocker lock(&d->filterMutex); + + bool res = false; + + if (d->filter) + res = d->filter->processSyncMessage(QGstreamerMessage(message)); + + return res ? GST_BUS_DROP : GST_BUS_PASS; +} + + +/*! + \class gstreamer::QGstreamerBusHelper + \internal +*/ + +QGstreamerBusHelper::QGstreamerBusHelper(GstBus* bus, QObject* parent): + QObject(parent), + d(QGstreamerBusHelperPrivate::instance()) +{ + d->bus = bus; + d->addWatch(bus, this); + + gst_bus_set_sync_handler(bus, (GstBusSyncHandler)syncGstBusFilter, d); +} + +QGstreamerBusHelper::~QGstreamerBusHelper() +{ + d->removeWatch(this); + gst_bus_set_sync_handler(d->bus,0,0); +} + +void QGstreamerBusHelper::installSyncEventFilter(QGstreamerSyncEventFilter *filter) +{ + QMutexLocker lock(&d->filterMutex); + d->filter = filter; +} + +#include "qgstreamerbushelper.moc" diff --git a/src/plugins/gstreamer/qgstreamerbushelper.h b/src/plugins/gstreamer/qgstreamerbushelper.h new file mode 100644 index 000000000..5375c44ae --- /dev/null +++ b/src/plugins/gstreamer/qgstreamerbushelper.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERBUSHELPER_H +#define QGSTREAMERBUSHELPER_H + +#include + +#include +#include + +class QGstreamerSyncEventFilter { +public: + //returns true if message was processed and should be dropped, false otherwise + virtual bool processSyncMessage(const QGstreamerMessage &message) = 0; +}; + +class QGstreamerBusHelperPrivate; + +class QGstreamerBusHelper : public QObject +{ + Q_OBJECT + friend class QGstreamerBusHelperPrivate; + +public: + QGstreamerBusHelper(GstBus* bus, QObject* parent = 0); + ~QGstreamerBusHelper(); + + void installSyncEventFilter(QGstreamerSyncEventFilter *filter); + +signals: + void message(QGstreamerMessage const& message); + + +private: + QGstreamerBusHelperPrivate* d; +}; + +#endif diff --git a/src/plugins/gstreamer/qgstreamergltexturerenderer.cpp b/src/plugins/gstreamer/qgstreamergltexturerenderer.cpp new file mode 100644 index 000000000..5d1a11ffb --- /dev/null +++ b/src/plugins/gstreamer/qgstreamergltexturerenderer.cpp @@ -0,0 +1,578 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideosurfacegstsink.h" +#include "qabstractvideosurface.h" +#include "qgstutils.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + + +#include +#include + +#include "qgstreamergltexturerenderer.h" + +//#define GL_TEXTURE_SINK_DEBUG 1 + +//from extdefs.h +typedef void *EGLSyncKHR; +typedef khronos_utime_nanoseconds_t EGLTimeKHR; + +#define GL_TEXTURE_EXTERNAL_OES 0x8D65 +#define EGL_SYNC_FENCE_KHR 0x30F9 + +typedef EGLSyncKHR (EGLAPIENTRYP _PFNEGLCREATESYNCKHRPROC) (EGLDisplay dpy, + EGLenum type, const EGLint * attrib_list); +typedef EGLBoolean (EGLAPIENTRYP _PFNEGLDESTROYSYNCKHRPROC) (EGLDisplay dpy, + EGLSyncKHR sync); + + +const QAbstractVideoBuffer::HandleType EGLImageTextureHandle = + QAbstractVideoBuffer::HandleType(QAbstractVideoBuffer::UserHandle+3434); + +// EGLSync functions +_PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR; +_PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR; + +class QGStreamerGLTextureBuffer : public QAbstractVideoBuffer +{ +public: + QGStreamerGLTextureBuffer(MeegoGstVideoTexture *textureSink, int frameNumber) : + QAbstractVideoBuffer(EGLImageTextureHandle), + m_textureSink(MEEGO_GST_VIDEO_TEXTURE(textureSink)), + m_frameNumber(frameNumber) + { + } + + ~QGStreamerGLTextureBuffer() + { + } + + + MapMode mapMode() const { return NotMapped; } + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) + { + Q_UNUSED(mode); + Q_UNUSED(numBytes); + Q_UNUSED(bytesPerLine); + + //acquire_frame should really be called at buffer construction time + //but it conflicts with id-less implementation of gst texture sink. +#if defined(GL_TEXTURE_SINK_DEBUG) && GL_TEXTURE_SINK_DEBUG > 1 + qDebug() << "acquire frame" << m_frameNumber; +#endif + if (!meego_gst_video_texture_acquire_frame(m_textureSink,m_frameNumber)) + qWarning() << Q_FUNC_INFO << "acquire-frame failed" << m_frameNumber; + + +#if defined(GL_TEXTURE_SINK_DEBUG) && GL_TEXTURE_SINK_DEBUG > 1 + qDebug() << "map frame" << m_frameNumber; +#endif + + gboolean bind_status = meego_gst_video_texture_bind_frame(m_textureSink, GL_TEXTURE_EXTERNAL_OES, m_frameNumber); + if (!bind_status) + qWarning() << Q_FUNC_INFO << "bind-frame failed"; + + return (uchar*)1; + } + + void unmap() + { + gboolean bind_status = meego_gst_video_texture_bind_frame(m_textureSink, GL_TEXTURE_EXTERNAL_OES, -1); + +#if defined(GL_TEXTURE_SINK_DEBUG) && GL_TEXTURE_SINK_DEBUG > 1 + qDebug() << "unmap frame" << m_frameNumber; +#endif + + if (!bind_status) + qWarning() << Q_FUNC_INFO << "unbind-frame failed"; + + //release_frame should really be called in destructor + //but this conflicts with id-less implementation of gst texture sink. +#if defined(GL_TEXTURE_SINK_DEBUG) && GL_TEXTURE_SINK_DEBUG > 1 + qDebug() << "release frame" << m_frameNumber; +#endif + EGLSyncKHR sync = eglCreateSyncKHR(eglGetDisplay((EGLNativeDisplayType)QX11Info::display()), EGL_SYNC_FENCE_KHR, NULL); + meego_gst_video_texture_release_frame(m_textureSink, m_frameNumber, sync); + } + + QVariant handle() const + { + return m_frameNumber; + } + +private: + MeegoGstVideoTexture *m_textureSink; + int m_frameNumber; +}; + + +QGstreamerGLTextureRenderer::QGstreamerGLTextureRenderer(QObject *parent) : + QVideoRendererControl(parent), + m_videoSink(0), + m_surface(0), + m_context(0), + m_winId(0), + m_colorKey(49,0,49), + m_overlayEnabled(false), + m_bufferProbeId(-1) +{ + eglCreateSyncKHR = + (_PFNEGLCREATESYNCKHRPROC)eglGetProcAddress("eglCreateSyncKHR"); + eglDestroySyncKHR = + (_PFNEGLDESTROYSYNCKHRPROC)eglGetProcAddress("eglDestroySyncKHR"); +} + +QGstreamerGLTextureRenderer::~QGstreamerGLTextureRenderer() +{ + if (m_surface && m_surface->isActive()) + m_surface->stop(); + + if (m_videoSink) + gst_object_unref(GST_OBJECT(m_videoSink)); +} + +GstElement *QGstreamerGLTextureRenderer::videoSink() +{ + if (!m_videoSink && isReady()) { + if (m_context && !m_surface->supportedPixelFormats(EGLImageTextureHandle).isEmpty()) { +#ifdef GL_TEXTURE_SINK_DEBUG + qDebug() << Q_FUNC_INFO << ": using gltexture sink"; +#endif + if (m_context) + m_context->makeCurrent(); + m_videoSink = gst_element_factory_make("gltexturesink", "egl-texture-sink"); + g_object_set(G_OBJECT(m_videoSink), + "x-display", QX11Info::display(), + "egl-display", eglGetDisplay((EGLNativeDisplayType)QX11Info::display()), + "egl-context", eglGetCurrentContext(), + "colorkey", m_colorKey.rgb(), + "autopaint-colorkey", false, + "use-framebuffer-memory", true, + "render-mode", m_overlayEnabled ? VIDEO_RENDERSWITCH_XOVERLAY_MODE + : VIDEO_RENDERSWITCH_TEXTURE_STREAMING_MODE, + (char*)NULL); + + g_signal_connect(G_OBJECT(m_videoSink), "frame-ready", G_CALLBACK(handleFrameReady), (gpointer)this); + } else { + qWarning() << Q_FUNC_INFO << ": Fallback to QVideoSurfaceGstSink since EGLImageTextureHandle is not supported"; + m_videoSink = reinterpret_cast(QVideoSurfaceGstSink::createSink(m_surface)); + } + + if (m_videoSink) { + gst_object_ref(GST_OBJECT(m_videoSink)); //Take ownership + gst_object_sink(GST_OBJECT(m_videoSink)); + + GstPad *pad = gst_element_get_static_pad(m_videoSink,"sink"); + m_bufferProbeId = gst_pad_add_buffer_probe(pad, G_CALLBACK(padBufferProbe), this); + } + } + + return m_videoSink; +} + +QAbstractVideoSurface *QGstreamerGLTextureRenderer::surface() const +{ + return m_surface; +} + +void QGstreamerGLTextureRenderer::setSurface(QAbstractVideoSurface *surface) +{ + if (m_surface != surface) { +#ifdef GL_TEXTURE_SINK_DEBUG + qDebug() << Q_FUNC_INFO << surface; +#endif + + bool oldReady = isReady(); + + m_context = const_cast(QGLContext::currentContext()); + + if (m_videoSink) + gst_object_unref(GST_OBJECT(m_videoSink)); + + m_videoSink = 0; + + if (m_surface) { + disconnect(m_surface, SIGNAL(supportedFormatsChanged()), + this, SLOT(handleFormatChange())); + } + + m_surface = surface; + + if (oldReady != isReady()) + emit readyChanged(!oldReady); + + if (m_surface) { + connect(m_surface, SIGNAL(supportedFormatsChanged()), + this, SLOT(handleFormatChange())); + } + + emit sinkChanged(); + } +} + +void QGstreamerGLTextureRenderer::handleFormatChange() +{ + if (m_videoSink) + gst_object_unref(GST_OBJECT(m_videoSink)); + + m_videoSink = 0; + emit sinkChanged(); +} + +void QGstreamerGLTextureRenderer::handleFrameReady(GstElement *sink, gint frame, gpointer data) +{ + Q_UNUSED(sink); + QGstreamerGLTextureRenderer* renderer = reinterpret_cast(data); + + QMutexLocker locker(&renderer->m_mutex); + QMetaObject::invokeMethod(renderer, "renderGLFrame", + Qt::QueuedConnection, + Q_ARG(int, frame)); + + //we have to wait to ensure the frame is not reused, + //timeout is added to avoid deadlocks when the main thread is + //waiting for rendering to complete, this is possible for example during state chages. + //If frame is not rendered during 60ms (~1-2 frames interval) it's better to unblock and drop it if necessary + renderer->m_renderCondition.wait(&renderer->m_mutex, 60); +} + +void QGstreamerGLTextureRenderer::renderGLFrame(int frame) +{ +#if defined(GL_TEXTURE_SINK_DEBUG) && GL_TEXTURE_SINK_DEBUG > 1 + qDebug() << Q_FUNC_INFO << "frame:" << frame << "surface active:" << m_surface->isActive(); +#endif + QMutexLocker locker(&m_mutex); + + if (!m_surface) { + m_renderCondition.wakeAll(); + return; + } + + MeegoGstVideoTexture *textureSink = MEEGO_GST_VIDEO_TEXTURE(m_videoSink); + + if (m_context) + m_context->makeCurrent(); + + //don't try to render the frame if state is changed to NULL or READY + GstState pendingState = GST_STATE_NULL; + GstState newState = GST_STATE_NULL; + GstStateChangeReturn res = gst_element_get_state(m_videoSink, + &newState, + &pendingState, + 0);//don't block and return immediately + + if (res == GST_STATE_CHANGE_FAILURE || + newState == GST_STATE_NULL || + pendingState == GST_STATE_NULL) { + stopRenderer(); + m_renderCondition.wakeAll(); + return; + } + + if (!m_surface->isActive()) { + //find the native video size + GstPad *pad = gst_element_get_static_pad(m_videoSink,"sink"); + GstCaps *caps = gst_pad_get_negotiated_caps(pad); + + if (caps) { + QSize newNativeSize = QGstUtils::capsCorrectedResolution(caps); + if (m_nativeSize != newNativeSize) { + m_nativeSize = newNativeSize; + emit nativeSizeChanged(); + } + gst_caps_unref(caps); + } + + //start the surface... + QVideoSurfaceFormat format(m_nativeSize, QVideoFrame::Format_RGB32, EGLImageTextureHandle); + if (!m_surface->start(format)) { + qWarning() << Q_FUNC_INFO << "failed to start video surface" << format; + m_renderCondition.wakeAll(); + return; + } + } + + QGStreamerGLTextureBuffer *buffer = new QGStreamerGLTextureBuffer(textureSink, frame); + QVideoFrame videoFrame(buffer, + m_surface->surfaceFormat().frameSize(), + m_surface->surfaceFormat().pixelFormat()); + m_surface->present(videoFrame); + m_renderCondition.wakeAll(); +} + +bool QGstreamerGLTextureRenderer::isReady() const +{ + if (!m_surface) + return false; + + if (m_winId > 0) + return true; + + //winId is required only for EGLImageTextureHandle compatible surfaces + return m_surface->supportedPixelFormats(EGLImageTextureHandle).isEmpty(); +} + +void QGstreamerGLTextureRenderer::handleBusMessage(GstMessage* gm) +{ +#ifdef GL_TEXTURE_SINK_DEBUG + qDebug() << Q_FUNC_INFO << GST_MESSAGE_TYPE_NAME(gm); +#endif + + if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_STATE_CHANGED) { + GstState oldState; + GstState newState; + gst_message_parse_state_changed(gm, &oldState, &newState, 0); + +#ifdef GL_TEXTURE_SINK_DEBUG + qDebug() << Q_FUNC_INFO << "State changed:" << oldState << newState; +#endif + + if (newState == GST_STATE_READY || newState == GST_STATE_NULL) { + stopRenderer(); + } + + if (oldState == GST_STATE_READY && newState == GST_STATE_PAUSED) { + updateNativeVideoSize(); + } + } +} + +void QGstreamerGLTextureRenderer::handleSyncMessage(GstMessage* gm) +{ +#ifdef GL_TEXTURE_SINK_DEBUG + qDebug() << Q_FUNC_INFO; +#endif + + if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ELEMENT && + gst_structure_has_name(gm->structure, "prepare-xwindow-id")) + precessNewStream(); +} + +void QGstreamerGLTextureRenderer::precessNewStream() +{ + if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) { + GstXOverlay *overlay = GST_X_OVERLAY(m_videoSink); + + gst_x_overlay_set_xwindow_id(overlay, m_winId); + + if (!m_displayRect.isEmpty()) { + gst_x_overlay_set_render_rectangle(overlay, + m_displayRect.x(), + m_displayRect.y(), + m_displayRect.width(), + m_displayRect.height()); + } + + GstPad *pad = gst_element_get_static_pad(m_videoSink,"sink"); + m_bufferProbeId = gst_pad_add_buffer_probe(pad, G_CALLBACK(padBufferProbe), this); + } +} + +void QGstreamerGLTextureRenderer::stopRenderer() +{ +#ifdef GL_TEXTURE_SINK_DEBUG + qDebug() << Q_FUNC_INFO; +#endif + + if (m_surface && m_surface->isActive()) + m_surface->stop(); + + if (!m_nativeSize.isEmpty()) { + m_nativeSize = QSize(); + emit nativeSizeChanged(); + } +} + +bool QGstreamerGLTextureRenderer::overlayEnabled() const +{ + return m_overlayEnabled; +} + +void QGstreamerGLTextureRenderer::setOverlayEnabled(bool enabled) +{ + + if (m_videoSink && (m_overlayEnabled != enabled)) { + qDebug() << Q_FUNC_INFO << enabled; + g_object_set(G_OBJECT(m_videoSink), + "render-mode", + enabled ? VIDEO_RENDERSWITCH_XOVERLAY_MODE : VIDEO_RENDERSWITCH_TEXTURE_STREAMING_MODE, + (char *)NULL); + } + + m_overlayEnabled = enabled; +} + + +WId QGstreamerGLTextureRenderer::winId() const +{ + return m_winId; +} + +void QGstreamerGLTextureRenderer::setWinId(WId id) +{ +#ifdef GL_TEXTURE_SINK_DEBUG + qDebug() << Q_FUNC_INFO << id; +#endif + + if (m_winId == id) + return; + + bool oldReady = isReady(); + + m_winId = id; + + if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) { + //don't set winId in NULL state, + //texture sink opens xvideo port on set_xwindow_id, + //this fails if video resource is not granted by resource policy yet. + //state is changed to READY/PAUSED/PLAYING only after resource is granted. + GstState pendingState = GST_STATE_NULL; + GstState newState = GST_STATE_NULL; + GstStateChangeReturn res = gst_element_get_state(m_videoSink, + &newState, + &pendingState, + 0);//don't block and return immediately + + if (res != GST_STATE_CHANGE_FAILURE && + newState != GST_STATE_NULL && + pendingState != GST_STATE_NULL) + gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(m_videoSink), m_winId); + } + + if (oldReady != isReady()) + emit readyChanged(!oldReady); +} + +QRect QGstreamerGLTextureRenderer::overlayGeometry() const +{ + return m_displayRect; +} + +void QGstreamerGLTextureRenderer::setOverlayGeometry(const QRect &geometry) +{ + if (m_displayRect != geometry) { +#ifdef GL_TEXTURE_SINK_DEBUG + qDebug() << Q_FUNC_INFO << geometry; +#endif + m_displayRect = geometry; + + if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) { + if (m_displayRect.isEmpty()) + gst_x_overlay_set_render_rectangle(GST_X_OVERLAY(m_videoSink), -1, -1, -1, -1); + else + gst_x_overlay_set_render_rectangle(GST_X_OVERLAY(m_videoSink), + m_displayRect.x(), + m_displayRect.y(), + m_displayRect.width(), + m_displayRect.height()); + repaintOverlay(); + } + } +} + +QColor QGstreamerGLTextureRenderer::colorKey() const +{ + return m_colorKey; +} + +void QGstreamerGLTextureRenderer::repaintOverlay() +{ + if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) { + //don't call gst_x_overlay_expose if the sink is in null state + GstState state = GST_STATE_NULL; + GstStateChangeReturn res = gst_element_get_state(m_videoSink, &state, NULL, 1000000); + if (res != GST_STATE_CHANGE_FAILURE && state != GST_STATE_NULL) { + gst_x_overlay_expose(GST_X_OVERLAY(m_videoSink)); + } + } +} + +QSize QGstreamerGLTextureRenderer::nativeSize() const +{ + return m_nativeSize; +} + +gboolean QGstreamerGLTextureRenderer::padBufferProbe(GstPad *pad, GstBuffer *buffer, gpointer user_data) +{ + QGstreamerGLTextureRenderer *control = reinterpret_cast(user_data); + QMetaObject::invokeMethod(control, "updateNativeVideoSize", Qt::QueuedConnection); + gst_pad_remove_buffer_probe(pad, control->m_bufferProbeId); + + return TRUE; +} + +void QGstreamerGLTextureRenderer::updateNativeVideoSize() +{ + const QSize oldSize = m_nativeSize; + + if (m_videoSink) { + //find video native size to update video widget size hint + GstPad *pad = gst_element_get_static_pad(m_videoSink,"sink"); + GstCaps *caps = gst_pad_get_negotiated_caps(pad); + + if (caps) { + m_nativeSize = QGstUtils::capsCorrectedResolution(caps); + gst_caps_unref(caps); + } + } else { + m_nativeSize = QSize(); + } +#ifdef GL_TEXTURE_SINK_DEBUG + qDebug() << Q_FUNC_INFO << oldSize << m_nativeSize << m_videoSink; +#endif + + if (m_nativeSize != oldSize) + emit nativeSizeChanged(); +} diff --git a/src/plugins/gstreamer/qgstreamergltexturerenderer.h b/src/plugins/gstreamer/qgstreamergltexturerenderer.h new file mode 100644 index 000000000..92beb1a17 --- /dev/null +++ b/src/plugins/gstreamer/qgstreamergltexturerenderer.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERGLTEXTURERENDERER_H +#define QGSTREAMERGLTEXTURERENDERER_H + +#include +#include "qvideosurfacegstsink.h" + +#include "qgstreamervideorendererinterface.h" +#include + +#include + +QT_USE_NAMESPACE + +class QGLContext; + +class QGstreamerGLTextureRenderer : public QVideoRendererControl, public QGstreamerVideoRendererInterface +{ + Q_OBJECT + Q_INTERFACES(QGstreamerVideoRendererInterface) + + Q_PROPERTY(bool overlayEnabled READ overlayEnabled WRITE setOverlayEnabled) + Q_PROPERTY(qulonglong winId READ winId WRITE setWinId) + Q_PROPERTY(QRect overlayGeometry READ overlayGeometry WRITE setOverlayGeometry) + Q_PROPERTY(QColor colorKey READ colorKey) + Q_PROPERTY(QSize nativeSize READ nativeSize NOTIFY nativeSizeChanged) + +public: + QGstreamerGLTextureRenderer(QObject *parent = 0); + virtual ~QGstreamerGLTextureRenderer(); + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + + GstElement *videoSink(); + + bool isReady() const; + void handleBusMessage(GstMessage* gm); + void handleSyncMessage(GstMessage* gm); + void precessNewStream(); + void stopRenderer(); + + int framebufferNumber() const; + + bool overlayEnabled() const; + WId winId() const; + QRect overlayGeometry() const; + QColor colorKey() const; + QSize nativeSize() const; + +public slots: + void renderGLFrame(int); + + void setOverlayEnabled(bool); + void setWinId(WId id); + void setOverlayGeometry(const QRect &geometry); + void repaintOverlay(); + +signals: + void sinkChanged(); + void readyChanged(bool); + void nativeSizeChanged(); + +private slots: + void handleFormatChange(); + void updateNativeVideoSize(); + +private: + static void handleFrameReady(GstElement *sink, gint frame, gpointer data); + static gboolean padBufferProbe(GstPad *pad, GstBuffer *buffer, gpointer user_data); + + GstElement *m_videoSink; + QAbstractVideoSurface *m_surface; + QGLContext *m_context; + QSize m_nativeSize; + + WId m_winId; + QColor m_colorKey; + QRect m_displayRect; + bool m_overlayEnabled; + int m_bufferProbeId; + + QMutex m_mutex; + QWaitCondition m_renderCondition; +}; + +#endif // QGSTREAMERVIDEORENDRER_H diff --git a/src/plugins/gstreamer/qgstreamermessage.cpp b/src/plugins/gstreamer/qgstreamermessage.cpp new file mode 100644 index 000000000..3b8057e09 --- /dev/null +++ b/src/plugins/gstreamer/qgstreamermessage.cpp @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "qgstreamermessage.h" + + +static int wuchi = qRegisterMetaType(); + + +/*! + \class gstreamer::QGstreamerMessage + \internal +*/ + +QGstreamerMessage::QGstreamerMessage(): + m_message(0) +{ +} + +QGstreamerMessage::QGstreamerMessage(GstMessage* message): + m_message(message) +{ + gst_message_ref(m_message); +} + +QGstreamerMessage::QGstreamerMessage(QGstreamerMessage const& m): + m_message(m.m_message) +{ + gst_message_ref(m_message); +} + + +QGstreamerMessage::~QGstreamerMessage() +{ + if (m_message != 0) + gst_message_unref(m_message); +} + +GstMessage* QGstreamerMessage::rawMessage() const +{ + return m_message; +} + +QGstreamerMessage& QGstreamerMessage::operator=(QGstreamerMessage const& rhs) +{ + if (m_message != 0) + gst_message_unref(m_message); + + if ((m_message = rhs.m_message) != 0) + gst_message_ref(m_message); + + return *this; +} diff --git a/src/plugins/gstreamer/qgstreamermessage.h b/src/plugins/gstreamer/qgstreamermessage.h new file mode 100644 index 000000000..2bdc2a9c8 --- /dev/null +++ b/src/plugins/gstreamer/qgstreamermessage.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERMESSAGE_H +#define QGSTREAMERMESSAGE_H + +#include + +#include + + +class QGstreamerMessage +{ +public: + QGstreamerMessage(); + QGstreamerMessage(GstMessage* message); + QGstreamerMessage(QGstreamerMessage const& m); + ~QGstreamerMessage(); + + GstMessage* rawMessage() const; + + QGstreamerMessage& operator=(QGstreamerMessage const& rhs); + +private: + GstMessage* m_message; +}; + +Q_DECLARE_METATYPE(QGstreamerMessage); + +#endif diff --git a/src/plugins/gstreamer/qgstreamerserviceplugin.cpp b/src/plugins/gstreamer/qgstreamerserviceplugin.cpp new file mode 100644 index 000000000..e74085664 --- /dev/null +++ b/src/plugins/gstreamer/qgstreamerserviceplugin.cpp @@ -0,0 +1,401 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "qgstreamerserviceplugin.h" + +//#define QT_SUPPORTEDMIMETYPES_DEBUG + +#ifdef QMEDIA_GSTREAMER_PLAYER +#include "qgstreamerplayerservice.h" +#endif + +#if defined(QMEDIA_GSTREAMER_CAPTURE) +#include "qgstreamercaptureservice.h" +#endif + +#ifdef QMEDIA_GSTREAMER_CAMERABIN +#include "camerabinservice.h" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +QStringList QGstreamerServicePlugin::keys() const +{ + return QStringList() +#ifdef QMEDIA_GSTREAMER_PLAYER + << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER) +#endif + +#ifdef QMEDIA_GSTREAMER_CAPTURE + << QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE) + << QLatin1String(Q_MEDIASERVICE_CAMERA) +#elif defined(QMEDIA_GSTREAMER_CAMERABIN) + << QLatin1String(Q_MEDIASERVICE_CAMERA) +#endif + ; + +} + +QMediaService* QGstreamerServicePlugin::create(const QString &key) +{ + static bool initialized = false; + if (!initialized) { + initialized = true; + gst_init(NULL, NULL); + } + +#ifdef QMEDIA_GSTREAMER_PLAYER + if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER)) + return new QGstreamerPlayerService; +#endif + +#ifdef QMEDIA_GSTREAMER_CAMERABIN + if (key == QLatin1String(Q_MEDIASERVICE_CAMERA) && CameraBinService::isCameraBinAvailable()) + return new CameraBinService(key); +#endif + +#ifdef QMEDIA_GSTREAMER_CAPTURE + if (key == QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE)) + return new QGstreamerCaptureService(key); + + if (key == QLatin1String(Q_MEDIASERVICE_CAMERA)) + return new QGstreamerCaptureService(key); +#endif + + qWarning() << "Gstreamer service plugin: unsupported key:" << key; + return 0; +} + +void QGstreamerServicePlugin::release(QMediaService *service) +{ + delete service; +} + +QMediaServiceProviderHint::Features QGstreamerServicePlugin::supportedFeatures( + const QByteArray &service) const +{ + if (service == Q_MEDIASERVICE_MEDIAPLAYER) + return QMediaServiceProviderHint::StreamPlayback | QMediaServiceProviderHint::VideoSurface; + else if (service == Q_MEDIASERVICE_CAMERA) + return QMediaServiceProviderHint::VideoSurface; + else + return QMediaServiceProviderHint::Features(); +} + +QList QGstreamerServicePlugin::devices(const QByteArray &service) const +{ + if (service == Q_MEDIASERVICE_CAMERA) { + if (m_cameraDevices.isEmpty()) + updateDevices(); + + return m_cameraDevices; + } + + return QList(); +} + +QString QGstreamerServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device) +{ + if (service == Q_MEDIASERVICE_CAMERA) { + if (m_cameraDevices.isEmpty()) + updateDevices(); + + for (int i=0; i= 0; ++input.index) { + if(input.type == V4L2_INPUT_TYPE_CAMERA || input.type == 0) { + isCamera = ::ioctl(fd, VIDIOC_S_INPUT, input.index) != 0; + break; + } + } + + if (isCamera) { + // find out its driver "name" + QString name; + struct v4l2_capability vcap; + memset(&vcap, 0, sizeof(struct v4l2_capability)); + + if (ioctl(fd, VIDIOC_QUERYCAP, &vcap) != 0) + name = entryInfo.fileName(); + else + name = QString((const char*)vcap.card); + //qDebug() << "found camera: " << name; + + m_cameraDevices.append(entryInfo.filePath().toLocal8Bit()); + m_cameraDescriptions.append(name); + } + ::close(fd); + } +} + +namespace { + const char* getCodecAlias(const QString &codec) + { + if (codec.startsWith("avc1.")) + return "video/x-h264"; + + if (codec.startsWith("mp4a.")) + return "audio/mpeg4"; + + if (codec.startsWith("mp4v.20.")) + return "video/mpeg4"; + + if (codec == "samr") + return "audio/amr"; + + return 0; + } + + const char* getMimeTypeAlias(const QString &mimeType) + { + if (mimeType == "video/mp4") + return "video/mpeg4"; + + if (mimeType == "audio/mp4") + return "audio/mpeg4"; + + if (mimeType == "video/ogg" + || mimeType == "audio/ogg") + return "application/ogg"; + + return 0; + } +} + +QtMultimediaKit::SupportEstimate QGstreamerServicePlugin::hasSupport(const QString &mimeType, + const QStringList& codecs) const +{ + if (m_supportedMimeTypeSet.isEmpty()) + updateSupportedMimeTypes(); + + QString mimeTypeLowcase = mimeType.toLower(); + bool containsMimeType = m_supportedMimeTypeSet.contains(mimeTypeLowcase); + if (!containsMimeType) { + const char* mimeTypeAlias = getMimeTypeAlias(mimeTypeLowcase); + containsMimeType = m_supportedMimeTypeSet.contains(mimeTypeAlias); + if (!containsMimeType) { + containsMimeType = m_supportedMimeTypeSet.contains("video/" + mimeTypeLowcase) + || m_supportedMimeTypeSet.contains("video/x-" + mimeTypeLowcase) + || m_supportedMimeTypeSet.contains("audio/" + mimeTypeLowcase) + || m_supportedMimeTypeSet.contains("audio/x-" + mimeTypeLowcase); + } + } + + int supportedCodecCount = 0; + foreach(const QString &codec, codecs) { + QString codecLowcase = codec.toLower(); + const char* codecAlias = getCodecAlias(codecLowcase); + if (codecAlias) { + if (m_supportedMimeTypeSet.contains(codecAlias)) + supportedCodecCount++; + } else if (m_supportedMimeTypeSet.contains("video/" + codecLowcase) + || m_supportedMimeTypeSet.contains("video/x-" + codecLowcase) + || m_supportedMimeTypeSet.contains("audio/" + codecLowcase) + || m_supportedMimeTypeSet.contains("audio/x-" + codecLowcase)) { + supportedCodecCount++; + } + } + if (supportedCodecCount > 0 && supportedCodecCount == codecs.size()) + return QtMultimediaKit::ProbablySupported; + + if (supportedCodecCount == 0 && !containsMimeType) + return QtMultimediaKit::NotSupported; + + return QtMultimediaKit::MaybeSupported; +} + +void QGstreamerServicePlugin::updateSupportedMimeTypes() const +{ + //enumerate supported mime types + gst_init(NULL, NULL); + + GList *plugins, *orig_plugins; + orig_plugins = plugins = gst_default_registry_get_plugin_list (); + + while (plugins) { + GList *features, *orig_features; + + GstPlugin *plugin = (GstPlugin *) (plugins->data); + plugins = g_list_next (plugins); + + if (plugin->flags & (1<<1)) //GST_PLUGIN_FLAG_BLACKLISTED + continue; + + orig_features = features = gst_registry_get_feature_list_by_plugin(gst_registry_get_default (), + plugin->desc.name); + while (features) { + if (!G_UNLIKELY(features->data == NULL)) { + GstPluginFeature *feature = GST_PLUGIN_FEATURE(features->data); + if (GST_IS_ELEMENT_FACTORY (feature)) { + GstElementFactory *factory = GST_ELEMENT_FACTORY(gst_plugin_feature_load(feature)); + if (factory + && factory->numpadtemplates > 0 + && (qstrcmp(factory->details.klass, "Codec/Decoder/Audio") == 0 + || qstrcmp(factory->details.klass, "Codec/Decoder/Video") == 0 + || qstrcmp(factory->details.klass, "Codec/Demux") == 0 )) { + const GList *pads = factory->staticpadtemplates; + while (pads) { + GstStaticPadTemplate *padtemplate = (GstStaticPadTemplate*)(pads->data); + pads = g_list_next (pads); + if (padtemplate->direction != GST_PAD_SINK) + continue; + if (padtemplate->static_caps.string) { + GstCaps *caps = gst_static_caps_get(&padtemplate->static_caps); + if (!gst_caps_is_any (caps) && ! gst_caps_is_empty (caps)) { + for (guint i = 0; i < gst_caps_get_size(caps); i++) { + GstStructure *structure = gst_caps_get_structure(caps, i); + QString nameLowcase = QString(gst_structure_get_name (structure)).toLower(); + + m_supportedMimeTypeSet.insert(nameLowcase); + if (nameLowcase.contains("mpeg")) { + //Because mpeg version number is only included in the detail + //description, it is necessary to manually extract this information + //in order to match the mime type of mpeg4. + const GValue *value = gst_structure_get_value(structure, "mpegversion"); + if (value) { + gchar *str = gst_value_serialize (value); + QString versions(str); + QStringList elements = versions.split(QRegExp("\\D+"), QString::SkipEmptyParts); + foreach(const QString &e, elements) + m_supportedMimeTypeSet.insert(nameLowcase + e); + g_free (str); + } + } + } + } + } + } + gst_object_unref (factory); + } + } else if (GST_IS_TYPE_FIND_FACTORY(feature)) { + QString name(gst_plugin_feature_get_name(feature)); + if (name.contains('/')) //filter out any string without '/' which is obviously not a mime type + m_supportedMimeTypeSet.insert(name.toLower()); + } + } + features = g_list_next (features); + } + gst_plugin_feature_list_free (orig_features); + } + gst_plugin_list_free (orig_plugins); + +#if defined QT_SUPPORTEDMIMETYPES_DEBUG + QStringList list = m_supportedMimeTypeSet.toList(); + list.sort(); + if (qgetenv("QT_DEBUG_PLUGINS").toInt() > 0) { + foreach(const QString &type, list) + qDebug() << type; + } +#endif +} + +QStringList QGstreamerServicePlugin::supportedMimeTypes() const +{ + return QStringList(); +} + +Q_EXPORT_PLUGIN2(qtmedia_gstengine, QGstreamerServicePlugin); diff --git a/src/plugins/gstreamer/qgstreamerserviceplugin.h b/src/plugins/gstreamer/qgstreamerserviceplugin.h new file mode 100644 index 000000000..0ce0bbd84 --- /dev/null +++ b/src/plugins/gstreamer/qgstreamerserviceplugin.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QGSTREAMERSERVICEPLUGIN_H +#define QGSTREAMERSERVICEPLUGIN_H + +#include +#include + +QT_USE_NAMESPACE + + +class QGstreamerServicePlugin + : public QMediaServiceProviderPlugin + , public QMediaServiceSupportedDevicesInterface + , public QMediaServiceFeaturesInterface + , public QMediaServiceSupportedFormatsInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceSupportedDevicesInterface) + Q_INTERFACES(QMediaServiceFeaturesInterface) + Q_INTERFACES(QMediaServiceSupportedFormatsInterface) +public: + QStringList keys() const; + QMediaService* create(QString const& key); + void release(QMediaService *service); + + QMediaServiceProviderHint::Features supportedFeatures(const QByteArray &service) const; + + QList devices(const QByteArray &service) const; + QString deviceDescription(const QByteArray &service, const QByteArray &device); + QVariant deviceProperty(const QByteArray &service, const QByteArray &device, const QByteArray &property); + + QtMultimediaKit::SupportEstimate hasSupport(const QString &mimeType, const QStringList& codecs) const; + QStringList supportedMimeTypes() const; + +private: + void updateDevices() const; + + mutable QList m_cameraDevices; + mutable QStringList m_cameraDescriptions; + mutable QSet m_supportedMimeTypeSet; //for fast access + + void updateSupportedMimeTypes() const; +}; + +#endif // QGSTREAMERSERVICEPLUGIN_H diff --git a/src/plugins/gstreamer/qgstreamervideoinputdevicecontrol.cpp b/src/plugins/gstreamer/qgstreamervideoinputdevicecontrol.cpp new file mode 100644 index 000000000..d53497d30 --- /dev/null +++ b/src/plugins/gstreamer/qgstreamervideoinputdevicecontrol.cpp @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamervideoinputdevicecontrol.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QGstreamerVideoInputDeviceControl::QGstreamerVideoInputDeviceControl(QObject *parent) + :QVideoDeviceControl(parent), m_selectedDevice(0) +{ + update(); +} + +QGstreamerVideoInputDeviceControl::~QGstreamerVideoInputDeviceControl() +{ +} + +int QGstreamerVideoInputDeviceControl::deviceCount() const +{ + return m_names.size(); +} + +QString QGstreamerVideoInputDeviceControl::deviceName(int index) const +{ + return m_names[index]; +} + +QString QGstreamerVideoInputDeviceControl::deviceDescription(int index) const +{ + return m_descriptions[index]; +} + +QIcon QGstreamerVideoInputDeviceControl::deviceIcon(int index) const +{ + Q_UNUSED(index); + return QIcon(); +} + +int QGstreamerVideoInputDeviceControl::defaultDevice() const +{ + return 0; +} + +int QGstreamerVideoInputDeviceControl::selectedDevice() const +{ + return m_selectedDevice; +} + + +void QGstreamerVideoInputDeviceControl::setSelectedDevice(int index) +{ + if (index != m_selectedDevice) { + m_selectedDevice = index; + emit selectedDeviceChanged(index); + emit selectedDeviceChanged(deviceName(index)); + } +} + + +void QGstreamerVideoInputDeviceControl::update() +{ + m_names.clear(); + m_descriptions.clear(); + +#ifdef Q_WS_MAEMO_6 + m_names << QLatin1String("primary") << QLatin1String("secondary"); + m_descriptions << tr("Main camera") << tr("Front camera"); +#else + QDir devDir("/dev"); + devDir.setFilter(QDir::System); + + QFileInfoList entries = devDir.entryInfoList(QStringList() << "video*"); + + foreach( const QFileInfo &entryInfo, entries ) { + //qDebug() << "Try" << entryInfo.filePath(); + + int fd = ::open(entryInfo.filePath().toLatin1().constData(), O_RDWR ); + if (fd == -1) + continue; + + bool isCamera = false; + + v4l2_input input; + memset(&input, 0, sizeof(input)); + for (; ::ioctl(fd, VIDIOC_ENUMINPUT, &input) >= 0; ++input.index) { + if(input.type == V4L2_INPUT_TYPE_CAMERA || input.type == 0) { + isCamera = ::ioctl(fd, VIDIOC_S_INPUT, input.index) != 0; + break; + } + } + + if (isCamera) { + // find out its driver "name" + QString name; + struct v4l2_capability vcap; + memset(&vcap, 0, sizeof(struct v4l2_capability)); + + if (ioctl(fd, VIDIOC_QUERYCAP, &vcap) != 0) + name = entryInfo.fileName(); + else + name = QString((const char*)vcap.card); + //qDebug() << "found camera: " << name; + + m_names.append(entryInfo.filePath()); + m_descriptions.append(name); + } + ::close(fd); + } +#endif +} diff --git a/src/plugins/gstreamer/qgstreamervideoinputdevicecontrol.h b/src/plugins/gstreamer/qgstreamervideoinputdevicecontrol.h new file mode 100644 index 000000000..a31636239 --- /dev/null +++ b/src/plugins/gstreamer/qgstreamervideoinputdevicecontrol.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERVIDEOINPUTDEVICECONTROL_H +#define QGSTREAMERVIDEOINPUTDEVICECONTROL_H + +#include +#include + +QT_USE_NAMESPACE + +class QGstreamerVideoInputDeviceControl : public QVideoDeviceControl +{ +Q_OBJECT +public: + QGstreamerVideoInputDeviceControl(QObject *parent); + ~QGstreamerVideoInputDeviceControl(); + + int deviceCount() const; + + QString deviceName(int index) const; + QString deviceDescription(int index) const; + QIcon deviceIcon(int index) const; + + int defaultDevice() const; + int selectedDevice() const; + +public Q_SLOTS: + void setSelectedDevice(int index); + +private: + void update(); + + int m_selectedDevice; + QStringList m_names; + QStringList m_descriptions; +}; + +#endif // QGSTREAMERAUDIOINPUTDEVICECONTROL_H diff --git a/src/plugins/gstreamer/qgstreamervideooverlay.cpp b/src/plugins/gstreamer/qgstreamervideooverlay.cpp new file mode 100644 index 000000000..3e19dd075 --- /dev/null +++ b/src/plugins/gstreamer/qgstreamervideooverlay.cpp @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamervideooverlay.h" +#include "qvideosurfacegstsink.h" + +#include + +#include "qx11videosurface.h" + +#ifndef QT_NO_XVIDEO + +QGstreamerVideoOverlay::QGstreamerVideoOverlay(QObject *parent) + : QVideoWindowControl(parent) + , m_surface(new QX11VideoSurface) + , m_videoSink(reinterpret_cast(QVideoSurfaceGstSink::createSink(m_surface))) + , m_aspectRatioMode(Qt::KeepAspectRatio) + , m_fullScreen(false) +{ + if (m_videoSink) { + gst_object_ref(GST_OBJECT(m_videoSink)); //Take ownership + gst_object_sink(GST_OBJECT(m_videoSink)); + } + + connect(m_surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + this, SLOT(surfaceFormatChanged())); +} + +QGstreamerVideoOverlay::~QGstreamerVideoOverlay() +{ + if (m_videoSink) + gst_object_unref(GST_OBJECT(m_videoSink)); + + delete m_surface; +} + +WId QGstreamerVideoOverlay::winId() const +{ + return m_surface->winId(); +} + +void QGstreamerVideoOverlay::setWinId(WId id) +{ + bool wasReady = isReady(); + m_surface->setWinId(id); + + if (isReady() != wasReady) + emit readyChanged(!wasReady); +} + +QRect QGstreamerVideoOverlay::displayRect() const +{ + return m_displayRect; +} + +void QGstreamerVideoOverlay::setDisplayRect(const QRect &rect) +{ + m_displayRect = rect; + + setScaledDisplayRect(); +} + +Qt::AspectRatioMode QGstreamerVideoOverlay::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void QGstreamerVideoOverlay::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + m_aspectRatioMode = mode; + + setScaledDisplayRect(); +} + +void QGstreamerVideoOverlay::repaint() +{ +} + +int QGstreamerVideoOverlay::brightness() const +{ + return m_surface->brightness(); +} + +void QGstreamerVideoOverlay::setBrightness(int brightness) +{ + m_surface->setBrightness(brightness); + + emit brightnessChanged(m_surface->brightness()); +} + +int QGstreamerVideoOverlay::contrast() const +{ + return m_surface->contrast(); +} + +void QGstreamerVideoOverlay::setContrast(int contrast) +{ + m_surface->setContrast(contrast); + + emit contrastChanged(m_surface->contrast()); +} + +int QGstreamerVideoOverlay::hue() const +{ + return m_surface->hue(); +} + +void QGstreamerVideoOverlay::setHue(int hue) +{ + m_surface->setHue(hue); + + emit hueChanged(m_surface->hue()); +} + +int QGstreamerVideoOverlay::saturation() const +{ + return m_surface->saturation(); +} + +void QGstreamerVideoOverlay::setSaturation(int saturation) +{ + m_surface->setSaturation(saturation); + + emit saturationChanged(m_surface->saturation()); +} + +bool QGstreamerVideoOverlay::isFullScreen() const +{ + return m_fullScreen; +} + +void QGstreamerVideoOverlay::setFullScreen(bool fullScreen) +{ + emit fullScreenChanged(m_fullScreen = fullScreen); +} + +QSize QGstreamerVideoOverlay::nativeSize() const +{ + return m_surface->surfaceFormat().sizeHint(); +} + +QAbstractVideoSurface *QGstreamerVideoOverlay::surface() const +{ + return m_surface; +} + +GstElement *QGstreamerVideoOverlay::videoSink() +{ + return m_videoSink; +} + +void QGstreamerVideoOverlay::surfaceFormatChanged() +{ + setScaledDisplayRect(); + + emit nativeSizeChanged(); +} + +void QGstreamerVideoOverlay::setScaledDisplayRect() +{ + QRect formatViewport = m_surface->surfaceFormat().viewport(); + + switch (m_aspectRatioMode) { + case Qt::KeepAspectRatio: + { + QSize size = m_surface->surfaceFormat().sizeHint(); + size.scale(m_displayRect.size(), Qt::KeepAspectRatio); + + QRect rect(QPoint(0, 0), size); + rect.moveCenter(m_displayRect.center()); + + m_surface->setDisplayRect(rect); + m_surface->setViewport(formatViewport); + } + break; + case Qt::IgnoreAspectRatio: + m_surface->setDisplayRect(m_displayRect); + m_surface->setViewport(formatViewport); + break; + case Qt::KeepAspectRatioByExpanding: + { + QSize size = m_displayRect.size(); + size.scale(m_surface->surfaceFormat().sizeHint(), Qt::KeepAspectRatio); + + QRect viewport(QPoint(0, 0), size); + viewport.moveCenter(formatViewport.center()); + m_surface->setDisplayRect(m_displayRect); + m_surface->setViewport(viewport); + } + break; + }; +} + +#endif //QT_NO_XVIDEO diff --git a/src/plugins/gstreamer/qgstreamervideooverlay.h b/src/plugins/gstreamer/qgstreamervideooverlay.h new file mode 100644 index 000000000..194c4ea32 --- /dev/null +++ b/src/plugins/gstreamer/qgstreamervideooverlay.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERVIDEOOVERLAY_H +#define QGSTREAMERVIDEOOVERLAY_H + +#include + +#include "qgstreamervideorendererinterface.h" + +QT_BEGIN_NAMESPACE +class QAbstractVideoSurface; +QT_END_NAMESPACE +class QX11VideoSurface; + +#if defined(Q_WS_X11) && !defined(QT_NO_XVIDEO) + +QT_USE_NAMESPACE + +class QGstreamerVideoOverlay : public QVideoWindowControl, public QGstreamerVideoRendererInterface +{ + Q_OBJECT + Q_INTERFACES(QGstreamerVideoRendererInterface) +public: + QGstreamerVideoOverlay(QObject *parent = 0); + ~QGstreamerVideoOverlay(); + + WId winId() const; + void setWinId(WId id); + + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + QSize nativeSize() const; + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + + void repaint(); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + QAbstractVideoSurface *surface() const; + + GstElement *videoSink(); + + bool isReady() const { return winId() != 0; } + +signals: + void sinkChanged(); + void readyChanged(bool); + +private slots: + void surfaceFormatChanged(); + +private: + void setScaledDisplayRect(); + + QX11VideoSurface *m_surface; + GstElement *m_videoSink; + Qt::AspectRatioMode m_aspectRatioMode; + QRect m_displayRect; + bool m_fullScreen; +}; + +#endif //QT_NO_XVIDEO + +#endif diff --git a/src/plugins/gstreamer/qgstreamervideorenderer.cpp b/src/plugins/gstreamer/qgstreamervideorenderer.cpp new file mode 100644 index 000000000..6c4e6b90c --- /dev/null +++ b/src/plugins/gstreamer/qgstreamervideorenderer.cpp @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamervideorenderer.h" +#include "qvideosurfacegstsink.h" +#include "qabstractvideosurface.h" + +#include +#include +#include + +#include + +QGstreamerVideoRenderer::QGstreamerVideoRenderer(QObject *parent) + :QVideoRendererControl(parent),m_videoSink(0), m_surface(0) +{ +} + +QGstreamerVideoRenderer::~QGstreamerVideoRenderer() +{ + if (m_videoSink) + gst_object_unref(GST_OBJECT(m_videoSink)); +} + +GstElement *QGstreamerVideoRenderer::videoSink() +{ + if (!m_videoSink && m_surface) { + m_videoSink = QVideoSurfaceGstSink::createSink(m_surface); + gst_object_ref(GST_OBJECT(m_videoSink)); //Take ownership + gst_object_sink(GST_OBJECT(m_videoSink)); + } + + return reinterpret_cast(m_videoSink); +} + + +QAbstractVideoSurface *QGstreamerVideoRenderer::surface() const +{ + return m_surface; +} + +void QGstreamerVideoRenderer::setSurface(QAbstractVideoSurface *surface) +{ + if (m_surface != surface) { + //qDebug() << Q_FUNC_INFO << surface; + if (m_videoSink) + gst_object_unref(GST_OBJECT(m_videoSink)); + + m_videoSink = 0; + + if (m_surface) { + disconnect(m_surface, SIGNAL(supportedFormatsChanged()), + this, SLOT(handleFormatChange())); + } + + m_surface = surface; + + if (surface && !m_surface) + emit readyChanged(true); + + if (!surface && m_surface) + emit readyChanged(false); + + if (m_surface) { + connect(m_surface, SIGNAL(supportedFormatsChanged()), + this, SLOT(handleFormatChange())); + } + + emit sinkChanged(); + } +} + +void QGstreamerVideoRenderer::handleFormatChange() +{ + //qDebug() << "Supported formats list has changed, reload video output"; + + if (m_videoSink) + gst_object_unref(GST_OBJECT(m_videoSink)); + + m_videoSink = 0; + emit sinkChanged(); +} diff --git a/src/plugins/gstreamer/qgstreamervideorenderer.h b/src/plugins/gstreamer/qgstreamervideorenderer.h new file mode 100644 index 000000000..b6c23ba51 --- /dev/null +++ b/src/plugins/gstreamer/qgstreamervideorenderer.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERVIDEORENDERER_H +#define QGSTREAMERVIDEORENDERER_H + +#include +#include "qvideosurfacegstsink.h" + +#include "qgstreamervideorendererinterface.h" + +QT_USE_NAMESPACE + +class QGstreamerVideoRenderer : public QVideoRendererControl, public QGstreamerVideoRendererInterface +{ + Q_OBJECT + Q_INTERFACES(QGstreamerVideoRendererInterface) +public: + QGstreamerVideoRenderer(QObject *parent = 0); + virtual ~QGstreamerVideoRenderer(); + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + + GstElement *videoSink(); + void precessNewStream() {} + + bool isReady() const { return m_surface != 0; } + +signals: + void sinkChanged(); + void readyChanged(bool); + +private slots: + void handleFormatChange(); + +private: + QVideoSurfaceGstSink *m_videoSink; + QAbstractVideoSurface *m_surface; +}; + +#endif // QGSTREAMERVIDEORENDRER_H diff --git a/src/plugins/gstreamer/qgstreamervideorendererinterface.cpp b/src/plugins/gstreamer/qgstreamervideorendererinterface.cpp new file mode 100644 index 000000000..b8358ba1c --- /dev/null +++ b/src/plugins/gstreamer/qgstreamervideorendererinterface.cpp @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamervideorendererinterface.h" + +QGstreamerVideoRendererInterface::~QGstreamerVideoRendererInterface() +{ +} diff --git a/src/plugins/gstreamer/qgstreamervideorendererinterface.h b/src/plugins/gstreamer/qgstreamervideorendererinterface.h new file mode 100644 index 000000000..08b046d9b --- /dev/null +++ b/src/plugins/gstreamer/qgstreamervideorendererinterface.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERVIDEOOUTPUTCONTROL_H +#define QGSTREAMERVIDEOOUTPUTCONTROL_H + +#include + +#include + +class QGstreamerVideoRendererInterface +{ +public: + virtual ~QGstreamerVideoRendererInterface(); + virtual GstElement *videoSink() = 0; + virtual void precessNewStream() {} + + //stopRenderer() is called when the renderer element is stopped. + //it can be reimplemented when video renderer can't detect + //changes to NULL state but has to free video resources. + virtual void stopRenderer() {} + + //the video output is configured, usually after the first paint event + //(winId is known, + virtual bool isReady() const { return true; } + + //video renderer may handle video sink specific gstreamer messages. + virtual void handleBusMessage(GstMessage*) {}; + virtual void handleSyncMessage(GstMessage*) {}; + + //signals: + //void sinkChanged(); + //void readyChanged(bool); +}; + +#define QGstreamerVideoRendererInterface_iid "com.nokia.Qt.QGstreamerVideoRendererInterface/1.0" +QT_BEGIN_NAMESPACE +Q_DECLARE_INTERFACE(QGstreamerVideoRendererInterface, QGstreamerVideoRendererInterface_iid) +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/gstreamer/qgstreamervideowidget.cpp b/src/plugins/gstreamer/qgstreamervideowidget.cpp new file mode 100644 index 000000000..38fa5ba8e --- /dev/null +++ b/src/plugins/gstreamer/qgstreamervideowidget.cpp @@ -0,0 +1,331 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamervideowidget.h" +#include "qgstutils.h" + +#include +#include +#include +#include + +#ifdef Q_WS_X11 +# include +#endif +#include +#include +#include + +class QGstreamerVideoWidget : public QWidget +{ +public: + QGstreamerVideoWidget(QWidget *parent = 0) + :QWidget(parent) + { + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + QPalette palette; + palette.setColor(QPalette::Background, Qt::black); + setPalette(palette); + } + + virtual ~QGstreamerVideoWidget() {} + + QSize sizeHint() const + { + return m_nativeSize; + } + + void setNativeSize( const QSize &size) + { + if (size != m_nativeSize) { + m_nativeSize = size; + if (size.isEmpty()) + setMinimumSize(0,0); + else + setMinimumSize(160,120); + + updateGeometry(); + } + } + +protected: + void paintEvent(QPaintEvent *) + { + QPainter painter(this); + painter.fillRect(rect(), palette().background()); + } + + QSize m_nativeSize; +}; + +QGstreamerVideoWidgetControl::QGstreamerVideoWidgetControl(QObject *parent) + : QVideoWidgetControl(parent) + , m_videoSink(0) + , m_widget(0) + , m_fullScreen(false) +{ +} + +QGstreamerVideoWidgetControl::~QGstreamerVideoWidgetControl() +{ + if (m_videoSink) + gst_object_unref(GST_OBJECT(m_videoSink)); + + delete m_widget; +} + +void QGstreamerVideoWidgetControl::createVideoWidget() +{ + if (m_widget) + return; + + m_widget = new QGstreamerVideoWidget; + + m_widget->installEventFilter(this); + m_windowId = m_widget->winId(); + + m_videoSink = gst_element_factory_make ("xvimagesink", NULL); + if (m_videoSink) { + // Check if the xv sink is usable + if (gst_element_set_state(m_videoSink, GST_STATE_READY) != GST_STATE_CHANGE_SUCCESS) { + gst_object_unref(GST_OBJECT(m_videoSink)); + m_videoSink = 0; + } else { + gst_element_set_state(m_videoSink, GST_STATE_NULL); + + g_object_set(G_OBJECT(m_videoSink), "force-aspect-ratio", 1, (const char*)NULL); +#ifdef Q_WS_MAEMO_5 + //the overlay xvideo adapter fails to switch winId, + //use "SGX Textured Video" adapter instead + g_object_set(G_OBJECT(m_videoSink), "device", "1", NULL); +#endif + } + } + + if (!m_videoSink) + m_videoSink = gst_element_factory_make ("ximagesink", NULL); + + gst_object_ref (GST_OBJECT (m_videoSink)); //Take ownership + gst_object_sink (GST_OBJECT (m_videoSink)); + + +} + +GstElement *QGstreamerVideoWidgetControl::videoSink() +{ + createVideoWidget(); + return m_videoSink; +} + +bool QGstreamerVideoWidgetControl::eventFilter(QObject *object, QEvent *e) +{ + if (m_widget && object == m_widget) { + if (e->type() == QEvent::ParentChange || e->type() == QEvent::Show) { + WId newWId = m_widget->winId(); + if (newWId != m_windowId) { + m_windowId = newWId; + // Even if we have created a winId at this point, other X applications + // need to be aware of it. + QApplication::syncX(); + setOverlay(); + } + } + + if (e->type() == QEvent::Show) { + // Setting these values ensures smooth resizing since it + // will prevent the system from clearing the background + m_widget->setAttribute(Qt::WA_NoSystemBackground, true); + m_widget->setAttribute(Qt::WA_PaintOnScreen, true); + } else if (e->type() == QEvent::Resize) { + // This is a workaround for missing background repaints + // when reducing window size + windowExposed(); + } + } + + return false; +} + +void QGstreamerVideoWidgetControl::precessNewStream() +{ + setOverlay(); + QMetaObject::invokeMethod(this, "updateNativeVideoSize", Qt::QueuedConnection); +} + +void QGstreamerVideoWidgetControl::setOverlay() +{ + if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) { + gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(m_videoSink), m_windowId); + } +} + +void QGstreamerVideoWidgetControl::updateNativeVideoSize() +{ + if (m_videoSink) { + //find video native size to update video widget size hint + GstPad *pad = gst_element_get_static_pad(m_videoSink,"sink"); + GstCaps *caps = gst_pad_get_negotiated_caps(pad); + + if (caps) { + m_widget->setNativeSize(QGstUtils::capsCorrectedResolution(caps)); + gst_caps_unref(caps); + } + } else { + if (m_widget) + m_widget->setNativeSize(QSize()); + } +} + + +void QGstreamerVideoWidgetControl::windowExposed() +{ + if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) + gst_x_overlay_expose(GST_X_OVERLAY(m_videoSink)); +} + +QWidget *QGstreamerVideoWidgetControl::videoWidget() +{ + createVideoWidget(); + return m_widget; +} + +Qt::AspectRatioMode QGstreamerVideoWidgetControl::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void QGstreamerVideoWidgetControl::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + if (m_videoSink) { + g_object_set(G_OBJECT(m_videoSink), + "force-aspect-ratio", + (mode == Qt::KeepAspectRatio), + (const char*)NULL); + } + + m_aspectRatioMode = mode; +} + +bool QGstreamerVideoWidgetControl::isFullScreen() const +{ + return m_fullScreen; +} + +void QGstreamerVideoWidgetControl::setFullScreen(bool fullScreen) +{ + emit fullScreenChanged(m_fullScreen = fullScreen); +} + +int QGstreamerVideoWidgetControl::brightness() const +{ + int brightness = 0; + + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "brightness")) + g_object_get(G_OBJECT(m_videoSink), "brightness", &brightness, NULL); + + return brightness / 10; +} + +void QGstreamerVideoWidgetControl::setBrightness(int brightness) +{ + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "brightness")) { + g_object_set(G_OBJECT(m_videoSink), "brightness", brightness * 10, NULL); + + emit brightnessChanged(brightness); + } +} + +int QGstreamerVideoWidgetControl::contrast() const +{ + int contrast = 0; + + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "contrast")) + g_object_get(G_OBJECT(m_videoSink), "contrast", &contrast, NULL); + + return contrast / 10; +} + +void QGstreamerVideoWidgetControl::setContrast(int contrast) +{ + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "contrast")) { + g_object_set(G_OBJECT(m_videoSink), "contrast", contrast * 10, NULL); + + emit contrastChanged(contrast); + } +} + +int QGstreamerVideoWidgetControl::hue() const +{ + int hue = 0; + + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "hue")) + g_object_get(G_OBJECT(m_videoSink), "hue", &hue, NULL); + + return hue / 10; +} + +void QGstreamerVideoWidgetControl::setHue(int hue) +{ + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "hue")) { + g_object_set(G_OBJECT(m_videoSink), "hue", hue * 10, NULL); + + emit hueChanged(hue); + } +} + +int QGstreamerVideoWidgetControl::saturation() const +{ + int saturation = 0; + + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "saturation")) + g_object_get(G_OBJECT(m_videoSink), "saturation", &saturation, NULL); + + return saturation / 10; +} + +void QGstreamerVideoWidgetControl::setSaturation(int saturation) +{ + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "saturation")) { + g_object_set(G_OBJECT(m_videoSink), "saturation", saturation * 10, NULL); + + emit saturationChanged(saturation); + } +} diff --git a/src/plugins/gstreamer/qgstreamervideowidget.h b/src/plugins/gstreamer/qgstreamervideowidget.h new file mode 100644 index 000000000..3342351d1 --- /dev/null +++ b/src/plugins/gstreamer/qgstreamervideowidget.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERVIDEOWIDGET_H +#define QGSTREAMERVIDEOWIDGET_H + +#include + +#include "qgstreamervideorendererinterface.h" + +QT_USE_NAMESPACE + +class QGstreamerVideoWidget; + +class QGstreamerVideoWidgetControl + : public QVideoWidgetControl + , public QGstreamerVideoRendererInterface +{ + Q_OBJECT + Q_INTERFACES(QGstreamerVideoRendererInterface) +public: + QGstreamerVideoWidgetControl(QObject *parent = 0); + virtual ~QGstreamerVideoWidgetControl(); + + GstElement *videoSink(); + void precessNewStream(); + + QWidget *videoWidget(); + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + void setOverlay(); + + bool eventFilter(QObject *object, QEvent *event); + +public slots: + void updateNativeVideoSize(); + +signals: + void sinkChanged(); + void readyChanged(bool); + +private: + void createVideoWidget(); + void windowExposed(); + + GstElement *m_videoSink; + QGstreamerVideoWidget *m_widget; + WId m_windowId; + Qt::AspectRatioMode m_aspectRatioMode; + bool m_fullScreen; +}; + +#endif // QGSTREAMERVIDEOWIDGET_H diff --git a/src/plugins/gstreamer/qgstreamervideowindow.cpp b/src/plugins/gstreamer/qgstreamervideowindow.cpp new file mode 100644 index 000000000..565000176 --- /dev/null +++ b/src/plugins/gstreamer/qgstreamervideowindow.cpp @@ -0,0 +1,342 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstreamervideowindow.h" +#include "qgstutils.h" + +#include + +#include +#include +#include + + +#ifndef QT_NO_XVIDEO + +/* + QGstreamerVideoWindow is similar to QGstreamerVideoOverlay, + but uses xvimagesink like gstreamer element instead of QX11VideoSurface. + + This allows to use the accelerated elements if available on the target platform, + but requires at least 0.10.29 gstreamer version + with gst_x_overlay_set_render_rectangle to set display rect. +*/ + +QGstreamerVideoWindow::QGstreamerVideoWindow(QObject *parent, const char *elementName) + : QVideoWindowControl(parent) + , m_videoSink(0) + , m_windowId(0) + , m_aspectRatioMode(Qt::KeepAspectRatio) + , m_fullScreen(false) + , m_colorKey(QColor::Invalid) +{ + if (elementName) + m_videoSink = gst_element_factory_make(elementName, NULL); + else + m_videoSink = gst_element_factory_make("xvimagesink", NULL); + + if (m_videoSink) { + gst_object_ref(GST_OBJECT(m_videoSink)); //Take ownership + gst_object_sink(GST_OBJECT(m_videoSink)); + + GstPad *pad = gst_element_get_static_pad(m_videoSink,"sink"); + m_bufferProbeId = gst_pad_add_buffer_probe(pad, G_CALLBACK(padBufferProbe), this); + } +} + +QGstreamerVideoWindow::~QGstreamerVideoWindow() +{ + if (m_videoSink) + gst_object_unref(GST_OBJECT(m_videoSink)); +} + +WId QGstreamerVideoWindow::winId() const +{ + return m_windowId; +} + +void QGstreamerVideoWindow::setWinId(WId id) +{ + if (m_windowId == id) + return; + + qDebug() << Q_FUNC_INFO << id; + + WId oldId = m_windowId; + + m_windowId = id; + + if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) { + gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(m_videoSink), m_windowId); + } + + if (!oldId) + emit readyChanged(true); + + if (!id) + emit readyChanged(false); +} + +void QGstreamerVideoWindow::precessNewStream() +{ + if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) { + gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(m_videoSink), m_windowId); + + GstPad *pad = gst_element_get_static_pad(m_videoSink,"sink"); + m_bufferProbeId = gst_pad_add_buffer_probe(pad, G_CALLBACK(padBufferProbe), this); + } +} + +QRect QGstreamerVideoWindow::displayRect() const +{ + return m_displayRect; +} + +void QGstreamerVideoWindow::setDisplayRect(const QRect &rect) +{ + m_displayRect = rect; + + if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) { +#if GST_VERSION_MICRO >= 29 + if (m_displayRect.isEmpty()) + gst_x_overlay_set_render_rectangle(GST_X_OVERLAY(m_videoSink), -1, -1, -1, -1); + else + gst_x_overlay_set_render_rectangle(GST_X_OVERLAY(m_videoSink), + m_displayRect.x(), + m_displayRect.y(), + m_displayRect.width(), + m_displayRect.height()); + repaint(); +#endif + } +} + +Qt::AspectRatioMode QGstreamerVideoWindow::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void QGstreamerVideoWindow::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + m_aspectRatioMode = mode; + + if (m_videoSink) { + g_object_set(G_OBJECT(m_videoSink), + "force-aspect-ratio", + (m_aspectRatioMode == Qt::KeepAspectRatio), + (const char*)NULL); + } +} + +void QGstreamerVideoWindow::repaint() +{ + if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) { + //don't call gst_x_overlay_expose if the sink is in null state + GstState state = GST_STATE_NULL; + GstStateChangeReturn res = gst_element_get_state(m_videoSink, &state, NULL, 1000000); + if (res != GST_STATE_CHANGE_FAILURE && state != GST_STATE_NULL) { + gst_x_overlay_expose(GST_X_OVERLAY(m_videoSink)); + } + } +} + +QColor QGstreamerVideoWindow::colorKey() const +{ + if (!m_colorKey.isValid()) { + gint colorkey = 0; + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "colorkey")) + g_object_get(G_OBJECT(m_videoSink), "colorkey", &colorkey, NULL); + + if (colorkey > 0) + m_colorKey.setRgb(colorkey); + } + + return m_colorKey; +} + +void QGstreamerVideoWindow::setColorKey(const QColor &color) +{ + m_colorKey = color; + + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "colorkey")) + g_object_set(G_OBJECT(m_videoSink), "colorkey", color.rgba(), NULL); +} + +bool QGstreamerVideoWindow::autopaintColorKey() const +{ + bool enabled = true; + + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "autopaint-colorkey")) + g_object_get(G_OBJECT(m_videoSink), "autopaint-colorkey", &enabled, NULL); + + return enabled; +} + +void QGstreamerVideoWindow::setAutopaintColorKey(bool enabled) +{ + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "autopaint-colorkey")) + g_object_set(G_OBJECT(m_videoSink), "autopaint-colorkey", enabled, NULL); +} + +int QGstreamerVideoWindow::brightness() const +{ + int brightness = 0; + + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "brightness")) + g_object_get(G_OBJECT(m_videoSink), "brightness", &brightness, NULL); + + return brightness / 10; +} + +void QGstreamerVideoWindow::setBrightness(int brightness) +{ + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "brightness")) { + g_object_set(G_OBJECT(m_videoSink), "brightness", brightness * 10, NULL); + + emit brightnessChanged(brightness); + } +} + +int QGstreamerVideoWindow::contrast() const +{ + int contrast = 0; + + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "contrast")) + g_object_get(G_OBJECT(m_videoSink), "contrast", &contrast, NULL); + + return contrast / 10; +} + +void QGstreamerVideoWindow::setContrast(int contrast) +{ + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "contrast")) { + g_object_set(G_OBJECT(m_videoSink), "contrast", contrast * 10, NULL); + + emit contrastChanged(contrast); + } +} + +int QGstreamerVideoWindow::hue() const +{ + int hue = 0; + + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "hue")) + g_object_get(G_OBJECT(m_videoSink), "hue", &hue, NULL); + + return hue / 10; +} + +void QGstreamerVideoWindow::setHue(int hue) +{ + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "hue")) { + g_object_set(G_OBJECT(m_videoSink), "hue", hue * 10, NULL); + + emit hueChanged(hue); + } +} + +int QGstreamerVideoWindow::saturation() const +{ + int saturation = 0; + + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "saturation")) + g_object_get(G_OBJECT(m_videoSink), "saturation", &saturation, NULL); + + return saturation / 10; +} + +void QGstreamerVideoWindow::setSaturation(int saturation) +{ + if (m_videoSink && g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "saturation")) { + g_object_set(G_OBJECT(m_videoSink), "saturation", saturation * 10, NULL); + + emit saturationChanged(saturation); + } +} + +bool QGstreamerVideoWindow::isFullScreen() const +{ + return m_fullScreen; +} + +void QGstreamerVideoWindow::setFullScreen(bool fullScreen) +{ + emit fullScreenChanged(m_fullScreen = fullScreen); +} + +QSize QGstreamerVideoWindow::nativeSize() const +{ + return m_nativeSize; +} + +void QGstreamerVideoWindow::padBufferProbe(GstPad *pad, GstBuffer *buffer, gpointer user_data) +{ + QGstreamerVideoWindow *control = reinterpret_cast(user_data); + QMetaObject::invokeMethod(control, "updateNativeVideoSize", Qt::QueuedConnection); + gst_pad_remove_buffer_probe(pad, control->m_bufferProbeId); +} + +void QGstreamerVideoWindow::updateNativeVideoSize() +{ + const QSize oldSize = m_nativeSize; + m_nativeSize = QSize(); + + if (m_videoSink) { + //find video native size to update video widget size hint + GstPad *pad = gst_element_get_static_pad(m_videoSink,"sink"); + GstCaps *caps = gst_pad_get_negotiated_caps(pad); + + if (caps) { + m_nativeSize = QGstUtils::capsCorrectedResolution(caps); + gst_caps_unref(caps); + } + } + + if (m_nativeSize != oldSize) + emit nativeSizeChanged(); +} + +GstElement *QGstreamerVideoWindow::videoSink() +{ + return m_videoSink; +} + +#endif //QT_NO_XVIDEO diff --git a/src/plugins/gstreamer/qgstreamervideowindow.h b/src/plugins/gstreamer/qgstreamervideowindow.h new file mode 100644 index 000000000..e2229ae9e --- /dev/null +++ b/src/plugins/gstreamer/qgstreamervideowindow.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTREAMERVIDEOWINDOW_H +#define QGSTREAMERVIDEOWINDOW_H + +#include + +#include "qgstreamervideorendererinterface.h" + +QT_BEGIN_NAMESPACE +class QAbstractVideoSurface; +QT_END_NAMESPACE +class QX11VideoSurface; + +#if defined(Q_WS_X11) && !defined(QT_NO_XVIDEO) + +QT_USE_NAMESPACE + +class QGstreamerVideoWindow : public QVideoWindowControl, public QGstreamerVideoRendererInterface +{ + Q_OBJECT + Q_INTERFACES(QGstreamerVideoRendererInterface) + Q_PROPERTY(QColor colorKey READ colorKey WRITE setColorKey) + Q_PROPERTY(bool autopaintColorKey READ autopaintColorKey WRITE setAutopaintColorKey) +public: + QGstreamerVideoWindow(QObject *parent = 0, const char *elementName = 0); + ~QGstreamerVideoWindow(); + + WId winId() const; + void setWinId(WId id); + + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + QSize nativeSize() const; + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + + QColor colorKey() const; + void setColorKey(const QColor &); + + bool autopaintColorKey() const; + void setAutopaintColorKey(bool); + + void repaint(); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + QAbstractVideoSurface *surface() const; + + GstElement *videoSink(); + + void precessNewStream(); + bool isReady() const { return m_windowId != 0; } + +signals: + void sinkChanged(); + void readyChanged(bool); + +private slots: + void updateNativeVideoSize(); + +private: + static void padBufferProbe(GstPad *pad, GstBuffer *buffer, gpointer user_data); + + GstElement *m_videoSink; + WId m_windowId; + Qt::AspectRatioMode m_aspectRatioMode; + QRect m_displayRect; + bool m_fullScreen; + QSize m_nativeSize; + mutable QColor m_colorKey; + int m_bufferProbeId; +}; + +#endif //QT_NO_XVIDEO + +#endif diff --git a/src/plugins/gstreamer/qgstutils.cpp b/src/plugins/gstreamer/qgstutils.cpp new file mode 100644 index 000000000..a0f2a9832 --- /dev/null +++ b/src/plugins/gstreamer/qgstutils.cpp @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstutils.h" + +#include +#include +#include +#include + +//internal +static void addTagToMap(const GstTagList *list, + const gchar *tag, + gpointer user_data) +{ + QMap *map = reinterpret_cast* >(user_data); + + GValue val; + val.g_type = 0; + gst_tag_list_copy_value(&val,list,tag); + + switch( G_VALUE_TYPE(&val) ) { + case G_TYPE_STRING: + { + const gchar *str_value = g_value_get_string(&val); + map->insert(QByteArray(tag), QString::fromUtf8(str_value)); + break; + } + case G_TYPE_INT: + map->insert(QByteArray(tag), g_value_get_int(&val)); + break; + case G_TYPE_UINT: + map->insert(QByteArray(tag), g_value_get_uint(&val)); + break; + case G_TYPE_LONG: + map->insert(QByteArray(tag), qint64(g_value_get_long(&val))); + break; + case G_TYPE_BOOLEAN: + map->insert(QByteArray(tag), g_value_get_boolean(&val)); + break; + case G_TYPE_CHAR: + map->insert(QByteArray(tag), g_value_get_char(&val)); + break; + case G_TYPE_DOUBLE: + map->insert(QByteArray(tag), g_value_get_double(&val)); + break; + default: + // GST_TYPE_DATE is a function, not a constant, so pull it out of the switch + if (G_VALUE_TYPE(&val) == GST_TYPE_DATE) { + const GDate *date = gst_value_get_date(&val); + if (g_date_valid(date)) { + int year = g_date_get_year(date); + int month = g_date_get_month(date); + int day = g_date_get_day(date); + map->insert(QByteArray(tag), QDate(year,month,day)); + if (!map->contains("year")) + map->insert("year", year); + } + } else if (G_VALUE_TYPE(&val) == GST_TYPE_FRACTION) { + int nom = gst_value_get_fraction_numerator(&val); + int denom = gst_value_get_fraction_denominator(&val); + + if (denom > 0) { + map->insert(QByteArray(tag), double(nom)/denom); + } + } + break; + } + + g_value_unset(&val); +} + +/*! + Convert GstTagList structure to QMap. + + Mapping to int, bool, char, string, fractions and date are supported. + Fraction values are converted to doubles. +*/ +QMap QGstUtils::gstTagListToMap(const GstTagList *tags) +{ + QMap res; + gst_tag_list_foreach(tags, addTagToMap, &res); + + return res; +} + +/*! + Returns resolution of \a caps. + If caps doesn't have a valid size, and ampty QSize is returned. +*/ +QSize QGstUtils::capsResolution(const GstCaps *caps) +{ + QSize size; + + if (caps) { + const GstStructure *structure = gst_caps_get_structure(caps, 0); + gst_structure_get_int(structure, "width", &size.rwidth()); + gst_structure_get_int(structure, "height", &size.rheight()); + } + + return size; +} + +/*! + Returns aspect ratio corrected resolution of \a caps. + If caps doesn't have a valid size, and ampty QSize is returned. +*/ +QSize QGstUtils::capsCorrectedResolution(const GstCaps *caps) +{ + QSize size; + + if (caps) { + const GstStructure *structure = gst_caps_get_structure(caps, 0); + gst_structure_get_int(structure, "width", &size.rwidth()); + gst_structure_get_int(structure, "height", &size.rheight()); + + gint aspectNum = 0; + gint aspectDenum = 0; + if (!size.isEmpty() && gst_structure_get_fraction( + structure, "pixel-aspect-ratio", &aspectNum, &aspectDenum)) { + if (aspectDenum > 0) + size.setWidth(qRound(size.width()*aspectNum/aspectDenum)); + } + } + + return size; +} diff --git a/src/plugins/gstreamer/qgstutils.h b/src/plugins/gstreamer/qgstutils.h new file mode 100644 index 000000000..396b32b98 --- /dev/null +++ b/src/plugins/gstreamer/qgstutils.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTUTILS_H +#define QGSTUTILS_H + +#include +#include + +class QSize; +class QVariant; +class QByteArray; + +namespace QGstUtils { + QMap gstTagListToMap(const GstTagList *list); + + QSize capsResolution(const GstCaps *caps); + QSize capsCorrectedResolution(const GstCaps *caps); +} + +#endif diff --git a/src/plugins/gstreamer/qgstvideobuffer.cpp b/src/plugins/gstreamer/qgstvideobuffer.cpp new file mode 100644 index 000000000..4ea6a7004 --- /dev/null +++ b/src/plugins/gstreamer/qgstvideobuffer.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgstvideobuffer.h" + + +QGstVideoBuffer::QGstVideoBuffer(GstBuffer *buffer, int bytesPerLine) + : QAbstractVideoBuffer(NoHandle) + , m_buffer(buffer) + , m_bytesPerLine(bytesPerLine) + , m_mode(NotMapped) +{ + gst_buffer_ref(m_buffer); +} + +QGstVideoBuffer::QGstVideoBuffer(GstBuffer *buffer, int bytesPerLine, + QGstVideoBuffer::HandleType handleType, + const QVariant &handle) + : QAbstractVideoBuffer(handleType) + , m_buffer(buffer) + , m_bytesPerLine(bytesPerLine) + , m_mode(NotMapped) + , m_handle(handle) +{ + gst_buffer_ref(m_buffer); +} + +QGstVideoBuffer::~QGstVideoBuffer() +{ + gst_buffer_unref(m_buffer); +} + + +QAbstractVideoBuffer::MapMode QGstVideoBuffer::mapMode() const +{ + return m_mode; +} + +uchar *QGstVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine) +{ + if (mode != NotMapped && m_mode == NotMapped) { + if (numBytes) + *numBytes = m_buffer->size; + + if (bytesPerLine) + *bytesPerLine = m_bytesPerLine; + + m_mode = mode; + + return m_buffer->data; + } else { + return 0; + } +} +void QGstVideoBuffer::unmap() +{ + m_mode = NotMapped; +} + diff --git a/src/plugins/gstreamer/qgstvideobuffer.h b/src/plugins/gstreamer/qgstvideobuffer.h new file mode 100644 index 000000000..8d5a36e53 --- /dev/null +++ b/src/plugins/gstreamer/qgstvideobuffer.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTVIDEOBUFFER_H +#define QGSTVIDEOBUFFER_H + +#include +#include + +#include + +class QGstVideoBuffer : public QAbstractVideoBuffer +{ +public: + QGstVideoBuffer(GstBuffer *buffer, int bytesPerLine); + QGstVideoBuffer(GstBuffer *buffer, int bytesPerLine, + HandleType handleType, const QVariant &handle); + ~QGstVideoBuffer(); + + MapMode mapMode() const; + + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine); + void unmap(); + + QVariant handle() const { return m_handle; } +private: + GstBuffer *m_buffer; + int m_bytesPerLine; + MapMode m_mode; + QVariant m_handle; +}; + + +#endif diff --git a/src/plugins/gstreamer/qgstxvimagebuffer.cpp b/src/plugins/gstreamer/qgstxvimagebuffer.cpp new file mode 100644 index 000000000..393456291 --- /dev/null +++ b/src/plugins/gstreamer/qgstxvimagebuffer.cpp @@ -0,0 +1,311 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#include "qgstxvimagebuffer.h" +#include "qvideosurfacegstsink.h" +#include "qgstvideobuffer.h" + +#ifndef QT_NO_XVIDEO + +GstBufferClass *QGstXvImageBuffer::parent_class = NULL; + +GType QGstXvImageBuffer::get_type(void) +{ + static GType buffer_type = 0; + + if (buffer_type == 0) { + static const GTypeInfo buffer_info = { + sizeof (GstBufferClass), + NULL, + NULL, + QGstXvImageBuffer::class_init, + NULL, + NULL, + sizeof(QGstXvImageBuffer), + 0, + (GInstanceInitFunc)QGstXvImageBuffer::buffer_init, + NULL + }; + buffer_type = g_type_register_static(GST_TYPE_BUFFER, + "QGstXvImageBuffer", &buffer_info, GTypeFlags(0)); + } + return buffer_type; +} + +void QGstXvImageBuffer::class_init(gpointer g_class, gpointer class_data) +{ + Q_UNUSED(class_data); + GST_MINI_OBJECT_CLASS(g_class)->finalize = + (GstMiniObjectFinalizeFunction)buffer_finalize; + parent_class = (GstBufferClass*)g_type_class_peek_parent(g_class); +} + +void QGstXvImageBuffer::buffer_init(QGstXvImageBuffer *xvImage, gpointer g_class) +{ + Q_UNUSED(g_class); + xvImage->pool = 0; + xvImage->shmInfo.shmaddr = ((char *) -1); + xvImage->shmInfo.shmid = -1; + xvImage->markedForDeletion = false; +} + +void QGstXvImageBuffer::buffer_finalize(QGstXvImageBuffer * xvImage) +{ + if (xvImage->pool) { + if (xvImage->markedForDeletion) + xvImage->pool->destroyBuffer(xvImage); + else + xvImage->pool->recycleBuffer(xvImage); + } +} + + +QGstXvImageBufferPool::QGstXvImageBufferPool(QObject *parent) + :QObject(parent) +{ + m_threadId = QThread::currentThreadId(); +} + +QGstXvImageBufferPool::~QGstXvImageBufferPool() +{ +} + +bool QGstXvImageBufferPool::isFormatSupported(const QVideoSurfaceFormat &surfaceFormat) const +{ + bool ok = true; + surfaceFormat.property("portId").toULongLong(&ok); + if (!ok) + return false; + + int xvFormatId = surfaceFormat.property("xvFormatId").toInt(&ok); + if (!ok || xvFormatId < 0) + return false; + + int dataSize = surfaceFormat.property("dataSize").toInt(&ok); + if (!ok || dataSize<=0) + return false; + + return true; +} + +GType QGstXvImageBufferPool::bufferType() const +{ + return QGstXvImageBuffer::get_type(); +} + +GstBuffer *QGstXvImageBufferPool::takeBuffer( + const QVideoSurfaceFormat &format, GstCaps *caps) +{ + m_poolMutex.lock(); + + m_caps = caps; + if (format != m_format) { + doClear(); + m_format = format; + } + + + if (m_pool.isEmpty()) { + //qDebug() << "QGstXvImageBufferPool::takeBuffer: no buffer available, allocate the new one" << QThread::currentThreadId() << m_threadId; + if (QThread::currentThreadId() == m_threadId) { + doAlloc(); + } else { + QMetaObject::invokeMethod(this, "queuedAlloc", Qt::QueuedConnection); + m_allocWaitCondition.wait(&m_poolMutex, 300); + } + } + QGstXvImageBuffer *res = 0; + + if (!m_pool.isEmpty()) { + res = m_pool.takeLast(); + } + + m_poolMutex.unlock(); + + return GST_BUFFER(res); +} + +QAbstractVideoBuffer::HandleType QGstXvImageBufferPool::handleType() const +{ + return QAbstractVideoBuffer::XvShmImageHandle; +} + +QAbstractVideoBuffer *QGstXvImageBufferPool::prepareVideoBuffer(GstBuffer *buffer, int bytesPerLine) +{ + QGstXvImageBuffer *xvBuffer = reinterpret_cast(buffer); + QVariant handle = QVariant::fromValue(xvBuffer->xvImage); + return new QGstVideoBuffer(buffer, bytesPerLine, QAbstractVideoBuffer::XvShmImageHandle, handle); +} + +void QGstXvImageBufferPool::queuedAlloc() +{ + QMutexLocker lock(&m_poolMutex); + doAlloc(); + m_allocWaitCondition.wakeOne(); +} + +void QGstXvImageBufferPool::doAlloc() +{ + //should be always called from the main thread with m_poolMutex locked + //Q_ASSERT(QThread::currentThread() == thread()); + + XSync(QX11Info::display(), false); + + QGstXvImageBuffer *xvBuffer = (QGstXvImageBuffer *)gst_mini_object_new(QGstXvImageBuffer::get_type()); + + quint64 portId = m_format.property("portId").toULongLong(); + int xvFormatId = m_format.property("xvFormatId").toInt(); + + xvBuffer->xvImage = XvShmCreateImage( + QX11Info::display(), + portId, + xvFormatId, + 0, + m_format.frameWidth(), + m_format.frameHeight(), + &xvBuffer->shmInfo + ); + + if (!xvBuffer->xvImage) { + qWarning() << "QGstXvImageBufferPool: XvShmCreateImage failed"; + return; + } + + XSync(QX11Info::display(), false); + + xvBuffer->shmInfo.shmid = shmget(IPC_PRIVATE, xvBuffer->xvImage->data_size, IPC_CREAT | 0777); + xvBuffer->shmInfo.shmaddr = xvBuffer->xvImage->data = (char*)shmat(xvBuffer->shmInfo.shmid, 0, 0); + xvBuffer->shmInfo.readOnly = False; + + if (!XShmAttach(QX11Info::display(), &xvBuffer->shmInfo)) { + qWarning() << "QGstXvImageBufferPool: XShmAttach failed"; + return; + } + + XSync(QX11Info::display(), false); + + shmctl (xvBuffer->shmInfo.shmid, IPC_RMID, NULL); + + xvBuffer->pool = this; + GST_MINI_OBJECT_CAST(xvBuffer)->flags = 0; + gst_buffer_set_caps(GST_BUFFER_CAST(xvBuffer), m_caps); + GST_BUFFER_DATA(xvBuffer) = (uchar*)xvBuffer->xvImage->data; + GST_BUFFER_SIZE(xvBuffer) = xvBuffer->xvImage->data_size; + + m_allBuffers.append(xvBuffer); + m_pool.append(xvBuffer); + + XSync(QX11Info::display(), false); +} + + +void QGstXvImageBufferPool::clear() +{ + QMutexLocker lock(&m_poolMutex); + doClear(); +} + +void QGstXvImageBufferPool::doClear() +{ + foreach (QGstXvImageBuffer *xvBuffer, m_allBuffers) { + xvBuffer->markedForDeletion = true; + } + m_allBuffers.clear(); + + foreach (QGstXvImageBuffer *xvBuffer, m_pool) { + gst_buffer_unref(GST_BUFFER(xvBuffer)); + } + m_pool.clear(); + + m_format = QVideoSurfaceFormat(); +} + +void QGstXvImageBufferPool::queuedDestroy() +{ + QMutexLocker lock(&m_destroyMutex); + + XSync(QX11Info::display(), false); + + foreach(XvShmImage xvImage, m_imagesToDestroy) { + if (xvImage.shmInfo.shmaddr != ((void *) -1)) { + XShmDetach(QX11Info::display(), &xvImage.shmInfo); + XSync(QX11Info::display(), false); + + shmdt(xvImage.shmInfo.shmaddr); + } + + if (xvImage.xvImage) + XFree(xvImage.xvImage); + } + + m_imagesToDestroy.clear(); + + XSync(QX11Info::display(), false); +} + +void QGstXvImageBufferPool::recycleBuffer(QGstXvImageBuffer *xvBuffer) +{ + QMutexLocker lock(&m_poolMutex); + gst_buffer_ref(GST_BUFFER_CAST(xvBuffer)); + m_pool.append(xvBuffer); +} + +void QGstXvImageBufferPool::destroyBuffer(QGstXvImageBuffer *xvBuffer) +{ + XvShmImage imageToDestroy; + imageToDestroy.xvImage = xvBuffer->xvImage; + imageToDestroy.shmInfo = xvBuffer->shmInfo; + + m_destroyMutex.lock(); + m_imagesToDestroy.append(imageToDestroy); + m_destroyMutex.unlock(); + + if (m_imagesToDestroy.size() == 1) + QMetaObject::invokeMethod(this, "queuedDestroy", Qt::QueuedConnection); +} + +#endif //QT_NO_XVIDEO + diff --git a/src/plugins/gstreamer/qgstxvimagebuffer.h b/src/plugins/gstreamer/qgstxvimagebuffer.h new file mode 100644 index 000000000..2ab5ea03b --- /dev/null +++ b/src/plugins/gstreamer/qgstxvimagebuffer.h @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTXVIMAGEBUFFER_H +#define QGSTXVIMAGEBUFFER_H + +#include +#include +#include +#include +#include + +#ifndef QT_NO_XVIDEO + +#include +#include +#include +#include +#include +#include +#include + + +#include +#include "qabstractgstbufferpool.h" + +class QGstXvImageBufferPool; + +struct QGstXvImageBuffer { + GstBuffer buffer; + QGstXvImageBufferPool *pool; + XvImage *xvImage; + XShmSegmentInfo shmInfo; + bool markedForDeletion; + + static GType get_type(void); + static void class_init(gpointer g_class, gpointer class_data); + static void buffer_init(QGstXvImageBuffer *xvimage, gpointer g_class); + static void buffer_finalize(QGstXvImageBuffer * xvimage); + static GstBufferClass *parent_class; +}; + +Q_DECLARE_METATYPE(XvImage*) + +class QGstXvImageBufferPool : public QObject, public QAbstractGstBufferPool { +Q_OBJECT +friend class QGstXvImageBuffer; +public: + QGstXvImageBufferPool(QObject *parent = 0); + virtual ~QGstXvImageBufferPool(); + + bool isFormatSupported(const QVideoSurfaceFormat &format) const; + + GType bufferType() const; + GstBuffer *takeBuffer(const QVideoSurfaceFormat &format, GstCaps *caps); + void clear(); + + QAbstractVideoBuffer::HandleType handleType() const; + QAbstractVideoBuffer *prepareVideoBuffer(GstBuffer *buffer, int bytesPerLine); + +private slots: + void queuedAlloc(); + void queuedDestroy(); + + void doClear(); + + void recycleBuffer(QGstXvImageBuffer *); + void destroyBuffer(QGstXvImageBuffer *); + +private: + void doAlloc(); + + struct XvShmImage { + XvImage *xvImage; + XShmSegmentInfo shmInfo; + }; + + QMutex m_poolMutex; + QMutex m_allocMutex; + QWaitCondition m_allocWaitCondition; + QMutex m_destroyMutex; + QVideoSurfaceFormat m_format; + GstCaps *m_caps; + QList m_pool; + QList m_allBuffers; + QList m_imagesToDestroy; + Qt::HANDLE m_threadId; +}; + +#endif //QT_NO_XVIDEO + +#endif diff --git a/src/plugins/gstreamer/qvideosurfacegstsink.cpp b/src/plugins/gstreamer/qvideosurfacegstsink.cpp new file mode 100644 index 000000000..f3c0e3468 --- /dev/null +++ b/src/plugins/gstreamer/qvideosurfacegstsink.cpp @@ -0,0 +1,772 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "qgstvideobuffer.h" + +#if defined(Q_WS_X11) && !defined(QT_NO_XVIDEO) +#include +#include "qgstxvimagebuffer.h" +#endif + +#include "qvideosurfacegstsink.h" + +//#define DEBUG_VIDEO_SURFACE_SINK + + +Q_DECLARE_METATYPE(QVideoSurfaceFormat) + +QVideoSurfaceGstDelegate::QVideoSurfaceGstDelegate( + QAbstractVideoSurface *surface) + : m_surface(surface) + , m_pool(0) + , m_renderReturn(GST_FLOW_ERROR) + , m_bytesPerLine(0) +{ + if (m_surface) { +#if defined(Q_WS_X11) && !defined(QT_NO_XVIDEO) + m_pools.append(new QGstXvImageBufferPool()); +#endif + updateSupportedFormats(); + connect(m_surface, SIGNAL(supportedFormatsChanged()), this, SLOT(updateSupportedFormats())); + } +} + +QVideoSurfaceGstDelegate::~QVideoSurfaceGstDelegate() +{ + qDeleteAll(m_pools); +} + +QList QVideoSurfaceGstDelegate::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const +{ + QMutexLocker locker(const_cast(&m_mutex)); + + if (!m_surface) + return QList(); + else if (handleType == QAbstractVideoBuffer::NoHandle) + return m_supportedPixelFormats; + else if (handleType == m_pool->handleType()) + return m_supportedPoolPixelFormats; + else + return m_surface->supportedPixelFormats(handleType); +} + +QVideoSurfaceFormat QVideoSurfaceGstDelegate::surfaceFormat() const +{ + QMutexLocker locker(const_cast(&m_mutex)); + return m_format; +} + +bool QVideoSurfaceGstDelegate::start(const QVideoSurfaceFormat &format, int bytesPerLine) +{ + if (!m_surface) + return false; + + QMutexLocker locker(&m_mutex); + + m_format = format; + m_bytesPerLine = bytesPerLine; + + if (QThread::currentThread() == thread()) { + m_started = !m_surface.isNull() ? m_surface->start(m_format) : false; + } else { + QMetaObject::invokeMethod(this, "queuedStart", Qt::QueuedConnection); + + m_setupCondition.wait(&m_mutex); + } + + m_format = m_surface->surfaceFormat(); + + return m_started; +} + +void QVideoSurfaceGstDelegate::stop() +{ + if (!m_surface) + return; + + QMutexLocker locker(&m_mutex); + + if (QThread::currentThread() == thread()) { + if (!m_surface.isNull()) + m_surface->stop(); + } else { + QMetaObject::invokeMethod(this, "queuedStop", Qt::QueuedConnection); + + m_setupCondition.wait(&m_mutex); + } + + m_started = false; +} + +bool QVideoSurfaceGstDelegate::isActive() +{ + QMutexLocker locker(&m_mutex); + return !m_surface.isNull() && m_surface->isActive(); +} + +GstFlowReturn QVideoSurfaceGstDelegate::render(GstBuffer *buffer) +{ + if (!m_surface) { + qWarning() << "Rendering video frame to deleted surface, skip."; + //return GST_FLOW_NOT_NEGOTIATED; + return GST_FLOW_OK; + } + + QMutexLocker locker(&m_mutex); + + QAbstractVideoBuffer *videoBuffer = 0; + + if (m_pool && G_TYPE_CHECK_INSTANCE_TYPE(buffer, m_pool->bufferType())) + videoBuffer = m_pool->prepareVideoBuffer(buffer, m_bytesPerLine); + else + videoBuffer = new QGstVideoBuffer(buffer, m_bytesPerLine); + + m_frame = QVideoFrame( + videoBuffer, + m_format.frameSize(), + m_format.pixelFormat()); + + qint64 startTime = GST_BUFFER_TIMESTAMP(buffer); + + if (startTime >= 0) { + m_frame.setStartTime(startTime/G_GINT64_CONSTANT (1000000)); + + qint64 duration = GST_BUFFER_DURATION(buffer); + + if (duration >= 0) + m_frame.setEndTime((startTime + duration)/G_GINT64_CONSTANT (1000000)); + } + + QMetaObject::invokeMethod(this, "queuedRender", Qt::QueuedConnection); + + if (!m_renderCondition.wait(&m_mutex, 300)) { + m_frame = QVideoFrame(); + + return GST_FLOW_OK; + } else { + return m_renderReturn; + } +} + +void QVideoSurfaceGstDelegate::queuedStart() +{ + QMutexLocker locker(&m_mutex); + + m_started = m_surface->start(m_format); + + m_setupCondition.wakeAll(); +} + +void QVideoSurfaceGstDelegate::queuedStop() +{ + QMutexLocker locker(&m_mutex); + + m_surface->stop(); + + m_setupCondition.wakeAll(); +} + +void QVideoSurfaceGstDelegate::queuedRender() +{ + QMutexLocker locker(&m_mutex); + + if (m_surface.isNull()) { + qWarning() << "Rendering video frame to deleted surface, skip the frame"; + m_renderReturn = GST_FLOW_OK; + } else if (m_surface->present(m_frame)) { + m_renderReturn = GST_FLOW_OK; + } else { + switch (m_surface->error()) { + case QAbstractVideoSurface::NoError: + m_renderReturn = GST_FLOW_OK; + break; + case QAbstractVideoSurface::StoppedError: + //It's likely we are in process of changing video output + //and the surface is already stopped, ignore the frame + m_renderReturn = GST_FLOW_OK; + break; + default: + qWarning() << "Failed to render video frame:" << m_surface->error(); + m_renderReturn = GST_FLOW_OK; + break; + } + } + + m_renderCondition.wakeAll(); +} + +void QVideoSurfaceGstDelegate::updateSupportedFormats() +{ + QAbstractGstBufferPool *newPool = 0; + foreach (QAbstractGstBufferPool *pool, m_pools) { + if (!m_surface->supportedPixelFormats(pool->handleType()).isEmpty()) { + newPool = pool; + break; + } + } + + if (newPool != m_pool) { + QMutexLocker lock(&m_poolMutex); + + if (m_pool) + m_pool->clear(); + m_pool = newPool; + } + + QMutexLocker locker(&m_mutex); + + m_supportedPixelFormats.clear(); + m_supportedPoolPixelFormats.clear(); + if (m_surface) { + m_supportedPixelFormats = m_surface->supportedPixelFormats(); + if (m_pool) + m_supportedPoolPixelFormats = m_surface->supportedPixelFormats(m_pool->handleType()); + } +} + +struct YuvFormat +{ + QVideoFrame::PixelFormat pixelFormat; + guint32 fourcc; + int bitsPerPixel; +}; + +static const YuvFormat qt_yuvColorLookup[] = +{ + { QVideoFrame::Format_YUV420P, GST_MAKE_FOURCC('I','4','2','0'), 8 }, + { QVideoFrame::Format_YV12, GST_MAKE_FOURCC('Y','V','1','2'), 8 }, + { QVideoFrame::Format_UYVY, GST_MAKE_FOURCC('U','Y','V','Y'), 16 }, + { QVideoFrame::Format_YUYV, GST_MAKE_FOURCC('Y','U','Y','2'), 16 }, + { QVideoFrame::Format_NV12, GST_MAKE_FOURCC('N','V','1','2'), 8 }, + { QVideoFrame::Format_NV21, GST_MAKE_FOURCC('N','V','2','1'), 8 }, + { QVideoFrame::Format_AYUV444, GST_MAKE_FOURCC('A','Y','U','V'), 32 } +}; + +static int indexOfYuvColor(QVideoFrame::PixelFormat format) +{ + const int count = sizeof(qt_yuvColorLookup) / sizeof(YuvFormat); + + for (int i = 0; i < count; ++i) + if (qt_yuvColorLookup[i].pixelFormat == format) + return i; + + return -1; +} + +static int indexOfYuvColor(guint32 fourcc) +{ + const int count = sizeof(qt_yuvColorLookup) / sizeof(YuvFormat); + + for (int i = 0; i < count; ++i) + if (qt_yuvColorLookup[i].fourcc == fourcc) + return i; + + return -1; +} + +struct RgbFormat +{ + QVideoFrame::PixelFormat pixelFormat; + int bitsPerPixel; + int depth; + int endianness; + int red; + int green; + int blue; + int alpha; +}; + +static const RgbFormat qt_rgbColorLookup[] = +{ + { QVideoFrame::Format_RGB32 , 32, 24, 4321, 0x0000FF00, 0x00FF0000, 0xFF000000, 0x00000000 }, + { QVideoFrame::Format_RGB32 , 32, 24, 1234, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000 }, + { QVideoFrame::Format_BGR32 , 32, 24, 4321, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x00000000 }, + { QVideoFrame::Format_BGR32 , 32, 24, 1234, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000 }, + { QVideoFrame::Format_ARGB32, 32, 24, 4321, 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF }, + { QVideoFrame::Format_ARGB32, 32, 24, 1234, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000 }, + { QVideoFrame::Format_RGB24 , 24, 24, 4321, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000 }, + { QVideoFrame::Format_BGR24 , 24, 24, 4321, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000 }, + { QVideoFrame::Format_RGB565, 16, 16, 1234, 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 } +}; + +static int indexOfRgbColor( + int bits, int depth, int endianness, int red, int green, int blue, int alpha) +{ + const int count = sizeof(qt_rgbColorLookup) / sizeof(RgbFormat); + + for (int i = 0; i < count; ++i) { + if (qt_rgbColorLookup[i].bitsPerPixel == bits + && qt_rgbColorLookup[i].depth == depth + && qt_rgbColorLookup[i].endianness == endianness + && qt_rgbColorLookup[i].red == red + && qt_rgbColorLookup[i].green == green + && qt_rgbColorLookup[i].blue == blue + && qt_rgbColorLookup[i].alpha == alpha) { + return i; + } + } + return -1; +} + +static GstVideoSinkClass *sink_parent_class; + +#define VO_SINK(s) QVideoSurfaceGstSink *sink(reinterpret_cast(s)) + +QVideoSurfaceGstSink *QVideoSurfaceGstSink::createSink(QAbstractVideoSurface *surface) +{ + QVideoSurfaceGstSink *sink = reinterpret_cast( + g_object_new(QVideoSurfaceGstSink::get_type(), 0)); + + sink->delegate = new QVideoSurfaceGstDelegate(surface); + + return sink; +} + +GType QVideoSurfaceGstSink::get_type() +{ + static GType type = 0; + + if (type == 0) { + static const GTypeInfo info = + { + sizeof(QVideoSurfaceGstSinkClass), // class_size + base_init, // base_init + NULL, // base_finalize + class_init, // class_init + NULL, // class_finalize + NULL, // class_data + sizeof(QVideoSurfaceGstSink), // instance_size + 0, // n_preallocs + instance_init, // instance_init + 0 // value_table + }; + + type = g_type_register_static( + GST_TYPE_VIDEO_SINK, "QVideoSurfaceGstSink", &info, GTypeFlags(0)); + } + + return type; +} + +void QVideoSurfaceGstSink::class_init(gpointer g_class, gpointer class_data) +{ + Q_UNUSED(class_data); + + sink_parent_class = reinterpret_cast(g_type_class_peek_parent(g_class)); + + GstBaseSinkClass *base_sink_class = reinterpret_cast(g_class); + base_sink_class->get_caps = QVideoSurfaceGstSink::get_caps; + base_sink_class->set_caps = QVideoSurfaceGstSink::set_caps; + base_sink_class->buffer_alloc = QVideoSurfaceGstSink::buffer_alloc; + base_sink_class->start = QVideoSurfaceGstSink::start; + base_sink_class->stop = QVideoSurfaceGstSink::stop; + // base_sink_class->unlock = QVideoSurfaceGstSink::unlock; // Not implemented. + // base_sink_class->event = QVideoSurfaceGstSink::event; // Not implemented. + base_sink_class->preroll = QVideoSurfaceGstSink::preroll; + base_sink_class->render = QVideoSurfaceGstSink::render; + + GstElementClass *element_class = reinterpret_cast(g_class); + element_class->change_state = QVideoSurfaceGstSink::change_state; + + GObjectClass *object_class = reinterpret_cast(g_class); + object_class->finalize = QVideoSurfaceGstSink::finalize; +} + +void QVideoSurfaceGstSink::base_init(gpointer g_class) +{ + static GstStaticPadTemplate sink_pad_template = GST_STATIC_PAD_TEMPLATE( + "sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS( + "video/x-raw-rgb, " + "framerate = (fraction) [ 0, MAX ], " + "width = (int) [ 1, MAX ], " + "height = (int) [ 1, MAX ]; " + "video/x-raw-yuv, " + "framerate = (fraction) [ 0, MAX ], " + "width = (int) [ 1, MAX ], " + "height = (int) [ 1, MAX ]")); + + gst_element_class_add_pad_template( + GST_ELEMENT_CLASS(g_class), gst_static_pad_template_get(&sink_pad_template)); +} + +void QVideoSurfaceGstSink::instance_init(GTypeInstance *instance, gpointer g_class) +{ + VO_SINK(instance); + + Q_UNUSED(g_class); + + sink->delegate = 0; + + sink->lastRequestedCaps = 0; + sink->lastBufferCaps = 0; + sink->lastSurfaceFormat = new QVideoSurfaceFormat; +} + +void QVideoSurfaceGstSink::finalize(GObject *object) +{ + VO_SINK(object); + + delete sink->lastSurfaceFormat; + sink->lastSurfaceFormat = 0; + + if (sink->lastBufferCaps) + gst_caps_unref(sink->lastBufferCaps); + sink->lastBufferCaps = 0; + + if (sink->lastRequestedCaps) + gst_caps_unref(sink->lastRequestedCaps); + sink->lastRequestedCaps = 0; +} + +GstStateChangeReturn QVideoSurfaceGstSink::change_state( + GstElement *element, GstStateChange transition) +{ + Q_UNUSED(element); + + return GST_ELEMENT_CLASS(sink_parent_class)->change_state( + element, transition); +} + +GstCaps *QVideoSurfaceGstSink::get_caps(GstBaseSink *base) +{ + VO_SINK(base); + + GstCaps *caps = gst_caps_new_empty(); + + foreach (QVideoFrame::PixelFormat format, sink->delegate->supportedPixelFormats()) { + int index = indexOfYuvColor(format); + + if (index != -1) { + gst_caps_append_structure(caps, gst_structure_new( + "video/x-raw-yuv", + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, INT_MAX, 1, + "width" , GST_TYPE_INT_RANGE, 1, INT_MAX, + "height" , GST_TYPE_INT_RANGE, 1, INT_MAX, + "format" , GST_TYPE_FOURCC, qt_yuvColorLookup[index].fourcc, + NULL)); + continue; + } + + const int count = sizeof(qt_rgbColorLookup) / sizeof(RgbFormat); + + for (int i = 0; i < count; ++i) { + if (qt_rgbColorLookup[i].pixelFormat == format) { + GstStructure *structure = gst_structure_new( + "video/x-raw-rgb", + "framerate" , GST_TYPE_FRACTION_RANGE, 0, 1, INT_MAX, 1, + "width" , GST_TYPE_INT_RANGE, 1, INT_MAX, + "height" , GST_TYPE_INT_RANGE, 1, INT_MAX, + "bpp" , G_TYPE_INT, qt_rgbColorLookup[i].bitsPerPixel, + "depth" , G_TYPE_INT, qt_rgbColorLookup[i].depth, + "endianness", G_TYPE_INT, qt_rgbColorLookup[i].endianness, + "red_mask" , G_TYPE_INT, qt_rgbColorLookup[i].red, + "green_mask", G_TYPE_INT, qt_rgbColorLookup[i].green, + "blue_mask" , G_TYPE_INT, qt_rgbColorLookup[i].blue, + NULL); + + if (qt_rgbColorLookup[i].alpha != 0) { + gst_structure_set( + structure, "alpha_mask", G_TYPE_INT, qt_rgbColorLookup[i].alpha, NULL); + } + gst_caps_append_structure(caps, structure); + } + } + } + + return caps; +} + +gboolean QVideoSurfaceGstSink::set_caps(GstBaseSink *base, GstCaps *caps) +{ + VO_SINK(base); + +#ifdef DEBUG_VIDEO_SURFACE_SINK + qDebug() << "set_caps:"; + qDebug() << gst_caps_to_string(caps); +#endif + + if (!caps) { + sink->delegate->stop(); + + return TRUE; + } else { + int bytesPerLine = 0; + QVideoSurfaceFormat format = formatForCaps(caps, &bytesPerLine); + + if (sink->delegate->isActive()) { + QVideoSurfaceFormat surfaceFormst = sink->delegate->surfaceFormat(); + + if (format.pixelFormat() == surfaceFormst.pixelFormat() && + format.frameSize() == surfaceFormst.frameSize()) + return TRUE; + else + sink->delegate->stop(); + } + + if (sink->lastRequestedCaps) + gst_caps_unref(sink->lastRequestedCaps); + sink->lastRequestedCaps = 0; + +#ifdef DEBUG_VIDEO_SURFACE_SINK + qDebug() << "Staring video surface, format:"; + qDebug() << format; + qDebug() << "bytesPerLine:" << bytesPerLine; +#endif + + if (sink->delegate->start(format, bytesPerLine)) + return TRUE; + else + qWarning() << "Failed to start video surface"; + } + + return FALSE; +} + +QVideoSurfaceFormat QVideoSurfaceGstSink::formatForCaps(GstCaps *caps, int *bytesPerLine) +{ + const GstStructure *structure = gst_caps_get_structure(caps, 0); + + QVideoFrame::PixelFormat pixelFormat = QVideoFrame::Format_Invalid; + int bitsPerPixel = 0; + + QSize size; + gst_structure_get_int(structure, "width", &size.rwidth()); + gst_structure_get_int(structure, "height", &size.rheight()); + + if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-yuv") == 0) { + guint32 fourcc = 0; + gst_structure_get_fourcc(structure, "format", &fourcc); + + int index = indexOfYuvColor(fourcc); + if (index != -1) { + pixelFormat = qt_yuvColorLookup[index].pixelFormat; + bitsPerPixel = qt_yuvColorLookup[index].bitsPerPixel; + } + } else if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-rgb") == 0) { + int depth = 0; + int endianness = 0; + int red = 0; + int green = 0; + int blue = 0; + int alpha = 0; + + gst_structure_get_int(structure, "bpp", &bitsPerPixel); + gst_structure_get_int(structure, "depth", &depth); + gst_structure_get_int(structure, "endianness", &endianness); + gst_structure_get_int(structure, "red_mask", &red); + gst_structure_get_int(structure, "green_mask", &green); + gst_structure_get_int(structure, "blue_mask", &blue); + gst_structure_get_int(structure, "alpha_mask", &alpha); + + int index = indexOfRgbColor(bitsPerPixel, depth, endianness, red, green, blue, alpha); + + if (index != -1) + pixelFormat = qt_rgbColorLookup[index].pixelFormat; + } + + if (pixelFormat != QVideoFrame::Format_Invalid) { + QVideoSurfaceFormat format(size, pixelFormat); + + QPair rate; + gst_structure_get_fraction(structure, "framerate", &rate.first, &rate.second); + + if (rate.second) + format.setFrameRate(qreal(rate.first)/rate.second); + + gint aspectNum = 0; + gint aspectDenum = 0; + if (gst_structure_get_fraction( + structure, "pixel-aspect-ratio", &aspectNum, &aspectDenum)) { + if (aspectDenum > 0) + format.setPixelAspectRatio(aspectNum, aspectDenum); + } + + if (bytesPerLine) + *bytesPerLine = ((size.width() * bitsPerPixel / 8) + 3) & ~3; + + return format; + } + + return QVideoSurfaceFormat(); +} + + +GstFlowReturn QVideoSurfaceGstSink::buffer_alloc( + GstBaseSink *base, guint64 offset, guint size, GstCaps *caps, GstBuffer **buffer) +{ + VO_SINK(base); + + Q_UNUSED(offset); + Q_UNUSED(size); + + if (!buffer) + return GST_FLOW_ERROR; + + *buffer = NULL; + + if (!sink->delegate->pool()) + return GST_FLOW_OK; + + QMutexLocker poolLock(sink->delegate->poolMutex()); + QAbstractGstBufferPool *pool = sink->delegate->pool(); + + if (!pool) + return GST_FLOW_OK; + + if (sink->lastRequestedCaps && gst_caps_is_equal(sink->lastRequestedCaps, caps)) { + //qDebug() << "reusing last caps"; + *buffer = GST_BUFFER(pool->takeBuffer(*sink->lastSurfaceFormat, sink->lastBufferCaps)); + return GST_FLOW_OK; + } + + if (sink->delegate->supportedPixelFormats(pool->handleType()).isEmpty()) { + //qDebug() << "sink doesn't support native pool buffers, skip buffers allocation"; + return GST_FLOW_OK; + } + + GstCaps *intersection = gst_caps_intersect(get_caps(GST_BASE_SINK(sink)), caps); + + if (gst_caps_is_empty (intersection)) { + gst_caps_unref(intersection); + return GST_FLOW_NOT_NEGOTIATED; + } + + poolLock.unlock(); + + if (sink->delegate->isActive()) { + //if format was changed, restart the surface + QVideoSurfaceFormat format = formatForCaps(intersection); + QVideoSurfaceFormat surfaceFormat = sink->delegate->surfaceFormat(); + + if (format.pixelFormat() != surfaceFormat.pixelFormat() || + format.frameSize() != surfaceFormat.frameSize()) { +#ifdef DEBUG_VIDEO_SURFACE_SINK + qDebug() << "new format requested, restart video surface"; +#endif + sink->delegate->stop(); + } + } + + if (!sink->delegate->isActive()) { + int bytesPerLine = 0; + QVideoSurfaceFormat format = formatForCaps(intersection, &bytesPerLine); + + if (!sink->delegate->start(format, bytesPerLine)) { + qWarning() << "failed to start video surface"; + return GST_FLOW_NOT_NEGOTIATED; + } + } + + poolLock.relock(); + pool = sink->delegate->pool(); + + QVideoSurfaceFormat surfaceFormat = sink->delegate->surfaceFormat(); + + if (!pool->isFormatSupported(surfaceFormat)) { + //qDebug() << "sink doesn't support native pool format, skip custom buffers allocation"; + return GST_FLOW_OK; + } + + if (sink->lastRequestedCaps) + gst_caps_unref(sink->lastRequestedCaps); + sink->lastRequestedCaps = caps; + gst_caps_ref(sink->lastRequestedCaps); + + if (sink->lastBufferCaps) + gst_caps_unref(sink->lastBufferCaps); + sink->lastBufferCaps = intersection; + gst_caps_ref(sink->lastBufferCaps); + + *sink->lastSurfaceFormat = surfaceFormat; + + *buffer = GST_BUFFER(pool->takeBuffer(surfaceFormat, intersection)); + + return GST_FLOW_OK; +} + +gboolean QVideoSurfaceGstSink::start(GstBaseSink *base) +{ + Q_UNUSED(base); + + return TRUE; +} + +gboolean QVideoSurfaceGstSink::stop(GstBaseSink *base) +{ + Q_UNUSED(base); + + return TRUE; +} + +gboolean QVideoSurfaceGstSink::unlock(GstBaseSink *base) +{ + Q_UNUSED(base); + + return TRUE; +} + +gboolean QVideoSurfaceGstSink::event(GstBaseSink *base, GstEvent *event) +{ + Q_UNUSED(base); + Q_UNUSED(event); + + return TRUE; +} + +GstFlowReturn QVideoSurfaceGstSink::preroll(GstBaseSink *base, GstBuffer *buffer) +{ + VO_SINK(base); + return sink->delegate->render(buffer); +} + +GstFlowReturn QVideoSurfaceGstSink::render(GstBaseSink *base, GstBuffer *buffer) +{ + VO_SINK(base); + return sink->delegate->render(buffer); +} + diff --git a/src/plugins/gstreamer/qvideosurfacegstsink.h b/src/plugins/gstreamer/qvideosurfacegstsink.h new file mode 100644 index 000000000..531a76e0f --- /dev/null +++ b/src/plugins/gstreamer/qvideosurfacegstsink.h @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef VIDEOSURFACEGSTSINK_H +#define VIDEOSURFACEGSTSINK_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qabstractgstbufferpool.h" + +QT_BEGIN_NAMESPACE +class QAbstractVideoSurface; +QT_END_NAMESPACE + +#if defined(Q_WS_X11) && !defined(QT_NO_XVIDEO) +class QGstXvImageBuffer; +class QGstXvImageBufferPool; +#endif + +class QVideoSurfaceGstDelegate : public QObject +{ + Q_OBJECT +public: + QVideoSurfaceGstDelegate(QAbstractVideoSurface *surface); + ~QVideoSurfaceGstDelegate(); + + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const; + + QVideoSurfaceFormat surfaceFormat() const; + + bool start(const QVideoSurfaceFormat &format, int bytesPerLine); + void stop(); + + bool isActive(); + + QAbstractGstBufferPool *pool() { return m_pool; } + QMutex *poolMutex() { return &m_poolMutex; } + + GstFlowReturn render(GstBuffer *buffer); + +private slots: + void queuedStart(); + void queuedStop(); + void queuedRender(); + + void updateSupportedFormats(); + +private: + QPointer m_surface; + QList m_supportedPixelFormats; + //pixel formats of buffers pool native type + QList m_supportedPoolPixelFormats; + QAbstractGstBufferPool *m_pool; + QList m_pools; + QMutex m_poolMutex; + QMutex m_mutex; + QWaitCondition m_setupCondition; + QWaitCondition m_renderCondition; + QVideoSurfaceFormat m_format; + QVideoFrame m_frame; + GstFlowReturn m_renderReturn; + int m_bytesPerLine; + bool m_started; +}; + +class QVideoSurfaceGstSink +{ +public: + GstVideoSink parent; + + static QVideoSurfaceGstSink *createSink(QAbstractVideoSurface *surface); + static QVideoSurfaceFormat formatForCaps(GstCaps *caps, int *bytesPerLine = 0); + +private: + static GType get_type(); + static void class_init(gpointer g_class, gpointer class_data); + static void base_init(gpointer g_class); + static void instance_init(GTypeInstance *instance, gpointer g_class); + + static void finalize(GObject *object); + + static GstStateChangeReturn change_state(GstElement *element, GstStateChange transition); + + static GstCaps *get_caps(GstBaseSink *sink); + static gboolean set_caps(GstBaseSink *sink, GstCaps *caps); + + static GstFlowReturn buffer_alloc( + GstBaseSink *sink, guint64 offset, guint size, GstCaps *caps, GstBuffer **buffer); + + static gboolean start(GstBaseSink *sink); + static gboolean stop(GstBaseSink *sink); + + static gboolean unlock(GstBaseSink *sink); + + static gboolean event(GstBaseSink *sink, GstEvent *event); + static GstFlowReturn preroll(GstBaseSink *sink, GstBuffer *buffer); + static GstFlowReturn render(GstBaseSink *sink, GstBuffer *buffer); + +private: + QVideoSurfaceGstDelegate *delegate; + + GstCaps *lastRequestedCaps; + GstCaps *lastBufferCaps; + QVideoSurfaceFormat *lastSurfaceFormat; +}; + + +class QVideoSurfaceGstSinkClass +{ +public: + GstVideoSinkClass parent_class; +}; + +#endif diff --git a/src/plugins/gstreamer/qx11videosurface.cpp b/src/plugins/gstreamer/qx11videosurface.cpp new file mode 100644 index 000000000..ea2a1a3a2 --- /dev/null +++ b/src/plugins/gstreamer/qx11videosurface.cpp @@ -0,0 +1,535 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#ifndef QT_NO_XVIDEO + +#include "qx11videosurface.h" + +Q_DECLARE_METATYPE(XvImage*); + +struct XvFormatRgb +{ + QVideoFrame::PixelFormat pixelFormat; + int bits_per_pixel; + int format; + int num_planes; + + int depth; + unsigned int red_mask; + unsigned int green_mask; + unsigned int blue_mask; + +}; + +bool operator ==(const XvImageFormatValues &format, const XvFormatRgb &rgb) +{ + return format.type == XvRGB + && format.bits_per_pixel == rgb.bits_per_pixel + && format.format == rgb.format + && format.num_planes == rgb.num_planes + && format.depth == rgb.depth + && format.red_mask == rgb.red_mask + && format.blue_mask == rgb.blue_mask; +} + +static const XvFormatRgb qt_xvRgbLookup[] = +{ + { QVideoFrame::Format_ARGB32, 32, XvPacked, 1, 32, 0x00FF0000, 0x0000FF00, 0x000000FF }, + { QVideoFrame::Format_RGB32 , 32, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF }, + { QVideoFrame::Format_RGB24 , 24, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF }, + { QVideoFrame::Format_RGB565, 16, XvPacked, 1, 16, 0x0000F800, 0x000007E0, 0x0000001F }, + { QVideoFrame::Format_BGRA32, 32, XvPacked, 1, 32, 0xFF000000, 0x00FF0000, 0x0000FF00 }, + { QVideoFrame::Format_BGR32 , 32, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF }, + { QVideoFrame::Format_BGR24 , 24, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF }, + { QVideoFrame::Format_BGR565, 16, XvPacked, 1, 16, 0x0000F800, 0x000007E0, 0x0000001F } +}; + +struct XvFormatYuv +{ + QVideoFrame::PixelFormat pixelFormat; + int bits_per_pixel; + int format; + int num_planes; + + unsigned int y_sample_bits; + unsigned int u_sample_bits; + unsigned int v_sample_bits; + unsigned int horz_y_period; + unsigned int horz_u_period; + unsigned int horz_v_period; + unsigned int vert_y_period; + unsigned int vert_u_period; + unsigned int vert_v_period; + char component_order[32]; +}; + +bool operator ==(const XvImageFormatValues &format, const XvFormatYuv &yuv) +{ + return format.type == XvYUV + && format.bits_per_pixel == yuv.bits_per_pixel + && format.format == yuv.format + && format.num_planes == yuv.num_planes + && format.y_sample_bits == yuv.y_sample_bits + && format.u_sample_bits == yuv.u_sample_bits + && format.v_sample_bits == yuv.v_sample_bits + && format.horz_y_period == yuv.horz_y_period + && format.horz_u_period == yuv.horz_u_period + && format.horz_v_period == yuv.horz_v_period + && format.horz_y_period == yuv.vert_y_period + && format.vert_u_period == yuv.vert_u_period + && format.vert_v_period == yuv.vert_v_period + && qstrncmp(format.component_order, yuv.component_order, 32) == 0; +} + +static const XvFormatYuv qt_xvYuvLookup[] = +{ + { QVideoFrame::Format_YUV444 , 24, XvPacked, 1, 8, 8, 8, 1, 1, 1, 1, 1, 1, "YUV" }, + { QVideoFrame::Format_YUV420P, 12, XvPlanar, 3, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YUV" }, + { QVideoFrame::Format_YV12 , 12, XvPlanar, 3, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YVU" }, + { QVideoFrame::Format_UYVY , 16, XvPacked, 1, 8, 8, 8, 1, 2, 2, 1, 1, 1, "UYVY" }, + { QVideoFrame::Format_YUYV , 16, XvPacked, 1, 8, 8, 8, 1, 2, 2, 1, 1, 1, "YUY2" }, + { QVideoFrame::Format_YUYV , 16, XvPacked, 1, 8, 8, 8, 1, 2, 2, 1, 1, 1, "YUYV" }, + { QVideoFrame::Format_NV12 , 12, XvPlanar, 2, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YUV" }, + { QVideoFrame::Format_NV12 , 12, XvPlanar, 2, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YVU" }, + { QVideoFrame::Format_Y8 , 8 , XvPlanar, 1, 8, 0, 0, 1, 0, 0, 1, 0, 0, "Y" } +}; + +QX11VideoSurface::QX11VideoSurface(QObject *parent) + : QAbstractVideoSurface(parent) + , m_winId(0) + , m_portId(0) + , m_gc(0) + , m_image(0) +{ +} + +QX11VideoSurface::~QX11VideoSurface() +{ + if (m_gc) + XFreeGC(QX11Info::display(), m_gc); + + if (m_portId != 0) + XvUngrabPort(QX11Info::display(), m_portId, 0); +} + +WId QX11VideoSurface::winId() const +{ + return m_winId; +} + +void QX11VideoSurface::setWinId(WId id) +{ + //qDebug() << "setWinID:" << id; + + if (id == m_winId) + return; + + if (m_image) + XFree(m_image); + + if (m_gc) { + XFreeGC(QX11Info::display(), m_gc); + m_gc = 0; + } + + if (m_portId != 0) + XvUngrabPort(QX11Info::display(), m_portId, 0); + + m_supportedPixelFormats.clear(); + m_formatIds.clear(); + + m_winId = id; + + if (m_winId && findPort()) { + querySupportedFormats(); + + m_gc = XCreateGC(QX11Info::display(), m_winId, 0, 0); + + if (m_image) { + m_image = 0; + + if (!start(surfaceFormat())) { + QAbstractVideoSurface::stop(); + qWarning() << "Failed to start video surface with format" << surfaceFormat(); + } + } + } else { + qWarning() << "Failed to find XVideo port"; + if (m_image) { + m_image = 0; + + QAbstractVideoSurface::stop(); + } + } + + emit supportedFormatsChanged(); +} + +QRect QX11VideoSurface::displayRect() const +{ + return m_displayRect; +} + +void QX11VideoSurface::setDisplayRect(const QRect &rect) +{ + m_displayRect = rect; +} + +QRect QX11VideoSurface::viewport() const +{ + return m_viewport; +} + +void QX11VideoSurface::setViewport(const QRect &rect) +{ + m_viewport = rect; +} + +int QX11VideoSurface::brightness() const +{ + return getAttribute("XV_BRIGHTNESS", m_brightnessRange.first, m_brightnessRange.second); +} + +void QX11VideoSurface::setBrightness(int brightness) +{ + setAttribute("XV_BRIGHTNESS", brightness, m_brightnessRange.first, m_brightnessRange.second); +} + +int QX11VideoSurface::contrast() const +{ + return getAttribute("XV_CONTRAST", m_contrastRange.first, m_contrastRange.second); +} + +void QX11VideoSurface::setContrast(int contrast) +{ + setAttribute("XV_CONTRAST", contrast, m_contrastRange.first, m_contrastRange.second); +} + +int QX11VideoSurface::hue() const +{ + return getAttribute("XV_HUE", m_hueRange.first, m_hueRange.second); +} + +void QX11VideoSurface::setHue(int hue) +{ + setAttribute("XV_HUE", hue, m_hueRange.first, m_hueRange.second); +} + +int QX11VideoSurface::saturation() const +{ + return getAttribute("XV_SATURATION", m_saturationRange.first, m_saturationRange.second); +} + +void QX11VideoSurface::setSaturation(int saturation) +{ + setAttribute("XV_SATURATION", saturation, m_saturationRange.first, m_saturationRange.second); +} + +int QX11VideoSurface::getAttribute(const char *attribute, int minimum, int maximum) const +{ + if (m_portId != 0) { + Display *display = QX11Info::display(); + + Atom atom = XInternAtom(display, attribute, True); + + int value = 0; + + XvGetPortAttribute(display, m_portId, atom, &value); + + return redistribute(value, minimum, maximum, -100, 100); + } else { + return 0; + } +} + +void QX11VideoSurface::setAttribute(const char *attribute, int value, int minimum, int maximum) +{ + if (m_portId != 0) { + Display *display = QX11Info::display(); + + Atom atom = XInternAtom(display, attribute, True); + + XvSetPortAttribute( + display, m_portId, atom, redistribute(value, -100, 100, minimum, maximum)); + } +} + +int QX11VideoSurface::redistribute( + int value, int fromLower, int fromUpper, int toLower, int toUpper) +{ + return fromUpper != fromLower + ? ((value - fromLower) * (toUpper - toLower) / (fromUpper - fromLower)) + toLower + : 0; +} + +QList QX11VideoSurface::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + return handleType == QAbstractVideoBuffer::NoHandle || handleType == QAbstractVideoBuffer::XvShmImageHandle + ? m_supportedPixelFormats + : QList(); +} + +bool QX11VideoSurface::start(const QVideoSurfaceFormat &format) +{ + if (m_image) + XFree(m_image); + + int xvFormatId = 0; + for (int i = 0; i < m_supportedPixelFormats.count(); ++i) { + if (m_supportedPixelFormats.at(i) == format.pixelFormat()) { + xvFormatId = m_formatIds.at(i); + break; + } + } + + if (xvFormatId == 0) { + setError(UnsupportedFormatError); + } else { + XvImage *image = XvCreateImage( + QX11Info::display(), + m_portId, + xvFormatId, + 0, + format.frameWidth(), + format.frameHeight()); + + if (!image) { + setError(ResourceError); + } else { + m_viewport = format.viewport(); + m_image = image; + + QVideoSurfaceFormat newFormat = format; + newFormat.setProperty("portId", QVariant(quint64(m_portId))); + newFormat.setProperty("xvFormatId", xvFormatId); + newFormat.setProperty("dataSize", image->data_size); + + return QAbstractVideoSurface::start(newFormat); + } + } + + if (m_image) { + m_image = 0; + + QAbstractVideoSurface::stop(); + } + + return false; +} + +void QX11VideoSurface::stop() +{ + if (m_image) { + XFree(m_image); + m_image = 0; + + QAbstractVideoSurface::stop(); + } +} + +bool QX11VideoSurface::present(const QVideoFrame &frame) +{ + if (!m_image) { + setError(StoppedError); + return false; + } else if (m_image->width != frame.width() || m_image->height != frame.height()) { + setError(IncorrectFormatError); + return false; + } else { + QVideoFrame frameCopy(frame); + + if (!frameCopy.map(QAbstractVideoBuffer::ReadOnly)) { + setError(IncorrectFormatError); + return false; + } else { + bool presented = false; + + if (frame.handleType() != QAbstractVideoBuffer::XvShmImageHandle && + m_image->data_size > frame.mappedBytes()) { + qWarning("Insufficient frame buffer size"); + setError(IncorrectFormatError); + } else if (frame.handleType() != QAbstractVideoBuffer::XvShmImageHandle && + m_image->num_planes > 0 && + m_image->pitches[0] != frame.bytesPerLine()) { + qWarning("Incompatible frame pitches"); + setError(IncorrectFormatError); + } else { + if (frame.handleType() != QAbstractVideoBuffer::XvShmImageHandle) { + m_image->data = reinterpret_cast(frameCopy.bits()); + + //qDebug() << "copy frame"; + XvPutImage( + QX11Info::display(), + m_portId, + m_winId, + m_gc, + m_image, + m_viewport.x(), + m_viewport.y(), + m_viewport.width(), + m_viewport.height(), + m_displayRect.x(), + m_displayRect.y(), + m_displayRect.width(), + m_displayRect.height()); + + m_image->data = 0; + } else { + XvImage *img = frame.handle().value(); + + //qDebug() << "render directly"; + if (img) + XvShmPutImage( + QX11Info::display(), + m_portId, + m_winId, + m_gc, + img, + m_viewport.x(), + m_viewport.y(), + m_viewport.width(), + m_viewport.height(), + m_displayRect.x(), + m_displayRect.y(), + m_displayRect.width(), + m_displayRect.height(), + false); + } + + presented = true; + } + + frameCopy.unmap(); + + return presented; + } + } +} + +bool QX11VideoSurface::findPort() +{ + unsigned int count = 0; + XvAdaptorInfo *adaptors = 0; + bool portFound = false; + + if (XvQueryAdaptors(QX11Info::display(), m_winId, &count, &adaptors) == Success) { +#ifdef Q_WS_MAEMO_5 + //the overlay xvideo adapter fails to switch winId, + //prefer the "SGX Textured Video" adapter instead + for (int i = count-1; i >= 0 && !portFound; --i) { +#else + for (unsigned int i = 0; i < count && !portFound; ++i) { +#endif + if (adaptors[i].type & XvImageMask) { + m_portId = adaptors[i].base_id; + + for (unsigned int j = 0; j < adaptors[i].num_ports && !portFound; ++j, ++m_portId) + portFound = XvGrabPort(QX11Info::display(), m_portId, 0) == Success; + } + } + XvFreeAdaptorInfo(adaptors); + } + + return portFound; +} + +void QX11VideoSurface::querySupportedFormats() +{ + int count = 0; + if (XvImageFormatValues *imageFormats = XvListImageFormats( + QX11Info::display(), m_portId, &count)) { + const int rgbCount = sizeof(qt_xvRgbLookup) / sizeof(XvFormatRgb); + const int yuvCount = sizeof(qt_xvYuvLookup) / sizeof(XvFormatYuv); + + for (int i = 0; i < count; ++i) { + switch (imageFormats[i].type) { + case XvRGB: + for (int j = 0; j < rgbCount; ++j) { + if (imageFormats[i] == qt_xvRgbLookup[j]) { + m_supportedPixelFormats.append(qt_xvRgbLookup[j].pixelFormat); + m_formatIds.append(imageFormats[i].id); + break; + } + } + break; + case XvYUV: + for (int j = 0; j < yuvCount; ++j) { + if (imageFormats[i] == qt_xvYuvLookup[j]) { + m_supportedPixelFormats.append(qt_xvYuvLookup[j].pixelFormat); + m_formatIds.append(imageFormats[i].id); + break; + } + } + break; + } + } + XFree(imageFormats); + } + + m_brightnessRange = qMakePair(0, 0); + m_contrastRange = qMakePair(0, 0); + m_hueRange = qMakePair(0, 0); + m_saturationRange = qMakePair(0, 0); + + if (XvAttribute *attributes = XvQueryPortAttributes(QX11Info::display(), m_portId, &count)) { + for (int i = 0; i < count; ++i) { + if (qstrcmp(attributes[i].name, "XV_BRIGHTNESS") == 0) + m_brightnessRange = qMakePair(attributes[i].min_value, attributes[i].max_value); + else if (qstrcmp(attributes[i].name, "XV_CONTRAST") == 0) + m_contrastRange = qMakePair(attributes[i].min_value, attributes[i].max_value); + else if (qstrcmp(attributes[i].name, "XV_HUE") == 0) + m_hueRange = qMakePair(attributes[i].min_value, attributes[i].max_value); + else if (qstrcmp(attributes[i].name, "XV_SATURATION") == 0) + m_saturationRange = qMakePair(attributes[i].min_value, attributes[i].max_value); + } + + XFree(attributes); + } +} + +#endif //QT_NO_XVIDEO + diff --git a/src/plugins/gstreamer/qx11videosurface.h b/src/plugins/gstreamer/qx11videosurface.h new file mode 100644 index 000000000..7bebe2f67 --- /dev/null +++ b/src/plugins/gstreamer/qx11videosurface.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QX11VIDEOSURFACE_H +#define QX11VIDEOSURFACE_H + +#include +#include + +#ifndef QT_NO_XVIDEO + +#include +#include +#include + +QT_USE_NAMESPACE + +class QX11VideoSurface : public QAbstractVideoSurface +{ + Q_OBJECT +public: + QX11VideoSurface(QObject *parent = 0); + ~QX11VideoSurface(); + + WId winId() const; + void setWinId(WId id); + + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + + QRect viewport() const; + void setViewport(const QRect &rect); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const; + + bool start(const QVideoSurfaceFormat &format); + void stop(); + + bool present(const QVideoFrame &frame); + +private: + WId m_winId; + XvPortID m_portId; + GC m_gc; + XvImage *m_image; + QList m_supportedPixelFormats; + QVector m_formatIds; + QRect m_viewport; + QRect m_displayRect; + QPair m_brightnessRange; + QPair m_contrastRange; + QPair m_hueRange; + QPair m_saturationRange; + + bool findPort(); + void querySupportedFormats(); + + int getAttribute(const char *attribute, int minimum, int maximum) const; + void setAttribute(const char *attribute, int value, int minimum, int maximum); + + static int redistribute(int value, int fromLower, int fromUpper, int toLower, int toUpper); +}; + +#endif //QT_NO_XVIDEO + +#endif diff --git a/src/plugins/m3u/m3u.pro b/src/plugins/m3u/m3u.pro new file mode 100644 index 000000000..f639445ee --- /dev/null +++ b/src/plugins/m3u/m3u.pro @@ -0,0 +1,23 @@ +load(qt_module) + +TARGET = qtmultimediakit_m3u +QT += multimediakit-private +PLUGIN_TYPE=playlistformats + +load(qt_plugin) +DESTDIR = $$QT.multimediakit.plugins/$${PLUGIN_TYPE} + + +HEADERS += qm3uhandler.h +SOURCES += main.cpp \ + qm3uhandler.cpp +symbian { + TARGET.UID3 = 0x2002BFC7 + TARGET.CAPABILITY = ALL -TCB + TARGET.EPOCALLOWDLLDATA = 1 + + #make a sis package from plugin + stub (plugin) + pluginDep.sources = $${TARGET}.dll + pluginDep.path = $${QT_PLUGINS_BASE_DIR}/$${PLUGIN_TYPE} + DEPLOYMENT += pluginDep +} diff --git a/src/plugins/m3u/main.cpp b/src/plugins/m3u/main.cpp new file mode 100644 index 000000000..4fd78d7dd --- /dev/null +++ b/src/plugins/m3u/main.cpp @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qm3uhandler.h" +#include + + +Q_EXPORT_STATIC_PLUGIN(QM3uPlaylistPlugin) +Q_EXPORT_PLUGIN2(qtmultimediakit_m3u, QM3uPlaylistPlugin) diff --git a/src/plugins/m3u/qm3uhandler.cpp b/src/plugins/m3u/qm3uhandler.cpp new file mode 100644 index 000000000..69e86a1a9 --- /dev/null +++ b/src/plugins/m3u/qm3uhandler.cpp @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qm3uhandler.h" +#include +#include +#include +#include +#include +#include + + +class QM3uPlaylistReader : public QMediaPlaylistReader +{ +public: + QM3uPlaylistReader(QIODevice *device) + :m_ownDevice(false), m_device(device), m_textStream(new QTextStream(m_device)) + { + readItem(); + } + + QM3uPlaylistReader(const QUrl& location) + :m_location(location), m_ownDevice(true) + { + QFile *f = new QFile(location.toLocalFile()); + if (f->open(QIODevice::ReadOnly | QIODevice::Text)) { + m_device = f; + m_textStream = new QTextStream(m_device); + readItem(); + } else { + delete f; + m_device = 0; + m_textStream = 0; + } + } + + virtual ~QM3uPlaylistReader() + { + if (m_ownDevice) { + delete m_device; + } + delete m_textStream; + } + + virtual bool atEnd() const + { + //we can't just use m_textStream->atEnd(), + //for files with empty lines/comments at end + return nextResource.isNull(); + } + + virtual QMediaContent readItem() + { + QMediaContent item; + if (!nextResource.isNull()) + item = QMediaContent(nextResource); + + nextResource = QMediaContent(); + + while (m_textStream && !m_textStream->atEnd()) { + QString line = m_textStream->readLine().trimmed(); + if (line.isEmpty() || line[0] == '#' || line.size() > 4096) + continue; + + QUrl fileUrl = QUrl::fromLocalFile(line); + QUrl url(line); + + //m3u may contain url encoded entries or absolute/relative file names + //prefer existing file if any + QList candidates; + if (!m_location.isEmpty()) { + candidates << m_location.resolved(fileUrl); + candidates << m_location.resolved(url); + } + candidates << fileUrl; + candidates << url; + + foreach (const QUrl &candidate, candidates) { + if (QFile::exists(candidate.toLocalFile())) { + nextResource = candidate; + break; + } + } + + if (nextResource.isNull()) { + //assume the relative urls are file names, not encoded urls if m3u is local file + if (!m_location.isEmpty() && url.isRelative()) { + if (m_location.scheme() == QLatin1String("file")) + nextResource = m_location.resolved(fileUrl); + else + nextResource = m_location.resolved(url); + } else { + nextResource = QMediaContent(QUrl::fromUserInput(line)); + } + } + + break; + } + + return item; + } + + virtual void close() + { + } + +private: + QUrl m_location; + bool m_ownDevice; + QIODevice *m_device; + QTextStream *m_textStream; + QMediaContent nextResource; +}; + +class QM3uPlaylistWriter : public QMediaPlaylistWriter +{ +public: + QM3uPlaylistWriter(QIODevice *device) + :m_device(device), m_textStream(new QTextStream(m_device)) + { + } + + virtual ~QM3uPlaylistWriter() + { + delete m_textStream; + } + + virtual bool writeItem(const QMediaContent& item) + { + *m_textStream << item.canonicalUrl().toString() << endl; + return true; + } + + virtual void close() + { + } + +private: + QIODevice *m_device; + QTextStream *m_textStream; +}; + + +QM3uPlaylistPlugin::QM3uPlaylistPlugin(QObject *parent) + :QMediaPlaylistIOPlugin(parent) +{ +} + +QM3uPlaylistPlugin::~QM3uPlaylistPlugin() +{ +} + +bool QM3uPlaylistPlugin::canRead(QIODevice *device, const QByteArray &format) const +{ + return device->isReadable() && (format == "m3u" || format.isEmpty()); +} + +bool QM3uPlaylistPlugin::canRead(const QUrl& location, const QByteArray &format) const +{ + if (!QFileInfo(location.toLocalFile()).isReadable()) + return false; + + if (format == "m3u") + return true; + + if (!format.isEmpty()) + return false; + else + return location.toLocalFile().toLower().endsWith(QLatin1String("m3u")); +} + +bool QM3uPlaylistPlugin::canWrite(QIODevice *device, const QByteArray &format) const +{ + return device->isOpen() && device->isWritable() && format == "m3u"; +} + +QStringList QM3uPlaylistPlugin::keys() const +{ + return QStringList() << QLatin1String("m3u"); +} + +QMediaPlaylistReader *QM3uPlaylistPlugin::createReader(QIODevice *device, const QByteArray &format) +{ + Q_UNUSED(format); + return new QM3uPlaylistReader(device); +} + +QMediaPlaylistReader *QM3uPlaylistPlugin::createReader(const QUrl& location, const QByteArray &format) +{ + Q_UNUSED(format); + return new QM3uPlaylistReader(location); +} + +QMediaPlaylistWriter *QM3uPlaylistPlugin::createWriter(QIODevice *device, const QByteArray &format) +{ + Q_UNUSED(format); + return new QM3uPlaylistWriter(device); +} + diff --git a/src/plugins/m3u/qm3uhandler.h b/src/plugins/m3u/qm3uhandler.h new file mode 100644 index 000000000..18d088ddd --- /dev/null +++ b/src/plugins/m3u/qm3uhandler.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QM3UHANDLER_H +#define QM3UHANDLER_H + +#include "qmediaplaylistioplugin.h" +#include + +QT_USE_NAMESPACE + +class QM3uPlaylistPlugin : public QMediaPlaylistIOPlugin +{ +Q_OBJECT +public: + explicit QM3uPlaylistPlugin(QObject *parent = 0); + virtual ~QM3uPlaylistPlugin(); + + virtual bool canRead(QIODevice *device, const QByteArray &format = QByteArray() ) const; + virtual bool canRead(const QUrl& location, const QByteArray &format = QByteArray()) const; + + virtual bool canWrite(QIODevice *device, const QByteArray &format) const; + + virtual QStringList keys() const; + + virtual QMediaPlaylistReader *createReader(QIODevice *device, const QByteArray &format = QByteArray()); + virtual QMediaPlaylistReader *createReader(const QUrl& location, const QByteArray &format = QByteArray()); + + virtual QMediaPlaylistWriter *createWriter(QIODevice *device, const QByteArray &format); +}; + +#endif // QM3UHANDLER_H diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro new file mode 100644 index 000000000..5a96fded0 --- /dev/null +++ b/src/plugins/plugins.pro @@ -0,0 +1,46 @@ +###################################################################### +# +# Mobility API project - multimedia +# +###################################################################### + +TEMPLATE = subdirs + +SUBDIRS += m3u + +win32 { + SUBDIRS += audiocapture +} + +win32:!wince* { + contains(directshow_enabled, yes): SUBDIRS += directshow +} + +simulator: SUBDIRS += simulator + +unix:!mac:!symbian { + TMP_GST_LIBS = \ + gstreamer-0.10 >= 0.10.19 \ + gstreamer-base-0.10 >= 0.10.19 \ + gstreamer-interfaces-0.10 >= 0.10.19 \ + gstreamer-audio-0.10 >= 0.10.19 \ + gstreamer-video-0.10 >= 0.10.19 + + system(pkg-config --exists \'$${TMP_GST_LIBS}\' --print-errors): { + SUBDIRS += gstreamer + } else { + SUBDIRS += audiocapture + } + + !maemo*:SUBDIRS += v4l + + contains(pulseaudio_enabled, yes) { + SUBDIRS += pulseaudio + } +} + +mac:!simulator { + SUBDIRS += audiocapture qt7 +} + +symbian:SUBDIRS += symbian diff --git a/src/plugins/pulseaudio/pulseaudio.pro b/src/plugins/pulseaudio/pulseaudio.pro new file mode 100644 index 000000000..2f9b7a854 --- /dev/null +++ b/src/plugins/pulseaudio/pulseaudio.pro @@ -0,0 +1,26 @@ +load(qt_module) + +TARGET = qtmedia_pulse +QT += multimediakit-private +PLUGIN_TYPE = audio + +load(qt_plugin) +DESTDIR = $$QT.multimediakit.plugins/$${PLUGIN_TYPE} + +CONFIG += link_pkgconfig +PKGCONFIG += libpulse + +# Input +HEADERS += qpulseaudioplugin.h \ + qaudiodeviceinfo_pulse.h \ + qaudiooutput_pulse.h \ + qaudioinput_pulse.h \ + qpulseaudioengine.h \ + qpulsehelpers.h + +SOURCES += qpulseaudioplugin.cpp \ + qaudiodeviceinfo_pulse.cpp \ + qaudiooutput_pulse.cpp \ + qaudioinput_pulse.cpp \ + qpulseaudioengine.cpp \ + qpulsehelpers.cpp diff --git a/src/plugins/pulseaudio/qaudiodeviceinfo_pulse.cpp b/src/plugins/pulseaudio/qaudiodeviceinfo_pulse.cpp new file mode 100644 index 000000000..54296861d --- /dev/null +++ b/src/plugins/pulseaudio/qaudiodeviceinfo_pulse.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaudiodeviceinfo_pulse.h" +#include "qpulseaudioengine.h" +#include "qpulsehelpers.h" + +QT_BEGIN_NAMESPACE + +QPulseAudioDeviceInfo::QPulseAudioDeviceInfo(const QByteArray &device, QAudio::Mode mode) + : m_device(device) + , m_mode(mode) +{ +} + +bool QPulseAudioDeviceInfo::isFormatSupported(const QAudioFormat &format) const +{ + pa_sample_spec spec = QPulseAudioInternal::audioFormatToSampleSpec(format); + if (!pa_sample_spec_valid(&spec)) + return false; + + return true; +} + +QAudioFormat QPulseAudioDeviceInfo::preferredFormat() const +{ + QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); + QAudioFormat format = pulseEngine->m_preferredFormats.value(m_device); + return format; +} + +QString QPulseAudioDeviceInfo::deviceName() const +{ + return m_device; +} + +QStringList QPulseAudioDeviceInfo::supportedCodecs() +{ + return QStringList() << "audio/pcm"; +} + +QList QPulseAudioDeviceInfo::supportedSampleRates() +{ + return QList() << 8000 << 11025 << 22050 << 44100 << 48000; +} + +QList QPulseAudioDeviceInfo::supportedChannelCounts() +{ + return QList() << 1 << 2 << 4 << 6 << 8; +} + +QList QPulseAudioDeviceInfo::supportedSampleSizes() +{ + return QList() << 8 << 16 << 24 << 32; +} + +QList QPulseAudioDeviceInfo::supportedByteOrders() +{ + return QList() << QAudioFormat::BigEndian << QAudioFormat::LittleEndian; +} + +QList QPulseAudioDeviceInfo::supportedSampleTypes() +{ + return QList() << QAudioFormat::SignedInt << QAudioFormat::UnSignedInt << QAudioFormat::Float; +} + +QT_END_NAMESPACE diff --git a/src/plugins/pulseaudio/qaudiodeviceinfo_pulse.h b/src/plugins/pulseaudio/qaudiodeviceinfo_pulse.h new file mode 100644 index 000000000..f76913ca3 --- /dev/null +++ b/src/plugins/pulseaudio/qaudiodeviceinfo_pulse.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAUDIODEVICEINFOPULSE_H +#define QAUDIODEVICEINFOPULSE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +#include "qaudio.h" +#include "qaudiodeviceinfo.h" +#include "qaudiosystem.h" + +QT_BEGIN_NAMESPACE + +class QPulseAudioDeviceInfo : public QAbstractAudioDeviceInfo +{ + Q_OBJECT + +public: + QPulseAudioDeviceInfo(const QByteArray &device, QAudio::Mode mode); + ~QPulseAudioDeviceInfo() {} + + QAudioFormat preferredFormat() const; + bool isFormatSupported(const QAudioFormat &format) const; + QString deviceName() const; + QStringList supportedCodecs(); + QList supportedSampleRates(); + QList supportedChannelCounts(); + QList supportedSampleSizes(); + QList supportedByteOrders(); + QList supportedSampleTypes(); + +private: + QByteArray m_device; + QAudio::Mode m_mode; +}; + +QT_END_NAMESPACE + +#endif + diff --git a/src/plugins/pulseaudio/qaudioinput_pulse.cpp b/src/plugins/pulseaudio/qaudioinput_pulse.cpp new file mode 100644 index 000000000..083bbabb6 --- /dev/null +++ b/src/plugins/pulseaudio/qaudioinput_pulse.cpp @@ -0,0 +1,600 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "qaudioinput_pulse.h" +#include "qaudiodeviceinfo_pulse.h" +#include "qpulseaudioengine.h" +#include "qpulsehelpers.h" + +QT_BEGIN_NAMESPACE + +const int PeriodTimeMs = 50; + +static void inputStreamReadCallback(pa_stream *stream, size_t length, void *userdata) +{ + Q_UNUSED(userdata); + Q_UNUSED(length); + Q_UNUSED(stream); + QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); + pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0); +} + +static void inputStreamStateCallback(pa_stream *stream, void *userdata) +{ + Q_UNUSED(userdata); + pa_stream_state_t state = pa_stream_get_state(stream); +#ifdef DEBUG_PULSE + qDebug() << "Stream state: " << QPulseAudioInternal::stateToQString(state); +#endif + switch (state) { + case PA_STREAM_CREATING: + break; + case PA_STREAM_READY: { +#ifdef DEBUG_PULSE + QPulseAudioInput *audioInput = static_cast(userdata); + const pa_buffer_attr *buffer_attr = pa_stream_get_buffer_attr(stream); + qDebug() << "*** maxlength: " << buffer_attr->maxlength; + qDebug() << "*** prebuf: " << buffer_attr->prebuf; + qDebug() << "*** fragsize: " << buffer_attr->fragsize; + qDebug() << "*** minreq: " << buffer_attr->minreq; + qDebug() << "*** tlength: " << buffer_attr->tlength; + + pa_sample_spec spec = QPulseAudioInternal::audioFormatToSampleSpec(audioInput->format()); + qDebug() << "*** bytes_to_usec: " << pa_bytes_to_usec(buffer_attr->fragsize, &spec); +#endif + } + break; + case PA_STREAM_TERMINATED: + break; + case PA_STREAM_FAILED: + default: + qWarning() << QString("Stream error: %1").arg(pa_strerror(pa_context_errno(pa_stream_get_context(stream)))); + QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); + pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0); + break; + } +} + +static void inputStreamUnderflowCallback(pa_stream *stream, void *userdata) +{ + Q_UNUSED(userdata) + Q_UNUSED(stream) + qWarning() << "Got a buffer underflow!"; +} + +static void inputStreamOverflowCallback(pa_stream *stream, void *userdata) +{ + Q_UNUSED(stream) + Q_UNUSED(userdata) + qWarning() << "Got a buffer overflow!"; +} + +static void inputStreamSuccessCallback(pa_stream *stream, int success, void *userdata) +{ + Q_UNUSED(stream); + Q_UNUSED(userdata); + Q_UNUSED(success); + + //if (!success) + //TODO: Is cork success? i->operation_success = success; + + QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); + pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0); +} + +QPulseAudioInput::QPulseAudioInput(const QByteArray &device) + : m_totalTimeValue(0) + , m_audioSource(0) + , m_errorState(QAudio::NoError) + , m_deviceState(QAudio::StoppedState) + , m_pullMode(true) + , m_opened(false) + , m_bytesAvailable(0) + , m_bufferSize(0) + , m_periodSize(0) + , m_intervalTime(1000) + , m_stream(0) + , m_device(device) +{ + m_timer = new QTimer(this); + connect(m_timer, SIGNAL(timeout()), SLOT(userFeed())); +} + +QPulseAudioInput::~QPulseAudioInput() +{ + close(); + disconnect(m_timer, SIGNAL(timeout())); + QCoreApplication::processEvents(); + delete m_timer; +} + +QAudio::Error QPulseAudioInput::error() const +{ + return m_errorState; +} + +QAudio::State QPulseAudioInput::state() const +{ + return m_deviceState; +} + +void QPulseAudioInput::setFormat(const QAudioFormat &format) +{ + if (m_deviceState == QAudio::StoppedState) + m_format = format; +} + +QAudioFormat QPulseAudioInput::format() const +{ + return m_format; +} + +void QPulseAudioInput::start(QIODevice *device) +{ + if (m_deviceState != QAudio::StoppedState) + close(); + + if (!m_pullMode && m_audioSource) + delete m_audioSource; + + m_pullMode = true; + m_audioSource = device; + + m_deviceState = QAudio::ActiveState; + + if (!open()) + return; + + emit stateChanged(m_deviceState); +} + +QIODevice *QPulseAudioInput::start() +{ + if (m_deviceState != QAudio::StoppedState) + close(); + + if (!m_pullMode && m_audioSource) + delete m_audioSource; + + m_pullMode = false; + m_audioSource = new InputPrivate(this); + m_audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered); + + m_deviceState = QAudio::IdleState; + + if (!open()) + return 0; + + emit stateChanged(m_deviceState); + + return m_audioSource; +} + +void QPulseAudioInput::stop() +{ + if (m_deviceState == QAudio::StoppedState) + return; + + m_errorState = QAudio::NoError; + m_deviceState = QAudio::StoppedState; + + close(); + emit stateChanged(m_deviceState); +} + +bool QPulseAudioInput::open() +{ + if (m_opened) + return false; + +#ifdef DEBUG_PULSE +// QTime now(QTime::currentTime()); +// qDebug()<mainloop()); + pa_channel_map channel_map; + + pa_channel_map_init_extend(&channel_map, spec.channels, PA_CHANNEL_MAP_DEFAULT); + + if (!pa_channel_map_compatible(&channel_map, &spec)) { + qWarning() << "Channel map doesn't match sample specification!"; + } + + m_stream = pa_stream_new(pulseEngine->context(), m_streamName.constData(), &spec, &channel_map); + + pa_stream_set_state_callback(m_stream, inputStreamStateCallback, this); + pa_stream_set_read_callback(m_stream, inputStreamReadCallback, this); + + pa_stream_set_underflow_callback(m_stream, inputStreamUnderflowCallback, this); + pa_stream_set_overflow_callback(m_stream, inputStreamOverflowCallback, this); + + m_periodSize = pa_usec_to_bytes(PeriodTimeMs*1000, &spec); + + int flags = 0; + pa_buffer_attr buffer_attr; + buffer_attr.maxlength = (uint32_t) -1; + buffer_attr.prebuf = (uint32_t) -1; + buffer_attr.tlength = (uint32_t) -1; + buffer_attr.minreq = (uint32_t) -1; + flags |= PA_STREAM_ADJUST_LATENCY; + + if (m_bufferSize > 0) + buffer_attr.fragsize = (uint32_t) m_bufferSize; + else + buffer_attr.fragsize = (uint32_t) m_periodSize; + + if (pa_stream_connect_record(m_stream, m_device.data(), &buffer_attr, (pa_stream_flags_t)flags) < 0) { + qWarning() << "pa_stream_connect_record() failed!"; + m_errorState = QAudio::FatalError; + return false; + } + + while (pa_stream_get_state(m_stream) != PA_STREAM_READY) { + pa_threaded_mainloop_wait(pulseEngine->mainloop()); + } + pa_threaded_mainloop_unlock(pulseEngine->mainloop()); + + m_opened = true; + m_periodSize = pa_usec_to_bytes(PeriodTimeMs*1000, &spec); + m_timer->start(PeriodTimeMs); + m_errorState = QAudio::NoError; + + m_totalTimeValue = 0; + + return true; +} + +void QPulseAudioInput::close() +{ + m_timer->stop(); + + if (m_stream) { + QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); + pa_threaded_mainloop_lock(pulseEngine->mainloop()); + + pa_stream_set_read_callback(m_stream, 0, 0); + + pa_stream_disconnect(m_stream); + pa_stream_unref(m_stream); + m_stream = 0; + + pa_threaded_mainloop_unlock(pulseEngine->mainloop()); + } + + if (!m_pullMode && m_audioSource) { + delete m_audioSource; + m_audioSource = 0; + } + m_opened = false; +} + +int QPulseAudioInput::checkBytesReady() +{ + if (m_deviceState != QAudio::ActiveState && m_deviceState != QAudio::IdleState) { + m_bytesAvailable = 0; + } else { + m_bytesAvailable = pa_stream_readable_size(m_stream); + } + + return m_bytesAvailable; +} + +int QPulseAudioInput::bytesReady() const +{ + return qMax(m_bytesAvailable, 0); +} + +qint64 QPulseAudioInput::read(char *data, qint64 len) +{ + m_bytesAvailable = checkBytesReady(); + + if (m_deviceState != QAudio::ActiveState) { + m_errorState = QAudio::NoError; + m_deviceState = QAudio::ActiveState; + emit stateChanged(m_deviceState); + } + + size_t readBytes = 0; + + if (!m_pullMode && !m_tempBuffer.isEmpty()) { + readBytes = qMin(static_cast(len), m_tempBuffer.size()); + memcpy(data, m_tempBuffer.constData(), readBytes); + m_totalTimeValue += readBytes; + + if (readBytes < m_tempBuffer.size()) { + m_tempBuffer.remove(0, readBytes); + return readBytes; + } + + m_tempBuffer.clear(); + } + + while (pa_stream_readable_size(m_stream) > 0) { + size_t readLength = 0; + +#ifdef DEBUG_PULSE + qDebug() << "QPulseAudioInput::read -- " << pa_stream_readable_size(m_stream) << " bytes available from pulse audio"; +#endif + + QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); + pa_threaded_mainloop_lock(pulseEngine->mainloop()); + const void *audioBuffer; + + // Second and third parameters (audioBuffer and length) to pa_stream_peek are output parameters, + // the audioBuffer pointer is set to point to the actual pulse audio data, + // and the length is set to the length of this data. + if (pa_stream_peek(m_stream, &audioBuffer, &readLength) < 0) { + qWarning() << QString("pa_stream_peek() failed: %1").arg(pa_strerror(pa_context_errno(pa_stream_get_context(m_stream)))); + pa_threaded_mainloop_unlock(pulseEngine->mainloop()); + return 0; + } + + qint64 actualLength = 0; + if (m_pullMode) { + actualLength = m_audioSource->write(static_cast(audioBuffer), readLength); + + if (actualLength < readLength) { + pa_threaded_mainloop_unlock(pulseEngine->mainloop()); + + m_errorState = QAudio::UnderrunError; + m_deviceState = QAudio::IdleState; + emit stateChanged(m_deviceState); + + return actualLength; + } + } else { + actualLength = qMin(static_cast(len - readBytes), static_cast(readLength)); + memcpy(data + readBytes, audioBuffer, actualLength); + } + +#ifdef DEBUG_PULSE + qDebug() << "QPulseAudioInput::read -- wrote " << actualLength << " to client"; +#endif + + if (actualLength < readLength) { +#ifdef DEBUG_PULSE + qDebug() << "QPulseAudioInput::read -- appending " << readLength - actualLength << " bytes of data to temp buffer"; +#endif + m_tempBuffer.append(static_cast(audioBuffer) + actualLength, readLength - actualLength); + QMetaObject::invokeMethod(this, "userFeed", Qt::QueuedConnection); + } + + m_totalTimeValue += actualLength; + readBytes += actualLength; + + pa_stream_drop(m_stream); + pa_threaded_mainloop_unlock(pulseEngine->mainloop()); + + if (!m_pullMode && readBytes >= len) + break; + } + +#ifdef DEBUG_PULSE + qDebug() << "QPulseAudioInput::read -- returning after reading " << readBytes << " bytes"; +#endif + + return readBytes; +} + +void QPulseAudioInput::resume() +{ + if (m_deviceState == QAudio::SuspendedState || m_deviceState == QAudio::IdleState) { + QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); + pa_operation *operation; + + pa_threaded_mainloop_lock(pulseEngine->mainloop()); + + operation = pa_stream_cork(m_stream, 0, inputStreamSuccessCallback, 0); + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(pulseEngine->mainloop()); + + pa_operation_unref(operation); + + pa_threaded_mainloop_unlock(pulseEngine->mainloop()); + + m_timer->start(PeriodTimeMs); + + m_deviceState = QAudio::ActiveState; + + emit stateChanged(m_deviceState); + } +} + +void QPulseAudioInput::setBufferSize(int value) +{ + m_bufferSize = value; +} + +int QPulseAudioInput::bufferSize() const +{ + return m_bufferSize; +} + +int QPulseAudioInput::periodSize() const +{ + return m_periodSize; +} + +void QPulseAudioInput::setNotifyInterval(int ms) +{ + m_intervalTime = qMax(0, ms); +} + +int QPulseAudioInput::notifyInterval() const +{ + return m_intervalTime; +} + +qint64 QPulseAudioInput::processedUSecs() const +{ + pa_sample_spec spec = QPulseAudioInternal::audioFormatToSampleSpec(m_format); + qint64 result = pa_bytes_to_usec(m_totalTimeValue, &spec); + + return result; +} + +void QPulseAudioInput::suspend() +{ + if (m_deviceState == QAudio::ActiveState) { + m_timer->stop(); + m_deviceState = QAudio::SuspendedState; + emit stateChanged(m_deviceState); + + QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); + pa_operation *operation; + + pa_threaded_mainloop_lock(pulseEngine->mainloop()); + + operation = pa_stream_cork(m_stream, 1, inputStreamSuccessCallback, 0); + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(pulseEngine->mainloop()); + + pa_operation_unref(operation); + + pa_threaded_mainloop_unlock(pulseEngine->mainloop()); + } +} + +void QPulseAudioInput::userFeed() +{ + if (m_deviceState == QAudio::StoppedState || m_deviceState == QAudio::SuspendedState) + return; +#ifdef DEBUG_PULSE +// QTime now(QTime::currentTime()); +// qDebug()<< now.second() << "s " << now.msec() << "ms :userFeed() IN"; +#endif + deviceReady(); +} + +bool QPulseAudioInput::deviceReady() +{ + if (m_pullMode) { + // reads some audio data and writes it to QIODevice + read(0,0); + } else { + // emits readyRead() so user will call read() on QIODevice to get some audio data + if (m_audioSource != 0) { + InputPrivate *a = qobject_cast(m_audioSource); + a->trigger(); + } + } + m_bytesAvailable = checkBytesReady(); + + if (m_deviceState != QAudio::ActiveState) + return true; + + if (m_intervalTime && (m_timeStamp.elapsed() + m_elapsedTimeOffset) > m_intervalTime) { + emit notify(); + m_elapsedTimeOffset = m_timeStamp.elapsed() + m_elapsedTimeOffset - m_intervalTime; + m_timeStamp.restart(); + } + + return true; +} + +qint64 QPulseAudioInput::elapsedUSecs() const +{ + if (m_deviceState == QAudio::StoppedState) + return 0; + + return m_clockStamp.elapsed() * 1000; +} + +void QPulseAudioInput::reset() +{ + stop(); + m_bytesAvailable = 0; +} + +InputPrivate::InputPrivate(QPulseAudioInput *audio) +{ + m_audioDevice = qobject_cast(audio); +} + +qint64 InputPrivate::readData(char *data, qint64 len) +{ + return m_audioDevice->read(data, len); +} + +qint64 InputPrivate::writeData(const char *data, qint64 len) +{ + Q_UNUSED(data) + Q_UNUSED(len) + return 0; +} + +void InputPrivate::trigger() +{ + emit readyRead(); +} + +QT_END_NAMESPACE + +#include "moc_qaudioinput_pulse.cpp" diff --git a/src/plugins/pulseaudio/qaudioinput_pulse.h b/src/plugins/pulseaudio/qaudioinput_pulse.h new file mode 100644 index 000000000..c186f91ab --- /dev/null +++ b/src/plugins/pulseaudio/qaudioinput_pulse.h @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QAUDIOINPUTPULSE_H +#define QAUDIOINPUTPULSE_H + +#include +#include +#include +#include +#include + +#include "qaudio.h" +#include "qaudiodeviceinfo.h" +#include "qaudiosystem.h" + +#include + +QT_BEGIN_NAMESPACE + +class InputPrivate; + +class QPulseAudioInput : public QAbstractAudioInput +{ + Q_OBJECT + +public: + QPulseAudioInput(const QByteArray &device); + ~QPulseAudioInput(); + + qint64 read(char *data, qint64 len); + + void start(QIODevice *device); + QIODevice *start(); + void stop(); + void reset(); + void suspend(); + void resume(); + int bytesReady() const; + int periodSize() const; + void setBufferSize(int value); + int bufferSize() const; + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + QAudio::Error error() const; + QAudio::State state() const; + void setFormat(const QAudioFormat &format); + QAudioFormat format() const; + + qint64 m_totalTimeValue; + QIODevice *m_audioSource; + QAudioFormat m_format; + QAudio::Error m_errorState; + QAudio::State m_deviceState; + +private slots: + void userFeed(); + bool deviceReady(); + +private: + int checkBytesReady(); + bool open(); + void close(); + + bool m_pullMode; + bool m_opened; + int m_bytesAvailable; + int m_bufferSize; + int m_periodSize; + int m_intervalTime; + unsigned int m_bufferTime; + unsigned int m_periodTime; + QTimer *m_timer; + qint64 m_elapsedTimeOffset; + char *audioBuffer; + pa_stream *m_stream; + QTime m_timeStamp; + QTime m_clockStamp; + QByteArray m_streamName; + QByteArray m_device; + QByteArray m_tempBuffer; +}; + +class InputPrivate : public QIODevice +{ + Q_OBJECT +public: + InputPrivate(QPulseAudioInput *audio); + ~InputPrivate() {}; + + qint64 readData(char *data, qint64 len); + qint64 writeData(const char *data, qint64 len); + + void trigger(); + +private: + QPulseAudioInput *m_audioDevice; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/pulseaudio/qaudiooutput_pulse.cpp b/src/plugins/pulseaudio/qaudiooutput_pulse.cpp new file mode 100644 index 000000000..8e5b3999c --- /dev/null +++ b/src/plugins/pulseaudio/qaudiooutput_pulse.cpp @@ -0,0 +1,573 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "qaudiooutput_pulse.h" +#include "qaudiodeviceinfo_pulse.h" +#include "qpulseaudioengine.h" +#include "qpulsehelpers.h" + +QT_BEGIN_NAMESPACE + +const int PeriodTimeMs = 20; + +static void outputStreamWriteCallback(pa_stream *stream, size_t length, void *userdata) +{ + Q_UNUSED(stream); + Q_UNUSED(length); + Q_UNUSED(userdata); + QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); + pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0); +} + +static void outputStreamStateCallback(pa_stream *stream, void *userdata) +{ + Q_UNUSED(userdata) + pa_stream_state_t state = pa_stream_get_state(stream); +#ifdef DEBUG_PULSE + qDebug() << "Stream state: " << QPulseAudioInternal::stateToQString(state); +#endif + switch (state) { + case PA_STREAM_CREATING: + case PA_STREAM_READY: + case PA_STREAM_TERMINATED: + break; + + case PA_STREAM_FAILED: + default: + qWarning() << QString("Stream error: %1").arg(pa_strerror(pa_context_errno(pa_stream_get_context(stream)))); + QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); + pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0); + break; + } +} + +static void outputStreamUnderflowCallback(pa_stream *stream, void *userdata) +{ + Q_UNUSED(stream) + ((QPulseAudioOutput*)userdata)->streamUnderflowCallback(); + qWarning() << "Got a buffer underflow!"; +} + +static void outputStreamOverflowCallback(pa_stream *stream, void *userdata) +{ + Q_UNUSED(stream) + Q_UNUSED(userdata) + qWarning() << "Got a buffer overflow!"; +} + +static void outputStreamLatencyCallback(pa_stream *stream, void *userdata) +{ + Q_UNUSED(stream) + Q_UNUSED(userdata) + +#ifdef DEBUG_PULSE + const pa_timing_info *info = pa_stream_get_timing_info(stream); + + qDebug() << "Write index corrupt: " << info->write_index_corrupt; + qDebug() << "Write index: " << info->write_index; + qDebug() << "Read index corrupt: " << info->read_index_corrupt; + qDebug() << "Read index: " << info->read_index; + qDebug() << "Sink usec: " << info->sink_usec; + qDebug() << "Configured sink usec: " << info->configured_sink_usec; +#endif +} + +static void outputStreamSuccessCallback(pa_stream *stream, int success, void *userdata) +{ + Q_UNUSED(stream); + Q_UNUSED(success); + Q_UNUSED(userdata); + + QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); + pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0); +} + +static void outputStreamDrainComplete(pa_stream *stream, int success, void *userdata) +{ + Q_UNUSED(stream); + Q_UNUSED(success); + Q_UNUSED(userdata); + +#ifdef DEBUG_PULSE + qDebug() << "Draining completed successfully: " << (bool)success; +#endif +} + +QPulseAudioOutput::QPulseAudioOutput(const QByteArray &device) + : m_device(device) + , m_errorState(QAudio::NoError) + , m_deviceState(QAudio::StoppedState) + , m_pullMode(true) + , m_opened(false) + , m_audioSource(0) + , m_bytesAvailable(0) + , m_stream(0) + , m_notifyInterval(1000) + , m_periodSize(0) + , m_bufferSize(0) + , m_totalTimeValue(0) + , m_tickTimer(new QTimer(this)) + , m_audioBuffer(0) + , m_resuming(false) +{ + connect(m_tickTimer, SIGNAL(timeout()), SLOT(userFeed())); +} + +QPulseAudioOutput::~QPulseAudioOutput() +{ + close(); + disconnect(m_tickTimer, SIGNAL(timeout())); + QCoreApplication::processEvents(); +} + +QAudio::Error QPulseAudioOutput::error() const +{ + return m_errorState; +} + +QAudio::State QPulseAudioOutput::state() const +{ + return m_deviceState; +} + +void QPulseAudioOutput::streamUnderflowCallback() +{ + if (m_deviceState != QAudio::IdleState && !m_resuming) { + m_errorState = QAudio::UnderrunError; + emit errorChanged(m_errorState); + m_deviceState = QAudio::IdleState; + emit stateChanged(m_deviceState); + } +} + +void QPulseAudioOutput::start(QIODevice *device) +{ + if (m_deviceState != QAudio::StoppedState) + m_deviceState = QAudio::StoppedState; + + m_errorState = QAudio::NoError; + + // Handle change of mode + if (m_audioSource && !m_pullMode) { + delete m_audioSource; + m_audioSource = 0; + } + + close(); + + m_pullMode = true; + m_audioSource = device; + + m_deviceState = QAudio::ActiveState; + + open(); + + emit stateChanged(m_deviceState); +} + +QIODevice *QPulseAudioOutput::start() +{ + if (m_deviceState != QAudio::StoppedState) + m_deviceState = QAudio::StoppedState; + + m_errorState = QAudio::NoError; + + // Handle change of mode + if (m_audioSource && !m_pullMode) { + delete m_audioSource; + m_audioSource = 0; + } + + close(); + + m_audioSource = new OutputPrivate(this); + m_audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered); + m_pullMode = false; + + m_deviceState = QAudio::IdleState; + + open(); + + emit stateChanged(m_deviceState); + + return m_audioSource; +} + +bool QPulseAudioOutput::open() +{ + if (m_opened) + return false; + + pa_sample_spec spec = QPulseAudioInternal::audioFormatToSampleSpec(m_format); + + if (!pa_sample_spec_valid(&spec)) { + m_errorState = QAudio::OpenError; + m_deviceState = QAudio::StoppedState; + return false; + } + + m_totalTimeValue = 0; + m_elapsedTimeOffset = 0; + m_timeStamp.restart(); + + if (m_streamName.isNull()) + m_streamName = QString(QLatin1String("QtmPulseStream-%1-%2")).arg(::getpid()).arg(quintptr(this)).toUtf8(); + +#ifdef DEBUG_PULSE + qDebug() << "Format: " << QPulseAudioInternal::sampleFormatToQString(spec.format); + qDebug() << "Rate: " << spec.rate; + qDebug() << "Channels: " << spec.channels; + qDebug() << "Frame size: " << pa_frame_size(&spec); +#endif + + QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); + pa_threaded_mainloop_lock(pulseEngine->mainloop()); + m_stream = pa_stream_new(pulseEngine->context(), m_streamName.constData(), &spec, 0); + + pa_stream_set_state_callback(m_stream, outputStreamStateCallback, this); + pa_stream_set_write_callback(m_stream, outputStreamWriteCallback, this); + + pa_stream_set_underflow_callback(m_stream, outputStreamUnderflowCallback, this); + pa_stream_set_overflow_callback(m_stream, outputStreamOverflowCallback, this); + pa_stream_set_latency_update_callback(m_stream, outputStreamLatencyCallback, this); + + if (pa_stream_connect_playback(m_stream, m_device.data(), NULL, (pa_stream_flags_t)0, NULL, NULL) < 0) { + qWarning() << "pa_stream_connect_playback() failed!"; + return false; + } + + while (pa_stream_get_state(m_stream) != PA_STREAM_READY) { + pa_threaded_mainloop_wait(pulseEngine->mainloop()); + } + pa_threaded_mainloop_unlock(pulseEngine->mainloop()); + +#ifdef DEBUG_PULSE + const pa_buffer_attr *buffer = pa_stream_get_buffer_attr(m_stream); + + qDebug() << "Buffering info:"; + qDebug() << "\tMax length: " << buffer->maxlength; + qDebug() << "\tTarget length: " << buffer->tlength; + qDebug() << "\tPre-buffering: " << buffer->prebuf; + qDebug() << "\tMinimum request: " << buffer->minreq; + qDebug() << "\tFragment size: " << buffer->fragsize; +#endif + + m_periodSize = pa_usec_to_bytes(PeriodTimeMs*1000, &spec); + m_opened = true; + m_tickTimer->start(PeriodTimeMs); + + m_elapsedTimeOffset = 0; + m_timeStamp.restart(); + m_clockStamp.restart(); + + return true; +} + +void QPulseAudioOutput::userFeed() +{ + if (m_deviceState == QAudio::StoppedState || m_deviceState == QAudio::SuspendedState) + return; + + if (m_deviceState == QAudio::IdleState) + m_bytesAvailable = bytesFree(); + + deviceReady(); +} + +void QPulseAudioOutput::close() +{ + m_tickTimer->stop(); + + if (m_stream) { + QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); + pa_threaded_mainloop_lock(pulseEngine->mainloop()); + pa_operation *o; + + pa_stream_set_write_callback(m_stream, NULL, NULL); + + if (!(o = pa_stream_drain(m_stream, outputStreamDrainComplete, NULL))) { + qWarning() << QString("pa_stream_drain(): %1").arg(pa_strerror(pa_context_errno(pa_stream_get_context(m_stream)))); + return; + } + pa_operation_unref(o); + + pa_stream_disconnect(m_stream); + pa_stream_unref(m_stream); + m_stream = NULL; + + pa_threaded_mainloop_unlock(pulseEngine->mainloop()); + } + + if (!m_pullMode && m_audioSource) { + delete m_audioSource; + m_audioSource = 0; + } + m_opened = false; +} + +bool QPulseAudioOutput::deviceReady() +{ + m_resuming = false; + + if (m_pullMode) { + int l = 0; + int chunks = m_bytesAvailable/m_periodSize; + if (chunks==0) { + m_bytesAvailable = bytesFree(); + return false; + } + + char buffer[m_periodSize]; + + l = m_audioSource->read(buffer, m_periodSize); + if (l > 0) { + if (m_deviceState != QAudio::ActiveState) + return true; + + qint64 bytesWritten = write(buffer, l); + Q_UNUSED(bytesWritten); + } + } + + if (m_deviceState != QAudio::ActiveState) + return true; + + if (m_notifyInterval && (m_timeStamp.elapsed() + m_elapsedTimeOffset) > m_notifyInterval) { + emit notify(); + m_elapsedTimeOffset = m_timeStamp.elapsed() + m_elapsedTimeOffset - m_notifyInterval; + m_timeStamp.restart(); + } + + return true; +} + +qint64 QPulseAudioOutput::write(const char *data, qint64 len) +{ + QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); + + pa_threaded_mainloop_lock(pulseEngine->mainloop()); + len = qMin(len, static_cast(pa_stream_writable_size(m_stream))); + pa_stream_write(m_stream, data, len, 0, 0, PA_SEEK_RELATIVE); + pa_threaded_mainloop_unlock(pulseEngine->mainloop()); + m_totalTimeValue += len; + + m_errorState = QAudio::NoError; + if (m_deviceState != QAudio::ActiveState) { + m_deviceState = QAudio::ActiveState; + emit stateChanged(m_deviceState); + } + + return len; +} + +void QPulseAudioOutput::stop() +{ + if (m_deviceState == QAudio::StoppedState) + return; + + m_errorState = QAudio::NoError; + m_deviceState = QAudio::StoppedState; + close(); + emit stateChanged(m_deviceState); +} + +int QPulseAudioOutput::bytesFree() const +{ + if (m_deviceState != QAudio::ActiveState && m_deviceState != QAudio::IdleState) + return 0; + + return pa_stream_writable_size(m_stream); +} + +int QPulseAudioOutput::periodSize() const +{ + return m_periodSize; +} + +void QPulseAudioOutput::setBufferSize(int value) +{ + m_bufferSize = value; +} + +int QPulseAudioOutput::bufferSize() const +{ + return m_bufferSize; +} + +void QPulseAudioOutput::setNotifyInterval(int ms) +{ + m_notifyInterval = qMax(0, ms); +} + +int QPulseAudioOutput::notifyInterval() const +{ + return m_notifyInterval; +} + +qint64 QPulseAudioOutput::processedUSecs() const +{ + qint64 result = qint64(1000000) * m_totalTimeValue / + (m_format.channels() * (m_format.sampleSize() / 8)) / + m_format.frequency(); + + return result; +} + +void QPulseAudioOutput::resume() +{ + if (m_deviceState == QAudio::SuspendedState) { + m_resuming = true; + + QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); + + pa_threaded_mainloop_lock(pulseEngine->mainloop()); + + pa_operation *operation = pa_stream_cork(m_stream, 0, outputStreamSuccessCallback, NULL); + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(pulseEngine->mainloop()); + + pa_operation_unref(operation); + + operation = pa_stream_trigger(m_stream, outputStreamSuccessCallback, NULL); + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(pulseEngine->mainloop()); + + pa_operation_unref(operation); + + pa_threaded_mainloop_unlock(pulseEngine->mainloop()); + + m_deviceState = QAudio::ActiveState; + + m_errorState = QAudio::NoError; + m_tickTimer->start(PeriodTimeMs); + + emit stateChanged(m_deviceState); + } +} + +void QPulseAudioOutput::setFormat(const QAudioFormat &format) +{ + m_format = format; +} + +QAudioFormat QPulseAudioOutput::format() const +{ + return m_format; +} + +void QPulseAudioOutput::suspend() +{ + if (m_deviceState == QAudio::ActiveState || m_deviceState == QAudio::IdleState) { + m_tickTimer->stop(); + m_deviceState = QAudio::SuspendedState; + m_errorState = QAudio::NoError; + emit stateChanged(m_deviceState); + + QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); + pa_operation *operation; + + pa_threaded_mainloop_lock(pulseEngine->mainloop()); + + operation = pa_stream_cork(m_stream, 1, outputStreamSuccessCallback, NULL); + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(pulseEngine->mainloop()); + + pa_operation_unref(operation); + + pa_threaded_mainloop_unlock(pulseEngine->mainloop()); + } +} + +qint64 QPulseAudioOutput::elapsedUSecs() const +{ + if (m_deviceState == QAudio::StoppedState) + return 0; + + return m_clockStamp.elapsed() * 1000; +} + +void QPulseAudioOutput::reset() +{ + stop(); +} + +OutputPrivate::OutputPrivate(QPulseAudioOutput *audio) +{ + m_audioDevice = qobject_cast(audio); +} + +qint64 OutputPrivate::readData(char *data, qint64 len) +{ + Q_UNUSED(data) + Q_UNUSED(len) + + return 0; +} + +qint64 OutputPrivate::writeData(const char *data, qint64 len) +{ + int retry = 0; + qint64 written = 0; + + if ((m_audioDevice->m_deviceState == QAudio::ActiveState) + ||(m_audioDevice->m_deviceState == QAudio::IdleState)) { + while(written < len) { + int chunk = m_audioDevice->write(data+written, (len-written)); + if (chunk <= 0) + retry++; + written+=chunk; + if (retry > 10) + return written; + } + } + + return written; +} + +QT_END_NAMESPACE + +#include "moc_qaudiooutput_pulse.cpp" diff --git a/src/plugins/pulseaudio/qaudiooutput_pulse.h b/src/plugins/pulseaudio/qaudiooutput_pulse.h new file mode 100644 index 000000000..064754dbc --- /dev/null +++ b/src/plugins/pulseaudio/qaudiooutput_pulse.h @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAUDIOOUTPUTPULSE_H +#define QAUDIOOUTPUTPULSE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include + +#include "qaudio.h" +#include "qaudiodeviceinfo.h" +#include "qaudiosystem.h" + +#include + +QT_BEGIN_NAMESPACE + +class QPulseAudioOutput : public QAbstractAudioOutput +{ + friend class OutputPrivate; + Q_OBJECT + +public: + QPulseAudioOutput(const QByteArray &device); + ~QPulseAudioOutput(); + + void start(QIODevice *device); + QIODevice *start(); + void stop(); + void reset(); + void suspend(); + void resume(); + int bytesFree() const; + int periodSize() const; + void setBufferSize(int value); + int bufferSize() const; + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + QAudio::Error error() const; + QAudio::State state() const; + void setFormat(const QAudioFormat &format); + QAudioFormat format() const; + +public: + void streamUnderflowCallback(); + +private: + bool open(); + void close(); + qint64 write(const char *data, qint64 len); + +private Q_SLOTS: + bool deviceReady(); + void userFeed(); + +private: + QByteArray m_device; + QByteArray m_streamName; + QAudioFormat m_format; + QAudio::Error m_errorState; + QAudio::State m_deviceState; + bool m_pullMode; + bool m_opened; + QIODevice *m_audioSource; + int m_bytesAvailable; + QTimer m_periodTimer; + pa_stream *m_stream; + int m_notifyInterval; + int m_periodSize; + int m_bufferSize; + QTime m_clockStamp; + qint64 m_totalTimeValue; + QTimer *m_tickTimer; + char *m_audioBuffer; + QTime m_timeStamp; + qint64 m_elapsedTimeOffset; + bool m_resuming; +}; + +class OutputPrivate : public QIODevice +{ + friend class QPulseAudioOutput; + Q_OBJECT + +public: + OutputPrivate(QPulseAudioOutput *audio); + virtual ~OutputPrivate() {} + +protected: + qint64 readData(char *data, qint64 len); + qint64 writeData(const char *data, qint64 len); + +private: + QPulseAudioOutput *m_audioDevice; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/pulseaudio/qpulseaudioengine.cpp b/src/plugins/pulseaudio/qpulseaudioengine.cpp new file mode 100644 index 000000000..da0963fa9 --- /dev/null +++ b/src/plugins/pulseaudio/qpulseaudioengine.cpp @@ -0,0 +1,354 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include +#include "qpulseaudioengine.h" +#include "qaudiodeviceinfo_pulse.h" +#include "qaudiooutput_pulse.h" +#include "qpulsehelpers.h" + +QT_BEGIN_NAMESPACE + +static void serverInfoCallback(pa_context *context, const pa_server_info *info, void *userdata) +{ + if (!info) { + qWarning() << QString("Failed to get server information: %s").arg(pa_strerror(pa_context_errno(context))); + return; + } + +#ifdef DEBUG_PULSE + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + + pa_sample_spec_snprint(ss, sizeof(ss), &info->sample_spec); + pa_channel_map_snprint(cm, sizeof(cm), &info->channel_map); + + qDebug() << QString("User name: %1\n" + "Host Name: %2\n" + "Server Name: %3\n" + "Server Version: %4\n" + "Default Sample Specification: %5\n" + "Default Channel Map: %6\n" + "Default Sink: %7\n" + "Default Source: %8\n").arg( + info->user_name, + info->host_name, + info->server_name, + info->server_version, + ss, + cm, + info->default_sink_name, + info->default_source_name); +#endif + + QPulseAudioEngine *pulseEngine = static_cast(userdata); + pulseEngine->m_defaultSink = info->default_sink_name; + pulseEngine->m_defaultSource = info->default_source_name; + + pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0); +} + +static void sinkInfoCallback(pa_context *context, const pa_sink_info *info, int isLast, void *userdata) +{ + QPulseAudioEngine *pulseEngine = static_cast(userdata); + QMap stateMap; + stateMap[PA_SINK_INVALID_STATE] = "n/a"; + stateMap[PA_SINK_RUNNING] = "RUNNING"; + stateMap[PA_SINK_IDLE] = "IDLE"; + stateMap[PA_SINK_SUSPENDED] = "SUSPENDED"; + + if (isLast < 0) { + qWarning() << QString("Failed to get sink information: %s").arg(pa_strerror(pa_context_errno(context))); + return; + } + + if (isLast) { + pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0); + return; + } + + Q_ASSERT(info); + +#ifdef DEBUG_PULSE + qDebug() << QString("Sink #%1\n" + "\tState: %2\n" + "\tName: %3\n" + "\tDescription: %4\n" + ).arg(QString::number(info->index), + stateMap.value(info->state), + info->name, + info->description); +#endif + + QAudioFormat format = QPulseAudioInternal::sampleSpecToAudioFormat(info->sample_spec); + pulseEngine->m_preferredFormats.insert(info->name, format); + pulseEngine->m_sinks.append(info->name); +} + +static void sourceInfoCallback(pa_context *context, const pa_source_info *info, int isLast, void *userdata) +{ + Q_UNUSED(context) + QPulseAudioEngine *pulseEngine = static_cast(userdata); + + QMap stateMap; + stateMap[PA_SOURCE_INVALID_STATE] = "n/a"; + stateMap[PA_SOURCE_RUNNING] = "RUNNING"; + stateMap[PA_SOURCE_IDLE] = "IDLE"; + stateMap[PA_SOURCE_SUSPENDED] = "SUSPENDED"; + + if (isLast) { + pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0); + return; + } + + Q_ASSERT(info); + +#ifdef DEBUG_PULSE + qDebug() << QString("Source #%1\n" + "\tState: %2\n" + "\tName: %3\n" + "\tDescription: %4\n" + ).arg(QString::number(info->index), + stateMap.value(info->state), + info->name, + info->description); +#endif + + QAudioFormat format = QPulseAudioInternal::sampleSpecToAudioFormat(info->sample_spec); + pulseEngine->m_preferredFormats.insert(info->name, format); + pulseEngine->m_sources.append(info->name); +} + +static void contextStateCallbackInit(pa_context *context, void *userdata) +{ + Q_UNUSED(context); +#ifdef DEBUG_PULSE + qDebug() << QPulseAudioInternal::stateToQString(pa_context_get_state(context)); +#endif + QPulseAudioEngine *pulseEngine = reinterpret_cast(userdata); + pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0); +} + +static void contextStateCallback(pa_context *context, void *userdata) +{ + Q_UNUSED(userdata); + Q_UNUSED(context); + +#ifdef DEBUG_PULSE + pa_context_state_t state = pa_context_get_state(context); + qDebug() << QPulseAudioInternal::stateToQString(state); +#endif +} + +Q_GLOBAL_STATIC(QPulseAudioEngine, pulseEngine); + +QPulseAudioEngine::QPulseAudioEngine(QObject *parent) + : QObject(parent) +{ + bool keepGoing = true; + bool ok = true; + + m_mainLoop = pa_threaded_mainloop_new(); + if (m_mainLoop == 0) { + qWarning("Unable to create pulseaudio mainloop"); + return; + } + + if (pa_threaded_mainloop_start(m_mainLoop) != 0) { + qWarning("Unable to start pulseaudio mainloop"); + pa_threaded_mainloop_free(m_mainLoop); + return; + } + + m_mainLoopApi = pa_threaded_mainloop_get_api(m_mainLoop); + + pa_threaded_mainloop_lock(m_mainLoop); + + m_context = pa_context_new(m_mainLoopApi, QString(QLatin1String("QtmPulseContext:%1")).arg(::getpid()).toAscii().constData()); + pa_context_set_state_callback(m_context, contextStateCallbackInit, this); + + if (!m_context) { + qWarning("Unable to create new pulseaudio context"); + pa_threaded_mainloop_free(m_mainLoop); + return; + } + + if (pa_context_connect(m_context, NULL, (pa_context_flags_t)0, NULL) < 0) { + qWarning("Unable to create a connection to the pulseaudio context"); + pa_context_unref(m_context); + pa_threaded_mainloop_free(m_mainLoop); + return; + } + + pa_threaded_mainloop_wait(m_mainLoop); + + while (keepGoing) { + switch (pa_context_get_state(m_context)) { + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + + case PA_CONTEXT_READY: +#ifdef DEBUG_PULSE + qDebug("Connection established."); +#endif + keepGoing = false; + break; + + case PA_CONTEXT_TERMINATED: + qCritical("Context terminated."); + keepGoing = false; + ok = false; + break; + + case PA_CONTEXT_FAILED: + default: + qCritical() << QString("Connection failure: %1").arg(pa_strerror(pa_context_errno(m_context))); + keepGoing = false; + ok = false; + } + + if (keepGoing) { + pa_threaded_mainloop_wait(m_mainLoop); + } + } + + if (ok) { + pa_context_set_state_callback(m_context, contextStateCallback, this); + } else { + if (m_context) { + pa_context_unref(m_context); + m_context = 0; + } + } + + pa_threaded_mainloop_unlock(m_mainLoop); + + serverInfo(); + sinks(); + sources(); +} + +QPulseAudioEngine::~QPulseAudioEngine() +{ + if (m_context) { + pa_threaded_mainloop_lock(m_mainLoop); + pa_context_disconnect(m_context); + pa_threaded_mainloop_unlock(m_mainLoop); + m_context = 0; + } + + if (m_mainLoop) { + pa_threaded_mainloop_stop(m_mainLoop); + pa_threaded_mainloop_free(m_mainLoop); + m_mainLoop = 0; + } +} + +void QPulseAudioEngine::serverInfo() +{ + pa_operation *operation; + + pa_threaded_mainloop_lock(m_mainLoop); + + operation = pa_context_get_server_info(m_context, serverInfoCallback, this); + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(m_mainLoop); + + pa_operation_unref(operation); + + pa_threaded_mainloop_unlock(m_mainLoop); +} + +void QPulseAudioEngine::sinks() +{ + pa_operation *operation; + + pa_threaded_mainloop_lock(m_mainLoop); + + operation = pa_context_get_sink_info_list(m_context, sinkInfoCallback, this); + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(m_mainLoop); + + pa_operation_unref(operation); + + pa_threaded_mainloop_unlock(m_mainLoop); + + // Swap the default sink to index 0 + m_sinks.removeOne(m_defaultSink); + m_sinks.prepend(m_defaultSink); +} + +void QPulseAudioEngine::sources() +{ + pa_operation *operation; + + pa_threaded_mainloop_lock(m_mainLoop); + + operation = pa_context_get_source_info_list(m_context, sourceInfoCallback, this); + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(m_mainLoop); + + pa_operation_unref(operation); + + pa_threaded_mainloop_unlock(m_mainLoop); + + // Swap the default source to index 0 + m_sources.removeOne(m_defaultSource); + m_sources.prepend(m_defaultSource); +} + +QPulseAudioEngine *QPulseAudioEngine::instance() +{ + return pulseEngine(); +} + +QList QPulseAudioEngine::availableDevices(QAudio::Mode mode) const +{ + return mode == QAudio::AudioOutput ? m_sinks : m_sources; +} + +QT_END_NAMESPACE diff --git a/src/plugins/pulseaudio/qpulseaudioengine.h b/src/plugins/pulseaudio/qpulseaudioengine.h new file mode 100644 index 000000000..3519be79d --- /dev/null +++ b/src/plugins/pulseaudio/qpulseaudioengine.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPULSEAUDIOENGINE_H +#define QPULSEAUDIOENGINE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include "qpulsehelpers.h" +#include + +QT_BEGIN_NAMESPACE + +class QPulseAudioEngine : public QObject +{ + Q_OBJECT + +public: + QPulseAudioEngine(QObject *parent = 0); + ~QPulseAudioEngine(); + + static QPulseAudioEngine *instance(); + pa_threaded_mainloop *mainloop() { return m_mainLoop; } + pa_context *context() { return m_context; } + + QList availableDevices(QAudio::Mode mode) const; + +private: + void serverInfo(); + void sinks(); + void sources(); + +public: + QList m_sinks; + QList m_sources; + QMap m_preferredFormats; + + QByteArray m_defaultSink; + QByteArray m_defaultSource; + +private: + pa_mainloop_api *m_mainLoopApi; + pa_threaded_mainloop *m_mainLoop; + pa_context *m_context; + }; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/pulseaudio/qpulseaudioplugin.cpp b/src/plugins/pulseaudio/qpulseaudioplugin.cpp new file mode 100644 index 000000000..99ff09211 --- /dev/null +++ b/src/plugins/pulseaudio/qpulseaudioplugin.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "qpulseaudioplugin.h" +#include "qaudiodeviceinfo_pulse.h" +#include "qaudiooutput_pulse.h" +#include "qaudioinput_pulse.h" +#include "qpulseaudioengine.h" + +QT_BEGIN_NAMESPACE + +QPulseAudioPlugin::QPulseAudioPlugin(QObject *parent) + : QAudioSystemPlugin(parent) + , m_pulseEngine(QPulseAudioEngine::instance()) +{ +} + +QStringList QPulseAudioPlugin::keys() const +{ + return QStringList() << "default"; +} + +QList QPulseAudioPlugin::availableDevices(QAudio::Mode mode) const +{ + return m_pulseEngine->availableDevices(mode); +} + +QAbstractAudioInput *QPulseAudioPlugin::createInput(const QByteArray &device) +{ + QPulseAudioInput *input = new QPulseAudioInput(device); + return input; +} + +QAbstractAudioOutput *QPulseAudioPlugin::createOutput(const QByteArray &device) +{ + + QPulseAudioOutput *output = new QPulseAudioOutput(device); + return output; +} + +QAbstractAudioDeviceInfo *QPulseAudioPlugin::createDeviceInfo(const QByteArray &device, QAudio::Mode mode) +{ + QPulseAudioDeviceInfo *deviceInfo = new QPulseAudioDeviceInfo(device, mode); + return deviceInfo; +} + +Q_EXPORT_PLUGIN2(qtmedia_pulse, QPulseAudioPlugin); + +QT_END_NAMESPACE diff --git a/src/plugins/pulseaudio/qpulseaudioplugin.h b/src/plugins/pulseaudio/qpulseaudioplugin.h new file mode 100644 index 000000000..e90270e0c --- /dev/null +++ b/src/plugins/pulseaudio/qpulseaudioplugin.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPULSEAUDIOPLUGIN_H +#define QPULSEAUDIOPLUGIN_H + +#include + +QT_BEGIN_NAMESPACE + +class QPulseAudioEngine; + +class QPulseAudioPlugin : public QAudioSystemPlugin +{ + Q_OBJECT + +public: + QPulseAudioPlugin(QObject *parent = 0); + ~QPulseAudioPlugin() {} + + QStringList keys() const; + QList availableDevices(QAudio::Mode mode) const; + QAbstractAudioInput *createInput(const QByteArray &device); + QAbstractAudioOutput *createOutput(const QByteArray &device); + QAbstractAudioDeviceInfo *createDeviceInfo(const QByteArray &device, QAudio::Mode mode); + +private: + QPulseAudioEngine *m_pulseEngine; +}; + +QT_BEGIN_NAMESPACE + +#endif diff --git a/src/plugins/pulseaudio/qpulsehelpers.cpp b/src/plugins/pulseaudio/qpulsehelpers.cpp new file mode 100644 index 000000000..57e50758f --- /dev/null +++ b/src/plugins/pulseaudio/qpulsehelpers.cpp @@ -0,0 +1,220 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpulsehelpers.h" + +QT_BEGIN_NAMESPACE + +namespace QPulseAudioInternal +{ +pa_sample_spec audioFormatToSampleSpec(const QAudioFormat &format) +{ + pa_sample_spec spec; + + spec.rate = format.frequency(); + spec.channels = format.channels(); + + if (format.sampleSize() == 8) { + spec.format = PA_SAMPLE_U8; + } else if (format.sampleSize() == 16) { + switch (format.byteOrder()) { + case QAudioFormat::BigEndian: spec.format = PA_SAMPLE_S16BE; break; + case QAudioFormat::LittleEndian: spec.format = PA_SAMPLE_S16LE; break; + } + } else if (format.sampleSize() == 24) { + switch (format.byteOrder()) { + case QAudioFormat::BigEndian: spec.format = PA_SAMPLE_S24BE; break; + case QAudioFormat::LittleEndian: spec.format = PA_SAMPLE_S24LE; break; + } + } else if (format.sampleSize() == 32) { + switch (format.byteOrder()) { + case QAudioFormat::BigEndian: + format.sampleType() == QAudioFormat::Float ? spec.format = PA_SAMPLE_FLOAT32BE : spec.format = PA_SAMPLE_S32BE; + break; + case QAudioFormat::LittleEndian: + format.sampleType() == QAudioFormat::Float ? spec.format = PA_SAMPLE_FLOAT32LE : spec.format = PA_SAMPLE_S32LE; + break; + } + } else { + spec.format = PA_SAMPLE_INVALID; + } + + return spec; +} + +#ifdef DEBUG_PULSE +QString stateToQString(pa_stream_state_t state) +{ + switch (state) + { + case PA_STREAM_UNCONNECTED: return "Unconnected"; + case PA_STREAM_CREATING: return "Creating"; + case PA_STREAM_READY: return "Ready"; + case PA_STREAM_FAILED: return "Failed"; + case PA_STREAM_TERMINATED: return "Terminated"; + } + + return QString("Unknown state: %0").arg(state); +} + +QString sampleFormatToQString(pa_sample_format format) +{ + switch (format) + { + case PA_SAMPLE_U8: return "Unsigned 8 Bit PCM."; + case PA_SAMPLE_ALAW: return "8 Bit a-Law "; + case PA_SAMPLE_ULAW: return "8 Bit mu-Law"; + case PA_SAMPLE_S16LE: return "Signed 16 Bit PCM, little endian (PC)."; + case PA_SAMPLE_S16BE: return "Signed 16 Bit PCM, big endian."; + case PA_SAMPLE_FLOAT32LE: return "32 Bit IEEE floating point, little endian (PC), range -1.0 to 1.0"; + case PA_SAMPLE_FLOAT32BE: return "32 Bit IEEE floating point, big endian, range -1.0 to 1.0"; + case PA_SAMPLE_S32LE: return "Signed 32 Bit PCM, little endian (PC)."; + case PA_SAMPLE_S32BE: return "Signed 32 Bit PCM, big endian."; + case PA_SAMPLE_S24LE: return "Signed 24 Bit PCM packed, little endian (PC)."; + case PA_SAMPLE_S24BE: return "Signed 24 Bit PCM packed, big endian."; + case PA_SAMPLE_S24_32LE: return "Signed 24 Bit PCM in LSB of 32 Bit words, little endian (PC)."; + case PA_SAMPLE_S24_32BE: return "Signed 24 Bit PCM in LSB of 32 Bit words, big endian."; + case PA_SAMPLE_MAX: return "Upper limit of valid sample types."; + case PA_SAMPLE_INVALID: return "Invalid sample format"; + } + + return QString("Invalid value: %0").arg(format); +} + +QString stateToQString(pa_context_state_t state) +{ + switch (state) + { + case PA_CONTEXT_UNCONNECTED: return "Unconnected"; + case PA_CONTEXT_CONNECTING: return "Connecting"; + case PA_CONTEXT_AUTHORIZING: return "Authorizing"; + case PA_CONTEXT_SETTING_NAME: return "Setting Name"; + case PA_CONTEXT_READY: return "Ready"; + case PA_CONTEXT_FAILED: return "Failed"; + case PA_CONTEXT_TERMINATED: return "Terminated"; + } + + return QString("Unknown state: %0").arg(state); +} +#endif + +QAudioFormat sampleSpecToAudioFormat(pa_sample_spec spec) +{ + QAudioFormat format; + format.setFrequency(spec.rate); + format.setChannelCount(spec.channels); + format.setCodec("audio/pcm"); + + switch (spec.format) { + case PA_SAMPLE_U8: + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleType(QAudioFormat::UnSignedInt); + format.setSampleSize(8); + break; + case PA_SAMPLE_ALAW: + // TODO: + break; + case PA_SAMPLE_ULAW: + // TODO: + break; + case PA_SAMPLE_S16LE: + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleType(QAudioFormat::SignedInt); + format.setSampleSize(16); + break; + case PA_SAMPLE_S16BE: + format.setByteOrder(QAudioFormat::BigEndian); + format.setSampleType(QAudioFormat::SignedInt); + format.setSampleSize(16); + break; + case PA_SAMPLE_FLOAT32LE: + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleType(QAudioFormat::Float); + format.setSampleSize(32); + break; + case PA_SAMPLE_FLOAT32BE: + format.setByteOrder(QAudioFormat::BigEndian); + format.setSampleType(QAudioFormat::Float); + format.setSampleSize(32); + break; + case PA_SAMPLE_S32LE: + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleType(QAudioFormat::SignedInt); + format.setSampleSize(32); + break; + case PA_SAMPLE_S32BE: + format.setByteOrder(QAudioFormat::BigEndian); + format.setSampleType(QAudioFormat::SignedInt); + format.setSampleSize(32); + break; + case PA_SAMPLE_S24LE: + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleType(QAudioFormat::SignedInt); + format.setSampleSize(24); + break; + case PA_SAMPLE_S24BE: + format.setByteOrder(QAudioFormat::BigEndian); + format.setSampleType(QAudioFormat::SignedInt); + format.setSampleSize(24); + break; + case PA_SAMPLE_S24_32LE: + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleType(QAudioFormat::SignedInt); + format.setSampleSize(24); + break; + case PA_SAMPLE_S24_32BE: + format.setByteOrder(QAudioFormat::BigEndian); + format.setSampleType(QAudioFormat::SignedInt); + format.setSampleSize(24); + break; + case PA_SAMPLE_MAX: + case PA_SAMPLE_INVALID: + default: + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleType(QAudioFormat::Unknown); + format.setSampleSize(0); + } + + return format; +} +} + +QT_END_NAMESPACE diff --git a/src/plugins/pulseaudio/qpulsehelpers.h b/src/plugins/pulseaudio/qpulsehelpers.h new file mode 100644 index 000000000..255f0cf90 --- /dev/null +++ b/src/plugins/pulseaudio/qpulsehelpers.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPULSEHELPER_H +#define QPULSEHELPER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qaudiodeviceinfo.h" +#include +#include + +QT_BEGIN_NAMESPACE + +namespace QPulseAudioInternal +{ +pa_sample_spec audioFormatToSampleSpec(const QAudioFormat &format); +QString stateToQString(pa_stream_state_t state); +QString stateToQString(pa_context_state_t state); +QString sampleFormatToQString(pa_sample_format format); +QAudioFormat sampleSpecToAudioFormat(pa_sample_spec spec); +} + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qt7/mediaplayer/mediaplayer.pri b/src/plugins/qt7/mediaplayer/mediaplayer.pri new file mode 100644 index 000000000..2edb1d2c7 --- /dev/null +++ b/src/plugins/qt7/mediaplayer/mediaplayer.pri @@ -0,0 +1,16 @@ +INCLUDEPATH += $$PWD + +DEFINES += QMEDIA_QT7_PLAYER + +HEADERS += \ + $$PWD/qt7playercontrol.h \ + $$PWD/qt7playermetadata.h \ + $$PWD/qt7playerservice.h \ + $$PWD/qt7playersession.h + +OBJECTIVE_SOURCES += \ + $$PWD/qt7playercontrol.mm \ + $$PWD/qt7playermetadata.mm \ + $$PWD/qt7playerservice.mm \ + $$PWD/qt7playersession.mm + diff --git a/src/plugins/qt7/mediaplayer/qt7playercontrol.h b/src/plugins/qt7/mediaplayer/qt7playercontrol.h new file mode 100644 index 000000000..064c0ccd3 --- /dev/null +++ b/src/plugins/qt7/mediaplayer/qt7playercontrol.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7PLAYERCONTROL_H +#define QT7PLAYERCONTROL_H + +#include + +#include +#include + +#include + + +QT_BEGIN_NAMESPACE + +class QT7PlayerSession; +class QT7PlayerService; +class QMediaPlaylist; +class QMediaPlaylistNavigator; + +class QT7PlayerControl : public QMediaPlayerControl +{ +Q_OBJECT +public: + QT7PlayerControl(QObject *parent = 0); + ~QT7PlayerControl(); + + void setSession(QT7PlayerSession *session); + + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + + QMediaContent media() const; + const QIODevice *mediaStream() const; + void setMedia(const QMediaContent &content, QIODevice *stream); + + qint64 position() const; + qint64 duration() const; + + int bufferStatus() const; + + int volume() const; + bool isMuted() const; + + bool isAudioAvailable() const; + bool isVideoAvailable() const; + + bool isSeekable() const; + QMediaTimeRange availablePlaybackRanges() const; + + qreal playbackRate() const; + void setPlaybackRate(qreal rate); + +public Q_SLOTS: + void setPosition(qint64 pos); + + void play(); + void pause(); + void stop(); + + void setVolume(int volume); + void setMuted(bool muted); + +private: + QT7PlayerSession *m_session; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qt7/mediaplayer/qt7playercontrol.mm b/src/plugins/qt7/mediaplayer/qt7playercontrol.mm new file mode 100644 index 000000000..ddfcc3570 --- /dev/null +++ b/src/plugins/qt7/mediaplayer/qt7playercontrol.mm @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qt7playercontrol.h" +#include "qt7playersession.h" + +#include + +#include +#include + +QT_USE_NAMESPACE + +QT7PlayerControl::QT7PlayerControl(QObject *parent) + : QMediaPlayerControl(parent) +{ +} + +QT7PlayerControl::~QT7PlayerControl() +{ +} + +void QT7PlayerControl::setSession(QT7PlayerSession *session) +{ + m_session = session; + + connect(m_session, SIGNAL(positionChanged(qint64)), this, SIGNAL(positionChanged(qint64))); + connect(m_session, SIGNAL(durationChanged(qint64)), this, SIGNAL(durationChanged(qint64))); + connect(m_session, SIGNAL(stateChanged(QMediaPlayer::State)), + this, SIGNAL(stateChanged(QMediaPlayer::State))); + connect(m_session, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + this, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(m_session, SIGNAL(volumeChanged(int)), this, SIGNAL(volumeChanged(int))); + connect(m_session, SIGNAL(mutedChanged(bool)), this, SIGNAL(mutedChanged(bool))); + connect(m_session, SIGNAL(audioAvailableChanged(bool)), this, SIGNAL(audioAvailableChanged(bool))); + connect(m_session, SIGNAL(videoAvailableChanged(bool)), this, SIGNAL(videoAvailableChanged(bool))); + connect(m_session, SIGNAL(error(int,QString)), this, SIGNAL(error(int,QString))); +} + +qint64 QT7PlayerControl::position() const +{ + return m_session->position(); +} + +qint64 QT7PlayerControl::duration() const +{ + return m_session->duration(); +} + +QMediaPlayer::State QT7PlayerControl::state() const +{ + return m_session->state(); +} + +QMediaPlayer::MediaStatus QT7PlayerControl::mediaStatus() const +{ + return m_session->mediaStatus(); +} + +int QT7PlayerControl::bufferStatus() const +{ + return m_session->bufferStatus(); +} + +int QT7PlayerControl::volume() const +{ + return m_session->volume(); +} + +bool QT7PlayerControl::isMuted() const +{ + return m_session->isMuted(); +} + +bool QT7PlayerControl::isSeekable() const +{ + return m_session->isSeekable(); +} + +QMediaTimeRange QT7PlayerControl::availablePlaybackRanges() const +{ + return m_session->availablePlaybackRanges(); +} + +qreal QT7PlayerControl::playbackRate() const +{ + return m_session->playbackRate(); +} + +void QT7PlayerControl::setPlaybackRate(qreal rate) +{ + m_session->setPlaybackRate(rate); +} + +void QT7PlayerControl::setPosition(qint64 pos) +{ + m_session->setPosition(pos); +} + +void QT7PlayerControl::play() +{ + m_session->play(); +} + +void QT7PlayerControl::pause() +{ + m_session->pause(); +} + +void QT7PlayerControl::stop() +{ + m_session->stop(); +} + +void QT7PlayerControl::setVolume(int volume) +{ + m_session->setVolume(volume); +} + +void QT7PlayerControl::setMuted(bool muted) +{ + m_session->setMuted(muted); +} + +QMediaContent QT7PlayerControl::media() const +{ + return m_session->media(); +} + +const QIODevice *QT7PlayerControl::mediaStream() const +{ + return m_session->mediaStream(); +} + +void QT7PlayerControl::setMedia(const QMediaContent &content, QIODevice *stream) +{ + m_session->setMedia(content, stream); + + emit mediaChanged(content); +} + +bool QT7PlayerControl::isAudioAvailable() const +{ + return m_session->isAudioAvailable(); +} + +bool QT7PlayerControl::isVideoAvailable() const +{ + return m_session->isVideoAvailable(); +} + + +#include "moc_qt7playercontrol.cpp" diff --git a/src/plugins/qt7/mediaplayer/qt7playermetadata.h b/src/plugins/qt7/mediaplayer/qt7playermetadata.h new file mode 100644 index 000000000..441ca07f6 --- /dev/null +++ b/src/plugins/qt7/mediaplayer/qt7playermetadata.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7PLAYERMETADATACONTROL_H +#define QT7PLAYERMETADATACONTROL_H + +#include + +QT_BEGIN_NAMESPACE + +class QT7PlayerSession; + +class QT7PlayerMetaDataControl : public QMetaDataReaderControl +{ + Q_OBJECT +public: + QT7PlayerMetaDataControl(QT7PlayerSession *session, QObject *parent); + virtual ~QT7PlayerMetaDataControl(); + + bool isMetaDataAvailable() const; + bool isWritable() const; + + QVariant metaData(QtMultimediaKit::MetaData key) const; + QList availableMetaData() const; + + QVariant extendedMetaData(const QString &key) const ; + QStringList availableExtendedMetaData() const; + +private slots: + void updateTags(); + +private: + QT7PlayerSession *m_session; + QMap m_tags; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qt7/mediaplayer/qt7playermetadata.mm b/src/plugins/qt7/mediaplayer/qt7playermetadata.mm new file mode 100644 index 000000000..ec0d41cc2 --- /dev/null +++ b/src/plugins/qt7/mediaplayer/qt7playermetadata.mm @@ -0,0 +1,260 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qt7backend.h" +#include "qt7playermetadata.h" +#include "qt7playersession.h" +#include + +#import + +#ifdef QUICKTIME_C_API_AVAILABLE + #include + #undef check // avoid name clash; +#endif + +QT_USE_NAMESPACE + +QT7PlayerMetaDataControl::QT7PlayerMetaDataControl(QT7PlayerSession *session, QObject *parent) + :QMetaDataReaderControl(parent), m_session(session) +{ +} + +QT7PlayerMetaDataControl::~QT7PlayerMetaDataControl() +{ +} + +bool QT7PlayerMetaDataControl::isMetaDataAvailable() const +{ + return !m_tags.isEmpty(); +} + +bool QT7PlayerMetaDataControl::isWritable() const +{ + return false; +} + +QVariant QT7PlayerMetaDataControl::metaData(QtMultimediaKit::MetaData key) const +{ + return m_tags.value(key); +} + +QList QT7PlayerMetaDataControl::availableMetaData() const +{ + return m_tags.keys(); +} + +QVariant QT7PlayerMetaDataControl::extendedMetaData(const QString &key) const +{ + Q_UNUSED(key); + return QVariant(); +} + +QStringList QT7PlayerMetaDataControl::availableExtendedMetaData() const +{ + return QStringList(); +} + +#ifdef QUICKTIME_C_API_AVAILABLE + +static QString stripCopyRightSymbol(const QString &key) +{ + return key.right(key.length()-1); +} + +static QString convertQuickTimeKeyToUserKey(const QString &key) +{ + if (key == QLatin1String("com.apple.quicktime.displayname")) + return QLatin1String("nam"); + else if (key == QLatin1String("com.apple.quicktime.album")) + return QLatin1String("alb"); + else if (key == QLatin1String("com.apple.quicktime.artist")) + return QLatin1String("ART"); + else + return QLatin1String("???"); +} + +static OSStatus readMetaValue(QTMetaDataRef metaDataRef, QTMetaDataItem item, QTPropertyClass propClass, + QTPropertyID id, QTPropertyValuePtr *value, ByteCount *size) +{ + QTPropertyValueType type; + ByteCount propSize; + UInt32 propFlags; + OSStatus err = QTMetaDataGetItemPropertyInfo(metaDataRef, item, propClass, id, &type, &propSize, &propFlags); + + if (err == noErr) { + *value = malloc(propSize); + if (*value != 0) { + err = QTMetaDataGetItemProperty(metaDataRef, item, propClass, id, propSize, *value, size); + + if (err == noErr && (type == 'code' || type == 'itsk' || type == 'itlk')) { + // convert from native endian to big endian + OSTypePtr pType = (OSTypePtr)*value; + *pType = EndianU32_NtoB(*pType); + } + } + else + return -1; + } + + return err; +} + +static UInt32 getMetaType(QTMetaDataRef metaDataRef, QTMetaDataItem item) +{ + QTPropertyValuePtr value = 0; + ByteCount ignore = 0; + OSStatus err = readMetaValue( + metaDataRef, item, kPropertyClass_MetaDataItem, kQTMetaDataItemPropertyID_DataType, &value, &ignore); + + if (err == noErr) { + UInt32 type = *((UInt32 *) value); + if (value) + free(value); + return type; + } + + return 0; +} + +static QString cFStringToQString(CFStringRef str) +{ + if(!str) + return QString(); + CFIndex length = CFStringGetLength(str); + const UniChar *chars = CFStringGetCharactersPtr(str); + if (chars) + return QString(reinterpret_cast(chars), length); + + QVarLengthArray buffer(length); + CFStringGetCharacters(str, CFRangeMake(0, length), buffer.data()); + return QString(reinterpret_cast(buffer.constData()), length); +} + + +static QString getMetaValue(QTMetaDataRef metaDataRef, QTMetaDataItem item, SInt32 id) +{ + QTPropertyValuePtr value = 0; + ByteCount size = 0; + OSStatus err = readMetaValue(metaDataRef, item, kPropertyClass_MetaDataItem, id, &value, &size); + QString string; + + if (err == noErr) { + UInt32 dataType = getMetaType(metaDataRef, item); + switch (dataType){ + case kQTMetaDataTypeUTF8: + case kQTMetaDataTypeMacEncodedText: + string = cFStringToQString(CFStringCreateWithBytes(0, (UInt8*)value, size, kCFStringEncodingUTF8, false)); + break; + case kQTMetaDataTypeUTF16BE: + string = cFStringToQString(CFStringCreateWithBytes(0, (UInt8*)value, size, kCFStringEncodingUTF16BE, false)); + break; + default: + break; + } + + if (value) + free(value); + } + + return string; +} + + +static void readFormattedData(QTMetaDataRef metaDataRef, OSType format, QMultiMap &result) +{ + QTMetaDataItem item = kQTMetaDataItemUninitialized; + OSStatus err = QTMetaDataGetNextItem(metaDataRef, format, item, kQTMetaDataKeyFormatWildcard, 0, 0, &item); + while (err == noErr){ + QString key = getMetaValue(metaDataRef, item, kQTMetaDataItemPropertyID_Key); + if (format == kQTMetaDataStorageFormatQuickTime) + key = convertQuickTimeKeyToUserKey(key); + else + key = stripCopyRightSymbol(key); + + if (!result.contains(key)){ + QString val = getMetaValue(metaDataRef, item, kQTMetaDataItemPropertyID_Value); + result.insert(key, val); + } + err = QTMetaDataGetNextItem(metaDataRef, format, item, kQTMetaDataKeyFormatWildcard, 0, 0, &item); + } +} +#endif + + +void QT7PlayerMetaDataControl::updateTags() +{ + bool wasEmpty = m_tags.isEmpty(); + m_tags.clear(); + + QTMovie *movie = (QTMovie*)m_session->movie(); + + if (movie) { + QMultiMap metaMap; + +#ifdef QUICKTIME_C_API_AVAILABLE + QTMetaDataRef metaDataRef; + OSStatus err = QTCopyMovieMetaData([movie quickTimeMovie], &metaDataRef); + if (err == noErr) { + readFormattedData(metaDataRef, kQTMetaDataStorageFormatUserData, metaMap); + readFormattedData(metaDataRef, kQTMetaDataStorageFormatQuickTime, metaMap); + readFormattedData(metaDataRef, kQTMetaDataStorageFormatiTunes, metaMap); + } +#else + AutoReleasePool pool; + NSString *name = [movie attributeForKey:@"QTMovieDisplayNameAttribute"]; + metaMap.insert(QLatin1String("nam"), QString::fromUtf8([name UTF8String])); +#endif // QUICKTIME_C_API_AVAILABLE + + m_tags.insert(QtMultimediaKit::AlbumArtist, metaMap.value(QLatin1String("ART"))); + m_tags.insert(QtMultimediaKit::AlbumTitle, metaMap.value(QLatin1String("alb"))); + m_tags.insert(QtMultimediaKit::Title, metaMap.value(QLatin1String("nam"))); + m_tags.insert(QtMultimediaKit::Date, metaMap.value(QLatin1String("day"))); + m_tags.insert(QtMultimediaKit::Genre, metaMap.value(QLatin1String("gnre"))); + m_tags.insert(QtMultimediaKit::TrackNumber, metaMap.value(QLatin1String("trk"))); + m_tags.insert(QtMultimediaKit::Description, metaMap.value(QLatin1String("des"))); + } + + if (!wasEmpty || !m_tags.isEmpty()) + emit metaDataChanged(); +} + +#include "moc_qt7playermetadata.cpp" diff --git a/src/plugins/qt7/mediaplayer/qt7playerservice.h b/src/plugins/qt7/mediaplayer/qt7playerservice.h new file mode 100644 index 000000000..65415f0a9 --- /dev/null +++ b/src/plugins/qt7/mediaplayer/qt7playerservice.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7PLAYERSERVICE_H +#define QT7PLAYERSERVICE_H + +#include +#include +#include + + +QT_BEGIN_NAMESPACE +class QMediaMetaData; +class QMediaPlayerControl; +class QMediaPlaylist; +class QMediaPlaylistNavigator; +class QT7PlayerControl; +class QT7PlayerMetaDataControl; +class QT7VideoWindowControl; +class QT7VideoWidgetControl; +class QT7VideoRendererControl; +class QT7VideoOutput; +class QT7PlayerSession; + +class QT7PlayerService : public QMediaService +{ +Q_OBJECT +public: + QT7PlayerService(QObject *parent = 0); + ~QT7PlayerService(); + + QMediaControl* requestControl(const char *name); + void releaseControl(QMediaControl *control); + +private: + QT7PlayerSession *m_session; + QT7PlayerControl *m_control; + QMediaControl * m_videoOutput; + QT7PlayerMetaDataControl *m_playerMetaDataControl; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qt7/mediaplayer/qt7playerservice.mm b/src/plugins/qt7/mediaplayer/qt7playerservice.mm new file mode 100644 index 000000000..39d06a4f3 --- /dev/null +++ b/src/plugins/qt7/mediaplayer/qt7playerservice.mm @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +#include "qt7backend.h" +#include "qt7playerservice.h" +#include "qt7playercontrol.h" +#include "qt7playersession.h" +#include "qt7videooutput.h" +#include "qt7movieviewoutput.h" +#include "qt7movieviewrenderer.h" +#include "qt7movierenderer.h" +#include "qt7movievideowidget.h" +#include "qt7playermetadata.h" + +#include +#include + +QT_USE_NAMESPACE + +QT7PlayerService::QT7PlayerService(QObject *parent): + QMediaService(parent), + m_videoOutput(0) +{ + m_session = new QT7PlayerSession(this); + + m_control = new QT7PlayerControl(this); + m_control->setSession(m_session); + + m_playerMetaDataControl = new QT7PlayerMetaDataControl(m_session, this); + connect(m_control, SIGNAL(mediaChanged(QMediaContent)), m_playerMetaDataControl, SLOT(updateTags())); +} + +QT7PlayerService::~QT7PlayerService() +{ +} + +QMediaControl *QT7PlayerService::requestControl(const char *name) +{ + if (qstrcmp(name, QMediaPlayerControl_iid) == 0) + return m_control; + + if (qstrcmp(name, QMetaDataReaderControl_iid) == 0) + return m_playerMetaDataControl; + +#ifndef QT_NO_OPENGL + if (!m_videoOutput) { + if (qstrcmp(name, QVideoWindowControl_iid) == 0) { +#if defined(QT_MAC_USE_COCOA) + m_videoOutput = new QT7MovieViewOutput(this); +#endif + } + + if (qstrcmp(name, QVideoRendererControl_iid) == 0) { +#ifdef QUICKTIME_C_API_AVAILABLE + m_videoOutput = new QT7MovieRenderer(this); +#else + m_videoOutput = new QT7MovieViewRenderer(this); +#endif + } + + if (qstrcmp(name, QVideoWidgetControl_iid) == 0) { +#ifdef QUICKTIME_C_API_AVAILABLE + m_videoOutput = new QT7MovieVideoWidget(this); +#endif + } + + if (m_videoOutput) { + QT7VideoOutput *videoOutput = qobject_cast(m_videoOutput); + m_session->setVideoOutput(videoOutput); + return m_videoOutput; + } + } +#endif // !defined(QT_NO_OPENGL) + + return 0; +} + +void QT7PlayerService::releaseControl(QMediaControl *control) +{ + if (m_videoOutput == control) { + m_videoOutput = 0; + m_session->setVideoOutput(0); + delete control; + } +} + +#include "moc_qt7playerservice.cpp" diff --git a/src/plugins/qt7/mediaplayer/qt7playersession.h b/src/plugins/qt7/mediaplayer/qt7playersession.h new file mode 100644 index 000000000..0b18748a4 --- /dev/null +++ b/src/plugins/qt7/mediaplayer/qt7playersession.h @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7PLAYERSESSION_H +#define QT7PLAYERSESSION_H + +#include +#include +#include +#include + +#include +#include + +#include + + +QT_BEGIN_NAMESPACE + +class QT7PlayerControl; +class QMediaPlaylist; +class QMediaPlaylistNavigator; +class QT7VideoOutput; +class QT7PlayerSession; +class QT7PlayerService; + + +class QT7PlayerSession : public QObject +{ + Q_OBJECT +public: + QT7PlayerSession(QObject *parent = 0); + ~QT7PlayerSession(); + + void *movie() const; + + void setControl(QT7PlayerControl *control); + + void setVideoOutput(QT7VideoOutput *output); + + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + + QMediaContent media() const; + const QIODevice *mediaStream() const; + void setMedia(const QMediaContent &content, QIODevice *stream); + + qint64 position() const; + qint64 duration() const; + + int bufferStatus() const; + + int volume() const; + bool isMuted() const; + + bool isAudioAvailable() const; + bool isVideoAvailable() const; + + bool isSeekable() const; + QMediaTimeRange availablePlaybackRanges() const; + + qreal playbackRate() const; + +public slots: + void setPlaybackRate(qreal rate); + + void setPosition(qint64 pos); + + void play(); + void pause(); + void stop(); + + void setVolume(int volume); + void setMuted(bool muted); + + void processEOS(); + void processLoadStateChange(); + void processVolumeChange(); + void processNaturalSizeChange(); + void processPositionChange(); + +signals: + void positionChanged(qint64 position); + void durationChanged(qint64 duration); + void stateChanged(QMediaPlayer::State newState); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void audioAvailableChanged(bool audioAvailable); + void videoAvailableChanged(bool videoAvailable); + void error(int error, const QString &errorString); + +private: + class ResourceHandler { + public: + ResourceHandler():resource(0) {} + ~ResourceHandler() { clear(); } + void setResourceFile(const QString &file) { + if (resource) { + if (resource->fileName() == file) + return; + delete resource; + rawData.clear(); + } + resource = new QResource(file); + } + bool isValid() const { return resource && resource->isValid() && resource->data() != 0; } + const uchar *data() { + if (!isValid()) + return 0; + if (resource->isCompressed()) { + if (rawData.size() == 0) + rawData = qUncompress(resource->data(), resource->size()); + return (const uchar *)rawData.constData(); + } + return resource->data(); + } + qint64 size() { + if (data() == 0) + return 0; + return resource->isCompressed() ? rawData.size() : resource->size(); + } + void clear() { + delete resource; + rawData.clear(); + } + QResource *resource; + QByteArray rawData; + }; + + void openMovie(bool tryAsync); + + void *m_QTMovie; + void *m_movieObserver; + + QMediaPlayer::State m_state; + QMediaPlayer::MediaStatus m_mediaStatus; + QIODevice *m_mediaStream; + QMediaContent m_resources; + ResourceHandler m_resourceHandler; + + QT7VideoOutput * m_videoOutput; + + bool m_muted; + bool m_tryingAsync; + int m_volume; + qreal m_rate; + + qint64 m_duration; + bool m_videoAvailable; + bool m_audioAvailable; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qt7/mediaplayer/qt7playersession.mm b/src/plugins/qt7/mediaplayer/qt7playersession.mm new file mode 100644 index 000000000..c4eef5c9d --- /dev/null +++ b/src/plugins/qt7/mediaplayer/qt7playersession.mm @@ -0,0 +1,751 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#import +#import + +#include "qt7backend.h" + +#include "qt7playersession.h" +#include "qt7playercontrol.h" +#include "qt7videooutput.h" + +#include +#include + +#include +#include + +#include +#include + +#include + +QT_USE_NAMESPACE + +//#define QT_DEBUG_QT7 + +@interface QTMovieObserver : NSObject +{ +@private + QT7PlayerSession *m_session; + QTMovie *m_movie; +} + +- (QTMovieObserver *) initWithPlayerSession:(QT7PlayerSession*)session; +- (void) setMovie:(QTMovie *)movie; +- (void) processEOS:(NSNotification *)notification; +- (void) processLoadStateChange:(NSNotification *)notification; +- (void) processVolumeChange:(NSNotification *)notification; +- (void) processNaturalSizeChange :(NSNotification *)notification; +- (void) processPositionChange :(NSNotification *)notification; +@end + +@implementation QTMovieObserver + +- (QTMovieObserver *) initWithPlayerSession:(QT7PlayerSession*)session +{ + if (!(self = [super init])) + return nil; + + self->m_session = session; + return self; +} + +- (void) setMovie:(QTMovie *)movie +{ + if (m_movie == movie) + return; + + if (m_movie) { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [m_movie release]; + } + + m_movie = movie; + + if (movie) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(processEOS:) + name:QTMovieDidEndNotification + object:m_movie]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(processLoadStateChange:) + name:QTMovieLoadStateDidChangeNotification + object:m_movie]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(processVolumeChange:) + name:QTMovieVolumeDidChangeNotification + object:m_movie]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(processPositionChange:) + name:QTMovieTimeDidChangeNotification + object:m_movie]; + + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(processNaturalSizeChange:) + name:@"QTMovieNaturalSizeDidChangeNotification" + object:m_movie]; + + } + else { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(processNaturalSizeChange:) + name:QTMovieEditedNotification + object:m_movie]; + } + + [movie retain]; + } +} + +- (void) processEOS:(NSNotification *)notification +{ + Q_UNUSED(notification); + QMetaObject::invokeMethod(m_session, "processEOS", Qt::AutoConnection); +} + +- (void) processLoadStateChange:(NSNotification *)notification +{ + Q_UNUSED(notification); + QMetaObject::invokeMethod(m_session, "processLoadStateChange", Qt::AutoConnection); +} + +- (void) processVolumeChange:(NSNotification *)notification +{ + Q_UNUSED(notification); + QMetaObject::invokeMethod(m_session, "processVolumeChange", Qt::AutoConnection); +} + +- (void) processNaturalSizeChange :(NSNotification *)notification +{ + Q_UNUSED(notification); + QMetaObject::invokeMethod(m_session, "processNaturalSizeChange", Qt::AutoConnection); +} + +- (void) processPositionChange :(NSNotification *)notification +{ + Q_UNUSED(notification); + QMetaObject::invokeMethod(m_session, "processPositionChange", Qt::AutoConnection); +} + +@end + +static inline NSString *qString2CFStringRef(const QString &string) +{ + return [NSString stringWithCharacters:reinterpret_cast(string.unicode()) length:string.length()]; +} + +QT7PlayerSession::QT7PlayerSession(QObject *parent) + : QObject(parent) + , m_QTMovie(0) + , m_state(QMediaPlayer::StoppedState) + , m_mediaStatus(QMediaPlayer::NoMedia) + , m_mediaStream(0) + , m_videoOutput(0) + , m_muted(false) + , m_tryingAsync(false) + , m_volume(100) + , m_rate(1.0) + , m_duration(0) + , m_videoAvailable(false) + , m_audioAvailable(false) +{ + m_movieObserver = [[QTMovieObserver alloc] initWithPlayerSession:this]; +} + +QT7PlayerSession::~QT7PlayerSession() +{ + if (m_videoOutput) + m_videoOutput->setMovie(0); + + [(QTMovieObserver*)m_movieObserver setMovie:nil]; + [(QTMovieObserver*)m_movieObserver release]; + [(QTMovie*)m_QTMovie release]; +} + +void *QT7PlayerSession::movie() const +{ + return m_QTMovie; +} + +void QT7PlayerSession::setVideoOutput(QT7VideoOutput *output) +{ + if (m_videoOutput == output) + return; + + if (m_videoOutput) + m_videoOutput->setMovie(0); + + m_videoOutput = output; + + if (m_videoOutput && m_state != QMediaPlayer::StoppedState) + m_videoOutput->setMovie(m_QTMovie); +} + +qint64 QT7PlayerSession::position() const +{ + if (!m_QTMovie) + return 0; + + QTTime qtTime = [(QTMovie*)m_QTMovie currentTime]; + + return static_cast(float(qtTime.timeValue) / float(qtTime.timeScale) * 1000.0f); +} + +qint64 QT7PlayerSession::duration() const +{ + if (!m_QTMovie) + return 0; + + QTTime qtTime = [(QTMovie*)m_QTMovie duration]; + + return static_cast(float(qtTime.timeValue) / float(qtTime.timeScale) * 1000.0f); +} + +QMediaPlayer::State QT7PlayerSession::state() const +{ + return m_state; +} + +QMediaPlayer::MediaStatus QT7PlayerSession::mediaStatus() const +{ + return m_mediaStatus; +} + +int QT7PlayerSession::bufferStatus() const +{ + return 100; +} + +int QT7PlayerSession::volume() const +{ + return m_volume; +} + +bool QT7PlayerSession::isMuted() const +{ + return m_muted; +} + +bool QT7PlayerSession::isSeekable() const +{ + return true; +} + +#ifndef QUICKTIME_C_API_AVAILABLE +@interface QTMovie(QtExtensions) +- (NSArray*)loadedRanges; +- (QTTime)maxTimeLoaded; +@end +#endif + +QMediaTimeRange QT7PlayerSession::availablePlaybackRanges() const +{ + QTMovie *movie = (QTMovie*)m_QTMovie; +#ifndef QUICKTIME_C_API_AVAILABLE + AutoReleasePool pool; + if ([movie respondsToSelector:@selector(loadedRanges)]) { + QMediaTimeRange rc; + NSArray *r = [movie loadedRanges]; + for (NSValue *tr in r) { + QTTimeRange timeRange = [tr QTTimeRangeValue]; + qint64 startTime = qint64(float(timeRange.time.timeValue) / timeRange.time.timeScale * 1000.0); + rc.addInterval(startTime, startTime + qint64(float(timeRange.duration.timeValue) / timeRange.duration.timeScale * 1000.0)); + } + return rc; + } + else if ([movie respondsToSelector:@selector(maxTimeLoaded)]) { + QTTime loadedTime = [movie maxTimeLoaded]; + return QMediaTimeRange(0, qint64(float(loadedTime.timeValue) / loadedTime.timeScale * 1000.0)); + } +#else + TimeValue loadedTime; + TimeScale scale; + Movie m = [movie quickTimeMovie]; + if (GetMaxLoadedTimeInMovie(m, &loadedTime) == noErr) { + scale = GetMovieTimeScale(m); + return QMediaTimeRange(0, qint64(float(loadedTime) / scale * 1000.0f)); + } +#endif + return QMediaTimeRange(0, duration()); +} + +qreal QT7PlayerSession::playbackRate() const +{ + return m_rate; +} + +void QT7PlayerSession::setPlaybackRate(qreal rate) +{ + if (qFuzzyCompare(m_rate, rate)) + return; + + m_rate = rate; + + if (m_QTMovie != 0 && m_state == QMediaPlayer::PlayingState) { + AutoReleasePool pool; + float preferredRate = [[(QTMovie*)m_QTMovie attributeForKey:@"QTMoviePreferredRateAttribute"] floatValue]; + [(QTMovie*)m_QTMovie setRate:preferredRate * m_rate]; + } +} + +void QT7PlayerSession::setPosition(qint64 pos) +{ + if ( !isSeekable() || pos == position()) + return; + + if (duration() > 0) + pos = qMin(pos, duration()); + + QTTime newQTTime = [(QTMovie*)m_QTMovie currentTime]; + newQTTime.timeValue = (pos / 1000.0f) * newQTTime.timeScale; + [(QTMovie*)m_QTMovie setCurrentTime:newQTTime]; + + //reset the EndOfMedia status position is changed after playback is finished + if (m_mediaStatus == QMediaPlayer::EndOfMedia) + processLoadStateChange(); +} + +void QT7PlayerSession::play() +{ + if (m_state == QMediaPlayer::PlayingState) + return; + + m_state = QMediaPlayer::PlayingState; + + if (m_videoOutput) + m_videoOutput->setMovie(m_QTMovie); + + //reset the EndOfMedia status if the same file is played again + if (m_mediaStatus == QMediaPlayer::EndOfMedia) + processLoadStateChange(); + + AutoReleasePool pool; + float preferredRate = [[(QTMovie*)m_QTMovie attributeForKey:@"QTMoviePreferredRateAttribute"] floatValue]; + [(QTMovie*)m_QTMovie setRate:preferredRate * m_rate]; + + processLoadStateChange(); + emit stateChanged(m_state); +} + +void QT7PlayerSession::pause() +{ + if (m_state == QMediaPlayer::PausedState) + return; + + m_state = QMediaPlayer::PausedState; + + if (m_videoOutput) + m_videoOutput->setMovie(m_QTMovie); + + //reset the EndOfMedia status if the same file is played again + if (m_mediaStatus == QMediaPlayer::EndOfMedia) + processLoadStateChange(); + + [(QTMovie*)m_QTMovie setRate:0]; + + processLoadStateChange(); + emit stateChanged(m_state); +} + +void QT7PlayerSession::stop() +{ + if (m_state == QMediaPlayer::StoppedState) + return; + + m_state = QMediaPlayer::StoppedState; + + [(QTMovie*)m_QTMovie setRate:0]; + setPosition(0); + + if (m_videoOutput) + m_videoOutput->setMovie(0); + + processLoadStateChange(); + emit stateChanged(m_state); + emit positionChanged(position()); +} + +void QT7PlayerSession::setVolume(int volume) +{ + if (m_volume == volume) + return; + + m_volume = volume; + + if (m_QTMovie != 0) + [(QTMovie*)m_QTMovie setVolume:m_volume / 100.0f]; + + emit volumeChanged(m_volume); +} + +void QT7PlayerSession::setMuted(bool muted) +{ + if (m_muted == muted) + return; + + m_muted = muted; + + if (m_QTMovie != 0) + [(QTMovie*)m_QTMovie setMuted:m_muted]; + + emit mutedChanged(muted); +} + +QMediaContent QT7PlayerSession::media() const +{ + return m_resources; +} + +const QIODevice *QT7PlayerSession::mediaStream() const +{ + return m_mediaStream; +} + +void QT7PlayerSession::setMedia(const QMediaContent &content, QIODevice *stream) +{ + AutoReleasePool pool; + +#ifdef QT_DEBUG_QT7 + qDebug() << Q_FUNC_INFO << content.canonicalUrl(); +#endif + + if (m_QTMovie) { + [(QTMovieObserver*)m_movieObserver setMovie:nil]; + + if (m_videoOutput) + m_videoOutput->setMovie(0); + + [(QTMovie*)m_QTMovie release]; + m_QTMovie = 0; + m_resourceHandler.clear(); + } + + m_resources = content; + m_mediaStream = stream; + QMediaPlayer::MediaStatus oldMediaStatus = m_mediaStatus; + + if (content.isNull()) { + m_mediaStatus = QMediaPlayer::NoMedia; + if (m_state != QMediaPlayer::StoppedState) + emit stateChanged(m_state = QMediaPlayer::StoppedState); + + if (m_mediaStatus != oldMediaStatus) + emit mediaStatusChanged(m_mediaStatus); + emit positionChanged(position()); + return; + } + + m_mediaStatus = QMediaPlayer::LoadingMedia; + if (m_mediaStatus != oldMediaStatus) + emit mediaStatusChanged(m_mediaStatus); + + QNetworkRequest request = content.canonicalResource().request(); + + QVariant cookies = request.header(QNetworkRequest::CookieHeader); + if (cookies.isValid()) { + NSHTTPCookieStorage *store = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + QList cookieList = cookies.value >(); + + foreach (const QNetworkCookie &requestCookie, cookieList) { + NSMutableDictionary *p = [NSMutableDictionary dictionaryWithObjectsAndKeys: + qString2CFStringRef(requestCookie.name()), NSHTTPCookieName, + qString2CFStringRef(requestCookie.value()), NSHTTPCookieValue, + qString2CFStringRef(requestCookie.domain()), NSHTTPCookieDomain, + qString2CFStringRef(requestCookie.path()), NSHTTPCookiePath, + nil + ]; + if (requestCookie.isSessionCookie()) + [p setObject:[NSString stringWithUTF8String:"TRUE"] forKey:NSHTTPCookieDiscard]; + else + [p setObject:[NSDate dateWithTimeIntervalSince1970:requestCookie.expirationDate().toTime_t()] forKey:NSHTTPCookieExpires]; + + [store setCookie:[NSHTTPCookie cookieWithProperties:p]]; + } + } + + // Attempt multiple times to open the movie. + // First try - attempt open in async mode + openMovie(true); + + emit positionChanged(position()); +} + +void QT7PlayerSession::openMovie(bool tryAsync) +{ + QUrl requestUrl = m_resources.canonicalResource().request().url(); + if (requestUrl.scheme().isEmpty()) + requestUrl.setScheme(QLatin1String("file")); + +#ifdef QT_DEBUG_QT7 + qDebug() << Q_FUNC_INFO << requestUrl; +#endif + + NSError *err = 0; + NSString *urlString = [NSString stringWithUTF8String:requestUrl.toEncoded().constData()]; + + NSMutableDictionary *attr = [NSMutableDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:YES], QTMovieOpenAsyncOKAttribute, + [NSNumber numberWithBool:YES], QTMovieIsActiveAttribute, + [NSNumber numberWithBool:YES], QTMovieResolveDataRefsAttribute, + [NSNumber numberWithBool:YES], QTMovieDontInteractWithUserAttribute, + nil]; + + + if (requestUrl.scheme() == QLatin1String("qrc")) { + // Load from Qt resource + m_resourceHandler.setResourceFile(QLatin1Char(':') + requestUrl.path()); + if (!m_resourceHandler.isValid()) { + emit error(QMediaPlayer::FormatError, tr("Attempting to play invalid Qt resource")); + return; + } + + CFDataRef resourceData = + CFDataCreateWithBytesNoCopy(0, m_resourceHandler.data(), m_resourceHandler.size(), kCFAllocatorNull); + + QTDataReference *dataReference = + [QTDataReference dataReferenceWithReferenceToData:(NSData*)resourceData + name:qString2CFStringRef(requestUrl.path()) + MIMEType:nil]; + + [attr setObject:dataReference forKey:QTMovieDataReferenceAttribute]; + + CFRelease(resourceData); + } else { + [attr setObject:[NSURL URLWithString:urlString] forKey:QTMovieURLAttribute]; + } + + if (tryAsync && QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) { + [attr setObject:[NSNumber numberWithBool:YES] forKey:@"QTMovieOpenAsyncRequiredAttribute"]; +// XXX: This is disabled for now. causes some problems with video playback for some formats +// [attr setObject:[NSNumber numberWithBool:YES] forKey:@"QTMovieOpenForPlaybackAttribute"]; + m_tryingAsync = true; + } + else + m_tryingAsync = false; + + m_QTMovie = [QTMovie movieWithAttributes:attr error:&err]; + if (err != nil) { + // First attempt to test for inability to perform async +// if ([err code] == QTErrorMovieOpeningCannotBeAsynchronous) { XXX: error code unknown! + if (m_tryingAsync) { + m_tryingAsync = false; + err = nil; + [attr removeObjectForKey:@"QTMovieOpenAsyncRequiredAttribute"]; + m_QTMovie = [QTMovie movieWithAttributes:attr error:&err]; + } + } + + if (err != nil) { + m_QTMovie = 0; + QString description = QString::fromUtf8([[err localizedDescription] UTF8String]); + emit error(QMediaPlayer::FormatError, description); + +#ifdef QT_DEBUG_QT7 + qDebug() << Q_FUNC_INFO << description; +#endif + } + else { + [(QTMovie*)m_QTMovie retain]; + + [(QTMovieObserver*)m_movieObserver setMovie:(QTMovie*)m_QTMovie]; + + if (m_state != QMediaPlayer::StoppedState && m_videoOutput) + m_videoOutput->setMovie(m_QTMovie); + + processLoadStateChange(); + + [(QTMovie*)m_QTMovie setMuted:m_muted]; + [(QTMovie*)m_QTMovie setVolume:m_volume / 100.0f]; + } +} + +bool QT7PlayerSession::isAudioAvailable() const +{ + if (!m_QTMovie) + return false; + + AutoReleasePool pool; + return [[(QTMovie*)m_QTMovie attributeForKey:@"QTMovieHasAudioAttribute"] boolValue] == YES; +} + +bool QT7PlayerSession::isVideoAvailable() const +{ + if (!m_QTMovie) + return false; + + AutoReleasePool pool; + return [[(QTMovie*)m_QTMovie attributeForKey:@"QTMovieHasVideoAttribute"] boolValue] == YES; +} + +void QT7PlayerSession::processEOS() +{ +#ifdef QT_DEBUG_QT7 + qDebug() << Q_FUNC_INFO; +#endif + emit positionChanged(position()); + m_mediaStatus = QMediaPlayer::EndOfMedia; + if (m_videoOutput) + m_videoOutput->setMovie(0); + emit stateChanged(m_state = QMediaPlayer::StoppedState); + emit mediaStatusChanged(m_mediaStatus); +} + +void QT7PlayerSession::processLoadStateChange() +{ + if (!m_QTMovie) + return; + + AutoReleasePool pool; + + long state = [[(QTMovie*)m_QTMovie attributeForKey:QTMovieLoadStateAttribute] longValue]; + +#ifdef QT_DEBUG_QT7 + qDebug() << Q_FUNC_INFO << state; +#endif + +#ifndef QUICKTIME_C_API_AVAILABLE + enum { + kMovieLoadStateError = -1L, + kMovieLoadStateLoading = 1000, + kMovieLoadStateLoaded = 2000, + kMovieLoadStatePlayable = 10000, + kMovieLoadStatePlaythroughOK = 20000, + kMovieLoadStateComplete = 100000 + }; +#endif + + if (state == kMovieLoadStateError) { + if (m_tryingAsync) { + NSError *error = [(QTMovie*)m_QTMovie attributeForKey:@"QTMovieLoadStateErrorAttribute"]; + if ([error code] == componentNotThreadSafeErr) { + // Last Async check, try again with no such flag + openMovie(false); + } + } + else { + if (m_videoOutput) + m_videoOutput->setMovie(0); + + emit error(QMediaPlayer::FormatError, tr("Failed to load media")); + emit mediaStatusChanged(m_mediaStatus = QMediaPlayer::InvalidMedia); + emit stateChanged(m_state = QMediaPlayer::StoppedState); + } + + return; + } + + QMediaPlayer::MediaStatus newStatus = QMediaPlayer::NoMedia; + bool isPlaying = (m_state != QMediaPlayer::StoppedState); + + if (state >= kMovieLoadStatePlaythroughOK) { + newStatus = isPlaying ? QMediaPlayer::BufferedMedia : QMediaPlayer::LoadedMedia; + } else if (state >= kMovieLoadStatePlayable) + newStatus = isPlaying ? QMediaPlayer::BufferingMedia : QMediaPlayer::LoadingMedia; + else if (state >= kMovieLoadStateLoading) { + if (!isPlaying) + newStatus = QMediaPlayer::LoadingMedia; + else if (m_mediaStatus >= QMediaPlayer::LoadedMedia) + newStatus = QMediaPlayer::StalledMedia; + else + newStatus = QMediaPlayer::LoadingMedia; + } + + if (state >= kMovieLoadStatePlayable && + m_state == QMediaPlayer::PlayingState && + [(QTMovie*)m_QTMovie rate] == 0) { + + float preferredRate = [[(QTMovie*)m_QTMovie attributeForKey:@"QTMoviePreferredRateAttribute"] floatValue]; + + [(QTMovie*)m_QTMovie setRate:preferredRate * m_rate]; + } + + if (state >= kMovieLoadStateLoaded) { + qint64 currentDuration = duration(); + if (m_duration != currentDuration) + emit durationChanged(m_duration = currentDuration); + + if (m_audioAvailable != isAudioAvailable()) + emit audioAvailableChanged(m_audioAvailable = !m_audioAvailable); + + if (m_videoAvailable != isVideoAvailable()) + emit videoAvailableChanged(m_videoAvailable = !m_videoAvailable); + } + + if (newStatus != m_mediaStatus) + emit mediaStatusChanged(m_mediaStatus = newStatus); +} + +void QT7PlayerSession::processVolumeChange() +{ + if (!m_QTMovie) + return; + + int newVolume = qRound(100.0f * [((QTMovie*)m_QTMovie) volume]); + + if (newVolume != m_volume) { + emit volumeChanged(m_volume = newVolume); + } +} + +void QT7PlayerSession::processNaturalSizeChange() +{ + AutoReleasePool pool; + NSSize size = [[(QTMovie*)m_QTMovie attributeForKey:@"QTMovieNaturalSizeAttribute"] sizeValue]; +#ifdef QT_DEBUG_QT7 + qDebug() << Q_FUNC_INFO << QSize(size.width, size.height); +#endif + + if (m_videoOutput) + m_videoOutput->updateNaturalSize(QSize(size.width, size.height)); +} + +void QT7PlayerSession::processPositionChange() +{ + emit positionChanged(position()); +} + +#include "moc_qt7playersession.cpp" diff --git a/src/plugins/qt7/qcvdisplaylink.h b/src/plugins/qt7/qcvdisplaylink.h new file mode 100644 index 000000000..536abbf58 --- /dev/null +++ b/src/plugins/qt7/qcvdisplaylink.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCVDISPLAYLINK_H +#define QCVDISPLAYLINK_H + +#include +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QCvDisplayLink : public QObject +{ +Q_OBJECT +public: + QCvDisplayLink(QObject *parent = 0); + virtual ~QCvDisplayLink(); + + bool isValid(); + bool isActive() const; + +public slots: + void start(); + void stop(); + +signals: + void tick(const CVTimeStamp &ts); + +public: + void displayLinkEvent(const CVTimeStamp *); + +protected: + virtual bool event(QEvent *); + +private: + CVDisplayLinkRef m_displayLink; + QMutex m_displayLinkMutex; + bool m_pendingDisplayLinkEvent; + bool m_isActive; + CVTimeStamp m_frameTimeStamp; +}; + +QT_END_NAMESPACE + +#endif + diff --git a/src/plugins/qt7/qcvdisplaylink.mm b/src/plugins/qt7/qcvdisplaylink.mm new file mode 100644 index 000000000..ecc4235bd --- /dev/null +++ b/src/plugins/qt7/qcvdisplaylink.mm @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcvdisplaylink.h" + +#include +#include + +QT_USE_NAMESPACE + +static CVReturn CVDisplayLinkCallback(CVDisplayLinkRef displayLink, + const CVTimeStamp *inNow, + const CVTimeStamp *inOutputTime, + CVOptionFlags flagsIn, + CVOptionFlags *flagsOut, + void *displayLinkContext) +{ + Q_UNUSED(displayLink); + Q_UNUSED(inNow); + Q_UNUSED(flagsIn); + Q_UNUSED(flagsOut); + + QCvDisplayLink *link = (QCvDisplayLink *)displayLinkContext; + + link->displayLinkEvent(inOutputTime); + return kCVReturnSuccess; +} + + +QCvDisplayLink::QCvDisplayLink(QObject *parent) + :QObject(parent), + m_pendingDisplayLinkEvent(false), + m_isActive(false) +{ + // create display link for the main display + CVDisplayLinkCreateWithCGDisplay(kCGDirectMainDisplay, &m_displayLink); + if (m_displayLink) { + // set the current display of a display link. + CVDisplayLinkSetCurrentCGDisplay(m_displayLink, kCGDirectMainDisplay); + + // set the renderer output callback function + CVDisplayLinkSetOutputCallback(m_displayLink, &CVDisplayLinkCallback, this); + } +} + +QCvDisplayLink::~QCvDisplayLink() +{ + if (m_displayLink) { + CVDisplayLinkStop(m_displayLink); + CVDisplayLinkRelease(m_displayLink); + m_displayLink = NULL; + } +} + +bool QCvDisplayLink::isValid() +{ + return m_displayLink != 0; +} + +bool QCvDisplayLink::isActive() const +{ + return m_isActive; +} + +void QCvDisplayLink::start() +{ + if (m_displayLink && !m_isActive) { + CVDisplayLinkStart(m_displayLink); + m_isActive = true; + } +} + +void QCvDisplayLink::stop() +{ + if (m_displayLink && m_isActive) { + CVDisplayLinkStop(m_displayLink); + m_isActive = false; + } +} + +void QCvDisplayLink::displayLinkEvent(const CVTimeStamp *ts) +{ + // This function is called from a + // thread != gui thread. So we post the event. + // But we need to make sure that we don't post faster + // than the event loop can eat: + m_displayLinkMutex.lock(); + bool pending = m_pendingDisplayLinkEvent; + m_pendingDisplayLinkEvent = true; + m_frameTimeStamp = *ts; + m_displayLinkMutex.unlock(); + + if (!pending) + qApp->postEvent(this, new QEvent(QEvent::User), Qt::HighEventPriority); +} + +bool QCvDisplayLink::event(QEvent *event) +{ + switch (event->type()){ + case QEvent::User: { + m_displayLinkMutex.lock(); + m_pendingDisplayLinkEvent = false; + CVTimeStamp ts = m_frameTimeStamp; + m_displayLinkMutex.unlock(); + + emit tick(ts); + + return false; + } + break; + default: + break; + } + return QObject::event(event); +} + +#include "moc_qcvdisplaylink.cpp" + diff --git a/src/plugins/qt7/qt7.pro b/src/plugins/qt7/qt7.pro new file mode 100644 index 000000000..db3728c33 --- /dev/null +++ b/src/plugins/qt7/qt7.pro @@ -0,0 +1,58 @@ +load(qt_module) + +TARGET = qqt7engine +QT += multimediakit-private network +PLUGIN_TYPE = mediaservice + +load(qt_plugin) +DESTDIR = $$QT.multimediakit.plugins/$${PLUGIN_TYPE} + +!simulator { +QT += opengl +} + +#DEFINES += QT_DEBUG_QT7 + +LIBS += -framework AppKit -framework AudioUnit \ + -framework AudioToolbox -framework CoreAudio \ + -framework QuartzCore -framework QTKit + +# The Quicktime framework is only awailable for 32-bit builds, so we +# need to check for this before linking against it. +# QMAKE_MAC_XARCH is not awailable on Tiger, but at the same time, +# we never build for 64-bit architechtures on Tiger either: +contains(QMAKE_MAC_XARCH, no) { + LIBS += -framework QuickTime +} else { + LIBS += -Xarch_i386 -framework QuickTime -Xarch_ppc -framework QuickTime +} + +HEADERS += \ + qt7backend.h \ + qt7videooutput.h \ + qt7serviceplugin.h + +OBJECTIVE_SOURCES += \ + qt7backend.mm \ + qt7serviceplugin.mm + +!simulator { + HEADERS += \ + qt7movieviewoutput.h \ + qt7movievideowidget.h \ + qt7movieviewrenderer.h \ + qt7movierenderer.h \ + qt7ciimagevideobuffer.h \ + qcvdisplaylink.h + + OBJECTIVE_SOURCES += \ + qt7movieviewoutput.mm \ + qt7movievideowidget.mm \ + qt7movieviewrenderer.mm \ + qt7movierenderer.mm \ + qt7videooutput.mm \ + qt7ciimagevideobuffer.mm \ + qcvdisplaylink.mm +} + +include(mediaplayer/mediaplayer.pri) diff --git a/src/plugins/qt7/qt7backend.h b/src/plugins/qt7/qt7backend.h new file mode 100644 index 000000000..d52f0396a --- /dev/null +++ b/src/plugins/qt7/qt7backend.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7BACKEND_H +#define QT7BACKEND_H + +#include "qmobilityglobal.h" + +#include + +#ifndef Q_WS_SIMULATOR +#ifndef Q_WS_MAC64 +#define QUICKTIME_C_API_AVAILABLE +#endif +#endif // !defined(Q_WS_SIMULATOR) + +QT_BEGIN_NAMESPACE + +class AutoReleasePool +{ +private: + void *pool; +public: + AutoReleasePool(); + ~AutoReleasePool(); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qt7/qt7backend.mm b/src/plugins/qt7/qt7backend.mm new file mode 100644 index 000000000..83a044dab --- /dev/null +++ b/src/plugins/qt7/qt7backend.mm @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qt7backend.h" + +#import +#include + + +QT_BEGIN_NAMESPACE + +AutoReleasePool::AutoReleasePool() +{ + pool = (void*)[[NSAutoreleasePool alloc] init]; +} + +AutoReleasePool::~AutoReleasePool() +{ + [(NSAutoreleasePool*)pool release]; +} + +QT_END_NAMESPACE diff --git a/src/plugins/qt7/qt7ciimagevideobuffer.h b/src/plugins/qt7/qt7ciimagevideobuffer.h new file mode 100644 index 000000000..d6ae19f80 --- /dev/null +++ b/src/plugins/qt7/qt7ciimagevideobuffer.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7CIIMAGEVIDEOBUFFER_H +#define QT7CIIMAGEVIDEOBUFFER_H + +#include "qt7backend.h" +#import + +#include +#include + + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +class QT7CIImageVideoBuffer : public QAbstractVideoBuffer +{ +public: + QT7CIImageVideoBuffer(CIImage *image); + + virtual ~QT7CIImageVideoBuffer(); + + MapMode mapMode() const; + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine); + void unmap(); + QVariant handle() const; + +private: + CIImage *m_image; + NSBitmapImageRep *m_buffer; + MapMode m_mode; +}; + + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qt7/qt7ciimagevideobuffer.mm b/src/plugins/qt7/qt7ciimagevideobuffer.mm new file mode 100644 index 000000000..e7758c0a6 --- /dev/null +++ b/src/plugins/qt7/qt7ciimagevideobuffer.mm @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qt7ciimagevideobuffer.h" + +#include +#include + +QT7CIImageVideoBuffer::QT7CIImageVideoBuffer(CIImage *image) + : QAbstractVideoBuffer(CoreImageHandle) + , m_image(image) + , m_buffer(0) + , m_mode(NotMapped) +{ + [m_image retain]; +} + +QT7CIImageVideoBuffer::~QT7CIImageVideoBuffer() +{ + [m_image release]; + [m_buffer release]; +} + +QAbstractVideoBuffer::MapMode QT7CIImageVideoBuffer::mapMode() const +{ + return m_mode; +} + +uchar *QT7CIImageVideoBuffer::map(QAbstractVideoBuffer::MapMode mode, int *numBytes, int *bytesPerLine) +{ + if (mode == NotMapped || m_mode != NotMapped || !m_image) + return 0; + + if (!m_buffer) { + //swap R and B channels + CIFilter *colorSwapFilter = [CIFilter filterWithName: @"CIColorMatrix" keysAndValues: + @"inputImage", m_image, + @"inputRVector", [CIVector vectorWithX: 0 Y: 0 Z: 1 W: 0], + @"inputGVector", [CIVector vectorWithX: 0 Y: 1 Z: 0 W: 0], + @"inputBVector", [CIVector vectorWithX: 1 Y: 0 Z: 0 W: 0], + @"inputAVector", [CIVector vectorWithX: 0 Y: 0 Z: 0 W: 1], + @"inputBiasVector", [CIVector vectorWithX: 0 Y: 0 Z: 0 W: 0], + nil]; + CIImage *img = [colorSwapFilter valueForKey: @"outputImage"]; + + m_buffer = [[NSBitmapImageRep alloc] initWithCIImage:img]; + } + + if (numBytes) + *numBytes = [m_buffer bytesPerPlane]; + + if (bytesPerLine) + *bytesPerLine = [m_buffer bytesPerRow]; + + m_mode = mode; + + return [m_buffer bitmapData]; +} + +void QT7CIImageVideoBuffer::unmap() +{ + m_mode = NotMapped; +} + +QVariant QT7CIImageVideoBuffer::handle() const +{ + return QVariant::fromValue(m_image); +} + diff --git a/src/plugins/qt7/qt7movierenderer.h b/src/plugins/qt7/qt7movierenderer.h new file mode 100644 index 000000000..42a2732da --- /dev/null +++ b/src/plugins/qt7/qt7movierenderer.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7MOVIERENDERER_H +#define QT7MOVIERENDERER_H + +#include "qt7backend.h" + +#include +#include + +#include +#include + +#include +#include "qt7videooutput.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class QGLContext; + +class QCvDisplayLink; +class QT7PlayerSession; +class QT7PlayerService; + +class QT7MovieRenderer : public QT7VideoRendererControl +{ +Q_OBJECT +public: + QT7MovieRenderer(QObject *parent = 0); + virtual ~QT7MovieRenderer(); + + void setMovie(void *movie); + void updateNaturalSize(const QSize &newSize); + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + + QSize nativeSize() const; + +private slots: + void updateVideoFrame(const CVTimeStamp &ts); + +private: + void setupVideoOutput(); + bool createPixelBufferVisualContext(); + bool createGLVisualContext(); + + void *m_movie; + + QMutex m_mutex; + + QCvDisplayLink *m_displayLink; +#ifdef QUICKTIME_C_API_AVAILABLE + QTVisualContextRef m_visualContext; + bool m_usingGLContext; + const QGLContext *m_currentGLContext; + QSize m_pixelBufferContextGeometry; +#endif + QAbstractVideoSurface *m_surface; + QSize m_nativeSize; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qt7/qt7movierenderer.mm b/src/plugins/qt7/qt7movierenderer.mm new file mode 100644 index 000000000..6818f02d1 --- /dev/null +++ b/src/plugins/qt7/qt7movierenderer.mm @@ -0,0 +1,479 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#import + +#include "qt7backend.h" + +#include "qt7playercontrol.h" +#include "qt7movierenderer.h" +#include "qt7playersession.h" +#include "qt7ciimagevideobuffer.h" +#include "qcvdisplaylink.h" +#include +#include + +#include + +#include +#include +#include + +QT_USE_NAMESPACE + +//#define USE_MAIN_MONITOR_COLOR_SPACE 1 + +class CVGLTextureVideoBuffer : public QAbstractVideoBuffer +{ +public: + CVGLTextureVideoBuffer(CVOpenGLTextureRef buffer) + : QAbstractVideoBuffer(GLTextureHandle) + , m_buffer(buffer) + , m_mode(NotMapped) + { + CVOpenGLTextureRetain(m_buffer); + } + + virtual ~CVGLTextureVideoBuffer() + { + CVOpenGLTextureRelease(m_buffer); + } + + QVariant handle() const + { + GLuint id = CVOpenGLTextureGetName(m_buffer); + return QVariant(int(id)); + } + + MapMode mapMode() const { return m_mode; } + + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) + { + if (numBytes) + *numBytes = 0; + + if (bytesPerLine) + *bytesPerLine = 0; + + m_mode = mode; + return 0; + } + + void unmap() { m_mode = NotMapped; } + +private: + CVOpenGLTextureRef m_buffer; + MapMode m_mode; +}; + + +class CVPixelBufferVideoBuffer : public QAbstractVideoBuffer +{ +public: + CVPixelBufferVideoBuffer(CVPixelBufferRef buffer) + : QAbstractVideoBuffer(NoHandle) + , m_buffer(buffer) + , m_mode(NotMapped) + { + CVPixelBufferRetain(m_buffer); + } + + virtual ~CVPixelBufferVideoBuffer() + { + CVPixelBufferRelease(m_buffer); + } + + MapMode mapMode() const { return m_mode; } + + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) + { + if (mode != NotMapped && m_mode == NotMapped) { + CVPixelBufferLockBaseAddress(m_buffer, 0); + + if (numBytes) + *numBytes = CVPixelBufferGetDataSize(m_buffer); + + if (bytesPerLine) + *bytesPerLine = CVPixelBufferGetBytesPerRow(m_buffer); + + m_mode = mode; + + return (uchar*)CVPixelBufferGetBaseAddress(m_buffer); + } else { + return 0; + } + } + + void unmap() + { + if (m_mode != NotMapped) { + m_mode = NotMapped; + CVPixelBufferUnlockBaseAddress(m_buffer, 0); + } + } + +private: + CVPixelBufferRef m_buffer; + MapMode m_mode; +}; + + + +QT7MovieRenderer::QT7MovieRenderer(QObject *parent) + :QT7VideoRendererControl(parent), + m_movie(0), +#ifdef QUICKTIME_C_API_AVAILABLE + m_visualContext(0), + m_usingGLContext(false), + m_currentGLContext(0), +#endif + m_surface(0) +{ +#ifdef QT_DEBUG_QT7 + qDebug() << "QT7MovieRenderer"; +#endif + m_displayLink = new QCvDisplayLink(this); + connect(m_displayLink, SIGNAL(tick(CVTimeStamp)), SLOT(updateVideoFrame(CVTimeStamp))); +} + + +bool QT7MovieRenderer::createGLVisualContext() +{ +#ifdef QUICKTIME_C_API_AVAILABLE + AutoReleasePool pool; + CGLContextObj cglContext = CGLGetCurrentContext(); + NSOpenGLPixelFormat *nsglPixelFormat = [NSOpenGLView defaultPixelFormat]; + CGLPixelFormatObj cglPixelFormat = static_cast([nsglPixelFormat CGLPixelFormatObj]); + + OSStatus err = QTOpenGLTextureContextCreate(kCFAllocatorDefault, cglContext, + cglPixelFormat, NULL, &m_visualContext); + if (err != noErr) + qWarning() << "Could not create visual context (OpenGL)"; + + return (err == noErr); +#endif // QUICKTIME_C_API_AVAILABLE + + return false; +} + +#ifdef QUICKTIME_C_API_AVAILABLE +static bool DictionarySetValue(CFMutableDictionaryRef dict, CFStringRef key, SInt32 value) +{ + CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value); + + if (number) { + CFDictionarySetValue( dict, key, number ); + CFRelease( number ); + return true; + } + return false; +} +#endif // QUICKTIME_C_API_AVAILABLE + +bool QT7MovieRenderer::createPixelBufferVisualContext() +{ +#ifdef QUICKTIME_C_API_AVAILABLE + if (m_visualContext) { + QTVisualContextRelease(m_visualContext); + m_visualContext = 0; + } + + m_pixelBufferContextGeometry = m_nativeSize; + + CFMutableDictionaryRef pixelBufferOptions = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + //DictionarySetValue(pixelBufferOptions, kCVPixelBufferPixelFormatTypeKey, k32ARGBPixelFormat ); + DictionarySetValue(pixelBufferOptions, kCVPixelBufferPixelFormatTypeKey, k32BGRAPixelFormat ); + DictionarySetValue(pixelBufferOptions, kCVPixelBufferWidthKey, m_nativeSize.width() ); + DictionarySetValue(pixelBufferOptions, kCVPixelBufferHeightKey, m_nativeSize.height() ); + DictionarySetValue(pixelBufferOptions, kCVPixelBufferBytesPerRowAlignmentKey, 16); + //CFDictionarySetValue(pixelBufferOptions, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue); + + CFMutableDictionaryRef visualContextOptions = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(visualContextOptions, kQTVisualContextPixelBufferAttributesKey, pixelBufferOptions); + + CGColorSpaceRef colorSpace = NULL; + +#if USE_MAIN_MONITOR_COLOR_SPACE + CMProfileRef sysprof = NULL; + + // Get the Systems Profile for the main display + if (CMGetSystemProfile(&sysprof) == noErr) { + // Create a colorspace with the systems profile + colorSpace = CGColorSpaceCreateWithPlatformColorSpace(sysprof); + CMCloseProfile(sysprof); + } +#endif + + if (!colorSpace) + colorSpace = CGColorSpaceCreateDeviceRGB(); + + CFDictionarySetValue(visualContextOptions, kQTVisualContextOutputColorSpaceKey, colorSpace); + + OSStatus err = QTPixelBufferContextCreate(kCFAllocatorDefault, + visualContextOptions, + &m_visualContext); + CFRelease(pixelBufferOptions); + CFRelease(visualContextOptions); + + if (err != noErr) { + qWarning() << "Could not create visual context (PixelBuffer)"; + return false; + } + + return true; +#endif // QUICKTIME_C_API_AVAILABLE + + return false; +} + + +QT7MovieRenderer::~QT7MovieRenderer() +{ + m_displayLink->stop(); +} + +void QT7MovieRenderer::setupVideoOutput() +{ + AutoReleasePool pool; + +#ifdef QT_DEBUG_QT7 + qDebug() << "QT7MovieRenderer::setupVideoOutput" << m_movie; +#endif + + if (m_movie == 0 || m_surface == 0) { + m_displayLink->stop(); + return; + } + + NSSize size = [[(QTMovie*)m_movie attributeForKey:@"QTMovieNaturalSizeAttribute"] sizeValue]; + m_nativeSize = QSize(size.width, size.height); + +#ifdef QUICKTIME_C_API_AVAILABLE + bool usedGLContext = m_usingGLContext; + + if (!m_nativeSize.isEmpty()) { + + bool glSupported = !m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).isEmpty(); + + //Try rendering using opengl textures first: + if (glSupported) { + QVideoSurfaceFormat format(m_nativeSize, QVideoFrame::Format_RGB32, QAbstractVideoBuffer::GLTextureHandle); + + if (m_surface->isActive()) + m_surface->stop(); + + if (!m_surface->start(format)) { + qWarning() << "failed to start video surface" << m_surface->error(); + qWarning() << "Surface format:" << format; + glSupported = false; + } else { + m_usingGLContext = true; + } + + } + + if (!glSupported) { + m_usingGLContext = false; + QVideoSurfaceFormat format(m_nativeSize, QVideoFrame::Format_RGB32); + + if (m_surface->isActive() && m_surface->surfaceFormat() != format) { +#ifdef QT_DEBUG_QT7 + qDebug() << "Surface format was changed, stop the surface."; +#endif + m_surface->stop(); + } + + if (!m_surface->isActive()) { +#ifdef QT_DEBUG_QT7 + qDebug() << "Starting the surface with format" << format; +#endif + if (!m_surface->start(format)) { + qWarning() << "failed to start video surface" << m_surface->error(); + qWarning() << "Surface format:" << format; + } + } + } + } + + + if (m_visualContext) { + //check if the visual context still can be reused + if (usedGLContext != m_usingGLContext || + (m_usingGLContext && (m_currentGLContext != QGLContext::currentContext())) || + (!m_usingGLContext && (m_pixelBufferContextGeometry != m_nativeSize))) { + QTVisualContextRelease(m_visualContext); + m_pixelBufferContextGeometry = QSize(); + m_visualContext = 0; + } + } + + if (!m_nativeSize.isEmpty()) { + if (!m_visualContext) { + if (m_usingGLContext) { +#ifdef QT_DEBUG_QT7 + qDebug() << "Building OpenGL visual context" << m_nativeSize; +#endif + m_currentGLContext = QGLContext::currentContext(); + if (!createGLVisualContext()) { + qWarning() << "QT7MovieRenderer: failed to create visual context"; + return; + } + } else { +#ifdef QT_DEBUG_QT7 + qDebug() << "Building Pixel Buffer visual context" << m_nativeSize; +#endif + if (!createPixelBufferVisualContext()) { + qWarning() << "QT7MovieRenderer: failed to create visual context"; + return; + } + } + } + + // targets a Movie to render into a visual context + SetMovieVisualContext([(QTMovie*)m_movie quickTimeMovie], m_visualContext); + + m_displayLink->start(); + } +#endif + +} + +void QT7MovieRenderer::setMovie(void *movie) +{ +#ifdef QT_DEBUG_QT7 + qDebug() << "QT7MovieRenderer::setMovie" << movie; +#endif + +#ifdef QUICKTIME_C_API_AVAILABLE + QMutexLocker locker(&m_mutex); + + if (m_movie != movie) { + if (m_movie) { + //ensure the old movie doesn't hold the visual context, otherwise it can't be reused + SetMovieVisualContext([(QTMovie*)m_movie quickTimeMovie], nil); + [(QTMovie*)m_movie release]; + } + + m_movie = movie; + [(QTMovie*)m_movie retain]; + + setupVideoOutput(); + } +#endif +} + +void QT7MovieRenderer::updateNaturalSize(const QSize &newSize) +{ + if (m_nativeSize != newSize) { + m_nativeSize = newSize; + setupVideoOutput(); + } +} + +QAbstractVideoSurface *QT7MovieRenderer::surface() const +{ + return m_surface; +} + +void QT7MovieRenderer::setSurface(QAbstractVideoSurface *surface) +{ +#ifdef QT_DEBUG_QT7 + qDebug() << "Set video surface" << surface; +#endif + + if (surface == m_surface) + return; + + QMutexLocker locker(&m_mutex); + + if (m_surface && m_surface->isActive()) + m_surface->stop(); + + m_surface = surface; + setupVideoOutput(); +} + + +QSize QT7MovieRenderer::nativeSize() const +{ + return m_nativeSize; +} + +void QT7MovieRenderer::updateVideoFrame(const CVTimeStamp &ts) +{ +#ifdef QUICKTIME_C_API_AVAILABLE + + QMutexLocker locker(&m_mutex); + + if (m_surface && m_surface->isActive() && + m_visualContext && QTVisualContextIsNewImageAvailable(m_visualContext, &ts)) { + + CVImageBufferRef imageBuffer = NULL; + + OSStatus status = QTVisualContextCopyImageForTime(m_visualContext, NULL, &ts, &imageBuffer); + + if (status == noErr && imageBuffer) { + QAbstractVideoBuffer *buffer = 0; + + if (m_usingGLContext) { + buffer = new QT7CIImageVideoBuffer([CIImage imageWithCVImageBuffer:imageBuffer]); + CVOpenGLTextureRelease((CVOpenGLTextureRef)imageBuffer); + } else { + buffer = new CVPixelBufferVideoBuffer((CVPixelBufferRef)imageBuffer); + //buffer = new QT7CIImageVideoBuffer( [CIImage imageWithCVImageBuffer:imageBuffer] ); + CVPixelBufferRelease((CVPixelBufferRef)imageBuffer); + } + + QVideoFrame frame(buffer, m_nativeSize, QVideoFrame::Format_RGB32); + m_surface->present(frame); + QTVisualContextTask(m_visualContext); + } + } +#else + Q_UNUSED(ts); +#endif +} + +#include "moc_qt7movierenderer.cpp" diff --git a/src/plugins/qt7/qt7movievideowidget.h b/src/plugins/qt7/qt7movievideowidget.h new file mode 100644 index 000000000..d69ead655 --- /dev/null +++ b/src/plugins/qt7/qt7movievideowidget.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7MOVIEVIDEOWIDGET_H +#define QT7MOVIEVIDEOWIDGET_H + +#include +#include + +#include +#include + +#include +#include "qt7videooutput.h" + +#include +#include + +class GLVideoWidget; + +QT_BEGIN_NAMESPACE + +class QCvDisplayLink; +class QT7PlayerSession; +class QT7PlayerService; + +class QT7MovieVideoWidget : public QT7VideoWidgetControl +{ +Q_OBJECT +public: + QT7MovieVideoWidget(QObject *parent = 0); + virtual ~QT7MovieVideoWidget(); + + void setMovie(void *movie); + void updateNaturalSize(const QSize &newSize); + + QWidget *videoWidget(); + + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + QSize nativeSize() const; + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + +private slots: + void updateVideoFrame(const CVTimeStamp &ts); + +private: + void setupVideoOutput(); + bool createVisualContext(); + + void updateColors(); + + void *m_movie; + GLVideoWidget *m_videoWidget; + + QCvDisplayLink *m_displayLink; + +#ifdef QUICKTIME_C_API_AVAILABLE + QTVisualContextRef m_visualContext; +#endif + + bool m_fullscreen; + QSize m_nativeSize; + Qt::AspectRatioMode m_aspectRatioMode; + int m_brightness; + int m_contrast; + int m_hue; + int m_saturation; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qt7/qt7movievideowidget.mm b/src/plugins/qt7/qt7movievideowidget.mm new file mode 100644 index 000000000..a0858c7fc --- /dev/null +++ b/src/plugins/qt7/qt7movievideowidget.mm @@ -0,0 +1,437 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qt7backend.h" + +#import +#import +#import +#import +#import +#import + + +#include "qt7playercontrol.h" +#include "qt7movievideowidget.h" +#include "qt7playersession.h" +#include "qcvdisplaylink.h" +#include +#include + +#include + +#include + +#import + +#include "math.h" + +QT_USE_NAMESPACE + +class GLVideoWidget : public QGLWidget +{ +public: + + GLVideoWidget(QWidget *parent, const QGLFormat &format) + : QGLWidget(format, parent), + m_texRef(0), + m_nativeSize(640,480), + m_aspectRatioMode(Qt::KeepAspectRatio) + { + setAutoFillBackground(false); + } + + void initializeGL() + { + QColor bgColor = palette().color(QPalette::Background); + glClearColor(bgColor.redF(), bgColor.greenF(), bgColor.blueF(), bgColor.alphaF()); + } + + void resizeGL(int w, int h) + { + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glViewport(0, 0, GLsizei(w), GLsizei(h)); + gluOrtho2D(0, GLsizei(w), 0, GLsizei(h)); + updateGL(); + } + + void paintGL() + { + glClear(GL_COLOR_BUFFER_BIT); + if (!m_texRef) + return; + + glPushMatrix(); + glDisable(GL_CULL_FACE); + GLenum target = CVOpenGLTextureGetTarget(m_texRef); + glEnable(target); + + glBindTexture(target, CVOpenGLTextureGetName(m_texRef)); + glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + GLfloat lowerLeft[2], lowerRight[2], upperRight[2], upperLeft[2]; + CVOpenGLTextureGetCleanTexCoords(m_texRef, lowerLeft, lowerRight, upperRight, upperLeft); + + glBegin(GL_QUADS); + QRect rect = displayRect(); + glTexCoord2f(lowerLeft[0], lowerLeft[1]); + glVertex2i(rect.topLeft().x(), rect.topLeft().y()); + glTexCoord2f(lowerRight[0], lowerRight[1]); + glVertex2i(rect.topRight().x() + 1, rect.topRight().y()); + glTexCoord2f(upperRight[0], upperRight[1]); + glVertex2i(rect.bottomRight().x() + 1, rect.bottomRight().y() + 1); + glTexCoord2f(upperLeft[0], upperLeft[1]); + glVertex2i(rect.bottomLeft().x(), rect.bottomLeft().y() + 1); + glEnd(); + glPopMatrix(); + } + + void setCVTexture(CVOpenGLTextureRef texRef) + { + if (m_texRef) + CVOpenGLTextureRelease(m_texRef); + + m_texRef = texRef; + + if (m_texRef) + CVOpenGLTextureRetain(m_texRef); + + if (isVisible()) { + makeCurrent(); + paintGL(); + swapBuffers(); + } + } + + QSize sizeHint() const + { + return m_nativeSize; + } + + void setNativeSize(const QSize &size) + { + m_nativeSize = size; + } + + void setAspectRatioMode(Qt::AspectRatioMode mode) + { + if (m_aspectRatioMode != mode) { + m_aspectRatioMode = mode; + update(); + } + } + +private: + QRect displayRect() const + { + QRect displayRect = rect(); + + if (m_aspectRatioMode == Qt::KeepAspectRatio) { + QSize size = m_nativeSize; + size.scale(displayRect.size(), Qt::KeepAspectRatio); + + displayRect = QRect(QPoint(0, 0), size); + displayRect.moveCenter(rect().center()); + } + return displayRect; + } + + CVOpenGLTextureRef m_texRef; + QSize m_nativeSize; + Qt::AspectRatioMode m_aspectRatioMode; +}; + +QT7MovieVideoWidget::QT7MovieVideoWidget(QObject *parent) + :QT7VideoWidgetControl(parent), + m_movie(0), + m_videoWidget(0), + m_fullscreen(false), + m_aspectRatioMode(Qt::KeepAspectRatio), + m_brightness(0), + m_contrast(0), + m_hue(0), + m_saturation(0) +{ +#ifdef QT_DEBUG_QT7 + qDebug() << "QT7MovieVideoWidget"; +#endif + + QGLFormat format = QGLFormat::defaultFormat(); + format.setSwapInterval(1); // Vertical sync (avoid tearing) + m_videoWidget = new GLVideoWidget(0, format); + + m_displayLink = new QCvDisplayLink(this); + + connect(m_displayLink, SIGNAL(tick(CVTimeStamp)), SLOT(updateVideoFrame(CVTimeStamp))); + + if (!createVisualContext()) { + qWarning() << "QT7MovieVideoWidget: failed to create visual context"; + } +} + +bool QT7MovieVideoWidget::createVisualContext() +{ +#ifdef QUICKTIME_C_API_AVAILABLE + m_videoWidget->makeCurrent(); + + AutoReleasePool pool; + CGLContextObj cglContext = CGLGetCurrentContext(); + NSOpenGLPixelFormat *nsglPixelFormat = [NSOpenGLView defaultPixelFormat]; + CGLPixelFormatObj cglPixelFormat = static_cast([nsglPixelFormat CGLPixelFormatObj]); + + CFTypeRef keys[] = { kQTVisualContextOutputColorSpaceKey }; + CGColorSpaceRef colorSpace = NULL; + CMProfileRef sysprof = NULL; + + // Get the Systems Profile for the main display + if (CMGetSystemProfile(&sysprof) == noErr) { + // Create a colorspace with the systems profile + colorSpace = CGColorSpaceCreateWithPlatformColorSpace(sysprof); + CMCloseProfile(sysprof); + } + + if (!colorSpace) + colorSpace = CGColorSpaceCreateDeviceRGB(); + + CFDictionaryRef textureContextAttributes = CFDictionaryCreate(kCFAllocatorDefault, + (const void **)keys, + (const void **)&colorSpace, 1, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + OSStatus err = QTOpenGLTextureContextCreate(kCFAllocatorDefault, + cglContext, + cglPixelFormat, + textureContextAttributes, + &m_visualContext); + if (err != noErr) + qWarning() << "Could not create visual context (OpenGL)"; + + + return (err == noErr); +#endif // QUICKTIME_C_API_AVAILABLE + + return false; +} + +QT7MovieVideoWidget::~QT7MovieVideoWidget() +{ + m_displayLink->stop(); + [(QTMovie*)m_movie release]; + delete m_videoWidget; +} + +QWidget *QT7MovieVideoWidget::videoWidget() +{ + return m_videoWidget; +} + +void QT7MovieVideoWidget::setupVideoOutput() +{ + AutoReleasePool pool; + +#ifdef QT_DEBUG_QT7 + qDebug() << "QT7MovieVideoWidget::setupVideoOutput" << m_movie; +#endif + + if (m_movie == 0) { + m_displayLink->stop(); + return; + } + + NSSize size = [[(QTMovie*)m_movie attributeForKey:@"QTMovieNaturalSizeAttribute"] sizeValue]; + m_nativeSize = QSize(size.width, size.height); + m_videoWidget->setNativeSize(m_nativeSize); + +#ifdef QUICKTIME_C_API_AVAILABLE + // targets a Movie to render into a visual context + SetMovieVisualContext([(QTMovie*)m_movie quickTimeMovie], m_visualContext); +#endif + + m_displayLink->start(); +} + +void QT7MovieVideoWidget::setMovie(void *movie) +{ + if (m_movie == movie) + return; + + if (m_movie) { +#ifdef QUICKTIME_C_API_AVAILABLE + SetMovieVisualContext([(QTMovie*)m_movie quickTimeMovie], nil); +#endif + [(QTMovie*)m_movie release]; + } + + m_movie = movie; + [(QTMovie*)m_movie retain]; + + setupVideoOutput(); +} + +void QT7MovieVideoWidget::updateNaturalSize(const QSize &newSize) +{ + if (m_nativeSize != newSize) { + m_nativeSize = newSize; + setupVideoOutput(); + } +} + +bool QT7MovieVideoWidget::isFullScreen() const +{ + return m_fullscreen; +} + +void QT7MovieVideoWidget::setFullScreen(bool fullScreen) +{ + m_fullscreen = fullScreen; +} + +QSize QT7MovieVideoWidget::nativeSize() const +{ + return m_nativeSize; +} + +Qt::AspectRatioMode QT7MovieVideoWidget::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void QT7MovieVideoWidget::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + m_aspectRatioMode = mode; + m_videoWidget->setAspectRatioMode(mode); +} + +int QT7MovieVideoWidget::brightness() const +{ + return m_brightness; +} + +void QT7MovieVideoWidget::setBrightness(int brightness) +{ + m_brightness = brightness; + updateColors(); +} + +int QT7MovieVideoWidget::contrast() const +{ + return m_contrast; +} + +void QT7MovieVideoWidget::setContrast(int contrast) +{ + m_contrast = contrast; + updateColors(); +} + +int QT7MovieVideoWidget::hue() const +{ + return m_hue; +} + +void QT7MovieVideoWidget::setHue(int hue) +{ + m_hue = hue; + updateColors(); +} + +int QT7MovieVideoWidget::saturation() const +{ + return m_saturation; +} + +void QT7MovieVideoWidget::setSaturation(int saturation) +{ + m_saturation = saturation; + updateColors(); +} + +void QT7MovieVideoWidget::updateColors() +{ +#ifdef QUICKTIME_C_API_AVAILABLE + if (m_movie) { + QTMovie *movie = (QTMovie*)m_movie; + + Float32 value; + value = m_brightness/100.0; + SetMovieVisualBrightness([movie quickTimeMovie], value, 0); + value = pow(2, m_contrast/50.0); + SetMovieVisualContrast([movie quickTimeMovie], value, 0); + value = m_hue/100.0; + SetMovieVisualHue([movie quickTimeMovie], value, 0); + value = 1.0+m_saturation/100.0; + SetMovieVisualSaturation([movie quickTimeMovie], value, 0); + } +#endif +} + +void QT7MovieVideoWidget::updateVideoFrame(const CVTimeStamp &ts) +{ +#ifdef QUICKTIME_C_API_AVAILABLE + AutoReleasePool pool; + // check for new frame + if (m_visualContext && QTVisualContextIsNewImageAvailable(m_visualContext, &ts)) { + CVOpenGLTextureRef currentFrame = NULL; + + // get a "frame" (image buffer) from the Visual Context, indexed by the provided time + OSStatus status = QTVisualContextCopyImageForTime(m_visualContext, NULL, &ts, ¤tFrame); + + // the above call may produce a null frame so check for this first + // if we have a frame, then draw it + if (status == noErr && currentFrame) { +#ifdef QT_DEBUG_QT7 + qDebug() << "render video frame"; +#endif + m_videoWidget->setCVTexture(currentFrame); + CVOpenGLTextureRelease(currentFrame); + } + QTVisualContextTask(m_visualContext); + } +#else + Q_UNUSED(ts); +#endif +} + +#include "moc_qt7movievideowidget.cpp" diff --git a/src/plugins/qt7/qt7movieviewoutput.h b/src/plugins/qt7/qt7movieviewoutput.h new file mode 100644 index 000000000..4b9cff3ea --- /dev/null +++ b/src/plugins/qt7/qt7movieviewoutput.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7MOVIEVIEWOUTPUT_H +#define QT7MOVIEVIEWOUTPUT_H + +#include + +#include +#include + +#include +#include "qt7videooutput.h" + + +QT_BEGIN_NAMESPACE + +class QT7PlayerSession; +class QT7PlayerService; + +class QT7MovieViewOutput : public QT7VideoWindowControl +{ +public: + QT7MovieViewOutput(QObject *parent = 0); + ~QT7MovieViewOutput(); + + void setMovie(void *movie); + void updateNaturalSize(const QSize &newSize); + + WId winId() const; + void setWinId(WId id); + + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + void repaint(); + + QSize nativeSize() const; + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + +private: + void setupVideoOutput(); + + void *m_movie; + void *m_movieView; + bool m_layouted; + + WId m_winId; + QRect m_displayRect; + bool m_fullscreen; + QSize m_nativeSize; + Qt::AspectRatioMode m_aspectRatioMode; + int m_brightness; + int m_contrast; + int m_hue; + int m_saturation; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qt7/qt7movieviewoutput.mm b/src/plugins/qt7/qt7movieviewoutput.mm new file mode 100644 index 000000000..6d38d6148 --- /dev/null +++ b/src/plugins/qt7/qt7movieviewoutput.mm @@ -0,0 +1,339 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#import + +#include "qt7backend.h" + +#include "qt7playercontrol.h" +#include "qt7movieviewoutput.h" +#include "qt7playersession.h" +#include + +#include +#include + +QT_USE_NAMESPACE + +#define VIDEO_TRANSPARENT(m) -(void)m:(NSEvent *)e{[[self superview] m:e];} + +@interface TransparentQTMovieView : QTMovieView +{ +@private + QRect *m_drawRect; + qreal m_brightness, m_contrast, m_saturation, m_hue; +} + +- (TransparentQTMovieView *) init; +- (void) setDrawRect:(QRect &)rect; +- (CIImage *) view:(QTMovieView *)view willDisplayImage:(CIImage *)img; +- (void) setContrast:(qreal) contrast; +@end + +@implementation TransparentQTMovieView + +- (TransparentQTMovieView *) init +{ + self = [super initWithFrame:NSZeroRect]; + if (self) { + [self setControllerVisible:NO]; + [self setContrast:1.0]; + [self setDelegate:self]; + } + return self; +} + +- (void) dealloc +{ + [super dealloc]; +} + +- (void) setContrast:(qreal) contrast +{ + m_hue = 0.0; + m_brightness = 0.0; + m_contrast = contrast; + m_saturation = 1.0; +} + + +- (void) setDrawRect:(QRect &)rect +{ + *m_drawRect = rect; + + NSRect nsrect; + nsrect.origin.x = m_drawRect->x(); + nsrect.origin.y = m_drawRect->y(); + nsrect.size.width = m_drawRect->width(); + nsrect.size.height = m_drawRect->height(); + [self setFrame:nsrect]; +} + +- (CIImage *) view:(QTMovieView *)view willDisplayImage:(CIImage *)img +{ + // This method is called from QTMovieView just + // before the image will be drawn. + Q_UNUSED(view); + + if ( !qFuzzyCompare(m_brightness, 0.0) || + !qFuzzyCompare(m_contrast, 1.0) || + !qFuzzyCompare(m_saturation, 1.0)){ + CIFilter *colorFilter = [CIFilter filterWithName:@"CIColorControls"]; + [colorFilter setValue:[NSNumber numberWithFloat:m_brightness] forKey:@"inputBrightness"]; + [colorFilter setValue:[NSNumber numberWithFloat:(m_contrast < 1) ? m_contrast : 1 + ((m_contrast-1)*3)] forKey:@"inputContrast"]; + [colorFilter setValue:[NSNumber numberWithFloat:m_saturation] forKey:@"inputSaturation"]; + [colorFilter setValue:img forKey:@"inputImage"]; + img = [colorFilter valueForKey:@"outputImage"]; + } + + /*if (m_hue){ + CIFilter *colorFilter = [CIFilter filterWithName:@"CIHueAdjust"]; + [colorFilter setValue:[NSNumber numberWithFloat:(m_hue * 3.14)] forKey:@"inputAngle"]; + [colorFilter setValue:img forKey:@"inputImage"]; + img = [colorFilter valueForKey:@"outputImage"]; + }*/ + + return img; +} + + +VIDEO_TRANSPARENT(mouseDown); +VIDEO_TRANSPARENT(mouseDragged); +VIDEO_TRANSPARENT(mouseUp); +VIDEO_TRANSPARENT(mouseMoved); +VIDEO_TRANSPARENT(mouseEntered); +VIDEO_TRANSPARENT(mouseExited); +VIDEO_TRANSPARENT(rightMouseDown); +VIDEO_TRANSPARENT(rightMouseDragged); +VIDEO_TRANSPARENT(rightMouseUp); +VIDEO_TRANSPARENT(otherMouseDown); +VIDEO_TRANSPARENT(otherMouseDragged); +VIDEO_TRANSPARENT(otherMouseUp); +VIDEO_TRANSPARENT(keyDown); +VIDEO_TRANSPARENT(keyUp); +VIDEO_TRANSPARENT(scrollWheel) + +@end + + +QT7MovieViewOutput::QT7MovieViewOutput(QObject *parent) + :QT7VideoWindowControl(parent), + m_movie(0), + m_movieView(0), + m_layouted(false), + m_winId(0), + m_fullscreen(false), + m_aspectRatioMode(Qt::KeepAspectRatio), + m_brightness(0), + m_contrast(0), + m_hue(0), + m_saturation(0) +{ +} + +QT7MovieViewOutput::~QT7MovieViewOutput() +{ + [(QTMovieView*)m_movieView release]; + [(QTMovie*)m_movie release]; +} + +void QT7MovieViewOutput::setupVideoOutput() +{ + AutoReleasePool pool; + +#ifdef QT_DEBUG_QT7 + qDebug() << "QT7MovieViewOutput::setupVideoOutput" << m_movie << m_winId; +#endif + if (m_movie == 0 || m_winId <= 0) + return; + + NSSize size = [[(QTMovie*)m_movie attributeForKey:@"QTMovieNaturalSizeAttribute"] sizeValue]; + m_nativeSize = QSize(size.width, size.height); + + if (!m_movieView) + m_movieView = [[TransparentQTMovieView alloc] init]; + + [(QTMovieView*)m_movieView setControllerVisible:NO]; + [(QTMovieView*)m_movieView setMovie:(QTMovie*)m_movie]; + + [(NSView *)m_winId addSubview:(QTMovieView*)m_movieView]; + m_layouted = true; + + setDisplayRect(m_displayRect); +} + +void QT7MovieViewOutput::setMovie(void *movie) +{ + if (m_movie != movie) { + if (m_movie) { + if (m_movieView) + [(QTMovieView*)m_movieView setMovie:nil]; + + [(QTMovie*)m_movie release]; + } + + m_movie = movie; + + if (m_movie) + [(QTMovie*)m_movie retain]; + + setupVideoOutput(); + } +} + +void QT7MovieViewOutput::updateNaturalSize(const QSize &newSize) +{ + if (m_nativeSize != newSize) { + m_nativeSize = newSize; + emit nativeSizeChanged(); + } +} + +WId QT7MovieViewOutput::winId() const +{ + return m_winId; +} + +void QT7MovieViewOutput::setWinId(WId id) +{ + if (m_winId != id) { + if (m_movieView && m_layouted) { + [(QTMovieView*)m_movieView removeFromSuperview]; + m_layouted = false; + } + + m_winId = id; + setupVideoOutput(); + } +} + +QRect QT7MovieViewOutput::displayRect() const +{ + return m_displayRect; +} + +void QT7MovieViewOutput::setDisplayRect(const QRect &rect) +{ + m_displayRect = rect; + + if (m_movieView) { + AutoReleasePool pool; + [(QTMovieView*)m_movieView setPreservesAspectRatio:(m_aspectRatioMode == Qt::KeepAspectRatio ? YES : NO)]; + [(QTMovieView*)m_movieView setFrame:NSMakeRect(m_displayRect.x(), + m_displayRect.y(), + m_displayRect.width(), + m_displayRect.height())]; + } + +} + +bool QT7MovieViewOutput::isFullScreen() const +{ + return m_fullscreen; +} + +void QT7MovieViewOutput::setFullScreen(bool fullScreen) +{ + m_fullscreen = fullScreen; + setDisplayRect(m_displayRect); +} + +void QT7MovieViewOutput::repaint() +{ +} + +QSize QT7MovieViewOutput::nativeSize() const +{ + return m_nativeSize; +} + +Qt::AspectRatioMode QT7MovieViewOutput::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void QT7MovieViewOutput::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + m_aspectRatioMode = mode; + setDisplayRect(m_displayRect); +} + +int QT7MovieViewOutput::brightness() const +{ + return m_brightness; +} + +void QT7MovieViewOutput::setBrightness(int brightness) +{ + m_brightness = brightness; +} + +int QT7MovieViewOutput::contrast() const +{ + return m_contrast; +} + +void QT7MovieViewOutput::setContrast(int contrast) +{ + m_contrast = contrast; + [(TransparentQTMovieView*)m_movieView setContrast:(contrast/100.0+1.0)]; +} + +int QT7MovieViewOutput::hue() const +{ + return m_hue; +} + +void QT7MovieViewOutput::setHue(int hue) +{ + m_hue = hue; +} + +int QT7MovieViewOutput::saturation() const +{ + return m_saturation; +} + +void QT7MovieViewOutput::setSaturation(int saturation) +{ + m_saturation = saturation; +} + diff --git a/src/plugins/qt7/qt7movieviewrenderer.h b/src/plugins/qt7/qt7movieviewrenderer.h new file mode 100644 index 000000000..f95f6097d --- /dev/null +++ b/src/plugins/qt7/qt7movieviewrenderer.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7MOVIEVIEWRENDERER_H +#define QT7MOVIEVIEWRENDERER_H + +#include +#include + +#include +#include + +#include +#include "qt7videooutput.h" +#include + +QT_BEGIN_NAMESPACE + +class QVideoFrame; + +class QT7PlayerSession; +class QT7PlayerService; + +class QT7MovieViewRenderer : public QT7VideoRendererControl +{ +public: + QT7MovieViewRenderer(QObject *parent = 0); + ~QT7MovieViewRenderer(); + + void setMovie(void *movie); + void updateNaturalSize(const QSize &newSize); + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + + void renderFrame(const QVideoFrame &); + +protected: + bool event(QEvent *event); + +private: + void setupVideoOutput(); + + void *m_movie; + void *m_movieView; + QSize m_nativeSize; + QAbstractVideoSurface *m_surface; + QVideoFrame m_currentFrame; + bool m_pendingRenderEvent; + QMutex m_mutex; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qt7/qt7movieviewrenderer.mm b/src/plugins/qt7/qt7movieviewrenderer.mm new file mode 100644 index 000000000..b9d4f64b9 --- /dev/null +++ b/src/plugins/qt7/qt7movieviewrenderer.mm @@ -0,0 +1,371 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#import + +#include "qt7backend.h" + +#include "qt7playercontrol.h" +#include "qt7movieviewrenderer.h" +#include "qt7playersession.h" +#include "qt7ciimagevideobuffer.h" +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +QT_USE_NAMESPACE + +class NSBitmapVideoBuffer : public QAbstractVideoBuffer +{ +public: + NSBitmapVideoBuffer(NSBitmapImageRep *buffer) + : QAbstractVideoBuffer(NoHandle) + , m_buffer(buffer) + , m_mode(NotMapped) + { + [m_buffer retain]; + } + + virtual ~NSBitmapVideoBuffer() + { + [m_buffer release]; + } + + MapMode mapMode() const { return m_mode; } + + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) + { + if (mode != NotMapped && m_mode == NotMapped) { + if (numBytes) + *numBytes = [m_buffer bytesPerPlane]; + + if (bytesPerLine) + *bytesPerLine = [m_buffer bytesPerRow]; + + m_mode = mode; + + return [m_buffer bitmapData]; + } else { + return 0; + } + } + + void unmap() { m_mode = NotMapped; } + +private: + NSBitmapImageRep *m_buffer; + MapMode m_mode; +}; + + +#define VIDEO_TRANSPARENT(m) -(void)m:(NSEvent *)e{[[self superview] m:e];} + +@interface HiddenQTMovieView : QTMovieView +{ +@private + QWidget *m_window; + QT7MovieViewRenderer *m_renderer; + QReadWriteLock m_rendererLock; +} + +- (HiddenQTMovieView *) initWithRenderer:(QT7MovieViewRenderer *)renderer; +- (void) setRenderer:(QT7MovieViewRenderer *)renderer; +- (void) setDrawRect:(const QRect &)rect; +- (CIImage *) view:(QTMovieView *)view willDisplayImage:(CIImage *)img; +@end + +@implementation HiddenQTMovieView + +- (HiddenQTMovieView *) initWithRenderer:(QT7MovieViewRenderer *)renderer +{ + self = [super initWithFrame:NSZeroRect]; + if (self) { + [self setControllerVisible:NO]; + [self setDelegate:self]; + + QWriteLocker lock(&self->m_rendererLock); + self->m_renderer = renderer; + + self->m_window = new QWidget; + self->m_window->setWindowOpacity(0.0); + self->m_window->show(); + self->m_window->hide(); + + [(NSView *)(self->m_window->winId()) addSubview:self]; + [self setDrawRect:QRect(0,0,1,1)]; + } + return self; +} + +- (void) dealloc +{ + [super dealloc]; +} + +- (void) setRenderer:(QT7MovieViewRenderer *)renderer +{ + QWriteLocker lock(&m_rendererLock); + m_renderer = renderer; +} + +- (void) setDrawRect:(const QRect &)rect +{ + NSRect nsrect; + nsrect.origin.x = rect.x(); + nsrect.origin.y = rect.y(); + nsrect.size.width = rect.width(); + nsrect.size.height = rect.height(); + [self setFrame:nsrect]; +} + +- (CIImage *) view:(QTMovieView *)view willDisplayImage:(CIImage *)img +{ + // This method is called from QTMovieView just + // before the image will be drawn. + Q_UNUSED(view); + QReadLocker lock(&m_rendererLock); + + if (m_renderer) { + CGRect bounds = [img extent]; + int w = bounds.size.width; + int h = bounds.size.height; + + QVideoFrame frame; + + QAbstractVideoSurface *surface = m_renderer->surface(); + if (!surface || !surface->isActive()) + return img; + + if (surface->surfaceFormat().handleType() == QAbstractVideoBuffer::CoreImageHandle) { + //surface supports rendering of opengl based CIImage + frame = QVideoFrame(new QT7CIImageVideoBuffer(img), QSize(w,h), QVideoFrame::Format_RGB32 ); + } else { + //Swap R and B colors + CIFilter *colorSwapFilter = [CIFilter filterWithName: @"CIColorMatrix" keysAndValues: + @"inputImage", img, + @"inputRVector", [CIVector vectorWithX: 0 Y: 0 Z: 1 W: 0], + @"inputGVector", [CIVector vectorWithX: 0 Y: 1 Z: 0 W: 0], + @"inputBVector", [CIVector vectorWithX: 1 Y: 0 Z: 0 W: 0], + @"inputAVector", [CIVector vectorWithX: 0 Y: 0 Z: 0 W: 1], + @"inputBiasVector", [CIVector vectorWithX: 0 Y: 0 Z: 0 W: 0], + nil]; + CIImage *img = [colorSwapFilter valueForKey: @"outputImage"]; + NSBitmapImageRep *bitmap =[[NSBitmapImageRep alloc] initWithCIImage:img]; + //requesting the bitmap data is slow, + //but it's better to do it here to avoid blocking the main thread for a long. + [bitmap bitmapData]; + frame = QVideoFrame(new NSBitmapVideoBuffer(bitmap), QSize(w,h), QVideoFrame::Format_RGB32 ); + [bitmap release]; + } + + m_renderer->renderFrame(frame); + } + + return img; +} + +// Override this method so that the movie doesn't stop if +// the window becomes invisible +- (void)viewWillMoveToWindow:(NSWindow *)newWindow +{ + Q_UNUSED(newWindow); +} + + +VIDEO_TRANSPARENT(mouseDown); +VIDEO_TRANSPARENT(mouseDragged); +VIDEO_TRANSPARENT(mouseUp); +VIDEO_TRANSPARENT(mouseMoved); +VIDEO_TRANSPARENT(mouseEntered); +VIDEO_TRANSPARENT(mouseExited); +VIDEO_TRANSPARENT(rightMouseDown); +VIDEO_TRANSPARENT(rightMouseDragged); +VIDEO_TRANSPARENT(rightMouseUp); +VIDEO_TRANSPARENT(otherMouseDown); +VIDEO_TRANSPARENT(otherMouseDragged); +VIDEO_TRANSPARENT(otherMouseUp); +VIDEO_TRANSPARENT(keyDown); +VIDEO_TRANSPARENT(keyUp); +VIDEO_TRANSPARENT(scrollWheel) + +@end + + +QT7MovieViewRenderer::QT7MovieViewRenderer(QObject *parent) + :QT7VideoRendererControl(parent), + m_movie(0), + m_movieView(0), + m_surface(0), + m_pendingRenderEvent(false) +{ +} + +QT7MovieViewRenderer::~QT7MovieViewRenderer() +{ + [(HiddenQTMovieView*)m_movieView setRenderer:0]; + + QMutexLocker locker(&m_mutex); + m_currentFrame = QVideoFrame(); + [(HiddenQTMovieView*)m_movieView release]; +} + +void QT7MovieViewRenderer::setupVideoOutput() +{ + AutoReleasePool pool; + +#ifdef QT_DEBUG_QT7 + qDebug() << "QT7MovieViewRenderer::setupVideoOutput" << m_movie << m_surface; +#endif + + HiddenQTMovieView *movieView = (HiddenQTMovieView*)m_movieView; + + if (movieView && !m_movie) { + [movieView setMovie:nil]; + } + + if (m_movie) { + NSSize size = [[(QTMovie*)m_movie attributeForKey:@"QTMovieNaturalSizeAttribute"] sizeValue]; + + m_nativeSize = QSize(size.width, size.height); + + if (!movieView) { + movieView = [[HiddenQTMovieView alloc] initWithRenderer:this]; + m_movieView = movieView; + [movieView setControllerVisible:NO]; + } + + [movieView setMovie:(QTMovie*)m_movie]; + [movieView setDrawRect:QRect(QPoint(0,0), m_nativeSize)]; + } + + if (m_surface && !m_nativeSize.isEmpty()) { + bool coreImageFrameSupported = !m_surface->supportedPixelFormats(QAbstractVideoBuffer::CoreImageHandle).isEmpty() && + !m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).isEmpty(); + + QVideoSurfaceFormat format(m_nativeSize, QVideoFrame::Format_RGB32, + coreImageFrameSupported ? QAbstractVideoBuffer::CoreImageHandle : QAbstractVideoBuffer::NoHandle); + + if (m_surface->isActive() && m_surface->surfaceFormat() != format) { +#ifdef QT_DEBUG_QT7 + qDebug() << "Surface format was changed, stop the surface."; +#endif + m_surface->stop(); + } + + if (!m_surface->isActive()) { +#ifdef QT_DEBUG_QT7 + qDebug() << "Starting the surface with format" << format; +#endif + if (!m_surface->start(format)) + qWarning() << "failed to start video surface" << m_surface->error(); + } + } +} + +void QT7MovieViewRenderer::setMovie(void *movie) +{ + if (movie == m_movie) + return; + + QMutexLocker locker(&m_mutex); + m_movie = movie; + setupVideoOutput(); +} + +void QT7MovieViewRenderer::updateNaturalSize(const QSize &newSize) +{ + if (m_nativeSize != newSize) { + m_nativeSize = newSize; + setupVideoOutput(); + } +} + +QAbstractVideoSurface *QT7MovieViewRenderer::surface() const +{ + return m_surface; +} + +void QT7MovieViewRenderer::setSurface(QAbstractVideoSurface *surface) +{ + if (surface == m_surface) + return; + + QMutexLocker locker(&m_mutex); + + if (m_surface && m_surface->isActive()) + m_surface->stop(); + + m_surface = surface; + setupVideoOutput(); +} + +void QT7MovieViewRenderer::renderFrame(const QVideoFrame &frame) +{ + + QMutexLocker locker(&m_mutex); + m_currentFrame = frame; + + if (!m_pendingRenderEvent) + qApp->postEvent(this, new QEvent(QEvent::User), Qt::HighEventPriority); + + m_pendingRenderEvent = true; +} + +bool QT7MovieViewRenderer::event(QEvent *event) +{ + if (event->type() == QEvent::User) { + QMutexLocker locker(&m_mutex); + m_pendingRenderEvent = false; + if (m_surface->isActive()) + m_surface->present(m_currentFrame); + } + + return QT7VideoRendererControl::event(event); +} diff --git a/src/plugins/qt7/qt7serviceplugin.h b/src/plugins/qt7/qt7serviceplugin.h new file mode 100644 index 000000000..fb0a546b3 --- /dev/null +++ b/src/plugins/qt7/qt7serviceplugin.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QT7SERVICEPLUGIN_H +#define QT7SERVICEPLUGIN_H + +#include + +QT_BEGIN_NAMESPACE + +class QT7ServicePlugin + : public QMediaServiceProviderPlugin + , public QMediaServiceSupportedFormatsInterface + , public QMediaServiceFeaturesInterface +{ + Q_INTERFACES(QMediaServiceFeaturesInterface) +public: + QT7ServicePlugin(); + + QStringList keys() const; + QMediaService* create(QString const& key); + void release(QMediaService *service); + + QMediaServiceProviderHint::Features supportedFeatures(const QByteArray &service) const; + QtMultimediaKit::SupportEstimate hasSupport(const QString &mimeType, const QStringList& codecs) const; + QStringList supportedMimeTypes() const; + +private: + void buildSupportedTypes(); + + QStringList m_supportedMimeTypes; +}; + +QT_END_NAMESPACE + +#endif // QGSTREAMERSERVICEPLUGIN_H diff --git a/src/plugins/qt7/qt7serviceplugin.mm b/src/plugins/qt7/qt7serviceplugin.mm new file mode 100644 index 000000000..a692e190f --- /dev/null +++ b/src/plugins/qt7/qt7serviceplugin.mm @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#import +#import + +#include +#include + +#include "qt7backend.h" +#include "qt7serviceplugin.h" +#include "qt7playerservice.h" + +#include + +QT_BEGIN_NAMESPACE + + +QT7ServicePlugin::QT7ServicePlugin() +{ + buildSupportedTypes(); +} + +QStringList QT7ServicePlugin::keys() const +{ + return QStringList() +#ifdef QMEDIA_QT7_PLAYER + << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER) +#endif + ; +} + +QMediaService* QT7ServicePlugin::create(QString const& key) +{ +#ifdef QT_DEBUG_QT7 + qDebug() << "QT7ServicePlugin::create" << key; +#endif +#ifdef QMEDIA_QT7_PLAYER + if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER)) + return new QT7PlayerService; +#endif + qWarning() << "unsupported key:" << key; + + return 0; +} + +void QT7ServicePlugin::release(QMediaService *service) +{ + delete service; +} + +QMediaServiceProviderHint::Features QT7ServicePlugin::supportedFeatures( + const QByteArray &service) const +{ + if (service == Q_MEDIASERVICE_MEDIAPLAYER) + return QMediaServiceProviderHint::VideoSurface; + else + return QMediaServiceProviderHint::Features(); +} + +QtMultimediaKit::SupportEstimate QT7ServicePlugin::hasSupport(const QString &mimeType, const QStringList& codecs) const +{ + Q_UNUSED(codecs); + + if (m_supportedMimeTypes.contains(mimeType)) + return QtMultimediaKit::ProbablySupported; + + return QtMultimediaKit::MaybeSupported; +} + +QStringList QT7ServicePlugin::supportedMimeTypes() const +{ + return m_supportedMimeTypes; +} + +void QT7ServicePlugin::buildSupportedTypes() +{ + AutoReleasePool pool; + NSArray *utis = [QTMovie movieTypesWithOptions:QTIncludeCommonTypes]; + for (NSString *uti in utis) { + NSString* mimeType = (NSString*)UTTypeCopyPreferredTagWithClass((CFStringRef)uti, kUTTagClassMIMEType); + if (mimeType != 0) { + m_supportedMimeTypes.append(QString::fromUtf8([mimeType UTF8String])); + [mimeType release]; + } + } +} + +Q_EXPORT_PLUGIN2(qtmedia_qt7engine, QT7ServicePlugin); + +QT_END_NAMESPACE diff --git a/src/plugins/qt7/qt7videooutput.h b/src/plugins/qt7/qt7videooutput.h new file mode 100644 index 000000000..060f7b910 --- /dev/null +++ b/src/plugins/qt7/qt7videooutput.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7VIDEOOUTPUTCONTROL_H +#define QT7VIDEOOUTPUTCONTROL_H + +#include +#include + +#include +#include +#include +#include + +#include + + +QT_BEGIN_NAMESPACE + +class QMediaPlaylist; +class QMediaPlaylistNavigator; +class QT7PlayerSession; +class QT7PlayerService; + + +class QT7VideoOutput { +public: + virtual ~QT7VideoOutput() {} + virtual void setMovie(void *movie) = 0; + virtual void updateNaturalSize(const QSize &newSize) = 0; +}; + +#define QT7VideoOutput_iid \ + "com.nokia.Qt.QT7VideoOutput/1.0" +Q_DECLARE_INTERFACE(QT7VideoOutput, QT7VideoOutput_iid) + +class QT7VideoWindowControl : public QVideoWindowControl, public QT7VideoOutput +{ +Q_OBJECT +Q_INTERFACES(QT7VideoOutput) +public: + virtual ~QT7VideoWindowControl() {} + +protected: + QT7VideoWindowControl(QObject *parent) + :QVideoWindowControl(parent) + {} +}; + +class QT7VideoRendererControl : public QVideoRendererControl, public QT7VideoOutput +{ +Q_OBJECT +Q_INTERFACES(QT7VideoOutput) +public: + virtual ~QT7VideoRendererControl() {} + +protected: + QT7VideoRendererControl(QObject *parent) + :QVideoRendererControl(parent) + {} +}; + +class QT7VideoWidgetControl : public QVideoWidgetControl, public QT7VideoOutput +{ +Q_OBJECT +Q_INTERFACES(QT7VideoOutput) +public: + virtual ~QT7VideoWidgetControl() {} + +protected: + QT7VideoWidgetControl(QObject *parent) + :QVideoWidgetControl(parent) + {} +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qt7/qt7videooutput.mm b/src/plugins/qt7/qt7videooutput.mm new file mode 100644 index 000000000..2be053669 --- /dev/null +++ b/src/plugins/qt7/qt7videooutput.mm @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qt7playercontrol.h" +#include "qt7playersession.h" +#include + +QT_USE_NAMESPACE + +/* +QT7VideoOutputControl::QT7VideoOutputControl(QObject *parent) + :QVideoOutputControl(parent), + m_session(0), + m_output(QVideoOutputControl::NoOutput) +{ +} + +QT7VideoOutputControl::~QT7VideoOutputControl() +{ +} + +void QT7VideoOutputControl::setSession(QT7PlayerSession *session) +{ + m_session = session; +} + +QList QT7VideoOutputControl::availableOutputs() const +{ + return m_outputs; +} + +void QT7VideoOutputControl::enableOutput(QVideoOutputControl::Output output) +{ + if (!m_outputs.contains(output)) + m_outputs.append(output); +} + +QVideoOutputControl::Output QT7VideoOutputControl::output() const +{ + return m_output; +} + +void QT7VideoOutputControl::setOutput(Output output) +{ + if (m_output != output) { + m_output = output; + emit videoOutputChanged(m_output); + } +} + +#include "moc_qt7videooutputcontrol.cpp" + +*/ diff --git a/src/plugins/simulator/camera/simulatorcamera.pri b/src/plugins/simulator/camera/simulatorcamera.pri new file mode 100644 index 000000000..867fc4b31 --- /dev/null +++ b/src/plugins/simulator/camera/simulatorcamera.pri @@ -0,0 +1,25 @@ +INCLUDEPATH += $$PWD \ + $${SOURCE_DIR}/src/multimedia + +INCLUDEPATH += camera + +HEADERS += \ + $$PWD/simulatorcameraservice.h \ + $$PWD/simulatorcamerasession.h \ + $$PWD/simulatorcameracontrol.h \ + $$PWD/simulatorvideorenderercontrol.h \ + $$PWD/simulatorvideoinputdevicecontrol.h \ + $$PWD/simulatorcameraimagecapturecontrol.h \ + $$PWD/simulatorcameraexposurecontrol.h \ + $$PWD/simulatorcamerasettings.h + +SOURCES += \ + $$PWD/simulatorcameraservice.cpp \ + $$PWD/simulatorcamerasession.cpp \ + $$PWD/simulatorcameracontrol.cpp \ + $$PWD/simulatorvideorenderercontrol.cpp \ + $$PWD/simulatorvideoinputdevicecontrol.cpp \ + $$PWD/simulatorcameraimagecapturecontrol.cpp \ + $$PWD/simulatorcameraexposurecontrol.cpp \ + $$PWD/simulatorcamerasettings.cpp + diff --git a/src/plugins/simulator/camera/simulatorcameracontrol.cpp b/src/plugins/simulator/camera/simulatorcameracontrol.cpp new file mode 100644 index 000000000..384215295 --- /dev/null +++ b/src/plugins/simulator/camera/simulatorcameracontrol.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "simulatorcameracontrol.h" + +#include + +SimulatorCameraControl::SimulatorCameraControl(SimulatorCameraSession *session) + :QCameraControl(session), + m_session(session), + mState(QCamera::UnloadedState), + mStatus(QCamera::UnloadedStatus) +{ +} + +SimulatorCameraControl::~SimulatorCameraControl() +{ +} + +QCamera::CaptureMode SimulatorCameraControl::captureMode() const +{ + return m_session->captureMode(); +} + +void SimulatorCameraControl::setCaptureMode(QCamera::CaptureMode mode) +{ + if (m_session->captureMode() != mode) { + m_session->setCaptureMode(mode); + emit captureModeChanged(mode); + } +} + +void SimulatorCameraControl::setState(QCamera::State state) +{ + if (mState == state) { + return; + } + + // Simulator only supports these status + Q_ASSERT(mStatus == QCamera::UnloadedStatus || mStatus == QCamera::LoadedStatus + || mStatus == QCamera::ActiveStatus); + + switch (state) { + case QCamera::UnloadedState: // To UnloadedState - Release resources + switch (mStatus) { + case QCamera::LoadedStatus: + // Unload + break; + case QCamera::ActiveStatus: + // Stop and Unload + emit stopCamera(); + break; + default: + // Unrecognized internal state (Status) + return; + } + mStatus = QCamera::UnloadedStatus; + emit statusChanged(mStatus); + break; + + case QCamera::LoadedState: // To LoadedState - Reserve resources OR Stop ViewFinder and Cancel Capture + switch (mStatus) { + case QCamera::UnloadedStatus: + // Load + mStatus = QCamera::LoadingStatus; + emit statusChanged(mStatus); + break; + case QCamera::ActiveStatus: + // Stop + emit stopCamera(); + break; + + default: + // Unregocnized internal state (Status) + return; + } + mStatus = QCamera::LoadedStatus; + emit statusChanged(mStatus); + break; + + case QCamera::ActiveState: // To ActiveState - (Reserve Resources and) Start ViewFinder + switch (mStatus) { + case QCamera::UnloadedStatus: + // Load and Start (setting state handles starting) + mStatus = QCamera::LoadingStatus; + emit statusChanged(mStatus); + mStatus = QCamera::LoadedStatus; + emit statusChanged(mStatus); + mStatus = QCamera::StartingStatus; + emit statusChanged(mStatus); + emit startCamera(); + break; + case QCamera::LoadedStatus: + // Start + mStatus = QCamera::StartingStatus; + emit statusChanged(mStatus); + emit startCamera(); + break; + default: + // Unregocnized internal state (Status) + return; + } + mStatus = QCamera::ActiveStatus; + emit statusChanged(mStatus); + break; + + default: + return; + } + + mState = state; + emit stateChanged(mState); +} + +QCamera::State SimulatorCameraControl::state() const +{ + return mState; +} + +bool SimulatorCameraControl::canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const +{ + Q_UNUSED(status); + + switch (changeType) { + case QCameraControl::CaptureMode: + case QCameraControl::Viewfinder: + return true; + default: + return false; + } +} + +bool SimulatorCameraControl::isCaptureModeSupported(QCamera::CaptureMode mode) const +{ + return mode == QCamera::CaptureStillImage; +} + +QCamera::Status SimulatorCameraControl::status() const +{ + return mStatus; +} diff --git a/src/plugins/simulator/camera/simulatorcameracontrol.h b/src/plugins/simulator/camera/simulatorcameracontrol.h new file mode 100644 index 000000000..779f8150c --- /dev/null +++ b/src/plugins/simulator/camera/simulatorcameracontrol.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef SIMULATORCAMERACONTROL_H +#define SIMULATORCAMERACONTROL_H + +#include +#include +#include "simulatorcamerasession.h" + +QT_USE_NAMESPACE +QT_USE_NAMESPACE + +class SimulatorCameraControl : public QCameraControl +{ + Q_OBJECT +public: + SimulatorCameraControl(SimulatorCameraSession *session ); + virtual ~SimulatorCameraControl(); + + bool isValid() const { return true; } + + QCamera::State state() const; + void setState(QCamera::State state); + + QCamera::Status status() const; + + QCamera::CaptureMode captureMode() const; + void setCaptureMode(QCamera::CaptureMode mode); + + bool isCaptureModeSupported(QCamera::CaptureMode mode) const; + + bool canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const; + +signals: + void startCamera(); + void stopCamera(); + +private: + void updateSupportedResolutions(const QString &device); + + SimulatorCameraSession *m_session; + QCamera::State mState; + QCamera::Status mStatus; + bool m_reloadPending; +}; + +#endif // CAMERACONTROL_H diff --git a/src/plugins/simulator/camera/simulatorcameraexposurecontrol.cpp b/src/plugins/simulator/camera/simulatorcameraexposurecontrol.cpp new file mode 100644 index 000000000..d99d521d1 --- /dev/null +++ b/src/plugins/simulator/camera/simulatorcameraexposurecontrol.cpp @@ -0,0 +1,502 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "simulatorcameraexposurecontrol.h" +#include "simulatorcamerasession.h" + +SimulatorCameraExposureControl::SimulatorCameraExposureControl(SimulatorCameraSession *session, QObject *parent) : + QCameraExposureControl(parent), + mExposureMode(QCameraExposure::ExposureAuto), + mMeteringMode(QCameraExposure::MeteringAverage), + mSession(session), + mSettings(0) +{ + mSettings = mSession->settings(); + + connect(mSettings, SIGNAL(apertureChanged()), this, SLOT(apertureChanged())); + connect(mSettings, SIGNAL(apertureRangeChanged()), this, SLOT(apertureRangeChanged())); + connect(mSettings, SIGNAL(shutterSpeedChanged()), this, SLOT(shutterSpeedChanged())); + connect(mSettings, SIGNAL(isoSensitivityChanged()), this, SLOT(isoSensitivityChanged())); +} + +SimulatorCameraExposureControl::~SimulatorCameraExposureControl() +{ +} + +void SimulatorCameraExposureControl::apertureChanged() +{ + emit exposureParameterChanged(QCameraExposureControl::Aperture); +} + +void SimulatorCameraExposureControl::apertureRangeChanged() +{ + emit exposureParameterRangeChanged(QCameraExposureControl::Aperture); +} + +void SimulatorCameraExposureControl::shutterSpeedChanged() +{ + emit exposureParameterChanged(QCameraExposureControl::ShutterSpeed); +} + +void SimulatorCameraExposureControl::isoSensitivityChanged() +{ + emit exposureParameterChanged(QCameraExposureControl::ISO); +} + +QCameraExposure::ExposureMode SimulatorCameraExposureControl::exposureMode() const +{ + return mExposureMode; +} + +void SimulatorCameraExposureControl::setExposureMode(QCameraExposure::ExposureMode mode) +{ + if (isExposureModeSupported(mode)) + mExposureMode = mode; +} + +bool SimulatorCameraExposureControl::isExposureModeSupported(QCameraExposure::ExposureMode mode) const +{ + switch (mode) { + case QCameraExposure::ExposureAuto: + case QCameraExposure::ExposureManual: + return true; + default: + return false; + } + + return false; +} + +QCameraExposure::MeteringMode SimulatorCameraExposureControl::meteringMode() const +{ + return mMeteringMode; +} + +void SimulatorCameraExposureControl::setMeteringMode(QCameraExposure::MeteringMode mode) +{ + if (isMeteringModeSupported(mode)) + mMeteringMode = mode; +} + +bool SimulatorCameraExposureControl::isMeteringModeSupported(QCameraExposure::MeteringMode mode) const +{ + switch (mode) { + case QCameraExposure::MeteringAverage: + case QCameraExposure::MeteringSpot: + case QCameraExposure::MeteringMatrix: + return true; + default: + return false; + } + return false; +} + +bool SimulatorCameraExposureControl::isParameterSupported(ExposureParameter parameter) const +{ + switch (parameter) { + case QCameraExposureControl::ISO: + case QCameraExposureControl::Aperture: + case QCameraExposureControl::ShutterSpeed: + case QCameraExposureControl::ExposureCompensation: + return true; + case QCameraExposureControl::FlashPower: + case QCameraExposureControl::FlashCompensation: + return false; + + default: + return false; + } + + return false; +} + +QVariant SimulatorCameraExposureControl::exposureParameter(ExposureParameter parameter) const +{ + switch (parameter) { + case QCameraExposureControl::ISO: + return QVariant(isoSensitivity()); + case QCameraExposureControl::Aperture: + return QVariant(aperture()); + case QCameraExposureControl::ShutterSpeed: + return QVariant(shutterSpeed()); + case QCameraExposureControl::ExposureCompensation: + return QVariant(exposureCompensation()); + case QCameraExposureControl::FlashPower: + case QCameraExposureControl::FlashCompensation: + // Not supported + return QVariant(); + + default: + // Not supported + return QVariant(); + } +} + +QCameraExposureControl::ParameterFlags SimulatorCameraExposureControl::exposureParameterFlags(ExposureParameter parameter) const +{ + QCameraExposureControl::ParameterFlags flags; + + /* + * ISO, Aperture, ShutterSpeed: + * - Automatic/Manual + * - Read/Write + * - Discrete range + * + * ExposureCompensation: + * - Automatic/Manual + * - Read/Write + * - Continuous range + * + * FlashPower, FlashCompensation: + * - Not supported + */ + switch (parameter) { + case QCameraExposureControl::ISO: + case QCameraExposureControl::Aperture: + case QCameraExposureControl::ShutterSpeed: + flags |= QCameraExposureControl::AutomaticValue; + break; + case QCameraExposureControl::ExposureCompensation: + flags |= QCameraExposureControl::AutomaticValue; + flags |= QCameraExposureControl::ContinuousRange; + break; + case QCameraExposureControl::FlashPower: + case QCameraExposureControl::FlashCompensation: + // Do nothing - no flags + break; + + default: + // Do nothing - no flags + break; + } + + return flags; +} + +QVariantList SimulatorCameraExposureControl::supportedParameterRange(ExposureParameter parameter) const +{ + QVariantList valueList; + switch (parameter) { + case QCameraExposureControl::ISO: { + QList exposureValues = mSettings->supportedIsoSensitivities(); + for (int i = 0; i < exposureValues.count(); ++i) { + valueList.append(QVariant(exposureValues[i])); + } + break; + } + case QCameraExposureControl::Aperture: { + QList apertureValues = mSettings->supportedApertures(); + for (int i = 0; i < apertureValues.count(); ++i) { + valueList.append(QVariant(apertureValues[i])); + } + break; + } + case QCameraExposureControl::ShutterSpeed: { + QList shutterSpeedValues = mSettings->supportedShutterSpeeds(); + for (int i = 0; i < shutterSpeedValues.count(); ++i) { + valueList.append(QVariant(shutterSpeedValues[i])); + } + break; + } + case QCameraExposureControl::ExposureCompensation: { + QList evValues = mSettings->supportedExposureCompensationValues(); + for (int i = 0; i < evValues.count(); ++i) { + valueList.append(QVariant(evValues[i])); + } + break; + } + case QCameraExposureControl::FlashPower: + case QCameraExposureControl::FlashCompensation: + // Not supported + break; + + default: + // Not supported + return QVariantList(); + } + + return valueList; +} + +bool SimulatorCameraExposureControl::setExposureParameter(ExposureParameter parameter, const QVariant& value) +{ + bool useDefaultValue = false; + + if (value.isNull()) + useDefaultValue = true; + + switch (parameter) { + case QCameraExposureControl::ISO: + if (useDefaultValue) { + setAutoIsoSensitivity(); + return false; + } + else + return setManualIsoSensitivity(value.toInt()); + + case QCameraExposureControl::Aperture: + if (useDefaultValue) { + setAutoAperture(); + return false; + } + else + return setManualAperture(value.toReal()); + + case QCameraExposureControl::ShutterSpeed: + if (useDefaultValue) { + setAutoShutterSpeed(); + return false; + } + else + return setManualShutterSpeed(value.toReal()); + + case QCameraExposureControl::ExposureCompensation: + if (useDefaultValue) { + setAutoExposureCompensation(); + return false; + } + else + return setManualExposureCompensation(value.toReal()); + + case QCameraExposureControl::FlashPower: + return false; + case QCameraExposureControl::FlashCompensation: + return false; + + default: + // Not supported + return false; + } +} + +QString SimulatorCameraExposureControl::extendedParameterName(ExposureParameter parameter) +{ + switch (parameter) { + case QCameraExposureControl::ISO: + return QString("ISO Sensitivity"); + case QCameraExposureControl::Aperture: + return QString("Aperture"); + case QCameraExposureControl::ShutterSpeed: + return QString("Shutter Speed"); + case QCameraExposureControl::ExposureCompensation: + return QString("Exposure Compensation"); + case QCameraExposureControl::FlashPower: + return QString("Flash Power"); + case QCameraExposureControl::FlashCompensation: + return QString("Flash Compensation"); + + default: + return QString(); + } +} + +int SimulatorCameraExposureControl::isoSensitivity() const +{ + return mSettings->isoSensitivity(); +} + +bool SimulatorCameraExposureControl::isIsoSensitivitySupported(const int iso) const +{ + return mSettings->supportedIsoSensitivities().contains(iso); +} + +bool SimulatorCameraExposureControl::setManualIsoSensitivity(int iso) +{ + if (isIsoSensitivitySupported(iso)) { + mSettings->setManualIsoSensitivity(iso); + return true; + } else { + QList supportedIsoValues = mSettings->supportedIsoSensitivities(); + int minIso = supportedIsoValues.first(); + int maxIso = supportedIsoValues.last(); + + if (iso < minIso) { // Smaller than minimum + iso = minIso; + } else if (iso > maxIso) { // Bigger than maximum + iso = maxIso; + } else { // Find closest + int indexOfClosest = 0; + int smallestDiff = 10000000; // Sensible max diff + for(int i = 0; i < supportedIsoValues.count(); ++i) { + int currentDiff = qAbs(iso - supportedIsoValues[i]); + if(currentDiff < smallestDiff) { + smallestDiff = currentDiff; + indexOfClosest = i; + } + } + iso = supportedIsoValues[indexOfClosest]; + } + mSettings->setManualIsoSensitivity(iso); + } + + return false; +} + +void SimulatorCameraExposureControl::setAutoIsoSensitivity() +{ + mSettings->setAutoIsoSensitivity(); +} + + +qreal SimulatorCameraExposureControl::aperture() const +{ + return mSettings->aperture(); +} + +bool SimulatorCameraExposureControl::isApertureSupported(const qreal aperture) const +{ + return mSettings->supportedApertures().contains(aperture); +} + +bool SimulatorCameraExposureControl::setManualAperture(qreal aperture) +{ + if (isApertureSupported(aperture)) { + mSettings->setManualAperture(aperture); + return true; + } else { + QList supportedApertureValues = mSettings->supportedApertures(); + qreal minAperture = supportedApertureValues.first(); + qreal maxAperture = supportedApertureValues.last(); + + if (aperture < minAperture) { // Smaller than minimum + aperture = minAperture; + } else if (aperture > maxAperture) { // Bigger than maximum + aperture = maxAperture; + } else { // Find closest + int indexOfClosest = 0; + qreal smallestDiff = 100000000; // Sensible max diff + for(int i = 0; i < supportedApertureValues.count(); ++i) { + qreal currentDiff = qAbs(aperture - supportedApertureValues[i]); + if(currentDiff < smallestDiff) { + smallestDiff = currentDiff; + indexOfClosest = i; + } + } + aperture = supportedApertureValues[indexOfClosest]; + } + mSettings->setManualAperture(aperture); + } + + return false; +} + +void SimulatorCameraExposureControl::setAutoAperture() +{ + mSettings->setAutoAperture(); +} + +qreal SimulatorCameraExposureControl::shutterSpeed() const +{ + return mSettings->shutterSpeed(); +} + +bool SimulatorCameraExposureControl::isShutterSpeedSupported(const qreal seconds) const +{ + return mSettings->supportedShutterSpeeds().contains(seconds); +} + +bool SimulatorCameraExposureControl::setManualShutterSpeed(qreal seconds) +{ + if (isShutterSpeedSupported(seconds)) { + mSettings->setManualShutterSpeed(seconds); + return true; + } else { + QList supportedShutterSpeeds = mSettings->supportedShutterSpeeds(); + + qreal minShutterSpeed = supportedShutterSpeeds.first(); + qreal maxShutterSpeed = supportedShutterSpeeds.last(); + + if (seconds < minShutterSpeed) { // Smaller than minimum + seconds = minShutterSpeed; + } else if (seconds > maxShutterSpeed) { // Bigger than maximum + seconds = maxShutterSpeed; + } else { // Find closest + int indexOfClosest = 0; + qreal smallestDiff = 100000000; // Sensible max diff + for(int i = 0; i < supportedShutterSpeeds.count(); ++i) { + qreal currentDiff = qAbs(seconds - supportedShutterSpeeds[i]); + if(currentDiff < smallestDiff) { + smallestDiff = currentDiff; + indexOfClosest = i; + } + } + seconds = supportedShutterSpeeds[indexOfClosest]; + } + mSettings->setManualShutterSpeed(seconds); + } + + return false; +} + +void SimulatorCameraExposureControl::setAutoShutterSpeed() +{ + mSettings->setAutoShutterSpeed(); +} + +qreal SimulatorCameraExposureControl::exposureCompensation() const +{ + return mSettings->exposureCompensation(); +} + +bool SimulatorCameraExposureControl::isExposureCompensationSupported(const qreal ev) const +{ + QList supportedValues = mSettings->supportedExposureCompensationValues(); + return (ev >= supportedValues.first() && ev <= supportedValues.last()); +} + +bool SimulatorCameraExposureControl::setManualExposureCompensation(qreal ev) +{ + if (isExposureCompensationSupported(ev)) { + mSettings->setExposureCompensation(ev); + return true; + } + + return false; +} + +void SimulatorCameraExposureControl::setAutoExposureCompensation() +{ + mSettings->setAutoExposureCompensation(); +} + +// End of file diff --git a/src/plugins/simulator/camera/simulatorcameraexposurecontrol.h b/src/plugins/simulator/camera/simulatorcameraexposurecontrol.h new file mode 100644 index 000000000..5ffa362e1 --- /dev/null +++ b/src/plugins/simulator/camera/simulatorcameraexposurecontrol.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIMULATORCAMERAEXPOSURECONTROL_H +#define SIMULATORCAMERAEXPOSURECONTROL_H + +#include + +#include "simulatorcamerasettings.h" + +QT_BEGIN_NAMESPACE + +class SimulatorCameraSession; + +/* + * Control for exposure related camera operation. + */ +class SimulatorCameraExposureControl : public QCameraExposureControl +{ + Q_OBJECT + +public: + + SimulatorCameraExposureControl(SimulatorCameraSession *session, QObject *parent = 0); + ~SimulatorCameraExposureControl(); + + // QCameraExposureControl + // Exposure Mode + QCameraExposure::ExposureMode exposureMode() const; + void setExposureMode(QCameraExposure::ExposureMode mode); + bool isExposureModeSupported(QCameraExposure::ExposureMode mode) const; + + // Metering Mode + QCameraExposure::MeteringMode meteringMode() const; + void setMeteringMode(QCameraExposure::MeteringMode mode); + bool isMeteringModeSupported(QCameraExposure::MeteringMode mode) const; + + // Exposure Parameter + bool isParameterSupported(ExposureParameter parameter) const; + QVariant exposureParameter(ExposureParameter parameter) const; + QCameraExposureControl::ParameterFlags exposureParameterFlags(ExposureParameter parameter) const; + QVariantList supportedParameterRange(ExposureParameter parameter) const; + bool setExposureParameter(ExposureParameter parameter, const QVariant& value); + + QString extendedParameterName(ExposureParameter parameter); + +private Q_SLOTS: // Internal Slots + void apertureChanged(); + void apertureRangeChanged(); + void shutterSpeedChanged(); + void isoSensitivityChanged(); + +private: // Internal - Implementing ExposureParameter + // ISO Sensitivity + int isoSensitivity() const; + bool setManualIsoSensitivity(int iso); + void setAutoIsoSensitivity(); + bool isIsoSensitivitySupported(const int iso) const; + + // Aperture + qreal aperture() const; + bool setManualAperture(qreal aperture); + void setAutoAperture(); + bool isApertureSupported(const qreal aperture) const; + + // Shutter Speed + qreal shutterSpeed() const; + bool setManualShutterSpeed(qreal seconds); + void setAutoShutterSpeed(); + bool isShutterSpeedSupported(const qreal seconds) const; + + // Exposure Compensation + qreal exposureCompensation() const; + bool setManualExposureCompensation(qreal ev); + void setAutoExposureCompensation(); + bool isExposureCompensationSupported(const qreal ev) const; + +private: // Data + QCameraExposure::ExposureMode mExposureMode; + QCameraExposure::MeteringMode mMeteringMode; + SimulatorCameraSession *mSession; + SimulatorCameraSettings *mSettings; +}; + +QT_END_NAMESPACE + +#endif // SIMULATORCAMERAEXPOSURECONTROL_H diff --git a/src/plugins/simulator/camera/simulatorcameraimagecapturecontrol.cpp b/src/plugins/simulator/camera/simulatorcameraimagecapturecontrol.cpp new file mode 100644 index 000000000..a0c8dce66 --- /dev/null +++ b/src/plugins/simulator/camera/simulatorcameraimagecapturecontrol.cpp @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "simulatorcameraimagecapturecontrol.h" +#include "simulatorcameraservice.h" +#include "simulatorcamerasession.h" +#include "simulatorcameracontrol.h" + +SimulatorCameraImageCaptureControl::SimulatorCameraImageCaptureControl(SimulatorCameraSession *session, SimulatorCameraService *service) : + QCameraImageCaptureControl(service), + mReadyForCapture(true), + m_driveMode(QCameraImageCapture::SingleImageCapture) // Default DriveMode +{ + m_session = session; + + m_service = service; + m_cameraControl = qobject_cast(m_service->requestControl(QCameraControl_iid)); + + // Chain these signals from session class + connect(m_session, SIGNAL(imageCaptured(const int, QImage)), + this, SIGNAL(imageCaptured(const int, QImage))); + connect(m_session, SIGNAL(imageSaved(const int, const QString&)), + this, SIGNAL(imageSaved(const int, const QString&))); + connect(m_session, SIGNAL(imageExposed(int)), + this, SIGNAL(imageExposed(int))); + connect(m_session, SIGNAL(captureError(int, int, const QString&)), + this, SIGNAL(error(int, int, const QString&))); +} + +SimulatorCameraImageCaptureControl::~SimulatorCameraImageCaptureControl() +{ +} + +bool SimulatorCameraImageCaptureControl::isReadyForCapture() const +{ + if (m_cameraControl && m_cameraControl->captureMode() != QCamera::CaptureStillImage) { + return false; + } + + return mReadyForCapture; +} + +QCameraImageCapture::DriveMode SimulatorCameraImageCaptureControl::driveMode() const +{ + return m_driveMode; +} + +void SimulatorCameraImageCaptureControl::setDriveMode(QCameraImageCapture::DriveMode mode) +{ + if (mode != QCameraImageCapture::SingleImageCapture) { + emit error(0, QCamera::NotSupportedFeatureError, tr("DriveMode not supported.")); + return; + } + + m_driveMode = mode; +} + +int SimulatorCameraImageCaptureControl::capture(const QString &fileName) +{ + if (m_cameraControl && m_cameraControl->captureMode() != QCamera::CaptureStillImage) { + emit error(0, QCameraImageCapture::NotReadyError, tr("Incorrect CaptureMode.")); + return 0; + } + updateReadyForCapture(false); + int imageId = m_session->captureImage(fileName); + updateReadyForCapture(true); + return imageId; +} + +void SimulatorCameraImageCaptureControl::cancelCapture() +{ +} + +void SimulatorCameraImageCaptureControl::updateReadyForCapture(bool ready) +{ + mReadyForCapture = ready; + emit readyForCaptureChanged(mReadyForCapture); +} + +// End of file diff --git a/src/plugins/simulator/camera/simulatorcameraimagecapturecontrol.h b/src/plugins/simulator/camera/simulatorcameraimagecapturecontrol.h new file mode 100644 index 000000000..e45483e72 --- /dev/null +++ b/src/plugins/simulator/camera/simulatorcameraimagecapturecontrol.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIMULATORCAMERAIMAGECAPTURECONTROL_H +#define SIMULATORCAMERAIMAGECAPTURECONTROL_H + +#include "qcameraimagecapturecontrol.h" + +QT_USE_NAMESPACE + +class SimulatorCameraService; +class SimulatorCameraSession; +class SimulatorCameraControl; + +/* + * Control for image capture operations. + */ +class SimulatorCameraImageCaptureControl : public QCameraImageCaptureControl +{ + Q_OBJECT + +public: // Contructors & Destrcutor + + SimulatorCameraImageCaptureControl(SimulatorCameraSession *session, SimulatorCameraService *service); + ~SimulatorCameraImageCaptureControl(); + +public: // QCameraImageCaptureControl + + bool isReadyForCapture() const; + + // Drive Mode + QCameraImageCapture::DriveMode driveMode() const; + void setDriveMode(QCameraImageCapture::DriveMode mode); + + // Capture + int capture(const QString &fileName); + void cancelCapture(); + +private: + void updateReadyForCapture(bool ready); + + bool mReadyForCapture; + SimulatorCameraSession *m_session; + SimulatorCameraService *m_service; + SimulatorCameraControl *m_cameraControl; + QCameraImageCapture::DriveMode m_driveMode; +}; + +#endif // SIMULATORCAMERAIMAGECAPTURECONTROL_H diff --git a/src/plugins/simulator/camera/simulatorcameraservice.cpp b/src/plugins/simulator/camera/simulatorcameraservice.cpp new file mode 100644 index 000000000..6eee2ec02 --- /dev/null +++ b/src/plugins/simulator/camera/simulatorcameraservice.cpp @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "simulatorcameraservice.h" +#include "simulatorcamerasession.h" +#include "simulatorcameracontrol.h" +#include "simulatorcameraimagecapturecontrol.h" +#include "simulatorcameraexposurecontrol.h" + +#include "simulatorvideoinputdevicecontrol.h" +#include "simulatorvideorenderercontrol.h" +#include "../qsimulatormultimediaconnection_p.h" + +#include +#include + +QTM_USE_NAMESPACE; +using namespace Simulator; + +SimulatorCameraService::SimulatorCameraService(const QString &service, MultimediaConnection *multimediaConnection, + QObject *parent): + QMediaService(parent) +{ + Q_UNUSED(service) + mCaptureSession = new SimulatorCameraSession(this); + mCameraControl = new SimulatorCameraControl(mCaptureSession); + mVideoInputDeviceControl = new QSimulatorVideoInputDeviceControl(mCaptureSession); + mVideoInputDeviceControl->updateDeviceList(get_qtCameraData()); + mVideoRendererControl = new SimulatorVideoRendererControl(mCaptureSession, this); + mImageCaptureControl = new SimulatorCameraImageCaptureControl(mCaptureSession, this); + mExposureControl = new SimulatorCameraExposureControl(mCaptureSession, this); + + connect(multimediaConnection, SIGNAL(cameraDataChanged(QtMobility::QCameraData)), + SLOT(updateCameraData(QtMobility::QCameraData))); + connect(multimediaConnection, SIGNAL(cameraAdded(QString,QtMobility::QCameraData::QCameraDetails)), + mVideoInputDeviceControl, SLOT(addDevice(QString,QtMobility::QCameraData::QCameraDetails))); + connect(multimediaConnection, SIGNAL(cameraRemoved(QString)), + mVideoInputDeviceControl, SLOT(removeDevice(QString))); + connect(multimediaConnection, SIGNAL(cameraChanged(QString,QtMobility::QCameraData::QCameraDetails)), + mVideoInputDeviceControl, SLOT(changeDevice(QString,QtMobility::QCameraData::QCameraDetails))); + connect(multimediaConnection, SIGNAL(cameraChanged(QString,QtMobility::QCameraData::QCameraDetails)), + SLOT(changeCamera(QString,QtMobility::QCameraData::QCameraDetails))); + connect(mCameraControl, SIGNAL(startCamera()), + mVideoRendererControl, SLOT(showImage())); + connect(mCameraControl, SIGNAL(stopCamera()), + mVideoRendererControl, SLOT(stop())); + connect(mVideoInputDeviceControl, SIGNAL(selectedDeviceChanged(QString)), + SLOT(updateCameraPicture(QString))); + connect(mCaptureSession->settings(), SIGNAL(isoSensitivityChanged()), mVideoRendererControl, SLOT(showImage())); + connect(mCaptureSession->settings(), SIGNAL(apertureChanged()), mVideoRendererControl, SLOT(showImage())); + connect(mCaptureSession->settings(), SIGNAL(shutterSpeedChanged()), mVideoRendererControl, SLOT(showImage())); + connect(mCaptureSession->settings(), SIGNAL(exposureCompensationChanged()), mVideoRendererControl, SLOT(showImage())); + mCaptureSession->setImage(mVideoRendererControl->image()); + mVideoInputDeviceControl->setSelectedDevice(mVideoInputDeviceControl->defaultDevice()); +} + +SimulatorCameraService::~SimulatorCameraService() +{ +} + +QMediaControl *SimulatorCameraService::requestControl(const char *name) +{ + if (!mCaptureSession) + return 0; + + if (qstrcmp(name,QCameraControl_iid) == 0) + return mCameraControl; + + if (qstrcmp(name,QVideoDeviceControl_iid) == 0) + return mVideoInputDeviceControl; + + if (qstrcmp(name, QVideoRendererControl_iid) == 0) + return mVideoRendererControl; + + if (qstrcmp(name, QCameraImageCaptureControl_iid) == 0) + return mImageCaptureControl; + + if (qstrcmp(name, QCameraExposureControl_iid) == 0) + return mExposureControl; + + return 0; +} + +void SimulatorCameraService::releaseControl(QMediaControl *control) +{ + Q_UNUSED(control) +} + +void SimulatorCameraService::updateCameraData(const QtMobility::QCameraData &data) +{ + mVideoInputDeviceControl->updateDeviceList(data); + QString currentDevice = mVideoInputDeviceControl->deviceName(mVideoInputDeviceControl->selectedDevice()); + if (!data.cameras.contains(currentDevice)) + return; + + updateCurrentDeviceImage(data.cameras.value(currentDevice).imagePath); +} + +void SimulatorCameraService::changeCamera(const QString &name, const QtMobility::QCameraData::QCameraDetails &details) +{ + QString currentDevice = mVideoInputDeviceControl->deviceName(mVideoInputDeviceControl->selectedDevice()); + if (currentDevice != name) + return; + + updateCurrentDeviceImage(details.imagePath); +} + +void SimulatorCameraService::updateCameraPicture(const QString &name) +{ + QtMobility::QCameraData data = QtMobility::get_qtCameraData(); + if (!data.cameras.contains(name)) + return; + + updateCurrentDeviceImage(data.cameras.value(name).imagePath); +} + +void SimulatorCameraService::updateCurrentDeviceImage(const QString &imagePath) +{ + mVideoRendererControl->setImagePath(imagePath); + mCaptureSession->setImage(mVideoRendererControl->image()); +} + +#include "moc_simulatorcameraservice.cpp" diff --git a/src/plugins/simulator/camera/simulatorcameraservice.h b/src/plugins/simulator/camera/simulatorcameraservice.h new file mode 100644 index 000000000..b159eb393 --- /dev/null +++ b/src/plugins/simulator/camera/simulatorcameraservice.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIMULATORCAMERACAPTURESERVICE_H +#define SIMULATORCAMERACAPTURESERVICE_H + +#include + +#include "../qsimulatormultimediaconnection_p.h" + +QTM_BEGIN_NAMESPACE +namespace Simulator { +class MultimediaConnection; +} +QTM_END_NAMESPACE +class SimulatorCameraSession; +class SimulatorCameraControl; +class SimulatorCameraImageCaptureControl; +class SimulatorCameraExposureControl; +class SimulatorVideoRendererControl; +class QSimulatorVideoInputDeviceControl; + +class SimulatorCameraService : public QMediaService +{ + Q_OBJECT + +public: + SimulatorCameraService(const QString &service, QTM_PREPEND_NAMESPACE(Simulator::MultimediaConnection) *cameraConnection, + QObject *parent = 0); + virtual ~SimulatorCameraService(); + + QMediaControl *requestControl(const char *name); + void releaseControl(QMediaControl *); + +private slots: + void updateCameraData(const QtMobility::QCameraData &data); + void changeCamera(const QString &name, const QtMobility::QCameraData::QCameraDetails &details); + void updateCameraPicture(const QString &name); + +private: + void updateCurrentDeviceImage(const QString &imagePath); + SimulatorCameraSession *mCaptureSession; + SimulatorCameraControl *mCameraControl; + SimulatorCameraImageCaptureControl *mImageCaptureControl; + SimulatorCameraExposureControl *mExposureControl; + + QSimulatorVideoInputDeviceControl *mVideoInputDeviceControl; + + QMediaControl *mVideoOutput; + + SimulatorVideoRendererControl *mVideoRendererControl; +}; + +#endif // CAMERACAPTURESERVICE_H diff --git a/src/plugins/simulator/camera/simulatorcamerasession.cpp b/src/plugins/simulator/camera/simulatorcamerasession.cpp new file mode 100644 index 000000000..17dd2f762 --- /dev/null +++ b/src/plugins/simulator/camera/simulatorcamerasession.cpp @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "simulatorcamerasession.h" +#include "simulatorcamerasettings.h" +#include "../qsimulatormultimediaconnection_p.h" +#include +#include + +#include +#include +#include + +#include + +//#define CAMERA_DEBUG 1 + +SimulatorCameraSession::SimulatorCameraSession(QObject *parent) + :QObject(parent), + mViewfinder(0), + mImage(0), + mRequestId(0) +{ + mSettings = new SimulatorCameraSettings(this); +} + +SimulatorCameraSession::~SimulatorCameraSession() +{ +} + +int SimulatorCameraSession::captureImage(const QString &fileName) +{ + QTM_USE_NAMESPACE; + ++mRequestId; + emit imageExposed(mRequestId); + + QString actualFileName = fileName; + if (actualFileName.isEmpty()) { + actualFileName = generateFileName("img_", defaultDir(QCamera::CaptureStillImage), "jpg"); + } + + emit imageCaptured(mRequestId, *mImage); + + if (!mImage->save(actualFileName)) { + emit captureError(mRequestId, QCameraImageCapture::ResourceError, "Could not save file"); + return mRequestId; + } + emit imageSaved(mRequestId, actualFileName); + return mRequestId; +} + +void SimulatorCameraSession::setCaptureMode(QCamera::CaptureMode mode) +{ + mCaptureMode = mode; +} + +QDir SimulatorCameraSession::defaultDir(QCamera::CaptureMode) const +{ + const QString temp = QDir::tempPath(); + if (QFileInfo(temp).isWritable()) + return QDir(temp); + + return QDir(); +} + +QString SimulatorCameraSession::generateFileName(const QString &prefix, const QDir &dir, const QString &ext) const +{ + int lastClip = 0; + foreach(QString fileName, dir.entryList(QStringList() << QString("%1*.%2").arg(prefix).arg(ext))) { + int imgNumber = fileName.mid(prefix.length(), fileName.size()-prefix.length()-ext.length()-1).toInt(); + lastClip = qMax(lastClip, imgNumber); + } + + QString name = QString("%1%2.%3").arg(prefix) + .arg(lastClip+1, + 4, //fieldWidth + 10, + QLatin1Char('0')) + .arg(ext); + + return dir.absoluteFilePath(name); +} + +void SimulatorCameraSession::setViewfinder(QObject *viewfinder) +{ + if (mViewfinder != viewfinder) { + mViewfinder = viewfinder; + emit viewfinderChanged(); + } +} + +QCamera::CaptureMode SimulatorCameraSession::captureMode() +{ + return mCaptureMode; +} + +void SimulatorCameraSession::setImage(const QImage *image) +{ + mImage = image; +} + +QObject *SimulatorCameraSession::viewfinder() const +{ + return mViewfinder; +} + +SimulatorCameraSettings *SimulatorCameraSession::settings() const +{ + return mSettings; +} diff --git a/src/plugins/simulator/camera/simulatorcamerasession.h b/src/plugins/simulator/camera/simulatorcamerasession.h new file mode 100644 index 000000000..6d1078e8d --- /dev/null +++ b/src/plugins/simulator/camera/simulatorcamerasession.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIMULATORCAMERACAPTURESESSION_H +#define SIMULATORCAMERACAPTURESESSION_H + +#include + +#include +#include + +#include "qcamera.h" + +class SimulatorCameraSettings; + +class SimulatorCameraSession : public QObject +{ + Q_OBJECT +public: + SimulatorCameraSession(QObject *parent); + ~SimulatorCameraSession(); + + QCamera::CaptureMode captureMode(); + void setCaptureMode(QCamera::CaptureMode mode); + + QDir defaultDir(QCamera::CaptureMode mode) const; + QString generateFileName(const QString &prefix, const QDir &dir, const QString &ext) const; + + void setImage(const QImage *image); + QObject *viewfinder() const; + void setViewfinder(QObject *viewfinder); + + int captureImage(const QString &fileName); + + SimulatorCameraSettings *settings() const; + +signals: + void stateChanged(QCamera::State state); + void captureError(int id, int error, const QString &errorString); + void error(int error, const QString &errorString); + void imageExposed(int requestId); + void imageCaptured(int requestId, const QImage &img); + void imageSaved(int requestId, const QString &fileName); + void viewfinderChanged(); + +private: + QCamera::CaptureMode mCaptureMode; + + QObject *mViewfinder; + const QImage *mImage; + + SimulatorCameraSettings *mSettings; + +public: + int mRequestId; +}; + +#endif // SIMULATORCAMERACAPTURESESSION_H diff --git a/src/plugins/simulator/camera/simulatorcamerasettings.cpp b/src/plugins/simulator/camera/simulatorcamerasettings.cpp new file mode 100644 index 000000000..dd617549b --- /dev/null +++ b/src/plugins/simulator/camera/simulatorcamerasettings.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "simulatorcamerasettings.h" + +SimulatorCameraSettings::SimulatorCameraSettings(QObject *parent) + : QObject(parent) + , mIsoSensitivity(400) + , mAperture(4) + , mShutterSpeed(0.008) + , mExposureCompensation(0) +{ + mSupportedIsoSensitivities << 50 << 100 << 200 << 400 << 800; + mSupportedApertures << 1.8 << 2.8 << 4 << 5.6 << 8; + mSupportedShutterSpeeds << 0.002 << 0.004 << 0.008 << 1./60 << 1./30; + mSupportedExposureCompensations << -2 << 2; +} + +SimulatorCameraSettings::~SimulatorCameraSettings() +{ +} + +int SimulatorCameraSettings::isoSensitivity() const +{ + return mIsoSensitivity; +} + +QList SimulatorCameraSettings::supportedIsoSensitivities() const +{ + return mSupportedIsoSensitivities; +} + +void SimulatorCameraSettings::setManualIsoSensitivity(int iso) +{ + if (iso != mIsoSensitivity && supportedIsoSensitivities().contains(iso)) { + mIsoSensitivity = iso; + emit isoSensitivityChanged(); + } +} + +void SimulatorCameraSettings::setAutoIsoSensitivity() +{ + setManualIsoSensitivity(defaultIsoSensitivity()); +} + +qreal SimulatorCameraSettings::aperture() const +{ + return mAperture; +} + +QList SimulatorCameraSettings::supportedApertures() const +{ + return mSupportedApertures; +} + +void SimulatorCameraSettings::setManualAperture(qreal aperture) +{ + if (aperture != mAperture && supportedApertures().contains(aperture)) { + mAperture = aperture; + emit apertureChanged(); + } +} + +void SimulatorCameraSettings::setAutoAperture() +{ + setManualAperture(defaultAperture()); +} + +qreal SimulatorCameraSettings::shutterSpeed() const +{ + return mShutterSpeed; +} + +QList SimulatorCameraSettings::supportedShutterSpeeds() const +{ + return mSupportedShutterSpeeds; +} + +void SimulatorCameraSettings::setManualShutterSpeed(qreal speed) +{ + if (speed != mShutterSpeed && supportedShutterSpeeds().contains(speed)) { + mShutterSpeed = speed; + emit shutterSpeedChanged(); + } +} + +void SimulatorCameraSettings::setAutoShutterSpeed() +{ + setManualShutterSpeed(defaultShutterSpeed()); +} + +void SimulatorCameraSettings::setExposureCompensation(qreal ev) +{ + if (ev != mExposureCompensation && ev >= mSupportedExposureCompensations.first() + && ev <= mSupportedExposureCompensations.last()) { + mExposureCompensation = ev; + emit exposureCompensationChanged(); + } +} + +qreal SimulatorCameraSettings::exposureCompensation() const +{ + return mExposureCompensation; +} + +QList SimulatorCameraSettings::supportedExposureCompensationValues() const +{ + return mSupportedExposureCompensations; +} + +void SimulatorCameraSettings::setAutoExposureCompensation() +{ + setExposureCompensation(defaultExposureCompensation()); +} + +int SimulatorCameraSettings::defaultIsoSensitivity() const +{ + return 400; +} + +qreal SimulatorCameraSettings::defaultAperture() const +{ + return 4; +} + +qreal SimulatorCameraSettings::defaultShutterSpeed() const +{ + return 0.008; +} + +qreal SimulatorCameraSettings::defaultExposureCompensation() const +{ + return 0; +} + +// End of file diff --git a/src/plugins/simulator/camera/simulatorcamerasettings.h b/src/plugins/simulator/camera/simulatorcamerasettings.h new file mode 100644 index 000000000..173a11549 --- /dev/null +++ b/src/plugins/simulator/camera/simulatorcamerasettings.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIMULATORCAMERASETTINGS_H +#define SIMULATORCAMERASETTINGS_H + +#include "qcamera.h" + +QT_BEGIN_NAMESPACE + +class SimulatorCameraSettings : public QObject +{ + Q_OBJECT + +public: + SimulatorCameraSettings(QObject *parent); + ~SimulatorCameraSettings(); + + // ISO Sensitivity + int isoSensitivity() const; + int defaultIsoSensitivity() const; + void setManualIsoSensitivity(int iso); + void setAutoIsoSensitivity(); + QList supportedIsoSensitivities() const; + + // Aperture + qreal aperture() const; + qreal defaultAperture() const; + void setManualAperture(qreal aperture); + void setAutoAperture(); + QList supportedApertures() const; + + // Shutter Speed + qreal shutterSpeed() const; + qreal defaultShutterSpeed() const; + void setManualShutterSpeed(qreal speed); + void setAutoShutterSpeed(); + QList supportedShutterSpeeds() const; + + // ExposureCompensation + qreal exposureCompensation() const; + qreal defaultExposureCompensation() const; + void setExposureCompensation(qreal ev); + void setAutoExposureCompensation(); + QList supportedExposureCompensationValues() const; + +Q_SIGNALS: // Notifications + // For QCameraExposureControl + void flashReady(bool ready); + void apertureChanged(); + void apertureRangeChanged(); + void shutterSpeedChanged(); + void isoSensitivityChanged(); + void exposureCompensationChanged(); + + // Errors + void error(int, const QString&); + +private: // Data + int mIsoSensitivity; + QList mSupportedIsoSensitivities; + qreal mAperture; + QList mSupportedApertures; + qreal mShutterSpeed; + QList mSupportedShutterSpeeds; + qreal mExposureCompensation; + QList mSupportedExposureCompensations; +}; + +QT_END_NAMESPACE + +#endif // SIMULATORCAMERASETTINGS_H diff --git a/src/plugins/simulator/camera/simulatorvideoinputdevicecontrol.cpp b/src/plugins/simulator/camera/simulatorvideoinputdevicecontrol.cpp new file mode 100644 index 000000000..154777392 --- /dev/null +++ b/src/plugins/simulator/camera/simulatorvideoinputdevicecontrol.cpp @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "simulatorvideoinputdevicecontrol.h" + +#include +#include +#include +#include + +using namespace QTM_NAMESPACE; +QSimulatorVideoInputDeviceControl::QSimulatorVideoInputDeviceControl(QObject *parent) + : QVideoDeviceControl(parent) + , mSelectedDevice(-1) +{ +} + +QSimulatorVideoInputDeviceControl::~QSimulatorVideoInputDeviceControl() +{ +} + +int QSimulatorVideoInputDeviceControl::deviceCount() const +{ + return mDevices.count(); +} + +QString QSimulatorVideoInputDeviceControl::deviceName(int index) const +{ + if (index >= mDevices.count() || index < 0) + return QString(); + return mDevices.at(index); +} + +QString QSimulatorVideoInputDeviceControl::deviceDescription(int index) const +{ + if (index >= mDevices.count() || index < 0) + return QString(); + + return mDescriptions[index]; +} + +QIcon QSimulatorVideoInputDeviceControl::deviceIcon(int index) const +{ + Q_UNUSED(index); + return QIcon(); +} + +int QSimulatorVideoInputDeviceControl::defaultDevice() const +{ + if (mDevices.isEmpty()) + return -1; + return 0; +} + +int QSimulatorVideoInputDeviceControl::selectedDevice() const +{ + return mSelectedDevice; +} + + +void QSimulatorVideoInputDeviceControl::setSelectedDevice(int index) +{ + if (index != mSelectedDevice) { + mSelectedDevice = index; + emit selectedDeviceChanged(index); + emit selectedDeviceChanged(deviceName(index)); + } +} + +void QSimulatorVideoInputDeviceControl::updateDeviceList(const QtMobility::QCameraData &data) +{ + mDevices.clear(); + mDescriptions.clear(); + QHashIterator iter(data.cameras); + while(iter.hasNext()) { + iter.next(); + mDevices.append(iter.key()); + mDescriptions.append(iter.value().description); + } + emit devicesChanged(); +} + +void QSimulatorVideoInputDeviceControl::addDevice(const QString &name, const QtMobility::QCameraData::QCameraDetails &details) +{ + if (mDevices.contains(name)) + return; + + mDevices.append(name); + mDescriptions.append(details.description); + emit devicesChanged(); +} + +void QSimulatorVideoInputDeviceControl::removeDevice(const QString &name) +{ + int index = mDevices.indexOf(name); + if (index == -1) + return; + + mDevices.removeAt(index); + mDescriptions.removeAt(index); + if (index == mSelectedDevice) + setSelectedDevice(defaultDevice()); + emit devicesChanged(); +} + +void QSimulatorVideoInputDeviceControl::changeDevice(const QString &name, const QtMobility::QCameraData::QCameraDetails &details) +{ + int index = mDevices.indexOf(name); + if (index == -1) + return; + + if (mDescriptions.at(index) != details.description) + mDescriptions[index] = details.description; +} diff --git a/src/plugins/simulator/camera/simulatorvideoinputdevicecontrol.h b/src/plugins/simulator/camera/simulatorvideoinputdevicecontrol.h new file mode 100644 index 000000000..cd5b7d04e --- /dev/null +++ b/src/plugins/simulator/camera/simulatorvideoinputdevicecontrol.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSIMULATORVIDEOINPUTDEVICECONTROL_H +#define QSIMULATORVIDEOINPUTDEVICECONTROL_H + +#include +#include +#include + +#include "../qsimulatormultimediaconnection_p.h" + +QT_USE_NAMESPACE + +class QSimulatorVideoInputDeviceControl : public QVideoDeviceControl +{ +Q_OBJECT +public: + QSimulatorVideoInputDeviceControl(QObject *parent); + ~QSimulatorVideoInputDeviceControl(); + + int deviceCount() const; + + QString deviceName(int index) const; + QString deviceDescription(int index) const; + QIcon deviceIcon(int index) const; + + int defaultDevice() const; + int selectedDevice() const; + + void updateDeviceList(const QtMobility::QCameraData &data); + +public Q_SLOTS: + void setSelectedDevice(int index); + void addDevice(const QString &name, const QtMobility::QCameraData::QCameraDetails &details); + void removeDevice(const QString &name); + void changeDevice(const QString &name, const QtMobility::QCameraData::QCameraDetails &details); + +private: + int mSelectedDevice; + QList mDevices; + QList mDescriptions; +}; + +#endif // QSIMULATORVIDEOINPUTDEVICECONTROL_H diff --git a/src/plugins/simulator/camera/simulatorvideorenderercontrol.cpp b/src/plugins/simulator/camera/simulatorvideorenderercontrol.cpp new file mode 100644 index 000000000..65cf38334 --- /dev/null +++ b/src/plugins/simulator/camera/simulatorvideorenderercontrol.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "simulatorvideorenderercontrol.h" +#include "simulatorcamerasettings.h" +#include "simulatorcamerasession.h" +#include +#include +#include +#include +#include +#include + +SimulatorVideoRendererControl::SimulatorVideoRendererControl(SimulatorCameraSession *session, QObject *parent) : + QVideoRendererControl(parent) + , mSession(session) + , mSurface(0) + , mRunning(false) +{ +} + +SimulatorVideoRendererControl::~SimulatorVideoRendererControl() +{ +} + +QAbstractVideoSurface *SimulatorVideoRendererControl::surface() const +{ + return mSurface; +} + +void SimulatorVideoRendererControl::setSurface(QAbstractVideoSurface *surface) +{ + mSurface = surface; +} + +void SimulatorVideoRendererControl::setImagePath(const QString &imagePath) +{ + if (QFile::exists(imagePath)) { + mImage = QImage(imagePath); + } else { + mImage = QImage(800, 600, QImage::Format_RGB32); + mImage.fill(qRgb(200, 50, 50)); + QPainter painter(&mImage); + painter.drawText(0, 0, 800, 600, Qt::AlignCenter, imagePath); + } + if (mRunning) + showImage(); +} + +void SimulatorVideoRendererControl::showImage() +{ + if (!mSurface) + return; + stop(); + mShownImage = mImage; + SimulatorCameraSettings *settings = mSession->settings(); + qreal colorDiff = .0; + colorDiff += settings->aperture() - settings->defaultAperture(); + colorDiff += (settings->shutterSpeed() - settings->defaultShutterSpeed()) * 400; + colorDiff += ((qreal)settings->isoSensitivity() - settings->defaultIsoSensitivity()) / 100; + colorDiff += settings->exposureCompensation(); + int diffToApply = qAbs(colorDiff * 20); + QPainter painter(&mShownImage); + if (colorDiff < 0) + painter.fillRect(mShownImage.rect(), QColor(0, 0, 0, qMin(diffToApply, 255))); + else + painter.fillRect(mShownImage.rect(), QColor(255, 255, 255, qMin(diffToApply, 255))); + QVideoFrame::PixelFormat pixelFormat = QVideoFrame::pixelFormatFromImageFormat(mShownImage.format()); + if (pixelFormat == QVideoFrame::Format_Invalid) { + mShownImage = mShownImage.convertToFormat(QImage::Format_RGB32); + pixelFormat = QVideoFrame::Format_RGB32; + } + QVideoSurfaceFormat format(mShownImage.size(), pixelFormat); + mSurface->start(format); + mSurface->present(mShownImage); + mRunning = true; +} + +void SimulatorVideoRendererControl::stop() +{ + if (!mSurface) + return; + + if (mSurface->isActive()) + mSurface->stop(); + mRunning = false; +} + +const QImage * SimulatorVideoRendererControl::image() const +{ + return &mShownImage; +} diff --git a/src/plugins/simulator/camera/simulatorvideorenderercontrol.h b/src/plugins/simulator/camera/simulatorvideorenderercontrol.h new file mode 100644 index 000000000..3085ad079 --- /dev/null +++ b/src/plugins/simulator/camera/simulatorvideorenderercontrol.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSIMULATORVIDEORENDERERCONTROL_H +#define QSIMULATORVIDEORENDERERCONTROL_H + +#include +#include + + +class SimulatorCameraSession; +/* + * Control for QGraphicsVideoItem. Viewfinder frames are streamed to a surface + * which is drawn to the display by the Qt Graphics Vide Framework. + */ +class SimulatorVideoRendererControl : public QVideoRendererControl +{ + Q_OBJECT + +public: + SimulatorVideoRendererControl(SimulatorCameraSession *session, QObject *parent = 0); + virtual ~SimulatorVideoRendererControl(); + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + + void setImagePath(const QString &imagePath); + const QImage *image() const; + +public slots: + void showImage(); + +private slots: + void stop(); + +private: + SimulatorCameraSession *mSession; + QAbstractVideoSurface *mSurface; + QImage mImage; + QImage mShownImage; + bool mRunning; +}; + +#endif // QSIMULATORVIDEORENDERERCONTROL_H diff --git a/src/plugins/simulator/qsimulatormultimediaconnection.cpp b/src/plugins/simulator/qsimulatormultimediaconnection.cpp new file mode 100644 index 000000000..ff9e0508e --- /dev/null +++ b/src/plugins/simulator/qsimulatormultimediaconnection.cpp @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../qsimulatormultimediaconnection_p.h" +#include "mobilitysimulatorglobal.h" +#include + +#include + +#include + +QTM_BEGIN_NAMESPACE + +using namespace QtSimulatorPrivate; + +Q_GLOBAL_STATIC(QCameraData, qtCameraData) + +namespace Simulator +{ + MultimediaConnection::MultimediaConnection(MobilityConnection *mobilityCon) + : QObject(mobilityCon) + , mConnection(mobilityCon) + , mInitialDataReceived(false) + { + qt_registerCameraTypes(); + mobilityCon->addMessageHandler(this); + } + + void MultimediaConnection::getInitialData() + { + RemoteMetacall::call(mConnection->sendSocket(), NoSync, "setRequestsCameras"); + + while (!mInitialDataReceived) + mConnection->receiveSocket()->waitForReadyRead(100); + } + + void MultimediaConnection::initialCameraDataSent() + { + mInitialDataReceived = true; + } + + void MultimediaConnection::setCameraData(const QCameraData &data) + { + *qtCameraData() = data; + emit cameraDataChanged(data); + } + + void MultimediaConnection::addCamera(const QString &name, const QCameraData::QCameraDetails &details) + { + if (qtCameraData()->cameras.contains(name)) + return; + + qtCameraData()->cameras.insert(name, details); + emit cameraAdded(name, details); + } + + void MultimediaConnection::removeCamera(const QString &name) + { + if (!qtCameraData()->cameras.contains(name)) + return; + + qtCameraData()->cameras.remove(name); + emit cameraRemoved(name); + } + + void MultimediaConnection::changeCamera(const QString &name, const QCameraData::QCameraDetails &details) + { + if (!qtCameraData()->cameras.contains(name)) + return; + + qtCameraData()->cameras[name] = details; + emit cameraChanged(name, details); + } + +} // namespace + +QCameraData get_qtCameraData() +{ + return *qtCameraData(); +} + +#include "moc_qsimulatormultimediaconnection_p.cpp" + +QTM_END_NAMESPACE diff --git a/src/plugins/simulator/qsimulatormultimediaconnection_p.h b/src/plugins/simulator/qsimulatormultimediaconnection_p.h new file mode 100644 index 000000000..752c0bfcb --- /dev/null +++ b/src/plugins/simulator/qsimulatormultimediaconnection_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIMULATORMULTIMEDIACONNECTION_H +#define SIMULATORMULTIMEDIACONNECTION_H + +#include "qsimulatormultimediadata_p.h" + +QT_BEGIN_HEADER + +QTM_BEGIN_NAMESPACE + +namespace Simulator +{ + class MobilityConnection; + + class MultimediaConnection : public QObject + { + Q_OBJECT + public: + MultimediaConnection (MobilityConnection *mobilityCon); + virtual ~MultimediaConnection () {} + + void getInitialData(); + + private slots: + void setCameraData(const QtMobility::QCameraData &); + void addCamera(const QString &, const QtMobility::QCameraData::QCameraDetails &); + void removeCamera(const QString &); + void changeCamera(const QString &, const QtMobility::QCameraData::QCameraDetails &); + void initialCameraDataSent(); + + private: + MobilityConnection *mConnection; + bool mInitialDataReceived; + + signals: + void cameraDataChanged(const QtMobility::QCameraData &data); + void cameraAdded(const QString &name, const QtMobility::QCameraData::QCameraDetails &details); + void cameraRemoved(const QString &name); + void cameraChanged(const QString &name, const QtMobility::QCameraData::QCameraDetails &details); + }; +} // end namespace Simulator + +QCameraData get_qtCameraData(); + +QTM_END_NAMESPACE +QT_END_HEADER + +#endif + diff --git a/src/plugins/simulator/qsimulatormultimediadata.cpp b/src/plugins/simulator/qsimulatormultimediadata.cpp new file mode 100644 index 000000000..4985bf5d1 --- /dev/null +++ b/src/plugins/simulator/qsimulatormultimediadata.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsimulatormultimediadata_p.h" + +#include + +QTM_BEGIN_NAMESPACE + +void qt_registerCameraTypes() +{ + qRegisterMetaTypeStreamOperators("QtMobility::QCameraData::QCameraDetails"); + qRegisterMetaTypeStreamOperators("QtMobility::QCameraData"); +} + +QDataStream &operator<<(QDataStream &out, const QCameraData &s) +{ + out << s.cameras; + return out; +} + +QDataStream &operator>>(QDataStream &in, QCameraData &s) +{ + in >> s.cameras; + return in; +} + +QDataStream &operator<<(QDataStream &out, const QCameraData::QCameraDetails &s) +{ + out << s.description << s.imagePath; + return out; +} + +QDataStream &operator>>(QDataStream &in, QCameraData::QCameraDetails &s) +{ + in >> s.description >> s.imagePath; + return in; +} + +QTM_END_NAMESPACE diff --git a/src/plugins/simulator/qsimulatormultimediadata_p.h b/src/plugins/simulator/qsimulatormultimediadata_p.h new file mode 100644 index 000000000..e0fcb046a --- /dev/null +++ b/src/plugins/simulator/qsimulatormultimediadata_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSIMULATORMULTIMEDIADATA_P_H +#define QSIMULATORMULTIMEDIADATA_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 "qmobilityglobal.h" +#include +#include +#include + +QT_BEGIN_HEADER +QTM_BEGIN_NAMESPACE + +struct QCameraData { + struct QCameraDetails { + QString description; + QString imagePath; + }; + QHash cameras; +}; + +void qt_registerCameraTypes(); + +QTM_END_NAMESPACE + +Q_DECLARE_METATYPE(QtMobility::QCameraData) +Q_DECLARE_METATYPE(QtMobility::QCameraData::QCameraDetails) + +QT_END_HEADER + +#endif // QMULTIMEDIADATA_SIMULATOR_P_H diff --git a/src/plugins/simulator/qsimulatorserviceplugin.cpp b/src/plugins/simulator/qsimulatorserviceplugin.cpp new file mode 100644 index 000000000..2039276ba --- /dev/null +++ b/src/plugins/simulator/qsimulatorserviceplugin.cpp @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "qsimulatorserviceplugin.h" +#include + +#include "simulatorcameraservice.h" + +#include + +#include +#include +#include +#include + +QTM_USE_NAMESPACE + +Simulator::MultimediaConnection *QSimulatorServicePlugin::mMultimediaConnection = 0; + +QSimulatorServicePlugin::QSimulatorServicePlugin() +{ + ensureSimulatorConnection(); +} + +QStringList QSimulatorServicePlugin::keys() const +{ + QStringList retList; + retList << QLatin1String(Q_MEDIASERVICE_CAMERA); + return retList; +} + +QMediaService* QSimulatorServicePlugin::create(const QString &key) +{ + if (key == QLatin1String(Q_MEDIASERVICE_CAMERA)) + return new SimulatorCameraService(key, mMultimediaConnection); + + qWarning() << "Simulator service plugin: unsupported key:" << key; + return 0; +} + +void QSimulatorServicePlugin::release(QMediaService *service) +{ + delete service; +} + +QList QSimulatorServicePlugin::devices(const QByteArray &service) const +{ + if (service == Q_MEDIASERVICE_CAMERA) { + QCameraData cams = get_qtCameraData(); + QList returnList; + foreach(const QString &key, cams.cameras.keys()) + returnList.append(key.toAscii()); + return returnList; + } + + return QList(); +} + +QString QSimulatorServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device) +{ + if (service == Q_MEDIASERVICE_CAMERA) { + QCameraData cams = get_qtCameraData(); + return cams.cameras.value(device).description; + } + + return QString(); +} + +void QSimulatorServicePlugin::ensureSimulatorConnection() +{ + using namespace QtMobility::Simulator; + + static bool connected = false; + if (connected) + return; + + connected = true; + MobilityConnection *connection = MobilityConnection::instance(); + mMultimediaConnection = new MultimediaConnection(connection); + mMultimediaConnection->getInitialData(); +} + +Q_EXPORT_PLUGIN2(qtmedia_simulatorengine, QSimulatorServicePlugin); diff --git a/src/plugins/simulator/qsimulatorserviceplugin.h b/src/plugins/simulator/qsimulatorserviceplugin.h new file mode 100644 index 000000000..02e4d6321 --- /dev/null +++ b/src/plugins/simulator/qsimulatorserviceplugin.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QSIMULATORSERVICEPLUGIN_H +#define QSIMULATORSERVICEPLUGIN_H + +#include +#include "qsimulatormultimediaconnection_p.h" + +QT_USE_NAMESPACE + +class QSimulatorServicePlugin : public QMediaServiceProviderPlugin, public QMediaServiceSupportedDevicesInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceSupportedDevicesInterface) +public: + QSimulatorServicePlugin(); + + // QMediaServiceProviderPlugin + QStringList keys() const; + QMediaService* create(QString const& key); + void release(QMediaService *service); + + // QMediaServiceSupportedDevicesInterface + QList devices(const QByteArray &service) const; + QString deviceDescription(const QByteArray &service, const QByteArray &device); + +private: + static void ensureSimulatorConnection(); + static QTM_PREPEND_NAMESPACE(Simulator::MultimediaConnection) *mMultimediaConnection; + +signals: + void cameraDataChanged(); +}; + +#endif // QSIMULATORSERVICEPLUGIN_H diff --git a/src/plugins/simulator/simulator.pro b/src/plugins/simulator/simulator.pro new file mode 100644 index 000000000..81117ca82 --- /dev/null +++ b/src/plugins/simulator/simulator.pro @@ -0,0 +1,28 @@ +TEMPLATE = lib +CONFIG += plugin +TARGET = $$qtLibraryTarget(qsimulatorengine) +PLUGIN_TYPE=mediaservice + +include(../../../common.pri) +INCLUDEPATH+=$${SOURCE_DIR}/src/multimedia \ + $${SOURCE_DIR}/src/multimedia/video \ + $${SOURCE_DIR}/src/multimedia/audio \ + $${SOURCE_DIR}/src/mobilitysimulator + +CONFIG += mobility +MOBILITY = multimedia + +DEPENDPATH += . + +# Input +HEADERS += \ + qsimulatormultimediaconnection_p.h \ + qsimulatormultimediadata_p.h \ + qsimulatorserviceplugin.h + +SOURCES += \ + qsimulatormultimediaconnection.cpp \ + qsimulatormultimediadata.cpp \ + qsimulatorserviceplugin.cpp \ + +include(camera/simulatorcamera.pri) diff --git a/src/plugins/symbian/ecam/camera_s60.pri b/src/plugins/symbian/ecam/camera_s60.pri new file mode 100644 index 000000000..beb44db8d --- /dev/null +++ b/src/plugins/symbian/ecam/camera_s60.pri @@ -0,0 +1,157 @@ +INCLUDEPATH += $$PWD + +include (../videooutput/videooutput.pri) + +# Camera Service +DEFINES += QMEDIA_SYMBIAN_CAMERA + +# S60 3.1 platform +contains(S60_VERSION, 3.1) { + DEFINES += S60_31_PLATFORM + DEFINES *= S60_3X_PLATFORM +} + +# S60 3.2 platform +contains(S60_VERSION, 3.2) { + DEFINES += S60_32_PLATFORM + DEFINES *= S60_3X_PLATFORM +} + +# S60 5.0 platform +!contains(DEFINES, S60_31_PLATFORM) { + !contains(DEFINES, S60_32_PLATFORM) { + !contains(DEFINES, SYMBIAN_3_PLATFORM) { + DEFINES += S60_50_PLATFORM + } + } +} + +# Symbian 3 platform +contains(DEFINES, VIDEOOUTPUT_GRAPHICS_SURFACES) { + DEFINES += SYMBIAN_3_PLATFORM +} + +# AutoFocusing (CamAutoFocus) from ForumNokia example +contains(symbian_camera_camautofocus_enabled, yes) { + exists($${EPOCROOT}epoc32\\include\\CCamAutoFocus.h) { + message ("CameraBE: Using S60 3.1 autofocusing") + MMP_RULES += \ + "$${LITERAL_HASH}ifdef WINSCW" \ + "LIBRARY camautofocus.lib" \ + "$${LITERAL_HASH}else" \ + "STATICLIBRARY camautofocus_s.lib" \ + "$${LITERAL_HASH}endif // WINS" \ + "MACRO S60_CAM_AUTOFOCUS_SUPPORT" + } +} + +# ECam AdvancedSettings +contains(symbian_camera_ecamadvsettings_enabled, yes) { + exists($${EPOCROOT}epoc32\\include\\ecamadvancedsettings.h) { + MMP_RULES += \ + "$${LITERAL_HASH}ifndef WINSCW" \ + "LIBRARY ecamadvsettings.lib" \ + "MACRO USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER" \ + "$${LITERAL_HASH}endif" + message("CameraBE: Using from S60 3.2 CCameraAdvancedSettings header") + } + exists($${EPOCROOT}epoc32\\include\\ecamadvsettings.h) { + symbian:LIBS += -lecamadvsettings + DEFINES += USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER + message("CameraBE: Using CCameraAdvancedSettings header from S60 5.0 or later") + } +} + +# DevVideo API Check (Requires both, DevVideoPlay and DevVideoRecord plugins): +# DevVideoConstants has been problematic since not being included in SDK plugins +# For S60 5.0 this has changed with plugin extension 1.1 +# But for S60 3.2 this is still a problem +contains(symbian_camera_devvideorecord_enabled, yes) { + exists($${EPOCROOT}epoc32\\include\\mmf\\devvideo\\devvideorecord.h) { + exists($${EPOCROOT}epoc32\\include\\mmf\\devvideo\\devvideobase.h) { + exists($${EPOCROOT}epoc32\\include\\mmf\\devvideo\\devvideoconstants.h) { + symbian:LIBS += -ldevvideo + DEFINES += S60_DEVVIDEO_RECORDING_SUPPORTED + message("CameraBE: Devvideo API supported") + } + } + } +} + +# ECam Snapshot API: +contains(symbian_camera_snapshot_enabled, yes) { + exists($${EPOCROOT}epoc32\\include\\platform\\ecam\\camerasnapshot.h) { + DEFINES += ECAM_PREVIEW_API + message("CameraBE: Using CCameraSnapshot API") + symbian:LIBS += -lecamsnapshot + } else { + message("CameraBE: Using custom snapshot proving methods") + } +} else { + message("CameraBE: Using custom snapshot proving methods") +} + +# Libraries: +symbian:LIBS += -lfbscli \ + -lmediaclientvideo \ + -lecam \ + -lbafl \ + -lPlatformEnv \ + -lcharconv \ + -lconvnames \ + -lgb2312_shared \ + -ljisx0201 \ + -ljisx0208 \ + -lmmfcontrollerframework \ + -lfbscli \ + -lefsrv \ + -lcone \ + -lws32 \ + -limageconversion + +# Source: +HEADERS += $$PWD/s60cameraconstants.h \ + $$PWD/s60cameralockscontrol.h \ + $$PWD/s60camerafocuscontrol.h \ + $$PWD/s60cameraexposurecontrol.h \ + $$PWD/s60cameraflashcontrol.h \ + $$PWD/s60cameracontrol.h \ + $$PWD/s60mediarecordercontrol.h \ + $$PWD/s60videocapturesession.h \ + $$PWD/s60imagecapturesession.h \ + $$PWD/s60mediacontainercontrol.h \ + $$PWD/s60videoencodercontrol.h \ + $$PWD/s60audioencodercontrol.h \ + $$PWD/s60cameraservice.h \ + $$PWD/s60cameraimageprocessingcontrol.h \ + $$PWD/s60cameraimagecapturecontrol.h \ + $$PWD/s60videodevicecontrol.h \ + $$PWD/s60imageencodercontrol.h \ + $$PWD/s60camerasettings.h \ + $$PWD/s60cameraengine.h \ + $$PWD/s60cameraviewfinderengine.h \ + $$PWD/s60cameraengineobserver.h \ + $$PWD/s60videorenderercontrol.h + +SOURCES += $$PWD/s60cameralockscontrol.cpp \ + $$PWD/s60camerafocuscontrol.cpp \ + $$PWD/s60cameraexposurecontrol.cpp \ + $$PWD/s60cameraflashcontrol.cpp \ + $$PWD/s60cameracontrol.cpp \ + $$PWD/s60mediarecordercontrol.cpp \ + $$PWD/s60videocapturesession.cpp \ + $$PWD/s60imagecapturesession.cpp \ + $$PWD/s60mediacontainercontrol.cpp \ + $$PWD/s60videoencodercontrol.cpp \ + $$PWD/s60audioencodercontrol.cpp \ + $$PWD/s60cameraservice.cpp \ + $$PWD/s60cameraimageprocessingcontrol.cpp \ + $$PWD/s60cameraimagecapturecontrol.cpp \ + $$PWD/s60videodevicecontrol.cpp \ + $$PWD/s60imageencodercontrol.cpp \ + $$PWD/s60camerasettings.cpp \ + $$PWD/s60cameraengine.cpp \ + $$PWD/s60cameraviewfinderengine.cpp \ + $$PWD/s60videorenderercontrol.cpp + +# End of file diff --git a/src/plugins/symbian/ecam/ecam.pro b/src/plugins/symbian/ecam/ecam.pro new file mode 100644 index 000000000..31f30b61c --- /dev/null +++ b/src/plugins/symbian/ecam/ecam.pro @@ -0,0 +1,40 @@ +###################################################################### +# +# Mobility API project - Symbian Camera backend +# +###################################################################### + +TEMPLATE = lib +CONFIG += plugin + +TARGET = $$qtLibraryTarget(qtmultimediakit_ecamengine) +PLUGIN_TYPE = mediaservice +include (../../../../common.pri) + +CONFIG += mobility +MOBILITY += multimedia + +# Include here so that all defines are added here also +include(camera_s60.pri) + +DEPENDPATH += . + +INCLUDEPATH += . \ + $${SOURCE_DIR}/include \ + $${SOURCE_DIR}/src/multimedia \ + $${SOURCE_DIR}/src/multimedia/audio \ + $${SOURCE_DIR}/src/multimedia/video \ + $${SOURCE_DIR} + +HEADERS += s60cameraserviceplugin.h +SOURCES += s60cameraserviceplugin.cpp + +load(data_caging_paths) +TARGET.EPOCALLOWDLLDATA = 1 +TARGET.UID3 = 0x2002BFC2 +TARGET.CAPABILITY = ALL -TCB + +# Make a sis package from plugin + api + stub (plugin) +pluginDep.sources = $${TARGET}.dll +pluginDep.path = $${QT_PLUGINS_BASE_DIR}/$${PLUGIN_TYPE} +DEPLOYMENT += pluginDep diff --git a/src/plugins/symbian/ecam/s60audioencodercontrol.cpp b/src/plugins/symbian/ecam/s60audioencodercontrol.cpp new file mode 100644 index 000000000..bd8f0147d --- /dev/null +++ b/src/plugins/symbian/ecam/s60audioencodercontrol.cpp @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "s60audioencodercontrol.h" +#include "s60videocapturesession.h" + +S60AudioEncoderControl::S60AudioEncoderControl(QObject *parent) : + QAudioEncoderControl(parent) +{ +} + +S60AudioEncoderControl::S60AudioEncoderControl(S60VideoCaptureSession *session, QObject *parent) : + QAudioEncoderControl(parent) +{ + m_session = session; +} + +S60AudioEncoderControl::~S60AudioEncoderControl() +{ +} + +QStringList S60AudioEncoderControl::supportedAudioCodecs() const +{ + return m_session->supportedAudioCaptureCodecs(); +} + +QString S60AudioEncoderControl::codecDescription(const QString &codecName) const +{ + // According to ForumNokia MMF camcorder plugin supports AAC, AMR and QCELP + // QCELP is speech codec and can be discarded + if (qstrcmp(codecName.toLocal8Bit().constData(), "audio/aac") == 0) + return QLatin1String("Advanced Audio Coding"); + else if (qstrcmp(codecName.toLocal8Bit().constData(), "audio/amr") == 0) + return QLatin1String("Adaptive Multi-Rate Audio Codec"); + + return QString(); +} + +QStringList S60AudioEncoderControl::supportedEncodingOptions(const QString &codec) const +{ + // Possible settings: EncodingMode, Codec, BitRate, ChannelCount, SampleRate, Quality + // Possible (codec specific) Options: None + Q_UNUSED(codec); + return QStringList(); +} + +QVariant S60AudioEncoderControl::encodingOption(const QString &codec, const QString &name) const +{ + // Possible settings: EncodingMode, Codec, BitRate, ChannelCount, SampleRate, Quality + // Possible (codec specific) Options: None + Q_UNUSED(codec); + Q_UNUSED(name); + return QVariant(); +} + +void S60AudioEncoderControl::setEncodingOption( + const QString &codec, const QString &name, const QVariant &value) +{ + m_session->setError(KErrNotSupported, tr("Audio encoding option is not supported")); + + // The audio settings can currently be set only using setAudioSettings() function + Q_UNUSED(value) + Q_UNUSED(codec) + Q_UNUSED(name) +} + +QList S60AudioEncoderControl::supportedSampleRates( + const QAudioEncoderSettings &settings, bool *continuous) const +{ + return m_session->supportedSampleRates(settings, continuous); +} + +QAudioEncoderSettings S60AudioEncoderControl::audioSettings() const +{ + QAudioEncoderSettings settings; + m_session->audioEncoderSettings(settings); + + return settings; +} + +void S60AudioEncoderControl::setAudioSettings(const QAudioEncoderSettings &settings) +{ + // Notify that settings have been implicitly set and there's no need to + // initialize them in case camera is changed + m_session->notifySettingsSet(); + + // Quality defines SampleRate/BitRate combination if either or both are missing + if (settings.codec().isEmpty()) { // Empty settings + m_session->setAudioCaptureQuality(settings.quality(), S60VideoCaptureSession::EOnlyAudioQuality); + + } else if (settings.bitRate() == -1 && settings.sampleRate() != -1) { // Only SampleRate set + m_session->setAudioCaptureCodec(settings.codec()); + m_session->setAudioChannelCount(settings.channelCount()); + m_session->setAudioSampleRate(settings.sampleRate()); + m_session->setAudioEncodingMode(settings.encodingMode()); + m_session->setAudioCaptureQuality(settings.quality(), S60VideoCaptureSession::EAudioQualityAndSampleRate); + + } else if (settings.bitRate() != -1 && settings.sampleRate() == -1) { // Only BitRate set + m_session->setAudioCaptureCodec(settings.codec()); + m_session->setAudioChannelCount(settings.channelCount()); + m_session->setAudioBitRate(settings.bitRate()); + m_session->setAudioEncodingMode(settings.encodingMode()); + m_session->setAudioCaptureQuality(settings.quality(), S60VideoCaptureSession::EAudioQualityAndBitRate); + + } else if (settings.bitRate() == -1 && settings.sampleRate() == -1) { // No BitRate or SampleRate set + m_session->setAudioCaptureCodec(settings.codec()); + m_session->setAudioChannelCount(settings.channelCount()); + m_session->setAudioEncodingMode(settings.encodingMode()); + m_session->setAudioCaptureQuality(settings.quality(), S60VideoCaptureSession::EOnlyAudioQuality); + + } else { // Both SampleRate and BitRate set + m_session->setAudioCaptureCodec(settings.codec()); + m_session->setAudioChannelCount(settings.channelCount()); + m_session->setAudioSampleRate(settings.sampleRate()); + m_session->setAudioBitRate(settings.bitRate()); + m_session->setAudioEncodingMode(settings.encodingMode()); + m_session->setAudioCaptureQuality(settings.quality(), S60VideoCaptureSession::ENoAudioQuality); + } +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60audioencodercontrol.h b/src/plugins/symbian/ecam/s60audioencodercontrol.h new file mode 100644 index 000000000..db6ada5d1 --- /dev/null +++ b/src/plugins/symbian/ecam/s60audioencodercontrol.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60AUDIOENCODERCONTROL_H +#define S60AUDIOENCODERCONTROL_H + +#include +#include + +#include + +QT_USE_NAMESPACE + +class S60VideoCaptureSession; + +/* + * Control for audio settings when recording video using QMediaRecorder. + */ +class S60AudioEncoderControl : public QAudioEncoderControl +{ + Q_OBJECT + +public: // Constructor & Destructor + + S60AudioEncoderControl(QObject *parent = 0); + S60AudioEncoderControl(S60VideoCaptureSession *session, QObject *parent = 0); + virtual ~S60AudioEncoderControl(); + +public: // QAudioEncoderControl + + // Audio Codec + QStringList supportedAudioCodecs() const; + QString codecDescription(const QString &codecName) const; + + // Sample Rate + QList supportedSampleRates(const QAudioEncoderSettings &settings, bool *continuous = 0) const; + + // Audio Settings + QAudioEncoderSettings audioSettings() const; + void setAudioSettings(const QAudioEncoderSettings &settings); + + // Encoding Option + QStringList supportedEncodingOptions(const QString &codec) const; + QVariant encodingOption(const QString &codec, const QString &name) const; + void setEncodingOption(const QString &codec, const QString &name, const QVariant &value); + +private: // Data + + S60VideoCaptureSession* m_session; +}; + +#endif // S60AUDIOENCODERCONTROL_H diff --git a/src/plugins/symbian/ecam/s60cameraconstants.h b/src/plugins/symbian/ecam/s60cameraconstants.h new file mode 100644 index 000000000..4b415c3e8 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraconstants.h @@ -0,0 +1,257 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60CAMERACONSTANTS_H +#define S60CAMERACONSTANTS_H + +//============================================================================= + +// GENERAL SETTINGS + +#define KDefaultCameraDevice 0 +#define KECamCameraPriority 0 +#define KInactivityTimerTimeout 30000 // msec +#define KSymbianFineResolutionFactor 100.0 +#define KDefaultOpticalZoom 1.0 +#define KDefaultDigitalZoom 1.0 +#define KSmoothZoomStep 1 +#define KDefaultFocusMode QCameraFocus::AutoFocus + +#define KDefaultViewfinderSize QSize(320,240) +#define KDefaultSizePreview_Normal TSize(640,480) +#define KDefaultSizePreview_Wide TSize(640,360) +#define KDefaultSizePreview_CIF TSize(352,288) +#define KDefaultSizePreview_PAL TSize(640,512) +#define KDefaultSizePreview_NTSC TSize(640,426) +#define KDefaultFormatPreview CCamera::EFormatFbsBitmapColor16MU +#define KViewfinderFrameRate 30 +#define KMaxVFErrorsSignalled 3 + +//============================================================================= + +// IMAGE SETTINGS + +#define KDefaultImagePath QLatin1String("c:\\Data\\Images") +#define KDefaultImageFileName QLatin1String("image.jpg") +#define KDefaultImageCodec QLatin1String("image/jpeg") +#define KDefaultImageFormatPrimaryCam CCamera::EFormatExif +#ifdef SYMBIAN_3_PLATFORM +#define KDefaultImageFormatSecondaryCam CCamera::EFormatExif +#define KDefaultImageResolution QSize(3264, 2448) +#else // Pre-Symbian3 Platforms +#define KDefaultImageFormatSecondaryCam CCamera::EFormatFbsBitmapColor64K +#define KDefaultImageResolution QSize(2048, 1536) +#endif // SYMBIAN_3_PLATFORM +#define KSymbianImageQualityCoefficient 25 +// This must be divisible by 4 and creater or equal to 8 +#define KSnapshotDownScaleFactor 8 +#define KSnapshotMinWidth 640 +#define KSnapshotMinHeight 360 +#define KJpegQualityVeryLow 40 +#define KJpegQualityLow 50 +#define KJpegQualityNormal 75 +#define KJpegQualityHigh 85 +#define KJpegQualityVeryHigh 95 +#define KDefaultImageQuality KJpegQualityHigh + +//============================================================================= + +// VIDEO SETTINGS + +// ================ +// General settings +// ================ + +// Dummy file name to execute CVideoRecorderUtility::OpenFileL() without +// knowing the actual outputLocation. This is needed to be able to query/set +// supported video settings. +_LIT(KDummyVideoFile, "c:\\data\\temp"); + +// Default container MIME type +#define KMimeTypeDefaultContainer QLatin1String("video/mp4") +#define KDefaultVideoPath QLatin1String("c:\\Data\\Videos") +#define KDefaultVideoFileName QLatin1String("video.mp4") +#define KDurationChangedInterval 1000 // 1 second + +// ============== +// Audio Settings +// ============== + +// Default audio codec MIME type +#define KMimeTypeDefaultAudioCodec QLatin1String("audio/aac") + +// Default audio settings for video recording +#define KDefaultChannelCount -1 // Not Supported on Symbian +#define KDefaultBitRate 32000 // 32kbps +#define KDefaultSampleRate -1 // Not Supported on Symbian + +// ============== +// Video Settings +// ============== + +// Default video codec MIME type +#ifdef SYMBIAN_3_PLATFORM + // H.264: BaselineProfile Level 3.1, Max resolution: 1280x720 + #define KMimeTypeDefaultVideoCodec QLatin1String("video/H264; profile-level-id=42801F") +#else + // MPEG-4: Simple Profile, Level 4, Max resolution: 640x480 + #define KMimeTypeDefaultVideoCodec QLatin1String("video/mp4v-es; profile-level-id=4") +#endif + +// Maximum resolutions for encoder MIME Types +// H.263 +#define KResH263 QSize(176,144); +#define KResH263_Profile0 QSize(176,144); +#define KResH263_Profile0_Level10 QSize(176,144); +#define KResH263_Profile0_Level20 QSize(352,288); +#define KResH263_Profile0_Level30 QSize(352,288); +#define KResH263_Profile0_Level40 QSize(352,288); +#define KResH263_Profile0_Level45 QSize(176,144); +#define KResH263_Profile0_Level50 QSize(352,288); +#define KResH263_Profile3 QSize(176,144); +// MPEG-4 +#define KResMPEG4 QSize(176,144); +#define KResMPEG4_PLID_1 QSize(176,144); +#define KResMPEG4_PLID_2 QSize(352,288); +#define KResMPEG4_PLID_3 QSize(352,288); +#define KResMPEG4_PLID_4 QSize(640,480); +#define KResMPEG4_PLID_5 QSize(720,576); +#define KResMPEG4_PLID_6 QSize(1280,720); +#define KResMPEG4_PLID_8 QSize(176,144); +#define KResMPEG4_PLID_9 QSize(176,144); +// H.264 (Baseline Profile, same resolutions apply to Main and High Profile) +#define KResH264 QSize(176,144); +#define KResH264_PLID_42800A QSize(176,144); +#define KResH264_PLID_42900B QSize(176,144); +#define KResH264_PLID_42800B QSize(352,288); +#define KResH264_PLID_42800C QSize(352,288); +#define KResH264_PLID_42800D QSize(352,288); +#define KResH264_PLID_428014 QSize(352,288); +#define KResH264_PLID_428015 QSize(352,288); +#define KResH264_PLID_428016 QSize(640,480); +#define KResH264_PLID_42801E QSize(640,480); +#define KResH264_PLID_42801F QSize(1280,720); +#define KResH264_PLID_428020 QSize(1280,720); +#define KResH264_PLID_428028 QSize(1920,1080); + +// Maximum framerates for encoder MIME Types +// H.263 +#define KFrR_H263 qreal(15); +#define KFrR_H263_Profile0 qreal(15); +#define KFrR_H263_Profile0_Level10 qreal(15); +#define KFrR_H263_Profile0_Level20 qreal(15); +#define KFrR_H263_Profile0_Level30 qreal(30); +#define KFrR_H263_Profile0_Level40 qreal(30); +#define KFrR_H263_Profile0_Level45 qreal(15); +#define KFrR_H263_Profile0_Level50 qreal(15); +#define KFrR_H263_Profile3 qreal(15); +// MPEG-4 +#define KFrR_MPEG4 qreal(15); +#define KFrR_MPEG4_PLID_1 qreal(15); +#define KFrR_MPEG4_PLID_2 qreal(15); +#define KFrR_MPEG4_PLID_3 qreal(30); +// This is a workaround for a known platform bug +#if (defined(S60_31_PLATFORM) | defined(S60_32_PLATFORM)) +#define KFrR_MPEG4_PLID_4 qreal(15); +#else // All other platforms +#define KFrR_MPEG4_PLID_4 qreal(30); +#endif // S60 3.1 or 3.2 +#define KFrR_MPEG4_PLID_5 qreal(30); +#define KFrR_MPEG4_PLID_6 qreal(30); +#define KFrR_MPEG4_PLID_8 qreal(15); +#define KFrR_MPEG4_PLID_9 qreal(15); +// H.264 (Baseline Profile, same framerates apply to Main and High Profile) +#define KFrR_H264 qreal(15); +#define KFrR_H264_PLID_42800A qreal(15); +#define KFrR_H264_PLID_42900B qreal(15); +#define KFrR_H264_PLID_42800B qreal(7.5); +#define KFrR_H264_PLID_42800C qreal(15); +#define KFrR_H264_PLID_42800D qreal(30); +#define KFrR_H264_PLID_428014 qreal(30); +#define KFrR_H264_PLID_428015 qreal(50); +#define KFrR_H264_PLID_428016 qreal(16.9); +#define KFrR_H264_PLID_42801E qreal(33.8); +#define KFrR_H264_PLID_42801F qreal(30); +#define KFrR_H264_PLID_428020 qreal(60); +#define KFrR_H264_PLID_428028 qreal(30); + +// Maximum bitrates for encoder MIME Types +// H.263 +#define KBiR_H263 int(64000); +#define KBiR_H263_Profile0 int(64000); +#define KBiR_H263_Profile0_Level10 int(64000); +#define KBiR_H263_Profile0_Level20 int(128000); +#define KBiR_H263_Profile0_Level30 int(384000); +#define KBiR_H263_Profile0_Level40 int(2048000); +#define KBiR_H263_Profile0_Level45 int(128000); +#define KBiR_H263_Profile0_Level50 int(4096000); +#define KBiR_H263_Profile3 int(64000); +// MPEG-4 +#define KBiR_MPEG4 int(64000); +#define KBiR_MPEG4_PLID_1 int(64000); +#define KBiR_MPEG4_PLID_2 int(128000); +#define KBiR_MPEG4_PLID_3 int(384000); +// This is a workaround for a known platform bug +#if (defined(S60_31_PLATFORM) | defined(S60_32_PLATFORM)) +#define KBiR_MPEG4_PLID_4 int(2000000); +#else // All other platforms +#define KBiR_MPEG4_PLID_4 int(4000000); +#endif // S60 3.1 or 3.2 +#define KBiR_MPEG4_PLID_5 int(8000000); +#define KBiR_MPEG4_PLID_6 int(12000000); +#define KBiR_MPEG4_PLID_8 int(64000); +#define KBiR_MPEG4_PLID_9 int(128000); +// H.264 (Baseline Profile, same bitrates apply to Main and High Profile) +#define KBiR_H264 int(64000); +#define KBiR_H264_PLID_42800A int(64000); +#define KBiR_H264_PLID_42900B int(128000); +#define KBiR_H264_PLID_42800B int(192000); +#define KBiR_H264_PLID_42800C int(384000); +#define KBiR_H264_PLID_42800D int(768000); +#define KBiR_H264_PLID_428014 int(2000000); +#define KBiR_H264_PLID_428015 int(4000000); +#define KBiR_H264_PLID_428016 int(4000000); +#define KBiR_H264_PLID_42801E int(10000000); +#define KBiR_H264_PLID_42801F int(14000000); +#define KBiR_H264_PLID_428020 int(20000000); +#define KBiR_H264_PLID_428028 int(20000000); + +#endif // S60CAMERACONSTANTS_H diff --git a/src/plugins/symbian/ecam/s60cameracontrol.cpp b/src/plugins/symbian/ecam/s60cameracontrol.cpp new file mode 100644 index 000000000..64a3ff37e --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameracontrol.cpp @@ -0,0 +1,983 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "s60cameraservice.h" +#include "s60cameraengine.h" +#include "s60cameracontrol.h" +#include "s60imagecapturesession.h" +#include "s60videowidgetcontrol.h" +#include "s60cameraviewfinderengine.h" +#include "s60cameraconstants.h" + +S60CameraControl::S60CameraControl(QObject *parent) : + QCameraControl(parent) +{ +} + +S60CameraControl::S60CameraControl(S60VideoCaptureSession *videosession, + S60ImageCaptureSession *imagesession, + QObject *parent): + QCameraControl(parent), + m_cameraEngine(0), + m_viewfinderEngine(0), + m_imageSession(0), + m_videoSession(0), + m_advancedSettings(0), + m_videoOutput(0), + m_inactivityTimer(0), + m_captureMode(QCamera::CaptureStillImage), // Default CaptureMode + m_requestedCaptureMode(QCamera::CaptureStillImage), + m_settingCaptureModeInternally(false), + m_internalState(QCamera::UnloadedStatus), // Default Status + m_requestedState(QCamera::UnloadedState), // Default State + m_deviceIndex(KDefaultCameraDevice), + m_error(KErrNone), + m_changeCaptureModeWhenReady(false), + m_rotateCameraWhenReady(false), + m_videoCaptureState(S60VideoCaptureSession::ENotInitialized) +{ + m_videoSession = videosession; + m_imageSession = imagesession; + + m_inactivityTimer = new QTimer; + if (m_inactivityTimer) + m_inactivityTimer->setSingleShot(true); + + TRAPD(err, m_cameraEngine = CCameraEngine::NewL(m_deviceIndex, KECamCameraPriority, this)); + if (err) { + m_error = err; + if (err == KErrPermissionDenied) + qWarning("Failed to create camera. Possibly missing capabilities."); + else + qWarning("Failed to create camera."); + return; + } + + m_viewfinderEngine = new S60CameraViewfinderEngine(this, m_cameraEngine, this); + if (m_viewfinderEngine == 0) { + m_error = KErrNoMemory; + qWarning("Failed to create viewfinder engine."); + return; + } + + // Connect signals + connect(m_inactivityTimer, SIGNAL(timeout()), this, SLOT(toStandByStatus())); + connect(this, SIGNAL(statusChanged(QCamera::Status)), + m_imageSession, SLOT(cameraStatusChanged(QCamera::Status))); + connect(this, SIGNAL(statusChanged(QCamera::Status)), + m_videoSession, SLOT(cameraStatusChanged(QCamera::Status))); + connect(m_videoSession, SIGNAL(stateChanged(S60VideoCaptureSession::TVideoCaptureState)), + this, SLOT(videoStateChanged(S60VideoCaptureSession::TVideoCaptureState))); + connect(m_imageSession, SIGNAL(advancedSettingChanged()), this, SLOT(advancedSettingsCreated())); + connect(this, SIGNAL(cameraReadyChanged(bool)), m_imageSession, SIGNAL(readyForCaptureChanged(bool))); + connect(m_viewfinderEngine, SIGNAL(error(int, const QString&)), this, SIGNAL(error(int,const QString&))); + connect(m_imageSession, SIGNAL(cameraError(int, const QString&)), this, SIGNAL(error(int, const QString&))); + connect(m_imageSession, SIGNAL(captureSizeChanged(const QSize&)), + m_viewfinderEngine, SLOT(handleContentAspectRatioChange(const QSize&))); + connect(m_videoSession, SIGNAL(captureSizeChanged(const QSize&)), + m_viewfinderEngine, SLOT(handleContentAspectRatioChange(const QSize&))); + + setCameraHandles(); +} + +S60CameraControl::~S60CameraControl() +{ + unloadCamera(); + + if (m_viewfinderEngine) { + delete m_viewfinderEngine; + m_viewfinderEngine = 0; + } + + // Make sure AdvancedSettings are destructed + m_imageSession->deleteAdvancedSettings(); + + if (m_cameraEngine) { + delete m_cameraEngine; + m_cameraEngine = 0; + } + + if (m_inactivityTimer) { + delete m_inactivityTimer; + m_inactivityTimer = 0; + } +} + +void S60CameraControl::setState(QCamera::State state) +{ + if (m_error) { // Most probably failure in contructor + setError(m_error, tr("Unexpected camera error.")); + return; + } + + if (m_requestedState == state) + return; + + if (m_inactivityTimer->isActive()) + m_inactivityTimer->stop(); + + // Save the target state + m_requestedState = state; + emit stateChanged(m_requestedState); + + switch (state) { + case QCamera::UnloadedState: // To UnloadedState - Release resources + switch (m_internalState) { + case QCamera::UnloadedStatus: + // Do nothing + break; + case QCamera::LoadingStatus: + case QCamera::StartingStatus: + // Release resources when ready (setting state handles this) + return; + case QCamera::LoadedStatus: + case QCamera::StandbyStatus: + // Unload + unloadCamera(); + break; + case QCamera::ActiveStatus: + // Stop and Unload + stopCamera(); + unloadCamera(); + break; + + default: + // Unrecognized internal state (Status) + setError(KErrGeneral, tr("Unexpected camera error.")); + return; + } + break; + + case QCamera::LoadedState: // To LoadedState - Reserve resources OR Stop ViewFinder and Cancel Capture + switch (m_internalState) { + case QCamera::UnloadedStatus: + case QCamera::StandbyStatus: + // Load + loadCamera(); + break; + case QCamera::LoadingStatus: + // Discard, already moving to LoadedStatus + return; + case QCamera::StartingStatus: + // Stop when ready (setting state handles this) + return; + case QCamera::LoadedStatus: + m_inactivityTimer->start(KInactivityTimerTimeout); + break; + case QCamera::ActiveStatus: + // Stop + stopCamera(); + break; + + default: + // Unregocnized internal state (Status) + setError(KErrGeneral, tr("Unexpected camera error.")); + return; + } + break; + + case QCamera::ActiveState: // To ActiveState - (Reserve Resources and) Start ViewFinder + switch (m_internalState) { + case QCamera::UnloadedStatus: + case QCamera::StandbyStatus: + // Load and Start (setting state handles starting) + loadCamera(); + break; + case QCamera::LoadingStatus: + // Start when loaded (setting state handles this) + break; + case QCamera::StartingStatus: + // Discard, already moving to ActiveStatus + return; + case QCamera::LoadedStatus: + // Start + startCamera(); + break; + case QCamera::ActiveStatus: + // Do nothing + break; + + default: + // Unregocnized internal state (Status) + setError(KErrGeneral, tr("Unexpected camera error.")); + return; + } + break; + + default: + setError(KErrNotSupported, tr("Requested state is not supported.")); + return; + } +} + +QCamera::State S60CameraControl::state() const +{ + return m_requestedState; +} + +QCamera::Status S60CameraControl::status() const +{ + return m_internalState; +} + +QCamera::CaptureMode S60CameraControl::captureMode() const +{ + return m_captureMode; +} + +void S60CameraControl::setCaptureMode(QCamera::CaptureMode mode) +{ + if (m_error) { // Most probably failure in contructor + setError(m_error, tr("Unexpected camera error.")); + return; + } + + if (m_captureMode == mode) + return; + + // Setting CaptureMode Internally or Externally (Client) + if (!m_settingCaptureModeInternally) { + // Save the requested mode + m_requestedCaptureMode = mode; + + // CaptureMode change pending (backend busy), wait + if (m_changeCaptureModeWhenReady) + return; + } else { + m_changeCaptureModeWhenReady = false; // Reset + } + m_settingCaptureModeInternally = false; // Reset + + if (!isCaptureModeSupported(mode)) { + setError(KErrNotSupported, tr("Requested capture mode is not supported.")); + return; + } + + if (m_inactivityTimer->isActive()) + m_inactivityTimer->stop(); + + switch (m_internalState) { + case QCamera::UnloadedStatus: + case QCamera::LoadedStatus: + case QCamera::StandbyStatus: + switch (mode) { + case QCamera::CaptureStillImage: + m_videoSession->releaseVideoRecording(); + m_captureMode = QCamera::CaptureStillImage; + if (m_internalState == QCamera::LoadedStatus) + m_inactivityTimer->start(KInactivityTimerTimeout); + else if (m_internalState == QCamera::StandbyStatus) + loadCamera(); + break; + case QCamera::CaptureVideo: + m_imageSession->releaseImageCapture(); + m_captureMode = QCamera::CaptureVideo; + if (m_internalState == QCamera::LoadedStatus) { + // Revet InternalState as we need to wait for the video + // side initialization to complete + m_internalState = QCamera::LoadingStatus; + emit statusChanged(m_internalState); + int prepareSuccess = m_videoSession->initializeVideoRecording(); + setError(prepareSuccess, tr("Loading video capture failed.")); + } else if (m_internalState == QCamera::StandbyStatus) + loadCamera(); + break; + } + break; + case QCamera::LoadingStatus: + case QCamera::StartingStatus: + m_changeCaptureModeWhenReady = true; + return; + case QCamera::ActiveStatus: + // Stop, Change Mode and Start again + stopCamera(); + switch (mode) { + case QCamera::CaptureStillImage: + m_videoSession->releaseVideoRecording(); + m_captureMode = QCamera::CaptureStillImage; + startCamera(); + break; + case QCamera::CaptureVideo: + m_imageSession->releaseImageCapture(); + m_captureMode = QCamera::CaptureVideo; + // Revet InternalState as we need to wait for the video + // side initialization to complete + m_internalState = QCamera::LoadingStatus; + emit statusChanged(m_internalState); + int prepareSuccess = m_videoSession->initializeVideoRecording(); + setError(prepareSuccess, tr("Loading video recorder failed.")); + break; + } + break; + + default: + // Unregocnized internal state (Status) + setError(KErrNotSupported, tr("Requested capture mode is not supported.")); + break; + } + + emit captureModeChanged(mode); +} + +bool S60CameraControl::isCaptureModeSupported(QCamera::CaptureMode mode) const +{ + switch (mode) { + case QCamera::CaptureStillImage: + return true; + case QCamera::CaptureVideo: + return true; + + default: + return false; + } +} + +bool S60CameraControl::canChangeProperty(QCameraControl::PropertyChangeType changeType, QCamera::Status status) const +{ + Q_UNUSED(status); + + bool returnValue = false; + + switch (changeType) { + case QCameraControl::CaptureMode: + case QCameraControl::VideoEncodingSettings: + case QCameraControl::ImageEncodingSettings: + returnValue = true; + break; + + case QCameraControl::Viewfinder: + returnValue = false; + break; + + default: + // Safer to revert state before the unknown operation + returnValue = false; + break; + } + + return returnValue; +} + +void S60CameraControl::setVideoOutput(QObject *output, + S60CameraViewfinderEngine::ViewfinderOutputType type) +{ + if (!m_viewfinderEngine) { + setError(KErrGeneral, tr("Failed to set viewfinder")); + return; + } + + switch (type) { + case S60CameraViewfinderEngine::OutputTypeVideoWidget: + m_viewfinderEngine->setVideoWidgetControl(output); + break; + case S60CameraViewfinderEngine::OutputTypeRenderer: + m_viewfinderEngine->setVideoRendererControl(output); + break; + case S60CameraViewfinderEngine::OutputTypeVideoWindow: + m_viewfinderEngine->setVideoWindowControl(output); + break; + + default: + break; + } +} + +void S60CameraControl::releaseVideoOutput(const S60CameraViewfinderEngine::ViewfinderOutputType type) +{ + m_viewfinderEngine->releaseControl(type); +} + +void S60CameraControl::loadCamera() +{ + if (m_internalState < QCamera::LoadingStatus) { + m_internalState = QCamera::LoadingStatus; + emit statusChanged(m_internalState); + } else if (m_internalState == QCamera::LoadedStatus + || m_internalState >= QCamera::StartingStatus) { + // Nothing to load (already loaded) + return; + } + // Status = Loading or Standby + + m_cameraEngine->ReserveAndPowerOn(); + + // Completion notified in MceoCameraReady() +} + +void S60CameraControl::unloadCamera() +{ + if (m_internalState > QCamera::LoadingStatus) { + m_internalState = QCamera::LoadingStatus; + emit statusChanged(m_internalState); + } else if (m_internalState < QCamera::LoadingStatus) { + // Nothing to unload + return; + } + // Status = Loading + + if (m_inactivityTimer->isActive()) + m_inactivityTimer->stop(); + + m_cameraEngine->ReleaseAndPowerOff(); + + m_internalState = QCamera::UnloadedStatus; + emit statusChanged(m_internalState); +} + +void S60CameraControl::startCamera() +{ + if (m_internalState < QCamera::StartingStatus) { + m_internalState = QCamera::StartingStatus; + emit statusChanged(m_internalState); + } else if (m_internalState > QCamera::StartingStatus) { + // Nothing to start (already started) + return; + } + // Status = Starting + + if (m_inactivityTimer->isActive()) + m_inactivityTimer->stop(); + + if (m_viewfinderEngine) + m_viewfinderEngine->startViewfinder(); + else + setError(KErrGeneral, tr("Failed to start viewfinder.")); + + m_internalState = QCamera::ActiveStatus; + emit statusChanged(m_internalState); + + emit cameraReadyChanged(true); + +#ifdef Q_CC_NOKIAX86 // Emulator + MceoCameraReady(); // Signal that we are ready +#endif +} + +void S60CameraControl::stopCamera() +{ + if (m_internalState > QCamera::StartingStatus) { + m_internalState = QCamera::StartingStatus; + emit statusChanged(m_internalState); + } else if (m_internalState < QCamera::StartingStatus) { + // Nothing to stop + return; + } + // Status = Starting + + // Cancel ongoing operations if any + m_imageSession->cancelCapture(); + m_videoSession->stopRecording(); + + emit cameraReadyChanged(false); + if (m_viewfinderEngine) + m_viewfinderEngine->stopViewfinder(); + else + setError(KErrGeneral, tr("Failed to stop viewfinder.")); + + m_internalState = QCamera::LoadedStatus; + emit statusChanged(m_internalState); + + m_inactivityTimer->start(KInactivityTimerTimeout); +} + +void S60CameraControl::videoStateChanged(const S60VideoCaptureSession::TVideoCaptureState state) +{ + // Save video state + m_videoCaptureState = state; + + if (m_rotateCameraWhenReady) { + if (m_videoCaptureState != S60VideoCaptureSession::ERecording && + m_videoCaptureState != S60VideoCaptureSession::EPaused) + resetCameraOrientation(); + } + + // If video recording was stopped, video state reverts back to + // Initializing. In that case revert also Camera status to notify that + // video initialization needs to be completed. + if (state == S60VideoCaptureSession::EInitializing) { + if (m_internalState > QCamera::LoadingStatus) { + m_internalState = QCamera::LoadingStatus; + emit statusChanged(m_internalState); + } + + // Handle video initialization completion + } else if (state == S60VideoCaptureSession::EInitialized) { + + // Make sure state is not downgraded + if (m_internalState == QCamera::LoadedStatus + || m_internalState == QCamera::ActiveStatus) { + // Do nothing (already in target state) + } else if (m_internalState == QCamera::StartingStatus) { + m_internalState = QCamera::ActiveStatus; + emit statusChanged(m_internalState); + } else { + m_internalState = QCamera::LoadedStatus; + emit statusChanged(m_internalState); + } + + switch (m_requestedState) { + case QCamera::UnloadedState: + stopCamera(); + unloadCamera(); + if (m_changeCaptureModeWhenReady) { + m_settingCaptureModeInternally = true; + setCaptureMode(m_requestedCaptureMode); + } + break; + case QCamera::LoadedState: + stopCamera(); + if (m_changeCaptureModeWhenReady) { + m_settingCaptureModeInternally = true; + setCaptureMode(m_requestedCaptureMode); + } + m_inactivityTimer->start(KInactivityTimerTimeout); + break; + case QCamera::ActiveState: + if (m_changeCaptureModeWhenReady) { + m_settingCaptureModeInternally = true; + setCaptureMode(m_requestedCaptureMode); + } + startCamera(); + break; + + default: + setError(KErrGeneral, tr("Unexpected camera error.")); + return; + } + } +} + +void S60CameraControl::imageCaptured(const int imageId, const QImage& preview) +{ + Q_UNUSED(imageId); + Q_UNUSED(preview); + + // Unsubscribe the readyForCaptureChanged notification + disconnect(m_imageSession, SIGNAL(imageCaptured(const int, const QImage&)), + this, SLOT(imageCaptured(const int, const QImage&))); + + if (m_rotateCameraWhenReady) + resetCameraOrientation(); +} + +void S60CameraControl::advancedSettingsCreated() +{ + m_advancedSettings = m_imageSession->advancedSettings(); + + if (m_advancedSettings) + connect(m_advancedSettings, SIGNAL(error(int, const QString&)), this, SIGNAL(error(int, const QString&))); +} + +void S60CameraControl::MceoCameraReady() +{ + // Rotate camera if requested + if (m_rotateCameraWhenReady) { + resetCameraOrientation(); + return; + } + + if (m_internalState != QCamera::LoadedStatus) { + + switch (m_requestedState) { + case QCamera::UnloadedState: + m_internalState = QCamera::LoadedStatus; + emit statusChanged(QCamera::LoadedStatus); + + stopCamera(); + unloadCamera(); + + if (m_changeCaptureModeWhenReady) { + m_settingCaptureModeInternally = true; + setCaptureMode(m_requestedCaptureMode); + } + break; + + case QCamera::LoadedState: + if (m_captureMode == QCamera::CaptureVideo) { + int prepareSuccess = m_videoSession->initializeVideoRecording(); + setError(prepareSuccess, tr("Loading video capture failed.")); + + // State change signalled when reservation is complete (in videoStateChanged()) + return; + } + m_internalState = QCamera::LoadedStatus; + emit statusChanged(QCamera::LoadedStatus); + + if (m_changeCaptureModeWhenReady) { + setCaptureMode(m_requestedCaptureMode); + m_changeCaptureModeWhenReady = false; // Reset + } + + if (m_requestedState == QCamera::LoadedStatus && + m_internalState == QCamera::LoadedStatus) + m_inactivityTimer->start(KInactivityTimerTimeout); + break; + + case QCamera::ActiveState: + if (m_captureMode == QCamera::CaptureVideo) { + int prepareSuccess = m_videoSession->initializeVideoRecording(); + setError(prepareSuccess, tr("Loading video capture failed.")); + + // State change signalled when reservation is complete (in videoStateChanged()) + return; + } + + m_internalState = QCamera::LoadedStatus; + emit statusChanged(QCamera::LoadedStatus); + + if (m_changeCaptureModeWhenReady) { + setCaptureMode(m_requestedCaptureMode); + m_changeCaptureModeWhenReady = false; // Reset + } + startCamera(); + break; + + default: + setError(KErrGeneral, tr("Unexpected camera error.")); + return; + } + } +} + +void S60CameraControl::MceoHandleError(TCameraEngineError aErrorType, TInt aError) +{ + Q_UNUSED(aErrorType); + + if (aError == KErrAccessDenied) { + setError(KErrGeneral, tr("Access to camera device was rejected.")); + } else if (aError == KErrHardwareNotAvailable) { + setError(aError, tr("Camera resources were lost.")); + toStandByStatus(); + } + else + setError(aError, tr("Unexpected camera error.")); +} + +void S60CameraControl::setError(const TInt error, const QString &description) +{ + if (error == KErrNone) + return; + + m_error = error; + QCamera::Error cameraError = fromSymbianErrorToQtMultimediaError(m_error); + + emit this->error(int(cameraError), description); + + // Reset everything, if other than not supported error or resource loss + if (error != KErrNotSupported && error != KErrHardwareNotAvailable) + resetCamera(true); // Try to recover from error + else + m_error = KErrNone; // Reset error +} + +QCamera::Error S60CameraControl::fromSymbianErrorToQtMultimediaError(int aError) +{ + switch(aError) { + case KErrNone: + return QCamera::NoError; // No errors have occurred + + case KErrNotSupported: + return QCamera::NotSupportedFeatureError; // The feature is not supported + case KErrNotFound: + case KErrBadHandle: + return QCamera::ServiceMissingError; // No camera service available + case KErrArgument: + case KErrNotReady: + return QCamera::InvalidRequestError; // Invalid parameter or state + + default: + return QCamera::CameraError; // An error has occurred (i.e. General Error) + } +} + +// For S60CameraVideoDeviceControl +int S60CameraControl::deviceCount() +{ +#ifdef Q_CC_NOKIAX86 // Emulator + return 1; +#endif + + return CCameraEngine::CamerasAvailable(); +} + +int S60CameraControl::defaultDevice() const +{ + return KDefaultCameraDevice; +} + +int S60CameraControl::selectedDevice() const +{ + return m_deviceIndex; +} + +void S60CameraControl::setSelectedDevice(const int index) +{ + if (m_deviceIndex != index) { + if (index >= 0 && index < deviceCount()) { + m_deviceIndex = index; + resetCamera(); + } else { + setError(KErrNotSupported, tr("Requested camera is not available.")); + } + } +} + +QString S60CameraControl::name(const int index) +{ + QString cameraName; + switch (index) { + case 0: + cameraName = tr("Primary camera"); + break; + case 1: + cameraName = tr("Secondary camera"); + break; + case 2: + cameraName = tr("Tertiary camera"); + break; + + default: + cameraName = tr("Unidentified Camera"); + break; + } + + return cameraName; +} + +QString S60CameraControl::description(const int index) +{ + QString cameraDesc; + switch (index) { + case 0: + cameraDesc = tr("Device primary camera"); + break; + case 1: + cameraDesc = tr("Device secondary camera"); + break; + case 2: + cameraDesc = tr("Device tertiary camera"); + break; + + default: + cameraDesc = tr("Unidentified Camera"); + break; + } + + return cameraDesc; +} + +void S60CameraControl::resetCamera(bool errorHandling) +{ + if (m_inactivityTimer->isActive()) + m_inactivityTimer->stop(); + + // Cancel ongoing activity + m_imageSession->cancelCapture(); + m_videoSession->stopRecording(false); // Don't re-initialize video + + // Advanced settings must be destructed before the camera + m_imageSession->deleteAdvancedSettings(); + + // Release resources + stopCamera(); + unloadCamera(); + + disconnect(m_viewfinderEngine, SIGNAL(error(int, const QString&)), this, SIGNAL(error(int,const QString&))); + if (m_viewfinderEngine) { + delete m_viewfinderEngine; + m_viewfinderEngine = 0; + } + + if (m_cameraEngine) { + delete m_cameraEngine; + m_cameraEngine = 0; + } + + TRAPD(err, m_cameraEngine = CCameraEngine::NewL(m_deviceIndex, 0, this)); + if (err) { + m_cameraEngine = 0; + if (errorHandling) { + qWarning("Failed to recover from error."); + if (err == KErrPermissionDenied) + emit error(int(QCamera::ServiceMissingError), tr("Recovering from error failed. Possibly missing capabilities.")); + else + emit error(int(QCamera::CameraError), tr("Recovering from error failed.")); + } else { + if (err == KErrPermissionDenied) + setError(err, tr("Camera device creation failed. Possibly missing capabilities.")); + else + setError(err, tr("Camera device creation failed.")); + } + return; + } + + // Notify list of available camera devices has been updated + emit devicesChanged(); + + m_viewfinderEngine = new S60CameraViewfinderEngine(this, m_cameraEngine, this); + if (m_viewfinderEngine == 0) + setError(KErrNoMemory, tr("Viewfinder device creation failed.")); + connect(m_viewfinderEngine, SIGNAL(error(int, const QString&)), this, SIGNAL(error(int,const QString&))); + + setCameraHandles(); + + // Reset state + //setState(QCamera::UnloadedState); + if (m_internalState != QCamera::UnloadedStatus) { + m_internalState = QCamera::UnloadedStatus; + emit statusChanged(m_internalState); + } + if (m_requestedState != QCamera::UnloadedState) { + m_requestedState = QCamera::UnloadedState; + emit stateChanged(m_requestedState); + } + + // Reset error + m_error = KErrNone; +} + +/* + * Reset everything else than viewfinder engine and errors. + */ +void S60CameraControl::resetCameraOrientation() +{ + // If camera has not been created, it will be created automatically to correct orientation + if (!m_cameraEngine) + return; + + // Check Image/VideoCapture allow rotation + if ((!m_cameraEngine->IsCameraReady() && m_internalState != QCamera::UnloadedStatus) || + m_videoCaptureState == S60VideoCaptureSession::ERecording || + m_videoCaptureState == S60VideoCaptureSession::EPaused) { + + // If image capture is ongoing, request notification about the + // completion (imageCaptured() is used because that comes asynchronously + // after the image is captured) + // Obs! If preview creation is changed to be synchnonously done during + // the image capture this implementation needs to be changed) + if (m_videoCaptureState != S60VideoCaptureSession::ERecording && + m_videoCaptureState != S60VideoCaptureSession::EPaused && + m_internalState == QCamera::ActiveStatus) + connect(m_imageSession, SIGNAL(imageCaptured(const int, const QImage&)), + this, SLOT(imageCaptured(const int, const QImage&))); + + m_rotateCameraWhenReady = true; + return; + } + + m_rotateCameraWhenReady = false; // Reset + + QCamera::State originalState = m_requestedState; + + // Cancel ongoing activity + m_imageSession->cancelCapture(); + m_videoSession->stopRecording(false); // Don't re-initialize video + + // Advanced settings must be destructed before the camera + m_imageSession->deleteAdvancedSettings(); + + // Release resources + stopCamera(); + unloadCamera(); + + // Unset CameraEngine to ViewfinderEngine + m_viewfinderEngine->setNewCameraEngine(0); + if (m_cameraEngine) { + delete m_cameraEngine; + m_cameraEngine = 0; + } + + TRAPD(err, m_cameraEngine = CCameraEngine::NewL(m_deviceIndex, 0, this)); + if (err) { + setError(err, tr("Camera device creation failed.")); + return; + } + // Reset CameraEngine to ViewfinderEngine + m_viewfinderEngine->setNewCameraEngine(m_cameraEngine); + + // Notify list of available camera devices has been updated + emit devicesChanged(); + + setCameraHandles(); + + // Reset state + if (m_internalState != QCamera::UnloadedStatus) { + m_internalState = QCamera::UnloadedStatus; + emit statusChanged(m_internalState); + } + if (m_requestedState != QCamera::UnloadedState) { + m_requestedState = QCamera::UnloadedState; + emit stateChanged(m_requestedState); + } + + setState(originalState); +} + +void S60CameraControl::setCameraHandles() +{ + m_imageSession->setCurrentDevice(m_deviceIndex); + m_imageSession->setCameraHandle(m_cameraEngine); + m_cameraEngine->SetImageCaptureObserver(m_imageSession); + m_videoSession->setCameraHandle(m_cameraEngine); +} + +void S60CameraControl::toStandByStatus() +{ + // Cancel ongoing operations if any + m_imageSession->cancelCapture(); + m_videoSession->stopRecording(false); // Don't re-initialize video + + emit cameraReadyChanged(false); + if (m_viewfinderEngine) + m_viewfinderEngine->stopViewfinder(); + else + setError(KErrGeneral, tr("Failed to stop viewfinder.")); + + m_cameraEngine->ReleaseAndPowerOff(); + + m_internalState = QCamera::StandbyStatus; + emit statusChanged(m_internalState); +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60cameracontrol.h b/src/plugins/symbian/ecam/s60cameracontrol.h new file mode 100644 index 000000000..95c31fb34 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameracontrol.h @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60CAMERACONTROL_H +#define S60CAMERACONTROL_H + +#include + +#include "s60cameraengineobserver.h" // MCameraEngineObserver +#include "s60videocapturesession.h" // TVideoCaptureState +#include "s60cameraviewfinderengine.h" // ViewfinderOutputType + +#include +#include + +QT_USE_NAMESPACE + +class S60CameraService; +class S60ImageCaptureSession; +class S60VideoCaptureSession; +class S60CameraSettings; +class CCameraEngine; +class S60CameraViewfinderEngine; +class QTimer; + +/* + * Control for controlling camera base operations (e.g. start/stop and capture + * mode). + */ +class S60CameraControl : public QCameraControl, public MCameraEngineObserver +{ + Q_OBJECT + +public: // Constructors & Destructor + + S60CameraControl(QObject *parent = 0); + S60CameraControl(S60VideoCaptureSession *videosession, + S60ImageCaptureSession *imagesession, + QObject *parent = 0); + ~S60CameraControl(); + +public: // QCameraControl + + // State + QCamera::State state() const; + void setState(QCamera::State state); + + // Status + QCamera::Status status() const; + + // Capture Mode + QCamera::CaptureMode captureMode() const; + void setCaptureMode(QCamera::CaptureMode); + bool isCaptureModeSupported(QCamera::CaptureMode mode) const; + + // Property Setting + bool canChangeProperty(QCameraControl::PropertyChangeType changeType, QCamera::Status status) const; + +/* +Q_SIGNALS: + void stateChanged(QCamera::State); + void statusChanged(QCamera::Status); + void error(int error, const QString &errorString); + void captureModeChanged(QCamera::CaptureMode); +*/ + +public: // Internal + + void setError(const TInt error, const QString &description); + void resetCameraOrientation(); + + // To provide QVideoDeviceControl info + static int deviceCount(); + static QString name(const int index); + static QString description(const int index); + int defaultDevice() const; + int selectedDevice() const; + void setSelectedDevice(const int index); + + void setVideoOutput(QObject *output, + const S60CameraViewfinderEngine::ViewfinderOutputType type); + void releaseVideoOutput(const S60CameraViewfinderEngine::ViewfinderOutputType type); + +private slots: // Internal Slots + + void videoStateChanged(const S60VideoCaptureSession::TVideoCaptureState state); + // Needed to detect image capture completion when trying to rotate the camera + void imageCaptured(const int imageId, const QImage& preview); + /* + * This method moves the camera to the StandBy status: + * - If camera access was lost + * - If camera has been inactive in LoadedStatus for a long time + */ + void toStandByStatus(); + void advancedSettingsCreated(); + +protected: // MCameraEngineObserver + + void MceoCameraReady(); + void MceoHandleError(TCameraEngineError aErrorType, TInt aError); + +private: // Internal + + QCamera::Error fromSymbianErrorToQtMultimediaError(int aError); + + void loadCamera(); + void unloadCamera(); + void startCamera(); + void stopCamera(); + + void resetCamera(bool errorHandling = false); + void setCameraHandles(); + +signals: // Internal Signals + + void cameraReadyChanged(bool); + void devicesChanged(); + +private: // Data + + CCameraEngine *m_cameraEngine; + S60CameraViewfinderEngine *m_viewfinderEngine; + S60ImageCaptureSession *m_imageSession; + S60VideoCaptureSession *m_videoSession; + S60CameraSettings *m_advancedSettings; + QObject *m_videoOutput; + QTimer *m_inactivityTimer; + QCamera::CaptureMode m_captureMode; + QCamera::CaptureMode m_requestedCaptureMode; + bool m_settingCaptureModeInternally; + QCamera::Status m_internalState; + QCamera::State m_requestedState; + int m_deviceIndex; + mutable int m_error; + bool m_changeCaptureModeWhenReady; + bool m_rotateCameraWhenReady; + S60VideoCaptureSession::TVideoCaptureState m_videoCaptureState; +}; + +#endif // S60CAMERACONTROL_H diff --git a/src/plugins/symbian/ecam/s60cameraengine.cpp b/src/plugins/symbian/ecam/s60cameraengine.cpp new file mode 100644 index 000000000..dbd5fb33e --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraengine.cpp @@ -0,0 +1,824 @@ +/**************************************************************************** + ** + ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + ** All rights reserved. + ** Contact: Nokia Corporation (qt-info@nokia.com) + ** + ** This file is part of the Qt Mobility Components. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** No Commercial Usage + ** This file contains pre-release code and may not be distributed. + ** You may use this file in accordance with the terms and conditions + ** contained in the Technology Preview License Agreement accompanying + ** this package. + ** + ** 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 as published by the Free Software + ** Foundation and appearing in the file LICENSE.LGPL included in the + ** packaging of this file. Please review the following information to + ** ensure the GNU Lesser General Public License version 2.1 requirements + ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + ** + ** In addition, as a special exception, Nokia gives you certain additional + ** rights. These rights are described in the Nokia Qt LGPL Exception + ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + ** + ** If you have questions regarding the use of this file, please contact + ** Nokia at qt-info@nokia.com. + ** + ** + ** + ** + ** + ** + ** + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#include "s60cameraengine.h" +#include "s60cameraengineobserver.h" +#include "s60cameraconstants.h" +#include +#include // CFbsBitmap +#ifdef ECAM_PREVIEW_API + #include +#endif // ECAM_PREVIEW_API + +CCameraEngine::CCameraEngine() +{ +} + +CCameraEngine::CCameraEngine(TInt aCameraHandle, + TInt aPriority, + MCameraEngineObserver* aObserver) : + // CBase initializes member variables to NULL + iObserver(aObserver), + iCameraIndex(aCameraHandle), + iPriority(aPriority), + iEngineState(EEngineNotReady), + iCaptureResolution(TSize(0,0)), + iNew2LImplementation(false), + iLatestImageBufferIndex(1) // Thus we start from index 0 +{ + // Observer is mandatory + ASSERT(aObserver != NULL); +} + +CCameraEngine::~CCameraEngine() +{ + StopViewFinder(); + ReleaseViewFinderBuffer(); // Releases iViewFinderBuffer + ReleaseImageBuffer(); // Releases iImageBuffer + iImageBitmap + + iAdvancedSettingsObserver = NULL; + iImageCaptureObserver = NULL; + iViewfinderObserver = NULL; + +#ifdef S60_CAM_AUTOFOCUS_SUPPORT + delete iAutoFocus; +#endif // S60_CAM_AUTOFOCUS_SUPPORT + + if (iCamera) { + iCamera->Release(); + delete iCamera; + iCamera = NULL; + } +} + +TInt CCameraEngine::CamerasAvailable() +{ + return CCamera::CamerasAvailable(); +} + +CCameraEngine* CCameraEngine::NewL(TInt aCameraHandle, + TInt aPriority, + MCameraEngineObserver* aObserver) +{ + CCameraEngine* self = new (ELeave) CCameraEngine(aCameraHandle, aPriority, aObserver); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; +} + +void CCameraEngine::ConstructL() +{ + if (!CCamera::CamerasAvailable()) + User::Leave(KErrHardwareNotAvailable); + +#ifndef Q_CC_NOKIAX86 // Not Emulator + TInt err(KErrNone); +#else // Emulator + TInt err(KErrNotFound); +#endif // !(Q_CC_NOKIAX86) + +#ifdef S60_31_PLATFORM + // Construct CCamera object for S60 3.1 (NewL) + iNew2LImplementation = false; + TRAP(err, iCamera = CCamera::NewL(*this, iCameraIndex)); + if (err) + User::Leave(err); +#else // For S60 3.2 onwards - use this constructor (New2L) + iNew2LImplementation = true; + TRAP(err, iCamera = CCamera::New2L(*this, iCameraIndex, iPriority)); + if (err) + User::Leave(err); +#endif // S60_31_PLATFORM + +#ifdef S60_CAM_AUTOFOCUS_SUPPORT + // Might not be supported for secondary camera, discard errors + TRAP(err, iAutoFocus = CCamAutoFocus::NewL(iCamera)); +#endif // S60_CAM_AUTOFOCUS_SUPPORT + + if (iCamera == NULL) + User::Leave(KErrNoMemory); + + iCamera->CameraInfo(iCameraInfo); +} + +void CCameraEngine::SetAdvancedObserver(MAdvancedSettingsObserver* aAdvancedSettingsObserver) +{ + iAdvancedSettingsObserver = aAdvancedSettingsObserver; +} + +void CCameraEngine::SetImageCaptureObserver(MCameraEngineImageCaptureObserver* aImageCaptureObserver) +{ + iImageCaptureObserver = aImageCaptureObserver; +} + +void CCameraEngine::SetViewfinderObserver(MCameraViewfinderObserver* aViewfinderObserver) +{ + iViewfinderObserver = aViewfinderObserver; +} + +void CCameraEngine::ReserveAndPowerOn() +{ + if (!iCamera || iEngineState > EEngineNotReady) { + iObserver->MceoHandleError(EErrReserve, KErrNotReady); + return; + } + + iCamera->Reserve(); +} + +void CCameraEngine::ReleaseAndPowerOff() +{ + if (iEngineState >= EEngineIdle) { + CancelCapture(); + StopViewFinder(); + FocusCancel(); + iCamera->PowerOff(); + iCamera->Release(); + } + iEngineState = EEngineNotReady; +} + +void CCameraEngine::StartViewFinderL(TSize& aSize) +{ + if (iEngineState < EEngineIdle) + User::Leave(KErrNotReady); + + if (0 == (iCameraInfo.iOptionsSupported & TCameraInfo::EViewFinderBitmapsSupported)) + User::Leave(KErrNotSupported); + + if (!iCamera->ViewFinderActive()) { + if (iCameraIndex != 0) + iCamera->SetViewFinderMirrorL(true); + iCamera->StartViewFinderBitmapsL(aSize); + } +} + +void CCameraEngine::StopViewFinder() +{ + if (iCamera && iCamera->ViewFinderActive()) + iCamera->StopViewFinder(); +} + +void CCameraEngine::StartDirectViewFinderL(RWsSession& aSession, + CWsScreenDevice& aScreenDevice, + RWindowBase& aWindow, + TRect& aScreenRect, + TRect& aClipRect) +{ + if (iEngineState < EEngineIdle) + User::Leave(KErrNotReady); + + if (0 == (iCameraInfo.iOptionsSupported & TCameraInfo::EViewFinderDirectSupported)) + User::Leave(KErrNotSupported); + + if (!iCamera->ViewFinderActive()) { + // Viewfinder extent needs to be clipped according to the clip rect. + // This is because the native camera framework does not support + // clipping and starting viewfinder with bigger than the display(S60 + // 5.0 and older)/window(Symbian^3 and later) would cause viewfinder + // starting to fail entirely. This causes shrinking effect in some + // cases, but is better than not having the viewfinder at all. + if (aScreenRect.Intersects(aClipRect)) + aScreenRect.Intersection(aClipRect); + + if (iCameraIndex != 0) + iCamera->SetViewFinderMirrorL(true); + if (aScreenRect.Width() > 0 && aScreenRect.Height() > 0) { + iCamera->StartViewFinderDirectL(aSession, aScreenDevice, aWindow, aScreenRect); + } else { + if (iObserver) + iObserver->MceoHandleError(EErrViewFinderReady, KErrArgument); + } + } +} + +void CCameraEngine::PrepareL(TSize& aCaptureSize, CCamera::TFormat aFormat) +{ + iImageCaptureFormat = aFormat; + + TInt closestVar = KMaxTInt, selected = 0; + TSize size; + + // Scan through supported capture sizes and select the closest match + for (TInt index = 0; index < iCameraInfo.iNumImageSizesSupported; index++) { + + iCamera->EnumerateCaptureSizes(size, index, aFormat); + if (size == aCaptureSize) { + selected = index; + break; + } + + TSize varSz = size - aCaptureSize; + TInt variation = varSz.iWidth * varSz.iHeight; + if (variation < closestVar) { + closestVar = variation; + selected = index; + } + } + + iCamera->EnumerateCaptureSizes(aCaptureSize, selected, aFormat); + iCaptureResolution = aCaptureSize; + iCamera->PrepareImageCaptureL(aFormat, selected); +} + +void CCameraEngine::CaptureL() +{ + if (iEngineState < EEngineIdle) + User::Leave(KErrNotReady); + + iCamera->CaptureImage(); + iEngineState = EEngineCapturing; +} + +void CCameraEngine::CancelCapture() +{ + if (iEngineState == EEngineCapturing) { + iCamera->CancelCaptureImage(); + iEngineState = EEngineIdle; + } +} + +void CCameraEngine::HandleEvent(const TECAMEvent &aEvent) +{ + if (aEvent.iEventType == KUidECamEventReserveComplete) { + ReserveComplete(aEvent.iErrorCode); + return; + } + + if (aEvent.iEventType == KUidECamEventPowerOnComplete) { + PowerOnComplete(aEvent.iErrorCode); + return; + } + + if (aEvent.iEventType == KUidECamEventCameraNoLongerReserved) { + // All camera related operations need to be stopped + iObserver->MceoHandleError(EErrReserve, KErrHardwareNotAvailable); + return; + } + +#ifdef ECAM_PREVIEW_API + if (aEvent.iEventType == KUidECamEventCameraSnapshot) { + HandlePreview(); + return; + } +#endif // ECAM_PREVIEW_API + +#if !defined(Q_CC_NOKIAX86) // Not Emulator + // Other events; Exposure, Zoom, etc. (See ecamadvancedsettings.h) + if (iAdvancedSettingsObserver) + iAdvancedSettingsObserver->HandleAdvancedEvent(aEvent); + + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleOtherEvent(aEvent); +#endif // !Q_CC_NOKIAX86 +} + +void CCameraEngine::ReserveComplete(TInt aError) +{ + if (aError == KErrNone) { + iCamera->PowerOn(); +#ifdef S60_31_PLATFORM + } else if (aError == KErrAlreadyExists) { // Known Issue on some S60 3.1 devices + User::After(500000); // Wait for 0,5 second and try again + iCamera->Reserve(); +#endif // S60_31_PLATFORM + } else { + iObserver->MceoHandleError(EErrReserve, aError); + } +} + +void CCameraEngine::PowerOnComplete(TInt aError) +{ + if (aError) { + iObserver->MceoHandleError(EErrPowerOn, aError); + iEngineState = EEngineNotReady; + return; + } + + // Init AutoFocus +#ifndef Q_CC_NOKIAX86 // Not Emulator +#ifdef S60_CAM_AUTOFOCUS_SUPPORT // S60 3.1 + if( iAutoFocus ) { + TRAPD(afErr, iAutoFocus->InitL( *this )); + if (afErr) { + delete iAutoFocus; + iAutoFocus = 0; + } + } +#endif // S60_CAM_AUTOFOCUS_SUPPORT +#endif // !Q_CC_NOKIAX86 + + iEngineState = EEngineIdle; + iObserver->MceoCameraReady(); +} + +#ifdef ECAM_PREVIEW_API +/** + * This method creates the CCameraPreview object and requests the previews to + * be provided during the image or video capture + */ +void CCameraEngine::EnablePreviewProvider(MCameraPreviewObserver *aPreviewObserver) +{ + // Delete old one if exists + if (iCameraSnapshot) + delete iCameraSnapshot; + + iPreviewObserver = aPreviewObserver; + + TInt error = KErrNone; + + if (iCamera) { + TRAP(error, iCameraSnapshot = CCamera::CCameraSnapshot::NewL(*iCamera)); + if (error) { + if (iObserver) + iObserver->MceoHandleError(EErrPreview, error); + return; + } + + TRAP(error, iCameraSnapshot->PrepareSnapshotL(KDefaultFormatPreview, SelectPreviewResolution(), EFalse)); + if (error) { + if (iObserver) + iObserver->MceoHandleError(EErrPreview, error); + return; + } + + iCameraSnapshot->StartSnapshot(); + } else { + if (iObserver) + iObserver->MceoHandleError(EErrPreview, KErrNotReady); + } +} + +/** + * This method disables and destroys the CCameraPreview object. Thus previews + * will not be provided during the image or video capture. + */ +void CCameraEngine::DisablePreviewProvider() +{ + if (!iCameraSnapshot) + return; + + iCameraSnapshot->StopSnapshot(); + + delete iCameraSnapshot; + iCameraSnapshot = 0; + + iPreviewObserver = 0; +} +#endif // ECAM_PREVIEW_API + +/* + * MCameraObserver2: + * New viewfinder frame available + */ +void CCameraEngine::ViewFinderReady(MCameraBuffer &aCameraBuffer, TInt aError) +{ + iViewFinderBuffer = &aCameraBuffer; + + if (aError == KErrNone) { + if (iViewfinderObserver) { + TRAPD(err, iViewfinderObserver->MceoViewFinderFrameReady(aCameraBuffer.BitmapL(0))); + if (err) + iObserver->MceoHandleError(EErrViewFinderReady, err); + } else { + iObserver->MceoHandleError(EErrViewFinderReady, KErrNotReady); + } + } + else { + iObserver->MceoHandleError(EErrViewFinderReady, aError); + } +} + +/* + * MCameraObserver: + * New viewfinder frame available + */ +void CCameraEngine::ViewFinderFrameReady(CFbsBitmap& aFrame) +{ + if (iViewfinderObserver) + iViewfinderObserver->MceoViewFinderFrameReady(aFrame); + else + iObserver->MceoHandleError(EErrViewFinderReady, KErrNotReady); +} + +void CCameraEngine::ReleaseViewFinderBuffer() +{ + if (iNew2LImplementation) { // NewL Implementation does not use MCameraBuffer + if (iViewFinderBuffer) { + iViewFinderBuffer->Release(); + iViewFinderBuffer = NULL; + } + } +} + +void CCameraEngine::ReleaseImageBuffer() +{ + // Reset Bitmap + if (iLatestImageBufferIndex == 1 || iImageBitmap2 == NULL) { + if (iImageBitmap1) { + if (!iNew2LImplementation) { // NewL - Ownership transferred + iImageBitmap1->Reset(); // Reset/Delete Bitmap + delete iImageBitmap1; + } + iImageBitmap1 = NULL; + } + } else { + if (iImageBitmap2) { + if (!iNew2LImplementation) { // NewL - Ownership transferred + iImageBitmap2->Reset(); // Reset/Delete Bitmap + delete iImageBitmap2; + } + iImageBitmap2 = NULL; + } + } + + // Reset Data pointers + if (iLatestImageBufferIndex == 1 || iImageData2 == NULL) { + if (!iNew2LImplementation) // NewL - Ownership transfers with buffer + delete iImageData1; + iImageData1 = NULL; + } else { + if (!iNew2LImplementation) // NewL - Ownership transfers with buffer + delete iImageData2; + iImageData2 = NULL; + } + + // Reset ImageBuffer - New2L Implementation only + if (iLatestImageBufferIndex == 1 || iImageBuffer2 == NULL) { + if (iImageBuffer1) { + iImageBuffer1->Release(); + iImageBuffer1 = NULL; + } + } else { + if (iImageBuffer2) { + iImageBuffer2->Release(); + iImageBuffer2 = NULL; + } + } +} + +/* + * MCameraObserver2 + * Captured image is ready (New2L version) + */ +void CCameraEngine::ImageBufferReady(MCameraBuffer &aCameraBuffer, TInt aError) +{ + // Use the buffer that is available + if (!iImageBuffer1) { + iLatestImageBufferIndex = 0; + iImageBuffer1 = &aCameraBuffer; + } else { + iLatestImageBufferIndex = 1; + iImageBuffer2 = &aCameraBuffer; + } + + bool isBitmap = true; + TInt err = KErrNone; + + switch (iImageCaptureFormat) { + case CCamera::EFormatFbsBitmapColor4K: + case CCamera::EFormatFbsBitmapColor64K: + case CCamera::EFormatFbsBitmapColor16M: + case CCamera::EFormatFbsBitmapColor16MU: + if (iLatestImageBufferIndex == 0) { + TRAP(err, iImageBitmap1 = &iImageBuffer1->BitmapL(0)); + if (err) { + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrImageReady, err); + } + } else { + TRAP(err, iImageBitmap2 = &iImageBuffer2->BitmapL(0)); + if (err) { + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrImageReady, err); + } + } + isBitmap = true; + break; + case CCamera::EFormatExif: + if (iLatestImageBufferIndex == 0) { + TRAP(err, iImageData1 = iImageBuffer1->DataL(0)); + if (err) { + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrImageReady, err); + } + } else { + TRAP(err, iImageData2 = iImageBuffer2->DataL(0)); + if (err) { + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrImageReady, err); + } + } + isBitmap = false; + break; + + default: + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrImageReady, KErrNotSupported); + return; + } + + // Handle captured image + HandleImageReady(aError, isBitmap); +} + +/* + * MCameraObserver + * Captured image is ready (NewL version) + */ +void CCameraEngine::ImageReady(CFbsBitmap* aBitmap, HBufC8* aData, TInt aError) +{ + bool isBitmap = true; + + // Toggle between the 2 buffers + if (iLatestImageBufferIndex == 1) { + iLatestImageBufferIndex = 0; + } else { + iLatestImageBufferIndex = 1; + } + + switch (iImageCaptureFormat) { + case CCamera::EFormatFbsBitmapColor4K: + case CCamera::EFormatFbsBitmapColor64K: + case CCamera::EFormatFbsBitmapColor16M: + case CCamera::EFormatFbsBitmapColor16MU: + if (iLatestImageBufferIndex == 0) + iImageBitmap1 = aBitmap; + else + iImageBitmap2 = aBitmap; + isBitmap = true; + break; + case CCamera::EFormatExif: + if (iLatestImageBufferIndex == 0) + iImageData1 = aData; + else + iImageData2 = aData; + isBitmap = false; + break; + + default: + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrImageReady, KErrNotSupported); + return; + } + + // Handle captured image + HandleImageReady(aError, isBitmap); +} + +void CCameraEngine::HandleImageReady(const TInt aError, const bool isBitmap) +{ + iEngineState = EEngineIdle; + + if (aError == KErrNone) { + if (isBitmap) + if (iImageCaptureObserver) { + if (iLatestImageBufferIndex == 0) + iImageCaptureObserver->MceoCapturedBitmapReady(iImageBitmap1); + else + iImageCaptureObserver->MceoCapturedBitmapReady(iImageBitmap2); + } + else + ReleaseImageBuffer(); + else { + if (iImageCaptureObserver) { + if (iLatestImageBufferIndex == 0) + iImageCaptureObserver->MceoCapturedDataReady(iImageData1); + else + iImageCaptureObserver->MceoCapturedDataReady(iImageData2); + } + else + ReleaseImageBuffer(); + } + } else { + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrImageReady, aError); + } +} + +#ifdef ECAM_PREVIEW_API +void CCameraEngine::HandlePreview() +{ + if (!iCameraSnapshot) { + if (iObserver) + iObserver->MceoHandleError(EErrPreview, KErrGeneral); + return; + } + + RArray previewIndices; + CleanupClosePushL(previewIndices); + + MCameraBuffer &newPreview = iCameraSnapshot->SnapshotDataL(previewIndices); + + for (TInt i = 0; i < previewIndices.Count(); ++i) + iPreviewObserver->MceoPreviewReady(newPreview.BitmapL(0)); + + CleanupStack::PopAndDestroy(); // RArray previewIndices +} + +TSize CCameraEngine::SelectPreviewResolution() +{ + TSize currentResolution(iCaptureResolution); + + TSize previewResolution(0, 0); + if (currentResolution == TSize(4000,2248) || + currentResolution == TSize(3264,1832) || + currentResolution == TSize(2592,1456) || + currentResolution == TSize(1920,1080) || + currentResolution == TSize(1280,720)) { + previewResolution = KDefaultSizePreview_Wide; + } else if (currentResolution == TSize(352,288) || + currentResolution == TSize(176,144)) { + previewResolution = KDefaultSizePreview_CIF; + } else if (currentResolution == TSize(720,576)) { + previewResolution = KDefaultSizePreview_PAL; + } else if (currentResolution == TSize(720,480)) { + previewResolution = KDefaultSizePreview_NTSC; + } else { + previewResolution = KDefaultSizePreview_Normal; + } + + return previewResolution; +} +#endif // ECAM_PREVIEW_API + +//============================================================================= +// S60 3.1 - AutoFocus support (Other platforms, see S60CameraSettings class) +//============================================================================= + +void CCameraEngine::InitComplete(TInt aError) +{ + if (aError) { + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrAutoFocusInit, aError); + } +} + +void CCameraEngine::OptimisedFocusComplete(TInt aError) +{ + iEngineState = EEngineIdle; + + if (aError == KErrNone) + if (iImageCaptureObserver) + iImageCaptureObserver->MceoFocusComplete(); + else { + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrOptimisedFocusComplete, aError); + } +} + +TBool CCameraEngine::IsCameraReady() const +{ + // If reserved and powered on, but not focusing or capturing + if (iEngineState == EEngineIdle) + return ETrue; + + return EFalse; +} + +TBool CCameraEngine::IsDirectViewFinderSupported() const +{ + if (iCameraInfo.iOptionsSupported & TCameraInfo::EViewFinderDirectSupported) + return true; + else + return false; +} + +TCameraInfo *CCameraEngine::CameraInfo() +{ + return &iCameraInfo; +} + +TBool CCameraEngine::IsAutoFocusSupported() const +{ +#ifndef Q_CC_NOKIAX86 // Not Emulator + +#ifdef S60_CAM_AUTOFOCUS_SUPPORT // S60 3.1 + return (iAutoFocus) ? ETrue : EFalse; +#else // !S60_CAM_AUTOFOCUS_SUPPORT + return EFalse; +#endif // S60_CAM_AUTOFOCUS_SUPPORT + +#else // Q_CC_NOKIAX86 - Emulator + return EFalse; +#endif // !Q_CC_NOKIAX86 +} + +/* + * This function is used for focusing in S60 3.1 platform. Platforms from S60 + * 3.2 onwards should use the focusing provided by the S60CameraSettings class. + */ +void CCameraEngine::StartFocusL() +{ + if (iEngineState != EEngineIdle) + return; + +#ifndef Q_CC_NOKIAX86 // Not Emulator +#ifdef S60_CAM_AUTOFOCUS_SUPPORT // S60 3.1 + if (iAutoFocus) { + if (!iAFRange) { + iAFRange = CCamAutoFocus::ERangeNormal; + iAutoFocus->SetFocusRangeL(iAFRange); + } + + iAutoFocus->AttemptOptimisedFocusL(); + iEngineState = EEngineFocusing; + } +#endif // S60_CAM_AUTOFOCUS_SUPPORT +#endif // !Q_CC_NOKIAX86 +} + +/* + * This function is used for cancelling focusing in S60 3.1 platform. Platforms + * from S60 3.2 onwards should use the focusing provided by the + * S60CameraSettings class. + */ +void CCameraEngine::FocusCancel() +{ +#ifndef Q_CC_NOKIAX86 // Not Emulator +#ifdef S60_CAM_AUTOFOCUS_SUPPORT + if (iAutoFocus) { + iAutoFocus->Cancel(); + iEngineState = EEngineIdle; + } +#endif // S60_CAM_AUTOFOCUS_SUPPORT +#endif // !Q_CC_NOKIAX86 +} + +void CCameraEngine::SupportedFocusRanges(TInt& aSupportedRanges) const +{ + aSupportedRanges = 0; + +#ifndef Q_CC_NOKIAX86 // Not Emulator +#ifdef S60_CAM_AUTOFOCUS_SUPPORT + if (iAutoFocus) { + // CCamAutoFocus doesn't provide a method for getting supported ranges! + // Assume everything is supported (rather optimistic) + aSupportedRanges = CCamAutoFocus::ERangeMacro | + CCamAutoFocus::ERangePortrait | + CCamAutoFocus::ERangeNormal | + CCamAutoFocus::ERangeInfinite; + } +#endif // S60_CAM_AUTOFOCUS_SUPPORT +#endif // !Q_CC_NOKIAX86 +} + +void CCameraEngine::SetFocusRange(TInt aFocusRange) +{ +#if !defined(Q_CC_NOKIAX86) // Not Emulator + +#ifdef S60_CAM_AUTOFOCUS_SUPPORT + if (iAutoFocus) { + TRAPD(focusErr, iAutoFocus->SetFocusRangeL((CCamAutoFocus::TAutoFocusRange)aFocusRange)); + if (focusErr) + iObserver->MceoHandleError(EErrAutoFocusRange, focusErr); + } +#endif // S60_CAM_AUTOFOCUS_SUPPORT + +#else // Q_CC_NOKIAX86 // Emulator + Q_UNUSED(aFocusRange); + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrAutoFocusRange, KErrNotSupported); +#endif // !Q_CC_NOKIAX86 +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60cameraengine.h b/src/plugins/symbian/ecam/s60cameraengine.h new file mode 100644 index 000000000..7a925c0ba --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraengine.h @@ -0,0 +1,407 @@ +/**************************************************************************** + ** + ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + ** All rights reserved. + ** Contact: Nokia Corporation (qt-info@nokia.com) + ** + ** This file is part of the Qt Mobility Components. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** No Commercial Usage + ** This file contains pre-release code and may not be distributed. + ** You may use this file in accordance with the terms and conditions + ** contained in the Technology Preview License Agreement accompanying + ** this package. + ** + ** 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 as published by the Free Software + ** Foundation and appearing in the file LICENSE.LGPL included in the + ** packaging of this file. Please review the following information to + ** ensure the GNU Lesser General Public License version 2.1 requirements + ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + ** + ** In addition, as a special exception, Nokia gives you certain additional + ** rights. These rights are described in the Nokia Qt LGPL Exception + ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + ** + ** If you have questions regarding the use of this file, please contact + ** Nokia at qt-info@nokia.com. + ** + ** + ** + ** + ** + ** + ** + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ +#ifndef S60CCAMERAENGINE_H +#define S60CCAMERAENGINE_H + +// INCLUDES +#include +#include // for MCameraObserver(2) +#ifdef S60_CAM_AUTOFOCUS_SUPPORT +#include // for CCamAutoFocus, MCamAutoFocusObserver +#endif + +// FORWARD DECLARATIONS +class MCameraEngineObserver; +class MCameraEngineImageCaptureObserver; +class MAdvancedSettingsObserver; +class MCameraViewfinderObserver; +class MCameraPreviewObserver; + +/* + * CameraEngine handling ECam operations needed. + */ +NONSHARABLE_CLASS( CCameraEngine ) : public CBase, + public MCameraObserver, + public MCameraObserver2 +#ifdef S60_CAM_AUTOFOCUS_SUPPORT + ,public MCamAutoFocusObserver +#endif + +{ +public: // Enums + + enum TCameraEngineState + { + EEngineNotReady = 0, // 0 - No resources reserved + EEngineInitializing, // 1 - Reserving and Powering On + EEngineIdle, // 2 - Reseved and Powered On + EEngineCapturing, // 3 - Capturing Still Image + EEngineFocusing // 4 - Focusing + }; + +public: // Constructor & Destructor + + static CCameraEngine* NewL( TInt aCameraHandle, + TInt aPriority, + MCameraEngineObserver* aObserver ); + ~CCameraEngine(); + +public: + + /** + * External Advanced Settings callback observer. + */ + void SetAdvancedObserver(MAdvancedSettingsObserver *aAdvancedSettingsObserver); + + /** + * External Image Capture callback observer. + */ + void SetImageCaptureObserver(MCameraEngineImageCaptureObserver *aImageCaptureObserver); + + /** + * External Viewfinder callback observer. + */ + void SetViewfinderObserver(MCameraViewfinderObserver *aViewfinderObserver); + + /** + * Static function that returns the number of cameras on the device. + */ + static TInt CamerasAvailable(); + + /** + * Returns the index of the currently active camera device + */ + TInt CurrentCameraIndex() const { return iCameraIndex; } + + /** + * Returns the current state (TCameraEngineState) + * of the camera engine. + */ + TCameraEngineState State() const { return iEngineState; } + + /** + * Returns true if the camera has been reserved and + * powered on, and not recording or capturing image + */ + TBool IsCameraReady() const; + + /** + * Returns whether DirectScreen ViewFinder is supported by the platform + */ + TBool IsDirectViewFinderSupported() const; + + /** + * Returns true if the camera supports AutoFocus. + */ + TBool IsAutoFocusSupported() const; + + /** + * Returns camera info + */ + TCameraInfo *CameraInfo(); + + /** + * Captures an image. When complete, observer will receive + * MceoCapturedDataReady() or MceoCapturedBitmapReady() callback, + * depending on which image format was used in PrepareL(). + * @leave May leave with KErrNotReady if camera is not + * reserved or prepared for capture. + */ + void CaptureL(); + + /** + * Cancels ongoing image capture + */ + void CancelCapture(); + + /** + * Reserves and powers on the camera. When complete, + * observer will receive MceoCameraReady() callback + * + */ + void ReserveAndPowerOn(); + + /** + * Releases and powers off the camera + * + */ + void ReleaseAndPowerOff(); + + /** + * Prepares for image capture. + * @param aCaptureSize requested capture size. On return, + * contains the selected size (closest match) + * @param aFormat Image format to use. Default is JPEG with + * EXIF information as provided by the camera module + * @leave KErrNotSupported, KErrNoMemory, KErrNotReady + */ + void PrepareL( TSize& aCaptureSize, + CCamera::TFormat aFormat = CCamera::EFormatExif ); + + /** + * Starts the viewfinder. Observer will receive + * MceoViewFinderFrameReady() callbacks periodically. + * @param aSize requested viewfinder size. On return, + * contains the selected size. + * + * @leave KErrNotSupported is viewfinding with bitmaps is not + * supported, KErrNotReady + */ + void StartViewFinderL( TSize& aSize ); + + /** + * Stops the viewfinder if active. + */ + void StopViewFinder(); + + void StartDirectViewFinderL(RWsSession& aSession, + CWsScreenDevice& aScreenDevice, + RWindowBase& aWindow, + TRect& aScreenRect, + TRect& aClipRect); + + /** + * Releases memory for the last received viewfinder frame. + * Client must call this in response to MceoViewFinderFrameReady() + * callback, after drawing the viewfinder frame is complete. + */ + void ReleaseViewFinderBuffer(); + + /** + * Releases memory for the last captured image. + * Client must call this in response to MceoCapturedDataReady() + * or MceoCapturedBitmapReady()callback, after processing the + * data/bitmap is complete. + */ + void ReleaseImageBuffer(); + + /** + * Starts focusing. Does nothing if AutoFocus is not supported. + * When complete, observer will receive MceoFocusComplete() + * callback. + * @leave KErrInUse, KErrNotReady + */ + void StartFocusL(); + + /** + * Cancels the ongoing focusing operation. + */ + void FocusCancel(); + + /** + * Gets a bitfield of supported focus ranges. + * @param aSupportedRanges a bitfield of either TAutoFocusRange + * (S60 3.0/3.1 devices) or TFocusRange (S60 3.2 and onwards) values + */ + void SupportedFocusRanges( TInt& aSupportedRanges ) const; + + /** + * Sets the focus range + * @param aFocusRange one of the values returned by + * SupportedFocusRanges(). + */ + void SetFocusRange( TInt aFocusRange ); + + /** + * Returns a pointer to CCamera object used by the engine. + * Allows getting access to additional functionality + * from CCamera - do not use for functionality already provided + * by CCameraEngine methods. + */ + CCamera* Camera() { return iCamera; } + +#ifdef ECAM_PREVIEW_API + /** + * This enables the preview creation during the capture (image or video). + */ + void EnablePreviewProvider(MCameraPreviewObserver *aPreviewObserver); + + /** + * This disabled the preview creation during the capture (image or video) + */ + void DisablePreviewProvider(); +#endif // ECAM_PREVIEW_API + +protected: // Protected constructors + + CCameraEngine(); + CCameraEngine( TInt aCameraHandle, + TInt aPriority, + MCameraEngineObserver* aObserver ); + void ConstructL(); + +protected: // MCameraObserver + + /** + * From MCameraObserver + * Gets called when CCamera::Reserve() is completed. + * (V2: Called internally from HandleEvent) + */ + virtual void ReserveComplete(TInt aError); + + /** + * From MCameraObserver. + * Gets called when CCamera::PowerOn() is completed. + * (V2: Called internally from HandleEvent) + */ + virtual void PowerOnComplete(TInt aError); + + /** + * From MCameraObserver. + * Gets called when CCamera::StartViewFinderBitmapsL() is completed. + * (V2: Called internally from ViewFinderReady) + */ + virtual void ViewFinderFrameReady( CFbsBitmap& aFrame ); + + /** + * From MCameraObserver. + * Gets called when CCamera::CaptureImage() is completed. + */ + virtual void ImageReady( CFbsBitmap* aBitmap, HBufC8* aData, TInt aError ); + + /** + * From MCameraObserver. + * Video capture not implemented. + */ + virtual void FrameBufferReady( MFrameBuffer* /*aFrameBuffer*/, TInt /*aError*/ ) {} + +protected: // MCameraObserver2 + + /** + * From MCameraObserver2 + * Camera event handler + */ + virtual void HandleEvent(const TECAMEvent &aEvent); + + /** + * From MCameraObserver2 + * Notifies the client of new viewfinder data + */ + virtual void ViewFinderReady(MCameraBuffer &aCameraBuffer, TInt aError); + + /** + * From MCameraObserver2 + * Notifies the client of a new captured image + */ + virtual void ImageBufferReady(MCameraBuffer &aCameraBuffer, TInt aError); + + /** + * From MCameraObserver2 + * Video capture not implemented. + */ + virtual void VideoBufferReady(MCameraBuffer& /*aCameraBuffer*/, TInt /*aError*/) {} + +protected: // MCamAutoFocusObserver + + /** + * From MCamAutoFocusObserver. + * Delivers notification of completion of auto focus initialisation to + * an interested party. + * @param aError Reason for completion of focus request. + */ + virtual void InitComplete( TInt aError ); + + /** + * From MCamAutoFocusObserver. + * Gets called when CCamAutoFocus::AttemptOptimisedFocusL() is + * completed. + * (V2: Called internally from HandleEvent) + */ + virtual void OptimisedFocusComplete( TInt aError ); + +private: // Internal functions + + /** + * Internal function to handle ImageReady callbacks from + * both observer (V1 & V2) interfaces + */ + void HandleImageReady(const TInt aError, const bool isBitmap); + +#ifdef ECAM_PREVIEW_API + /** + * Handle preview. Retrieve preview data and notify observer about the + * preview availability. + */ + void HandlePreview(); + + /** + * Calculate proper resolution for the SnapShot (Preview) image. + */ + TSize SelectPreviewResolution(); +#endif // ECAM_PREVIEW_API + +private: // Data + + CCamera *iCamera; + MCameraEngineObserver *iObserver; + MCameraEngineImageCaptureObserver *iImageCaptureObserver; + MAdvancedSettingsObserver *iAdvancedSettingsObserver; + MCameraViewfinderObserver *iViewfinderObserver; + MCameraPreviewObserver *iPreviewObserver; + MCameraBuffer *iViewFinderBuffer; + /* + * Following pointers are for the image buffers: + * * Makes buffering of 2 concurrent image buffers possible + */ + MCameraBuffer *iImageBuffer1; + MCameraBuffer *iImageBuffer2; + TDesC8 *iImageData1; + TDesC8 *iImageData2; + CFbsBitmap *iImageBitmap1; + CFbsBitmap *iImageBitmap2; + TInt iCameraIndex; + TInt iPriority; + TCameraEngineState iEngineState; + TCameraInfo iCameraInfo; + CCamera::TFormat iImageCaptureFormat; + TSize iCaptureResolution; + bool iNew2LImplementation; + int iLatestImageBufferIndex; // 0 = Buffer1, 1 = Buffer2 +#ifdef ECAM_PREVIEW_API + CCamera::CCameraSnapshot *iCameraSnapshot; +#endif // ECAM_PREVIEW_API +#ifdef S60_CAM_AUTOFOCUS_SUPPORT + CCamAutoFocus* iAutoFocus; + CCamAutoFocus::TAutoFocusRange iAFRange; +#endif // S60_CAM_AUTOFOCUS_SUPPORT +}; + +#endif // S60CCAMERAENGINE_H diff --git a/src/plugins/symbian/ecam/s60cameraengineobserver.h b/src/plugins/symbian/ecam/s60cameraengineobserver.h new file mode 100644 index 000000000..b1e669d70 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraengineobserver.h @@ -0,0 +1,178 @@ +/**************************************************************************** + ** + ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + ** All rights reserved. + ** Contact: Nokia Corporation (qt-info@nokia.com) + ** + ** This file is part of the Qt Mobility Components. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** No Commercial Usage + ** This file contains pre-release code and may not be distributed. + ** You may use this file in accordance with the terms and conditions + ** contained in the Technology Preview License Agreement accompanying + ** this package. + ** + ** 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 as published by the Free Software + ** Foundation and appearing in the file LICENSE.LGPL included in the + ** packaging of this file. Please review the following information to + ** ensure the GNU Lesser General Public License version 2.1 requirements + ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + ** + ** In addition, as a special exception, Nokia gives you certain additional + ** rights. These rights are described in the Nokia Qt LGPL Exception + ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + ** + ** If you have questions regarding the use of this file, please contact + ** Nokia at qt-info@nokia.com. + ** + ** + ** + ** + ** + ** + ** + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ +#ifndef S60CCAMERAENGINEOBSERVER_H +#define S60CCAMERAENGINEOBSERVER_H + +// FORWARD DECLARATIONS +class CFbsBitmap; +class TECAMEvent; + +enum TCameraEngineError +{ + EErrReserve, + EErrPowerOn, + EErrViewFinderReady, + EErrImageReady, + EErrPreview, + EErrAutoFocusInit, + EErrAutoFocusMode, + EErrAutoFocusArea, + EErrAutoFocusRange, + EErrAutoFocusType, + EErrOptimisedFocusComplete, +}; + +/* + * CameraEngine Observer class towards Camera AdvancedSettings + */ +class MAdvancedSettingsObserver +{ +public: + + virtual void HandleAdvancedEvent( const TECAMEvent &aEvent ) = 0; + +}; + +//============================================================================= + +/* + * CameraEngine Observer class towards Camera Control + */ +class MCameraEngineObserver +{ +public: + + /** + * Camera is ready to use for capturing images. + */ + virtual void MceoCameraReady() = 0; + + /** + * Notifies clients about errors in camera engine + * @param aErrorType type of error (see TCameraEngineError) + * @param aError Symbian system-wide error code + */ + virtual void MceoHandleError( TCameraEngineError aErrorType, TInt aError ) = 0; + +}; + +//============================================================================= + +/* + * CameraEngine Observer class towards Camera ImageCaptureSession + */ +class MCameraEngineImageCaptureObserver +{ +public: + + /** + * Camera AF lens has attained optimal focus + */ + virtual void MceoFocusComplete() = 0; + + /** + * Captured data is ready - call CCameraEngine::ReleaseImageBuffer() + * after processing/saving the data (typically, JPG-encoded image) + * @param aData Pointer to a descriptor containing a frame of camera data. + */ + virtual void MceoCapturedDataReady( TDesC8* aData ) = 0; + + /** + * Captured bitmap is ready. + * after processing/saving the image, call + * CCameraEngine::ReleaseImageBuffer() to free the bitmap. + * @param aBitmap Pointer to an FBS bitmap containing a captured image. + */ + virtual void MceoCapturedBitmapReady( CFbsBitmap* aBitmap ) = 0; + + /** + * Notifies clients about errors in camera engine + * @param aErrorType type of error (see TCameraEngineError) + * @param aError Symbian system-wide error code + */ + virtual void MceoHandleError( TCameraEngineError aErrorType, TInt aError ) = 0; + + /** + * Notifies client about other events not recognized by camera engine. + * The default implementation is empty. + * @param aEvent camera event (see MCameraObserver2::HandleEvent()) + */ + virtual void MceoHandleOtherEvent( const TECAMEvent& /*aEvent*/ ) {} +}; + +//============================================================================= + +/* + * CameraEngine Observer class towards Camera ViewFinderEngine + */ +class MCameraViewfinderObserver +{ +public: + /** + * A new viewfinder frame is ready. + * after displaying the frame, call + * CCameraEngine::ReleaseViewFinderBuffer() + * to free the bitmap. + * @param aFrame Pointer to an FBS bitmap containing a viewfinder frame. + */ + virtual void MceoViewFinderFrameReady( CFbsBitmap& aFrame ) = 0; +}; + +//============================================================================= + +#ifdef ECAM_PREVIEW_API +/* + * CameraEngine Observer class towards Camera ViewFinderEngine + */ +class MCameraPreviewObserver +{ +public: + /** + * A new preview is available. + * @param aPreview Pointer to an FBS bitmap containing a preview. + */ + virtual void MceoPreviewReady( CFbsBitmap& aPreview ) = 0; +}; +#endif // ECAM_PREVIEW_API + +#endif // CCAMERAENGINEOBSERVER_H + +// End of file diff --git a/src/plugins/symbian/ecam/s60cameraexposurecontrol.cpp b/src/plugins/symbian/ecam/s60cameraexposurecontrol.cpp new file mode 100644 index 000000000..9ebdd2c6e --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraexposurecontrol.cpp @@ -0,0 +1,584 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "s60cameraexposurecontrol.h" +#include "s60cameraservice.h" +#include "s60imagecapturesession.h" + +S60CameraExposureControl::S60CameraExposureControl(QObject *parent) : + QCameraExposureControl(parent) +{ +} + +S60CameraExposureControl::S60CameraExposureControl(S60ImageCaptureSession *session, QObject *parent) : + QCameraExposureControl(parent), + m_session(0), + m_service(0), + m_advancedSettings(0), + m_exposureMode(QCameraExposure::ExposureAuto), + m_meteringMode(QCameraExposure::MeteringMatrix) +{ + m_session = session; + + connect(m_session, SIGNAL(advancedSettingChanged()), this, SLOT(resetAdvancedSetting())); + m_advancedSettings = m_session->advancedSettings(); + + if (m_advancedSettings) { + connect(m_advancedSettings, SIGNAL(apertureChanged()), this, SLOT(apertureChanged())); + connect(m_advancedSettings, SIGNAL(apertureRangeChanged()), this, SLOT(apertureRangeChanged())); + connect(m_advancedSettings, SIGNAL(shutterSpeedChanged()), this, SLOT(shutterSpeedChanged())); + connect(m_advancedSettings, SIGNAL(isoSensitivityChanged()), this, SLOT(isoSensitivityChanged())); + connect(m_advancedSettings, SIGNAL(evChanged()), this, SLOT(evChanged())); + } +} + +S60CameraExposureControl::~S60CameraExposureControl() +{ + m_advancedSettings = 0; +} + +void S60CameraExposureControl::resetAdvancedSetting() +{ + m_advancedSettings = m_session->advancedSettings(); + if (m_advancedSettings) { + connect(m_advancedSettings, SIGNAL(apertureChanged()), this, SLOT(apertureChanged())); + connect(m_advancedSettings, SIGNAL(apertureRangeChanged()), this, SLOT(apertureRangeChanged())); + connect(m_advancedSettings, SIGNAL(shutterSpeedChanged()), this, SLOT(shutterSpeedChanged())); + connect(m_advancedSettings, SIGNAL(isoSensitivityChanged()), this, SLOT(isoSensitivityChanged())); + connect(m_advancedSettings, SIGNAL(evChanged()), this, SLOT(evChanged())); + } +} + +void S60CameraExposureControl::apertureChanged() +{ + emit exposureParameterChanged(QCameraExposureControl::Aperture); +} + +void S60CameraExposureControl::apertureRangeChanged() +{ + emit exposureParameterRangeChanged(QCameraExposureControl::Aperture); +} + +void S60CameraExposureControl::shutterSpeedChanged() +{ + emit exposureParameterChanged(QCameraExposureControl::ShutterSpeed); +} + +void S60CameraExposureControl::isoSensitivityChanged() +{ + emit exposureParameterChanged(QCameraExposureControl::ISO); +} + +void S60CameraExposureControl::evChanged() +{ + emit exposureParameterChanged(QCameraExposureControl::ExposureCompensation); +} + +QCameraExposure::ExposureMode S60CameraExposureControl::exposureMode() const +{ + return m_session->exposureMode(); +} + +void S60CameraExposureControl::setExposureMode(QCameraExposure::ExposureMode mode) +{ + if (isExposureModeSupported(mode)) { + m_exposureMode = mode; + m_session->setExposureMode(m_exposureMode); + return; + } + + m_session->setError(KErrNotSupported, tr("Requested exposure mode is not supported.")); +} + +bool S60CameraExposureControl::isExposureModeSupported(QCameraExposure::ExposureMode mode) const +{ + if (m_session->isExposureModeSupported(mode)) + return true; + + return false; +} + +QCameraExposure::MeteringMode S60CameraExposureControl::meteringMode() const +{ + if (m_advancedSettings) + return m_advancedSettings->meteringMode(); + + return QCameraExposure::MeteringMode(); +} + +void S60CameraExposureControl::setMeteringMode(QCameraExposure::MeteringMode mode) +{ + if (m_advancedSettings) { + if (isMeteringModeSupported(mode)) { + m_meteringMode = mode; + m_advancedSettings->setMeteringMode(mode); + return; + } + } + + m_session->setError(KErrNotSupported, tr("Requested metering mode is not supported.")); +} + +bool S60CameraExposureControl::isMeteringModeSupported(QCameraExposure::MeteringMode mode) const +{ + if (m_advancedSettings) + return m_advancedSettings->isMeteringModeSupported(mode); + + return false; +} + +bool S60CameraExposureControl::isParameterSupported(ExposureParameter parameter) const +{ + // Settings supported only if advanced settings available + if (m_advancedSettings) { + switch (parameter) { + case QCameraExposureControl::ISO: + if (m_advancedSettings->supportedIsoSensitivities().count() > 0) + return true; + else + return false; + case QCameraExposureControl::Aperture: + if (m_advancedSettings->supportedApertures().count() > 0) + return true; + else + return false; + case QCameraExposureControl::ShutterSpeed: + if (m_advancedSettings->supportedShutterSpeeds().count() > 0) + return true; + else + return false; + case QCameraExposureControl::ExposureCompensation: + if (m_advancedSettings->supportedExposureCompensationValues().count() > 0) + return true; + else + return false; + case QCameraExposureControl::FlashPower: + case QCameraExposureControl::FlashCompensation: + return false; + + default: + return false; + } + } + + return false; +} + +QVariant S60CameraExposureControl::exposureParameter(ExposureParameter parameter) const +{ + switch (parameter) { + case QCameraExposureControl::ISO: + return QVariant(isoSensitivity()); + case QCameraExposureControl::Aperture: + return QVariant(aperture()); + case QCameraExposureControl::ShutterSpeed: + return QVariant(shutterSpeed()); + case QCameraExposureControl::ExposureCompensation: + return QVariant(exposureCompensation()); + case QCameraExposureControl::FlashPower: + case QCameraExposureControl::FlashCompensation: + // Not supported in Symbian + return QVariant(); + + default: + // Not supported in Symbian + return QVariant(); + } +} + +QCameraExposureControl::ParameterFlags S60CameraExposureControl::exposureParameterFlags(ExposureParameter parameter) const +{ + QCameraExposureControl::ParameterFlags flags; + + /* + * ISO, ExposureCompensation: + * - Automatic/Manual + * - Read/Write + * - Discrete range + * + * Aperture, ShutterSpeed, FlashPower, FlashCompensation: + * - Not supported + */ + switch (parameter) { + case QCameraExposureControl::ISO: + case QCameraExposureControl::ExposureCompensation: + flags |= QCameraExposureControl::AutomaticValue; + break; + case QCameraExposureControl::Aperture: + case QCameraExposureControl::ShutterSpeed: + case QCameraExposureControl::FlashPower: + case QCameraExposureControl::FlashCompensation: + // Do nothing - no flags + break; + + default: + // Do nothing - no flags + break; + } + + return flags; +} + +QVariantList S60CameraExposureControl::supportedParameterRange(ExposureParameter parameter) const +{ + QVariantList valueList; + + if (m_advancedSettings) { + switch (parameter) { + case QCameraExposureControl::ISO: { + foreach (int iso, m_advancedSettings->supportedIsoSensitivities()) + valueList << QVariant(iso); + break; + } + case QCameraExposureControl::Aperture: { + foreach (qreal aperture, m_advancedSettings->supportedApertures()) + valueList << QVariant(aperture); + break; + } + case QCameraExposureControl::ShutterSpeed: { + foreach (qreal shutterSpeed, m_advancedSettings->supportedShutterSpeeds()) + valueList << QVariant(shutterSpeed); + break; + } + case QCameraExposureControl::ExposureCompensation: { + foreach (qreal ev, m_advancedSettings->supportedExposureCompensationValues()) + valueList << QVariant(ev); + break; + } + case QCameraExposureControl::FlashPower: + case QCameraExposureControl::FlashCompensation: + // Not supported in Symbian + break; + + default: + // Not supported in Symbian + break; + } + } + + return valueList; +} + +bool S60CameraExposureControl::setExposureParameter(ExposureParameter parameter, const QVariant& value) +{ + bool useDefaultValue = false; + + if (value.isNull()) + useDefaultValue = true; + + switch (parameter) { + case QCameraExposureControl::ISO: + if (useDefaultValue) { + setAutoIsoSensitivity(); + return false; + } + else + return setManualIsoSensitivity(value.toInt()); + + case QCameraExposureControl::Aperture: + if (useDefaultValue) { + setAutoAperture(); + return false; + } + else + return setManualAperture(value.toFloat()); + + case QCameraExposureControl::ShutterSpeed: + if (useDefaultValue) { + setAutoShutterSpeed(); + return false; + } + else + return setManualShutterSpeed(value.toFloat()); + + case QCameraExposureControl::ExposureCompensation: + if (useDefaultValue) { + setAutoExposureCompensation(); + return false; + } + else + return setManualExposureCompensation(value.toFloat()); + + case QCameraExposureControl::FlashPower: + return false; + case QCameraExposureControl::FlashCompensation: + return false; + + default: + // Not supported in Symbian + return false; + } +} + +QString S60CameraExposureControl::extendedParameterName(ExposureParameter parameter) +{ + switch (parameter) { + case QCameraExposureControl::ISO: + return QLatin1String("ISO Sensitivity"); + case QCameraExposureControl::Aperture: + return QLatin1String("Aperture"); + case QCameraExposureControl::ShutterSpeed: + return QLatin1String("Shutter Speed"); + case QCameraExposureControl::ExposureCompensation: + return QLatin1String("Exposure Compensation"); + case QCameraExposureControl::FlashPower: + return QLatin1String("Flash Power"); + case QCameraExposureControl::FlashCompensation: + return QLatin1String("Flash Compensation"); + + default: + return QString(); + } +} + +int S60CameraExposureControl::isoSensitivity() const +{ + if (m_advancedSettings) + return m_advancedSettings->isoSensitivity(); + return 0; +} + +bool S60CameraExposureControl::isIsoSensitivitySupported(const int iso) const +{ + if (m_advancedSettings && + m_advancedSettings->supportedIsoSensitivities().contains(iso)) + return true; + else + return false; +} + +bool S60CameraExposureControl::setManualIsoSensitivity(int iso) +{ + if (m_advancedSettings) { + if (isIsoSensitivitySupported(iso)) { + m_advancedSettings->setManualIsoSensitivity(iso); + return true; + } + } + + return false; +} + +void S60CameraExposureControl::setAutoIsoSensitivity() +{ + if (m_advancedSettings) + m_advancedSettings->setAutoIsoSensitivity(); +} + +qreal S60CameraExposureControl::aperture() const +{ + if (m_advancedSettings) + return m_advancedSettings->aperture(); + return 0.0; +} + +bool S60CameraExposureControl::isApertureSupported(const qreal aperture) const +{ + if (m_advancedSettings) { + QList supportedValues = m_advancedSettings->supportedApertures(); + if(supportedValues.indexOf(aperture) != -1) + return true; + } + + return false; +} + +bool S60CameraExposureControl::setManualAperture(qreal aperture) +{ + if (m_advancedSettings) { + if (isApertureSupported(aperture)) { + m_advancedSettings->setManualAperture(aperture); + return true; + } else { + QList supportedApertureValues = m_advancedSettings->supportedApertures(); + int minAperture = supportedApertureValues.first(); + int maxAperture = supportedApertureValues.last(); + + if (aperture < minAperture) { // Smaller than minimum + aperture = minAperture; + } else if (aperture > maxAperture) { // Bigger than maximum + aperture = maxAperture; + } else { // Find closest + int indexOfClosest = 0; + int smallestDiff = 100000000; // Sensible max diff + for(int i = 0; i < supportedApertureValues.count(); ++i) { + if((abs((aperture*100) - (supportedApertureValues[i]*100))) < smallestDiff) { + smallestDiff = abs((aperture*100) - (supportedApertureValues[i]*100)); + indexOfClosest = i; + } + } + aperture = supportedApertureValues[indexOfClosest]; + } + m_advancedSettings->setManualAperture(aperture); + } + } + + return false; +} + +void S60CameraExposureControl::setAutoAperture() +{ + // Not supported in Symbian +} + +qreal S60CameraExposureControl::shutterSpeed() const +{ + if (m_advancedSettings) + return m_advancedSettings->shutterSpeed(); + return 0.0; +} + +bool S60CameraExposureControl::isShutterSpeedSupported(const qreal seconds) const +{ + if (m_advancedSettings) { + QList supportedValues = m_advancedSettings->supportedShutterSpeeds(); + if(supportedValues.indexOf(seconds) != -1) + return true; + } + + return false; +} + +bool S60CameraExposureControl::setManualShutterSpeed(qreal seconds) +{ + if (m_advancedSettings) { + if (isShutterSpeedSupported(seconds)) { + m_advancedSettings->setManualShutterSpeed(seconds); + return true; + } else { + QList supportedShutterSpeeds = m_advancedSettings->supportedShutterSpeeds(); + + if (supportedShutterSpeeds.count() == 0) + return false; + + int minShutterSpeed = supportedShutterSpeeds.first(); + int maxShutterSpeed = supportedShutterSpeeds.last(); + + if (seconds < minShutterSpeed) { // Smaller than minimum + seconds = minShutterSpeed; + } else if (seconds > maxShutterSpeed) { // Bigger than maximum + seconds = maxShutterSpeed; + } else { // Find closest + int indexOfClosest = 0; + int smallestDiff = 100000000; // Sensible max diff + for(int i = 0; i < supportedShutterSpeeds.count(); ++i) { + if((abs((seconds*100) - (supportedShutterSpeeds[i]*100))) < smallestDiff) { + smallestDiff = abs((seconds*100) - (supportedShutterSpeeds[i]*100)); + indexOfClosest = i; + } + } + seconds = supportedShutterSpeeds[indexOfClosest]; + } + m_advancedSettings->setManualShutterSpeed(seconds); + } + } + + return false; +} + +void S60CameraExposureControl::setAutoShutterSpeed() +{ + // Not supported in Symbian +} + +qreal S60CameraExposureControl::exposureCompensation() const +{ + if (m_advancedSettings) + return m_advancedSettings->exposureCompensation(); + return 0.0; +} + +bool S60CameraExposureControl::isExposureCompensationSupported(const qreal ev) const +{ + if (m_advancedSettings) { + QList supportedValues = m_advancedSettings->supportedExposureCompensationValues(); + if(supportedValues.indexOf(ev) != -1) + return true; + } + + return false; +} + +bool S60CameraExposureControl::setManualExposureCompensation(qreal ev) +{ + if (m_advancedSettings) { + if (isExposureCompensationSupported(ev)) { + m_advancedSettings->setExposureCompensation(ev); + return true; + } else { + QList supportedEVs = m_advancedSettings->supportedExposureCompensationValues(); + + if (supportedEVs.count() == 0) + return false; + + int minEV = supportedEVs.first(); + int maxEV = supportedEVs.last(); + + if (ev < minEV) { // Smaller than minimum + ev = minEV; + } else if (ev > maxEV) { // Bigger than maximum + ev = maxEV; + } else { // Find closest + int indexOfClosest = 0; + int smallestDiff = 100000000; // Sensible max diff + for(int i = 0; i < supportedEVs.count(); ++i) { + if((abs((ev*100) - (supportedEVs[i]*100))) < smallestDiff) { + smallestDiff = abs((ev*100) - (supportedEVs[i]*100)); + indexOfClosest = i; + } + } + ev = supportedEVs[indexOfClosest]; + } + m_advancedSettings->setExposureCompensation(ev); + } + } + + return false; +} + +void S60CameraExposureControl::setAutoExposureCompensation() +{ + // Not supported in Symbian +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60cameraexposurecontrol.h b/src/plugins/symbian/ecam/s60cameraexposurecontrol.h new file mode 100644 index 000000000..1c623c774 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraexposurecontrol.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60CAMERAEXPOSURECONTROL_H +#define S60CAMERAEXPOSURECONTROL_H + +#include + +#include "s60camerasettings.h" + +QT_USE_NAMESPACE + +class S60CameraService; +class S60ImageCaptureSession; + +/* + * Control for exposure related camera operation. + */ +class S60CameraExposureControl : public QCameraExposureControl +{ + Q_OBJECT + +public: // Constructors & Destructor + + S60CameraExposureControl(QObject *parent = 0); + S60CameraExposureControl(S60ImageCaptureSession *session, QObject *parent = 0); + ~S60CameraExposureControl(); + +public: // QCameraExposureControl + + // Exposure Mode + QCameraExposure::ExposureMode exposureMode() const; + void setExposureMode(QCameraExposure::ExposureMode mode); + bool isExposureModeSupported(QCameraExposure::ExposureMode mode) const; + + // Metering Mode + QCameraExposure::MeteringMode meteringMode() const; + void setMeteringMode(QCameraExposure::MeteringMode mode); + bool isMeteringModeSupported(QCameraExposure::MeteringMode mode) const; + + // Exposure Parameter + bool isParameterSupported(ExposureParameter parameter) const; + QVariant exposureParameter(ExposureParameter parameter) const; + QCameraExposureControl::ParameterFlags exposureParameterFlags(ExposureParameter parameter) const; + QVariantList supportedParameterRange(ExposureParameter parameter) const; + bool setExposureParameter(ExposureParameter parameter, const QVariant& value); + + QString extendedParameterName(ExposureParameter parameter); + +/* +Q_SIGNALS: // QCameraExposureControl + void exposureParameterChanged(int parameter); + void exposureParameterRangeChanged(int parameter); +*/ + +private slots: // Internal Slots + + void resetAdvancedSetting(); + void apertureChanged(); + void apertureRangeChanged(); + void shutterSpeedChanged(); + void isoSensitivityChanged(); + void evChanged(); + +private: // Internal - Implementing ExposureParameter + + // ISO Sensitivity + int isoSensitivity() const; + bool setManualIsoSensitivity(int iso); + void setAutoIsoSensitivity(); + bool isIsoSensitivitySupported(const int iso) const; + + // Aperture + qreal aperture() const; + bool setManualAperture(qreal aperture); + void setAutoAperture(); + bool isApertureSupported(const qreal aperture) const; + + // Shutter Speed + qreal shutterSpeed() const; + bool setManualShutterSpeed(qreal seconds); + void setAutoShutterSpeed(); + bool isShutterSpeedSupported(const qreal seconds) const; + + // Exposure Compensation + qreal exposureCompensation() const; + bool setManualExposureCompensation(qreal ev); + void setAutoExposureCompensation(); + bool isExposureCompensationSupported(const qreal ev) const; + +private: // Data + + S60ImageCaptureSession *m_session; + S60CameraService *m_service; + S60CameraSettings *m_advancedSettings; + QCameraExposure::ExposureMode m_exposureMode; + QCameraExposure::MeteringMode m_meteringMode; +}; + +#endif // S60CAMERAEXPOSURECONTROL_H diff --git a/src/plugins/symbian/ecam/s60cameraflashcontrol.cpp b/src/plugins/symbian/ecam/s60cameraflashcontrol.cpp new file mode 100644 index 000000000..a18c57a03 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraflashcontrol.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "s60cameraflashcontrol.h" +#include "s60cameraservice.h" +#include "s60imagecapturesession.h" + +S60CameraFlashControl::S60CameraFlashControl(QObject *parent) : + QCameraFlashControl(parent) +{ +} + +S60CameraFlashControl::S60CameraFlashControl(S60ImageCaptureSession *session, QObject *parent) : + QCameraFlashControl(parent), + m_session(0), + m_service(0), + m_advancedSettings(0), + m_flashMode(QCameraExposure::FlashOff) +{ + m_session = session; + + connect(m_session, SIGNAL(advancedSettingChanged()), this, SLOT(resetAdvancedSetting())); + m_advancedSettings = m_session->advancedSettings(); + + if (m_advancedSettings) + connect(m_advancedSettings, SIGNAL(flashReady(bool)), this, SIGNAL(flashReady(bool))); +} + +S60CameraFlashControl::~S60CameraFlashControl() +{ + m_advancedSettings = 0; +} + +void S60CameraFlashControl::resetAdvancedSetting() +{ + m_advancedSettings = m_session->advancedSettings(); + if (m_advancedSettings) + connect(m_advancedSettings, SIGNAL(flashReady(bool)), this, SIGNAL(flashReady(bool))); +} + +QCameraExposure::FlashModes S60CameraFlashControl::flashMode() const +{ + return m_session->flashMode(); +} + +void S60CameraFlashControl::setFlashMode(QCameraExposure::FlashModes mode) +{ + if (isFlashModeSupported(mode)) { + m_flashMode = mode; + m_session->setFlashMode(m_flashMode); + } + else + m_session->setError(KErrNotSupported, tr("Requested flash mode is not supported.")); +} + +bool S60CameraFlashControl::isFlashModeSupported(QCameraExposure::FlashModes mode) const +{ + return m_session->supportedFlashModes() & mode; +} + +bool S60CameraFlashControl::isFlashReady() const +{ + if (m_advancedSettings) + return m_advancedSettings->isFlashReady(); + + return false; +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60cameraflashcontrol.h b/src/plugins/symbian/ecam/s60cameraflashcontrol.h new file mode 100644 index 000000000..50dbc41dc --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraflashcontrol.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60CAMERAFLASHCONTROL_H +#define S60CAMERAFLASHCONTROL_H + +#include + +#include "s60camerasettings.h" + +QT_USE_NAMESPACE + +class S60CameraService; +class S60ImageCaptureSession; + +/* + * Control to setup Flash related camera settings. + */ +class S60CameraFlashControl : public QCameraFlashControl +{ + Q_OBJECT + +public: // Constructors & Destructor + + S60CameraFlashControl(QObject *parent = 0); + S60CameraFlashControl(S60ImageCaptureSession *session, QObject *parent = 0); + ~S60CameraFlashControl(); + +public: // QCameraExposureControl + + // Flash Mode + QCameraExposure::FlashModes flashMode() const; + void setFlashMode(QCameraExposure::FlashModes mode); + bool isFlashModeSupported(QCameraExposure::FlashModes mode) const; + + bool isFlashReady() const; + +/* +Q_SIGNALS: // QCameraExposureControl + void flashReady(bool); +*/ + +private slots: // Internal Slots + + void resetAdvancedSetting(); + +private: // Data + + S60ImageCaptureSession *m_session; + S60CameraService *m_service; + S60CameraSettings *m_advancedSettings; + QCameraExposure::FlashModes m_flashMode; +}; + +#endif // S60CAMERAFLASHCONTROL_H diff --git a/src/plugins/symbian/ecam/s60camerafocuscontrol.cpp b/src/plugins/symbian/ecam/s60camerafocuscontrol.cpp new file mode 100644 index 000000000..a7941ce20 --- /dev/null +++ b/src/plugins/symbian/ecam/s60camerafocuscontrol.cpp @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "s60camerafocuscontrol.h" +#include "s60cameraservice.h" +#include "s60imagecapturesession.h" +#include "s60cameraconstants.h" + +S60CameraFocusControl::S60CameraFocusControl(QObject *parent) : + QCameraFocusControl(parent) +{ +} + +S60CameraFocusControl::S60CameraFocusControl(S60ImageCaptureSession *session, QObject *parent) : + QCameraFocusControl(parent), + m_session(0), + m_service(0), + m_advancedSettings(0), + m_isFocusLocked(false), + m_opticalZoomValue(KDefaultOpticalZoom), + m_digitalZoomValue(KDefaultDigitalZoom), + m_focusMode(KDefaultFocusMode) +{ + m_session = session; + + connect(m_session, SIGNAL(advancedSettingChanged()), this, SLOT(resetAdvancedSetting())); + m_advancedSettings = m_session->advancedSettings(); + + TRAPD(err, m_session->doSetZoomFactorL(m_opticalZoomValue, m_digitalZoomValue)); + if (err) + m_session->setError(KErrNotSupported, tr("Setting default zoom factors failed.")); +} + +S60CameraFocusControl::~S60CameraFocusControl() +{ +} + +QCameraFocus::FocusMode S60CameraFocusControl::focusMode() const +{ + return m_focusMode; +} + +void S60CameraFocusControl::setFocusMode(QCameraFocus::FocusMode mode) +{ + if (isFocusModeSupported(mode)) { + // FocusMode and FocusRange are set. Focusing is triggered by setting + // the corresponding FocusType active by calling searchAndLock in LocksControl. + m_focusMode = mode; + if (m_advancedSettings) + m_advancedSettings->setFocusMode(m_focusMode); + else + m_session->setError(KErrGeneral, tr("Unable to set focus mode before camera is started.")); + } else { + m_session->setError(KErrNotSupported, tr("Requested focus mode is not supported.")); + } +} + +bool S60CameraFocusControl::isFocusModeSupported(QCameraFocus::FocusMode mode) const +{ + if (m_advancedSettings) { + return m_advancedSettings->supportedFocusModes() & mode; + } else { + if (mode == QCameraFocus::AutoFocus) + return m_session->isFocusSupported(); + } + + return false; +} + +qreal S60CameraFocusControl::maximumOpticalZoom() const +{ + return m_session->maximumZoom(); +} + +qreal S60CameraFocusControl::maximumDigitalZoom() const +{ + return m_session->maxDigitalZoom(); +} + +qreal S60CameraFocusControl::opticalZoom() const +{ + return m_session->opticalZoomFactor(); +} + +qreal S60CameraFocusControl::digitalZoom() const +{ + return m_session->digitalZoomFactor(); +} + +void S60CameraFocusControl::zoomTo(qreal optical, qreal digital) +{ + TRAPD(err, m_session->doSetZoomFactorL(optical, digital)); + if (err) + m_session->setError(KErrNotSupported, tr("Requested zoom factor is not supported.")); + + // Query new values + if (m_opticalZoomValue != m_session->opticalZoomFactor()) { + m_opticalZoomValue = m_session->opticalZoomFactor(); + emit opticalZoomChanged(m_opticalZoomValue); + } + if (m_digitalZoomValue != m_session->digitalZoomFactor()) { + m_digitalZoomValue = m_session->digitalZoomFactor(); + emit digitalZoomChanged(m_digitalZoomValue); + } +} + +void S60CameraFocusControl::resetAdvancedSetting() +{ + m_advancedSettings = m_session->advancedSettings(); +} + +QCameraFocus::FocusPointMode S60CameraFocusControl::focusPointMode() const +{ + // Not supported in Symbian + return QCameraFocus::FocusPointAuto; +} + +void S60CameraFocusControl::setFocusPointMode(QCameraFocus::FocusPointMode mode) +{ + if (mode != QCameraFocus::FocusPointAuto) + m_session->setError(KErrNotSupported, tr("Requested focus point mode is not supported.")); +} + +bool S60CameraFocusControl::isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const +{ + // Not supported in Symbian + if (mode == QCameraFocus::FocusPointAuto) + return true; + else + return false; +} + +QPointF S60CameraFocusControl::customFocusPoint() const +{ + // Not supported in Symbian, return image center + return QPointF(0.5, 0.5); +} + +void S60CameraFocusControl::setCustomFocusPoint(const QPointF &point) +{ + // Not supported in Symbian + Q_UNUSED(point); + m_session->setError(KErrNotSupported, tr("Setting custom focus point is not supported.")); +} + +QCameraFocusZoneList S60CameraFocusControl::focusZones() const +{ + // Not supported in Symbian + return QCameraFocusZoneList(); // Return empty list +} + +// End of file + diff --git a/src/plugins/symbian/ecam/s60camerafocuscontrol.h b/src/plugins/symbian/ecam/s60camerafocuscontrol.h new file mode 100644 index 000000000..28c83ed70 --- /dev/null +++ b/src/plugins/symbian/ecam/s60camerafocuscontrol.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60CAMERAFOCUSCONTROL_H +#define S60CAMERAFOCUSCONTROL_H + +#include + +#include "s60camerasettings.h" + +QT_USE_NAMESPACE + +class S60CameraService; +class S60ImageCaptureSession; + +/* + * Control for focusing related operations (inc. zooming) + */ +class S60CameraFocusControl : public QCameraFocusControl +{ + Q_OBJECT + +public: // Constructors & Destructor + + S60CameraFocusControl(QObject *parent = 0); + S60CameraFocusControl(S60ImageCaptureSession *session, QObject *parent = 0); + ~S60CameraFocusControl(); + +public: // QCameraFocusControl + + // Focus Mode + QCameraFocus::FocusMode focusMode() const; + void setFocusMode(QCameraFocus::FocusMode mode); + bool isFocusModeSupported(QCameraFocus::FocusMode) const; + + // Zoom + qreal maximumOpticalZoom() const; + qreal maximumDigitalZoom() const; + qreal opticalZoom() const; + qreal digitalZoom() const; + + void zoomTo(qreal optical, qreal digital); + + // Focus Point + QCameraFocus::FocusPointMode focusPointMode() const; + void setFocusPointMode(QCameraFocus::FocusPointMode mode); + bool isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const; + QPointF customFocusPoint() const; + void setCustomFocusPoint(const QPointF &point); + + QCameraFocusZoneList focusZones() const; + +/* +Q_SIGNALS: // QCameraFocusControl + void opticalZoomChanged(qreal opticalZoom); + void digitalZoomChanged(qreal digitalZoom); + void focusZonesChanged(); +*/ + +private slots: // Internal Slots + + void resetAdvancedSetting(); + +private: // Data + S60ImageCaptureSession *m_session; + S60CameraService *m_service; + S60CameraSettings *m_advancedSettings; + bool m_isFocusLocked; + qreal m_opticalZoomValue; + qreal m_digitalZoomValue; + QCameraFocus::FocusMode m_focusMode; +}; + +#endif // S60CAMERAFOCUSCONTROL_H diff --git a/src/plugins/symbian/ecam/s60cameraimagecapturecontrol.cpp b/src/plugins/symbian/ecam/s60cameraimagecapturecontrol.cpp new file mode 100644 index 000000000..427a3bd97 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraimagecapturecontrol.cpp @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "s60cameraimagecapturecontrol.h" +#include "s60cameraservice.h" +#include "s60imagecapturesession.h" +#include "s60cameracontrol.h" + +S60CameraImageCaptureControl::S60CameraImageCaptureControl(QObject *parent) : + QCameraImageCaptureControl(parent) +{ +} + +S60CameraImageCaptureControl::S60CameraImageCaptureControl(S60CameraService *service, + S60ImageCaptureSession *session, + QObject *parent) : + QCameraImageCaptureControl(parent), + m_driveMode(QCameraImageCapture::SingleImageCapture) // Default DriveMode +{ + m_session = session; + m_service = service; + m_cameraControl = qobject_cast(m_service->requestControl(QCameraControl_iid)); + + if (!m_cameraControl) + m_session->setError(KErrGeneral, tr("Unexpected camera error.")); + + // Chain these signals from session class + connect(m_session, SIGNAL(imageCaptured(const int, QImage)), + this, SIGNAL(imageCaptured(const int, QImage))); + connect(m_session, SIGNAL(readyForCaptureChanged(bool)), + this, SIGNAL(readyForCaptureChanged(bool)), Qt::QueuedConnection); + connect(m_session, SIGNAL(imageSaved(const int, const QString&)), + this, SIGNAL(imageSaved(const int, const QString&))); + connect(m_session, SIGNAL(imageExposed(int)), + this, SIGNAL(imageExposed(int))); + connect(m_session, SIGNAL(captureError(int, int, const QString&)), + this, SIGNAL(error(int, int, const QString&))); +} + +S60CameraImageCaptureControl::~S60CameraImageCaptureControl() +{ +} + +bool S60CameraImageCaptureControl::isReadyForCapture() const +{ + if (m_cameraControl && m_cameraControl->captureMode() != QCamera::CaptureStillImage) + return false; + + return m_session->isDeviceReady(); +} + +QCameraImageCapture::DriveMode S60CameraImageCaptureControl::driveMode() const +{ + return m_driveMode; +} + +void S60CameraImageCaptureControl::setDriveMode(QCameraImageCapture::DriveMode mode) +{ + if (mode != QCameraImageCapture::SingleImageCapture) { + emit error((m_session->currentImageId() + 1), QCamera::NotSupportedFeatureError, tr("DriveMode not supported.")); + return; + } + + m_driveMode = mode; +} + +int S60CameraImageCaptureControl::capture(const QString &fileName) +{ + if (m_cameraControl && m_cameraControl->captureMode() != QCamera::CaptureStillImage) { + emit error((m_session->currentImageId() + 1), QCameraImageCapture::NotReadyError, tr("Incorrect CaptureMode.")); + return 0; + } + + int imageId = m_session->capture(fileName); + + return imageId; +} + +void S60CameraImageCaptureControl::cancelCapture() +{ + m_session->cancelCapture(); +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60cameraimagecapturecontrol.h b/src/plugins/symbian/ecam/s60cameraimagecapturecontrol.h new file mode 100644 index 000000000..4c369e807 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraimagecapturecontrol.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60CAMERAIMAGECAPTURECONTROL_H +#define S60CAMERAIMAGECAPTURECONTROL_H + +#include "qcameraimagecapturecontrol.h" + +QT_USE_NAMESPACE + +class S60CameraService; +class S60ImageCaptureSession; +class S60CameraControl; + +/* + * Control for image capture operations. + */ +class S60CameraImageCaptureControl : public QCameraImageCaptureControl +{ + Q_OBJECT + +public: // Contructors & Destrcutor + + S60CameraImageCaptureControl(QObject *parent = 0); + S60CameraImageCaptureControl(S60CameraService *service, + S60ImageCaptureSession *session, + QObject *parent = 0); + ~S60CameraImageCaptureControl(); + +public: // QCameraImageCaptureControl + + bool isReadyForCapture() const; + + // Drive Mode + QCameraImageCapture::DriveMode driveMode() const; + void setDriveMode(QCameraImageCapture::DriveMode mode); + + // Capture + int capture(const QString &fileName); + void cancelCapture(); + +/* +Q_SIGNALS: // QCameraImageCaptureControl + void readyForCaptureChanged(bool); + + void imageExposed(int id); + void imageCaptured(int id, const QImage &preview); + void imageSaved(int id, const QString &fileName); + + void error(int id, int error, const QString &errorString); +*/ + +private: // Data + + S60ImageCaptureSession *m_session; + S60CameraService *m_service; + S60CameraControl *m_cameraControl; + QCameraImageCapture::DriveMode m_driveMode; +}; + +#endif // S60CAMERAIMAGECAPTURECONTROL_H diff --git a/src/plugins/symbian/ecam/s60cameraimageprocessingcontrol.cpp b/src/plugins/symbian/ecam/s60cameraimageprocessingcontrol.cpp new file mode 100644 index 000000000..ae2c4535a --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraimageprocessingcontrol.cpp @@ -0,0 +1,254 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "s60cameraimageprocessingcontrol.h" +#include "s60cameraservice.h" +#include "s60imagecapturesession.h" + +S60CameraImageProcessingControl::S60CameraImageProcessingControl(QObject *parent) : + QCameraImageProcessingControl(parent) +{ +} + +S60CameraImageProcessingControl::S60CameraImageProcessingControl(S60ImageCaptureSession *session, QObject *parent) : + QCameraImageProcessingControl(parent), + m_session(0), + m_advancedSettings(0) +{ + m_session = session; + m_advancedSettings = m_session->advancedSettings(); +} + +S60CameraImageProcessingControl::~S60CameraImageProcessingControl() +{ + m_advancedSettings = 0; +} + +void S60CameraImageProcessingControl::resetAdvancedSetting() +{ + m_advancedSettings = m_session->advancedSettings(); +} + +QCameraImageProcessing::WhiteBalanceMode S60CameraImageProcessingControl::whiteBalanceMode() const +{ + return m_session->whiteBalanceMode(); +} + +void S60CameraImageProcessingControl::setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode) +{ + if (isWhiteBalanceModeSupported(mode)) + m_session->setWhiteBalanceMode(mode); + else + m_session->setError(KErrNotSupported, tr("Requested white balance mode is not supported.")); +} + +bool S60CameraImageProcessingControl::isWhiteBalanceModeSupported( + QCameraImageProcessing::WhiteBalanceMode mode) const +{ + return m_session->isWhiteBalanceModeSupported(mode); +} + +int S60CameraImageProcessingControl::manualWhiteBalance() const +{ + return 0; +} + +void S60CameraImageProcessingControl::setManualWhiteBalance(int colorTemperature) +{ + m_session->setError(KErrNotSupported, tr("Setting manual white balance is not supported.")); + Q_UNUSED(colorTemperature) +} + +bool S60CameraImageProcessingControl::isProcessingParameterSupported(ProcessingParameter parameter) const +{ + // First check settings requiring Adv. Settings + if (m_advancedSettings) { + switch (parameter) { + case QCameraImageProcessingControl::Saturation: + return true; + case QCameraImageProcessingControl::Sharpening: + return isSharpeningSupported(); + case QCameraImageProcessingControl::Denoising: + return isDenoisingSupported(); + case QCameraImageProcessingControl::ColorTemperature: + return false; + } + } + + // Then the rest + switch (parameter) { + case QCameraImageProcessingControl::Contrast: + case QCameraImageProcessingControl::Brightness: + return true; + + default: + return false; + } +} + +QVariant S60CameraImageProcessingControl::processingParameter( + QCameraImageProcessingControl::ProcessingParameter parameter) const +{ + switch (parameter) { + case QCameraImageProcessingControl::Contrast: + return QVariant(contrast()); + case QCameraImageProcessingControl::Saturation: + return QVariant(saturation()); + case QCameraImageProcessingControl::Brightness: + return QVariant(brightness()); + case QCameraImageProcessingControl::Sharpening: + return QVariant(sharpeningLevel()); + case QCameraImageProcessingControl::Denoising: + return QVariant(denoisingLevel()); + case QCameraImageProcessingControl::ColorTemperature: + return QVariant(manualWhiteBalance()); + + default: + return QVariant(); + } +} + +void S60CameraImageProcessingControl::setProcessingParameter( + QCameraImageProcessingControl::ProcessingParameter parameter, QVariant value) +{ + switch (parameter) { + case QCameraImageProcessingControl::Contrast: + setContrast(value.toInt()); + break; + case QCameraImageProcessingControl::Saturation: + setSaturation(value.toInt()); + break; + case QCameraImageProcessingControl::Brightness: + setBrightness(value.toInt()); + break; + case QCameraImageProcessingControl::Sharpening: + if (isSharpeningSupported()) + setSharpeningLevel(value.toInt()); + break; + case QCameraImageProcessingControl::Denoising: + if (isDenoisingSupported()) + setDenoisingLevel(value.toInt()); + break; + case QCameraImageProcessingControl::ColorTemperature: + setManualWhiteBalance(value.toInt()); + break; + + default: + break; + } +} + +void S60CameraImageProcessingControl::setContrast(int value) +{ + m_session->setContrast(value); +} + +int S60CameraImageProcessingControl::contrast() const +{ + return m_session->contrast(); +} + +void S60CameraImageProcessingControl::setBrightness(int value) +{ + m_session->setBrightness(value); +} + +int S60CameraImageProcessingControl::brightness() const +{ + return m_session->brightness(); +} + +void S60CameraImageProcessingControl::setSaturation(int value) +{ + if (m_advancedSettings) + m_advancedSettings->setSaturation(value); + else + m_session->setError(KErrNotSupported, tr("Setting saturation is not supported.")); +} + +int S60CameraImageProcessingControl::saturation() const +{ + if (m_advancedSettings) + return m_advancedSettings->saturation(); + return 0; +} + +void S60CameraImageProcessingControl::setDenoisingLevel(int value) +{ + m_session->setError(KErrNotSupported, tr("Setting denoising level is not supported.")); + Q_UNUSED(value); // Not supported for Symbian +} + +bool S60CameraImageProcessingControl::isDenoisingSupported() const +{ + return false; // Not supported for Symbian +} + +int S60CameraImageProcessingControl::denoisingLevel() const +{ + return 0; // Not supported for Symbian +} + +void S60CameraImageProcessingControl::setSharpeningLevel(int value) +{ + if (m_advancedSettings) + m_advancedSettings->setSharpeningLevel(value); + else + m_session->setError(KErrNotSupported, tr("Setting sharpening level is not supported.")); +} + +bool S60CameraImageProcessingControl::isSharpeningSupported() const +{ + if (m_advancedSettings) + return m_advancedSettings->isSharpeningSupported(); + return false; +} + +int S60CameraImageProcessingControl::sharpeningLevel() const +{ + if (m_advancedSettings) + return m_advancedSettings->sharpeningLevel(); + return 0; +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60cameraimageprocessingcontrol.h b/src/plugins/symbian/ecam/s60cameraimageprocessingcontrol.h new file mode 100644 index 000000000..7fc6b8900 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraimageprocessingcontrol.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60CAMERAIMAGEPROCESSINGCONTROL_H +#define S60CAMERAIMAGEPROCESSINGCONTROL_H + +#include +#include + +#include "s60camerasettings.h" + +QT_USE_NAMESPACE + +class S60CameraService; +class S60ImageCaptureSession; + +/* + * Control for image processing related camera operations (inc. white balance). + */ +class S60CameraImageProcessingControl : public QCameraImageProcessingControl +{ + Q_OBJECT + +public: // Constructors & Destructor + + S60CameraImageProcessingControl(QObject *parent = 0); + S60CameraImageProcessingControl(S60ImageCaptureSession *session, QObject *parent = 0); + ~S60CameraImageProcessingControl(); + +public: // QCameraImageProcessingControl + + // White Balance + QCameraImageProcessing::WhiteBalanceMode whiteBalanceMode() const; + void setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode); + bool isWhiteBalanceModeSupported(QCameraImageProcessing::WhiteBalanceMode mode) const; + + // Processing Parameter + bool isProcessingParameterSupported(ProcessingParameter parameter) const; + QVariant processingParameter(QCameraImageProcessingControl::ProcessingParameter parameter) const; + void setProcessingParameter(QCameraImageProcessingControl::ProcessingParameter parameter, QVariant value); + +private slots: // Internal Slots + + void resetAdvancedSetting(); + +private: // Internal operations - Implementing ProcessingParameter + + // Manual White Balance (Color Temperature) + int manualWhiteBalance() const; + void setManualWhiteBalance(int colorTemperature); + + // Contrast + int contrast() const; + void setContrast(int value); + + // Brightness + int brightness() const; + void setBrightness(int value); + + // Saturation + int saturation() const; + void setSaturation(int value); + + // Sharpening + bool isSharpeningSupported() const; + int sharpeningLevel() const; + void setSharpeningLevel(int value); + + // Denoising + bool isDenoisingSupported() const; + int denoisingLevel() const; + void setDenoisingLevel(int value); + +private: // Data + + S60ImageCaptureSession *m_session; + S60CameraSettings *m_advancedSettings; +}; + +#endif // S60CAMERAIMAGEPROCESSINGCONTROL_H diff --git a/src/plugins/symbian/ecam/s60cameralockscontrol.cpp b/src/plugins/symbian/ecam/s60cameralockscontrol.cpp new file mode 100644 index 000000000..cce030f22 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameralockscontrol.cpp @@ -0,0 +1,263 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include // FocusMode + +#include "s60cameralockscontrol.h" +#include "s60cameraservice.h" +#include "s60imagecapturesession.h" +#include "s60camerasettings.h" +#include "s60camerafocuscontrol.h" + +S60CameraLocksControl::S60CameraLocksControl(QObject *parent) : + QCameraLocksControl(parent) +{ +} + +S60CameraLocksControl::S60CameraLocksControl(S60CameraService *service, + S60ImageCaptureSession *session, + QObject *parent) : + QCameraLocksControl(parent), + m_session(0), + m_service(0), + m_advancedSettings(0), + m_focusControl(0), + m_focusStatus(QCamera::Unlocked), + m_exposureStatus(QCamera::Unlocked), + m_whiteBalanceStatus(QCamera::Unlocked) +{ + m_session = session; + m_service = service; + m_focusControl = qobject_cast(m_service->requestControl(QCameraFocusControl_iid)); + + connect(m_session, SIGNAL(advancedSettingChanged()), this, SLOT(resetAdvancedSetting())); + m_advancedSettings = m_session->advancedSettings(); + + // Exposure Lock Signals + if (m_advancedSettings) + connect(m_advancedSettings, SIGNAL(exposureStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason)), + this, SLOT(exposureStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason))); + + // Focus Lock Signal + // * S60 3.2 and later (through Adv. Settings) + if (m_advancedSettings) + connect(m_advancedSettings, SIGNAL(focusStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason)), + this, SLOT(focusStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason))); + // * S60 3.1 (through ImageSession) + connect(m_session, SIGNAL(focusStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason)), + this, SLOT(focusStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason))); +} + +S60CameraLocksControl::~S60CameraLocksControl() +{ + m_advancedSettings = 0; +} + +QCamera::LockTypes S60CameraLocksControl::supportedLocks() const +{ + QCamera::LockTypes supportedLocks = 0; + +#ifdef S60_CAM_AUTOFOCUS_SUPPORT // S60 3.1 + if (m_session) + if (m_session->isFocusSupported()) + supportedLocks |= QCamera::LockFocus; +#else // S60 3.2 and later + if (m_advancedSettings) { + QCameraFocus::FocusModes supportedFocusModes = m_advancedSettings->supportedFocusModes(); + if (supportedFocusModes & QCameraFocus::AutoFocus) + supportedLocks |= QCamera::LockFocus; + + // Exposure/WhiteBalance Locking not implemented in Symbian + // supportedLocks |= QCamera::LockExposure; + // supportedLocks |= QCamera::LockWhiteBalance; + } +#endif // S60_CAM_AUTOFOCUS_SUPPORT + + return supportedLocks; +} + +QCamera::LockStatus S60CameraLocksControl::lockStatus(QCamera::LockType lock) const +{ + switch (lock) { + case QCamera::LockExposure: + return m_exposureStatus; + case QCamera::LockWhiteBalance: + return m_whiteBalanceStatus; + case QCamera::LockFocus: + return m_focusStatus; + + default: + // Unsupported lock + return QCamera::Unlocked; + } +} + +void S60CameraLocksControl::searchAndLock(QCamera::LockTypes locks) +{ + if (locks & QCamera::LockExposure) { + // Not implemented in Symbian + //startExposureLocking(); + } + if (locks & QCamera::LockWhiteBalance) { + // Not implemented in Symbian + } + if (locks & QCamera::LockFocus) + startFocusing(); +} + +void S60CameraLocksControl::unlock(QCamera::LockTypes locks) +{ + if (locks & QCamera::LockExposure) { + // Not implemented in Symbian + //cancelExposureLocking(); + } + + if (locks & QCamera::LockFocus) + cancelFocusing(); +} + +void S60CameraLocksControl::resetAdvancedSetting() +{ + m_advancedSettings = m_session->advancedSettings(); + + // Reconnect Lock Signals + if (m_advancedSettings) { + connect(m_advancedSettings, SIGNAL(exposureStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason)), + this, SLOT(exposureStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason))); + connect(m_advancedSettings, SIGNAL(focusStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason)), + this, SLOT(focusStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason))); + } +} + +void S60CameraLocksControl::exposureStatusChanged(QCamera::LockStatus status, + QCamera::LockChangeReason reason) +{ + if(status != m_exposureStatus) { + m_exposureStatus = status; + emit lockStatusChanged(QCamera::LockExposure, status, reason); + } +} + +void S60CameraLocksControl::focusStatusChanged(QCamera::LockStatus status, + QCamera::LockChangeReason reason) +{ + if(status != m_focusStatus) { + m_focusStatus = status; + emit lockStatusChanged(QCamera::LockFocus, status, reason); + } +} + +void S60CameraLocksControl::startFocusing() +{ +#ifndef S60_CAM_AUTOFOCUS_SUPPORT // S60 3.2 or later + // Focusing is triggered on Symbian by setting the FocusType corresponding + // to the FocusMode set to FocusControl + if (m_focusControl) { + if (m_advancedSettings) { + m_advancedSettings->startFocusing(); + m_focusStatus = QCamera::Searching; + emit lockStatusChanged(QCamera::LockFocus, QCamera::Searching, QCamera::UserRequest); + } + else + emit lockStatusChanged(QCamera::LockFocus, QCamera::Unlocked, QCamera::LockFailed); + } + else + emit lockStatusChanged(QCamera::LockFocus, QCamera::Unlocked, QCamera::LockFailed); + +#else // S60 3.1 + if (m_focusControl && m_focusControl->focusMode() == QCameraFocus::AutoFocus) { + m_session->startFocus(); + m_focusStatus = QCamera::Searching; + emit lockStatusChanged(QCamera::LockFocus, QCamera::Searching, QCamera::UserRequest); + } + else + emit lockStatusChanged(QCamera::LockFocus, QCamera::Unlocked, QCamera::LockFailed); +#endif // S60_CAM_AUTOFOCUS_SUPPORT +} + +void S60CameraLocksControl::cancelFocusing() +{ + if (m_focusStatus == QCamera::Unlocked) + return; + +#ifndef S60_CAM_AUTOFOCUS_SUPPORT // S60 3.2 or later + if (m_advancedSettings) { + m_advancedSettings->cancelFocusing(); + m_focusStatus = QCamera::Unlocked; + emit lockStatusChanged(QCamera::LockFocus, QCamera::Unlocked, QCamera::UserRequest); + } + else + emit lockStatusChanged(QCamera::LockFocus, QCamera::Unlocked, QCamera::LockFailed); + +#else // S60 3.1 + m_session->cancelFocus(); + m_focusStatus = QCamera::Unlocked; + emit lockStatusChanged(QCamera::LockFocus, QCamera::Unlocked, QCamera::UserRequest); +#endif // S60_CAM_AUTOFOCUS_SUPPORT +} + +void S60CameraLocksControl::startExposureLocking() +{ + if (m_advancedSettings) { + m_advancedSettings->lockExposure(true); + m_exposureStatus = QCamera::Searching; + emit lockStatusChanged(QCamera::LockExposure, QCamera::Searching, QCamera::UserRequest); + } + else + emit lockStatusChanged(QCamera::LockExposure, QCamera::Unlocked, QCamera::LockFailed); +} + +void S60CameraLocksControl::cancelExposureLocking() +{ + if (m_exposureStatus == QCamera::Unlocked) + return; + + if (m_advancedSettings) { + m_advancedSettings->lockExposure(false); + m_exposureStatus = QCamera::Unlocked; + emit lockStatusChanged(QCamera::LockExposure, QCamera::Unlocked, QCamera::UserRequest); + } + else + emit lockStatusChanged(QCamera::LockExposure, QCamera::Unlocked, QCamera::LockFailed); +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60cameralockscontrol.h b/src/plugins/symbian/ecam/s60cameralockscontrol.h new file mode 100644 index 000000000..3b49cbaba --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameralockscontrol.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60CAMERALOCKSCONTROL_H +#define S60CAMERALOCKSCONTROL_H + +#include +#include "qcameralockscontrol.h" + +QT_USE_NAMESPACE + +class S60CameraService; +class S60ImageCaptureSession; +class S60CameraSettings; +class S60CameraFocusControl; + +/* + * Control for searching and locking 3A algorithms (AutoFocus, AutoExposure + * and AutoWhitebalance). + */ +class S60CameraLocksControl : public QCameraLocksControl +{ + Q_OBJECT + +public: // Contructors & Destrcutor + + S60CameraLocksControl(QObject *parent = 0); + S60CameraLocksControl(S60CameraService *service, + S60ImageCaptureSession *session, + QObject *parent = 0); + ~S60CameraLocksControl(); + +public: // QCameraLocksControl + + QCamera::LockTypes supportedLocks() const; + + QCamera::LockStatus lockStatus(QCamera::LockType lock) const; + + void searchAndLock(QCamera::LockTypes locks); + void unlock(QCamera::LockTypes locks); + +/* +Q_SIGNALS: // QCameraLocksControl + + void lockStatusChanged(QCamera::LockType type, + QCamera::LockStatus status, + QCamera::LockChangeReason reason); +*/ + +private slots: // Internal Slots + + void exposureStatusChanged(QCamera::LockStatus status, QCamera::LockChangeReason reason); + void focusStatusChanged(QCamera::LockStatus status, QCamera::LockChangeReason reason); + void resetAdvancedSetting(); + +private: // Internal + + // Focus + void startFocusing(); + void cancelFocusing(); + + // Exposure + void startExposureLocking(); + void cancelExposureLocking(); + +private: // Data + + S60ImageCaptureSession *m_session; + S60CameraService *m_service; + S60CameraSettings *m_advancedSettings; + S60CameraFocusControl *m_focusControl; + QCamera::LockStatus m_focusStatus; + QCamera::LockStatus m_exposureStatus; + QCamera::LockStatus m_whiteBalanceStatus; +}; + +#endif // S60CAMERALOCKSCONTROL_H diff --git a/src/plugins/symbian/ecam/s60cameraservice.cpp b/src/plugins/symbian/ecam/s60cameraservice.cpp new file mode 100644 index 000000000..5cc4485c1 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraservice.cpp @@ -0,0 +1,259 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +#include "s60cameraservice.h" +#include "s60cameracontrol.h" +#include "s60videodevicecontrol.h" +#include "s60camerafocuscontrol.h" +#include "s60cameraexposurecontrol.h" +#include "s60cameraflashcontrol.h" +#include "s60cameraimageprocessingcontrol.h" +#include "s60cameraimagecapturecontrol.h" +#include "s60mediarecordercontrol.h" +#include "s60videocapturesession.h" +#include "s60imagecapturesession.h" +#include "s60videowidgetcontrol.h" +#include "s60mediacontainercontrol.h" +#include "s60videoencodercontrol.h" +#include "s60audioencodercontrol.h" +#include "s60imageencodercontrol.h" +#include "s60cameralockscontrol.h" +#include "s60videorenderercontrol.h" +#include "s60videowindowcontrol.h" + +#include "s60cameraviewfinderengine.h" // ViewfinderOutputType + +S60CameraService::S60CameraService(QObject *parent) : + QMediaService(parent) +{ + // Session classes for video and image capturing + m_imagesession = new S60ImageCaptureSession(this); + m_videosession = new S60VideoCaptureSession(this); + + if (m_imagesession && m_videosession) { + // Different control classes implementing the Camera API + m_control = new S60CameraControl(m_videosession, m_imagesession, this); + m_videoDeviceControl = new S60VideoDeviceControl(m_control, this); + m_focusControl = new S60CameraFocusControl(m_imagesession, this); + m_exposureControl = new S60CameraExposureControl(m_imagesession, this); + m_flashControl = new S60CameraFlashControl(m_imagesession, this); + m_imageProcessingControl = new S60CameraImageProcessingControl(m_imagesession, this); + m_imageCaptureControl = new S60CameraImageCaptureControl(this, m_imagesession, this); + m_media = new S60MediaRecorderControl(this, m_videosession, this); + m_mediaFormat = new S60MediaContainerControl(m_videosession, this); + m_videoEncoder = new S60VideoEncoderControl(m_videosession, this); + m_audioEncoder = new S60AudioEncoderControl(m_videosession, this); + m_viewFinderWidget = new S60VideoWidgetControl(this); + m_imageEncoderControl = new S60ImageEncoderControl(m_imagesession, this); + m_locksControl = new S60CameraLocksControl(this, m_imagesession, this); + m_rendererControl = new S60VideoRendererControl(this); + m_windowControl = new S60VideoWindowControl(this); + } +} + +S60CameraService::~S60CameraService() +{ + // Delete controls + if (m_videoDeviceControl) + delete m_videoDeviceControl; + if (m_focusControl) + delete m_focusControl; + if (m_exposureControl) + delete m_exposureControl; + if (m_flashControl) + delete m_flashControl; + if (m_imageProcessingControl) + delete m_imageProcessingControl; + if (m_imageCaptureControl) + delete m_imageCaptureControl; + if (m_media) + delete m_media; + if (m_mediaFormat) + delete m_mediaFormat; + if (m_videoEncoder) + delete m_videoEncoder; + if (m_audioEncoder) + delete m_audioEncoder; + if (m_imageEncoderControl) + delete m_imageEncoderControl; + if (m_locksControl) + delete m_locksControl; + + // CameraControl destroys: + // * ViewfinderEngine + // * CameraEngine + if (m_control) + delete m_control; + + // Delete viewfinder controls after CameraControl to be sure that + // ViewFinder gets stopped before widget (and window) is destroyed + if (m_viewFinderWidget) + delete m_viewFinderWidget; + if (m_rendererControl) + delete m_rendererControl; + if (m_windowControl) + delete m_windowControl; + + // Delete sessions + if (m_videosession) + delete m_videosession; + if (m_imagesession) + delete m_imagesession; +} + +QMediaControl *S60CameraService::requestControl(const char *name) +{ + if (qstrcmp(name, QMediaRecorderControl_iid) == 0) + return m_media; + + if (qstrcmp(name, QCameraControl_iid) == 0) + return m_control; + + if (qstrcmp(name, QVideoEncoderControl_iid) == 0) + return m_videoEncoder; + + if (qstrcmp(name, QAudioEncoderControl_iid) == 0) + return m_audioEncoder; + + if (qstrcmp(name, QMediaContainerControl_iid) == 0) + return m_mediaFormat; + + if (qstrcmp(name, QCameraExposureControl_iid) == 0) + return m_exposureControl; + + if (qstrcmp(name, QCameraFlashControl_iid) == 0) + return m_flashControl; + + if (qstrcmp(name, QVideoWidgetControl_iid) == 0) { + if (m_viewFinderWidget) { + m_control->setVideoOutput(m_viewFinderWidget, + S60CameraViewfinderEngine::OutputTypeVideoWidget); + return m_viewFinderWidget; + } + else + return 0; + } + + if (qstrcmp(name, QVideoRendererControl_iid) == 0) { + if (m_rendererControl) { + m_control->setVideoOutput(m_rendererControl, + S60CameraViewfinderEngine::OutputTypeRenderer); + return m_rendererControl; + } + else + return 0; + } + + if (qstrcmp(name, QVideoWindowControl_iid) == 0) { + if (m_windowControl) { + m_control->setVideoOutput(m_windowControl, + S60CameraViewfinderEngine::OutputTypeVideoWindow); + return m_windowControl; + } + else + return 0; + } + + + if (qstrcmp(name, QCameraFocusControl_iid) == 0) + return m_focusControl; + + if (qstrcmp(name, QCameraImageProcessingControl_iid) == 0) + return m_imageProcessingControl; + + if (qstrcmp(name, QCameraImageCaptureControl_iid) == 0) + return m_imageCaptureControl; + + if (qstrcmp(name, QVideoDeviceControl_iid) == 0) + return m_videoDeviceControl; + + if (qstrcmp(name, QImageEncoderControl_iid) == 0) + return m_imageEncoderControl; + + if (qstrcmp(name, QCameraLocksControl_iid) == 0) + return m_locksControl; + + return 0; +} + +void S60CameraService::releaseControl(QMediaControl *control) +{ + if (control == 0) + return; + + // Release viewfinder output + if (control == m_viewFinderWidget) { + if (m_viewFinderWidget) + m_control->releaseVideoOutput(S60CameraViewfinderEngine::OutputTypeVideoWidget); + } + + if (control == m_rendererControl) { + if (m_rendererControl) + m_control->releaseVideoOutput(S60CameraViewfinderEngine::OutputTypeRenderer); + } + + if (control == m_windowControl) { + if (m_windowControl) + m_control->releaseVideoOutput(S60CameraViewfinderEngine::OutputTypeVideoWindow); + } +} + +int S60CameraService::deviceCount() +{ + return S60CameraControl::deviceCount(); +} + +QString S60CameraService::deviceDescription(const int index) +{ + return S60CameraControl::description(index); +} + +QString S60CameraService::deviceName(const int index) +{ + return S60CameraControl::name(index); +} + +// End of file + diff --git a/src/plugins/symbian/ecam/s60cameraservice.h b/src/plugins/symbian/ecam/s60cameraservice.h new file mode 100644 index 000000000..a2744c1fa --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraservice.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60CAMERASERVICE_H +#define S60CAMERASERVICE_H + +#include +#include + +QT_USE_NAMESPACE + +class S60MediaContainerControl; +class S60VideoEncoderControl; +class S60AudioEncoderControl; +class S60CameraControl; +class S60VideoDeviceControl; +class S60MediaRecorderControl; +class S60ImageCaptureSession; +class S60VideoCaptureSession; +class S60CameraFocusControl; +class S60CameraExposureControl; +class S60CameraFlashControl; +class S60CameraImageProcessingControl; +class S60CameraImageCaptureControl; +class S60VideoWidgetControl; +class S60ImageEncoderControl; +class S60CameraLocksControl; +class S60VideoRendererControl; +class S60VideoWindowControl; + +class S60CameraService : public QMediaService +{ + Q_OBJECT + +public: // Contructor & Destructor + + S60CameraService(QObject *parent = 0); + ~S60CameraService(); + +public: // QMediaService + + QMediaControl *requestControl(const char *name); + void releaseControl(QMediaControl *control); + +public: // Static Device Info + + static int deviceCount(); + static QString deviceName(const int index); + static QString deviceDescription(const int index); + +private: // Data + + S60ImageCaptureSession *m_imagesession; + S60VideoCaptureSession *m_videosession; + S60MediaContainerControl *m_mediaFormat; + S60VideoEncoderControl *m_videoEncoder; + S60AudioEncoderControl *m_audioEncoder; + S60CameraControl *m_control; + S60VideoDeviceControl *m_videoDeviceControl; + S60CameraFocusControl *m_focusControl; + S60CameraExposureControl *m_exposureControl; + S60CameraFlashControl *m_flashControl; + S60CameraImageProcessingControl *m_imageProcessingControl; + S60CameraImageCaptureControl *m_imageCaptureControl; + S60MediaRecorderControl *m_media; + S60VideoWidgetControl *m_viewFinderWidget; + S60ImageEncoderControl *m_imageEncoderControl; + S60CameraLocksControl *m_locksControl; + S60VideoRendererControl *m_rendererControl; + S60VideoWindowControl *m_windowControl; +}; + +#endif // S60CAMERASERVICE_H diff --git a/src/plugins/symbian/ecam/s60cameraserviceplugin.cpp b/src/plugins/symbian/ecam/s60cameraserviceplugin.cpp new file mode 100644 index 000000000..8f22fd205 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraserviceplugin.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "s60cameraserviceplugin.h" +#ifdef QMEDIA_SYMBIAN_CAMERA +#include "s60cameraservice.h" +#endif + +QStringList S60CameraServicePlugin::keys() const +{ + QStringList list; +#ifdef QMEDIA_SYMBIAN_CAMERA + list << QLatin1String(Q_MEDIASERVICE_CAMERA); +#endif + return list; +} + +QMediaService* S60CameraServicePlugin::create(QString const& key) +{ +#ifdef QMEDIA_SYMBIAN_CAMERA + if (key == QLatin1String(Q_MEDIASERVICE_CAMERA)) + return new S60CameraService; +#endif + return 0; +} + +void S60CameraServicePlugin::release(QMediaService *service) +{ + delete service; +} + +QList S60CameraServicePlugin::devices(const QByteArray &service) const +{ +#ifdef QMEDIA_SYMBIAN_CAMERA + if (service == Q_MEDIASERVICE_CAMERA) { + if (m_cameraDevices.isEmpty()) + updateDevices(); + + return m_cameraDevices; + } +#endif + return QList(); +} + +QString S60CameraServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device) +{ +#ifdef QMEDIA_SYMBIAN_CAMERA + if (service == Q_MEDIASERVICE_CAMERA) { + if (m_cameraDevices.isEmpty()) + updateDevices(); + + for (int i=0; i +#include + +QT_USE_NAMESPACE + +/* + * Plugin implementation for the Camera Service + */ +class S60CameraServicePlugin : public QMediaServiceProviderPlugin, + public QMediaServiceSupportedDevicesInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceSupportedDevicesInterface) + +public: // QMediaServiceProviderPlugin + + QStringList keys() const; + QMediaService* create(QString const& key); + void release(QMediaService *service); + +public: // QMediaServiceSupportedDevicesInterface + + QList devices(const QByteArray &service) const; + QString deviceDescription(const QByteArray &service, const QByteArray &device); + +private: // Internal + + void updateDevices() const; + +private: // Data + + mutable QList m_cameraDevices; + mutable QStringList m_cameraDescriptions; +}; + +#endif // S60CAMERASERVICEPLUGIN_H diff --git a/src/plugins/symbian/ecam/s60camerasettings.cpp b/src/plugins/symbian/ecam/s60camerasettings.cpp new file mode 100644 index 000000000..a5918078f --- /dev/null +++ b/src/plugins/symbian/ecam/s60camerasettings.cpp @@ -0,0 +1,986 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "s60camerasettings.h" +#include "s60cameraconstants.h" + +// S60 3.2 Platform +#ifdef USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER +#define POST_31_PLATFORM +#include // CCameraAdvancedSettings (inc. TValueInfo) +#endif // S60 3.2 + +// S60 5.0 or later +#ifdef USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER +#define POST_31_PLATFORM +#include // CCameraAdvancedSettings +#include // TValueInfo +#endif // S60 5.0 or later + +S60CameraSettings::S60CameraSettings(QObject *parent, CCameraEngine *engine) : + QObject(parent), +#ifndef S60_31_PLATFORM // Post S60 3.1 Platforms + m_advancedSettings(0), + m_imageProcessingSettings(0), +#endif // S60_31_PLATFORM + m_cameraEngine(engine), + m_continuousFocusing(false) +{ +} + +S60CameraSettings::~S60CameraSettings() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + delete m_advancedSettings; + m_advancedSettings = 0; + } + + if (m_imageProcessingSettings) { + delete m_imageProcessingSettings; + m_imageProcessingSettings = 0; + } +#endif // POST_31_PLATFORM +} + +/* + * This is Symbian NewL kind of consructor, but unlike Symbian version this + * constructor will not leave, but instead it will return possible errors in + * the error variable. This is to be able to write the class without deriving + * it form CBase. Also CleanupStack is cleaned here if the ConstructL leaves. + */ +S60CameraSettings* S60CameraSettings::New(int &error, QObject *parent, CCameraEngine *engine) +{ + S60CameraSettings* self = new S60CameraSettings(parent, engine); + if (!self) { + error = KErrNoMemory; + return 0; + } + + TRAPD(err, self->ConstructL()); + if (err) { + // Clean created object + delete self; + self = 0; + error = err; + return 0; + } + + error = KErrNone; + return self; +} + +void S60CameraSettings::ConstructL() +{ +#ifdef POST_31_PLATFORM + if (!m_cameraEngine) + User::Leave(KErrGeneral); + // From now on it is safe to assume engine exists + + // If no AdvancedSettings is available, there's no benefit of S60CameraSettings + // Leave if creation fails + m_advancedSettings = CCamera::CCameraAdvancedSettings::NewL(*m_cameraEngine->Camera()); + CleanupStack::PushL(m_advancedSettings); + + // ImageProcessing module may not be supported, don't Leave + TRAPD(err, m_imageProcessingSettings = CCamera::CCameraImageProcessing::NewL(*m_cameraEngine->Camera())); + if (err == KErrNone && m_imageProcessingSettings) { + CleanupStack::PushL(m_imageProcessingSettings); + } else { + if (err == KErrNotSupported) + m_imageProcessingSettings = 0; + else { + // Leave with error + if (!m_imageProcessingSettings) + User::Leave(KErrNoMemory); + else + User::Leave(err); + } + } + + if (m_advancedSettings) { + RArray digitalZoomFactors; + CleanupClosePushL(digitalZoomFactors); + + TValueInfo info = ENotActive; + m_advancedSettings->GetDigitalZoomStepsL(digitalZoomFactors, info); + + for (int i = 0; i < digitalZoomFactors.Count(); ++i) + m_supportedSymbianDigitalZoomFactors << digitalZoomFactors[i]; + + CleanupStack::PopAndDestroy(); // RArray digitalZoomFactors + } + + // Pop objects from CleanupStack + if (m_imageProcessingSettings) + CleanupStack::Pop(m_imageProcessingSettings); + CleanupStack::Pop(m_advancedSettings); + +#else // S60 3.1 + // AdvancedSettings are not suppoted on S60 3.1 (There's no use for S60CameraSettings) + User::Leave(KErrNotSupported); +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::setFocusMode(QCameraFocus::FocusMode mode) +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + switch (mode) { + case QCameraFocus::ManualFocus: // Manual focus mode + m_advancedSettings->SetFocusMode(CCamera::CCameraAdvancedSettings::EFocusModeManual); + m_continuousFocusing = false; + break; + case QCameraFocus::AutoFocus: // Single-shot AutoFocus mode + m_advancedSettings->SetFocusMode(CCamera::CCameraAdvancedSettings::EFocusModeAuto); + m_advancedSettings->SetFocusRange(CCamera::CCameraAdvancedSettings::EFocusRangeAuto); + m_continuousFocusing = false; + break; + case QCameraFocus::HyperfocalFocus: + m_advancedSettings->SetFocusMode(CCamera::CCameraAdvancedSettings::EFocusModeAuto); + m_advancedSettings->SetFocusRange(CCamera::CCameraAdvancedSettings::EFocusRangeHyperfocal); + m_continuousFocusing = false; + break; + case QCameraFocus::InfinityFocus: + m_advancedSettings->SetFocusMode(CCamera::CCameraAdvancedSettings::EFocusModeAuto); + m_advancedSettings->SetFocusRange(CCamera::CCameraAdvancedSettings::EFocusRangeInfinite); + m_continuousFocusing = false; + break; + case QCameraFocus::ContinuousFocus: + m_advancedSettings->SetFocusMode(CCamera::CCameraAdvancedSettings::EFocusModeAuto); + m_advancedSettings->SetFocusRange(CCamera::CCameraAdvancedSettings::EFocusRangeAuto); + m_continuousFocusing = true; + break; + case QCameraFocus::MacroFocus: + m_advancedSettings->SetFocusMode(CCamera::CCameraAdvancedSettings::EFocusModeAuto); + m_advancedSettings->SetFocusRange(CCamera::CCameraAdvancedSettings::EFocusRangeMacro); + m_continuousFocusing = false; + break; + + default: + emit error(QCamera::NotSupportedFeatureError, tr("Requested focus mode is not supported.")); + break; + } + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } +#else // S60 3.1 + Q_UNUSED(mode); + emit error(QCamera::NotSupportedFeatureError, tr("Settings focus mode is not supported.")); +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::startFocusing() +{ +#ifdef POST_31_PLATFORM + // Setting AutoFocusType triggers the focusing on Symbian + if (m_advancedSettings) { + if (m_continuousFocusing) + m_advancedSettings->SetAutoFocusType(CCamera::CCameraAdvancedSettings::EAutoFocusTypeContinuous); + else + m_advancedSettings->SetAutoFocusType(CCamera::CCameraAdvancedSettings::EAutoFocusTypeSingle); + } else { + emit error(QCamera::CameraError, tr("Unable to focus.")); + } +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::cancelFocusing() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) + m_advancedSettings->SetAutoFocusType(CCamera::CCameraAdvancedSettings::EAutoFocusTypeOff); + else + emit error(QCamera::CameraError, tr("Unable to cancel focusing.")); +#endif // POST_31_PLATFORM +} + +QCameraFocus::FocusMode S60CameraSettings::focusMode() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + // First request needed info + CCamera::CCameraAdvancedSettings::TFocusMode mode = m_advancedSettings->FocusMode(); + CCamera::CCameraAdvancedSettings::TFocusRange range = m_advancedSettings->FocusRange(); + CCamera::CCameraAdvancedSettings::TAutoFocusType autoType = m_advancedSettings->AutoFocusType(); + + switch (mode) { + case CCamera::CCameraAdvancedSettings::EFocusModeManual: + case CCamera::CCameraAdvancedSettings::EFocusModeFixed: + return QCameraFocus::ManualFocus; + + case CCamera::CCameraAdvancedSettings::EFocusModeAuto: + if (autoType == CCamera::CCameraAdvancedSettings::EAutoFocusTypeContinuous) { + return QCameraFocus::ContinuousFocus; + } else { + // Single-shot focusing + switch (range) { + case CCamera::CCameraAdvancedSettings::EFocusRangeMacro: + case CCamera::CCameraAdvancedSettings::EFocusRangeSuperMacro: + return QCameraFocus::MacroFocus; + case CCamera::CCameraAdvancedSettings::EFocusRangeHyperfocal: + return QCameraFocus::HyperfocalFocus; + case CCamera::CCameraAdvancedSettings::EFocusRangeInfinite: + return QCameraFocus::InfinityFocus; + case CCamera::CCameraAdvancedSettings::EFocusRangeAuto: + case CCamera::CCameraAdvancedSettings::EFocusRangeNormal: + return QCameraFocus::AutoFocus; + + default: + return QCameraFocus::AutoFocus; + } + } + default: + return QCameraFocus::AutoFocus; // Return automatic focusing + } + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } +#endif // POST_31_PLATFORM + return QCameraFocus::AutoFocus; // Return automatic focusing +} + +QCameraFocus::FocusModes S60CameraSettings::supportedFocusModes() +{ + QCameraFocus::FocusModes modes = 0; + +#ifdef POST_31_PLATFORM + TInt supportedModes = 0; + TInt autoFocusTypes = 0; + TInt supportedRanges = 0; + + if (m_advancedSettings) { + supportedModes = m_advancedSettings->SupportedFocusModes(); + autoFocusTypes = m_advancedSettings->SupportedAutoFocusTypes(); + supportedRanges = m_advancedSettings->SupportedFocusRanges(); + + if (supportedModes == 0 || autoFocusTypes == 0 || supportedRanges == 0) + return modes; + + // EFocusModeAuto is the only supported on Symbian + if (supportedModes & CCamera::CCameraAdvancedSettings::EFocusModeAuto) { + // Check supported types (Single-shot Auto vs. Continuous) + if (autoFocusTypes & CCamera::CCameraAdvancedSettings::EAutoFocusTypeSingle) + modes |= QCameraFocus::AutoFocus; + if (autoFocusTypes & CCamera::CCameraAdvancedSettings::EAutoFocusTypeContinuous) + modes |= QCameraFocus::ContinuousFocus; + + // Check supported ranges (Note! Some are actually fixed focuses + // even though the mode is Auto on Symbian) + if (supportedRanges & CCamera::CCameraAdvancedSettings::EFocusRangeMacro) + modes |= QCameraFocus::MacroFocus; + if (supportedRanges & CCamera::CCameraAdvancedSettings::EFocusRangeHyperfocal) + modes |= QCameraFocus::HyperfocalFocus; + if (supportedRanges & CCamera::CCameraAdvancedSettings::EFocusRangeInfinite) + modes |= QCameraFocus::InfinityFocus; + } + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } +#endif // POST_31_PLATFORM + + return modes; +} + +qreal S60CameraSettings::opticalZoomFactorL() const +{ + // Not supported on Symbian + return 1.0; +} + +void S60CameraSettings::setOpticalZoomFactorL(const qreal zoomFactor) +{ + // Not supported on Symbian + Q_UNUSED(zoomFactor); +} + +QList S60CameraSettings::supportedDigitalZoomFactors() const +{ + QList zoomFactors; + foreach (int factor, m_supportedSymbianDigitalZoomFactors) + zoomFactors << qreal(factor) / KSymbianFineResolutionFactor; + + return zoomFactors; +} + +qreal S60CameraSettings::digitalZoomFactorL() const +{ + qreal factor = 1.0; + +#ifdef POST_31_PLATFORM + int symbianFactor = 0; + if (m_advancedSettings) + symbianFactor = m_advancedSettings->DigitalZoom(); + else + User::Leave(KErrNotSupported); + + if (symbianFactor != 0) + factor = qreal(symbianFactor) / KSymbianFineResolutionFactor; +#endif // POST_31_PLATFORM + + return factor; +} + +void S60CameraSettings::setDigitalZoomFactorL(const qreal zoomFactor) +{ +#ifdef POST_31_PLATFORM + int symbianFactor = zoomFactor * KSymbianFineResolutionFactor; + + // Find closest supported Symbian ZoomFactor if needed + if (!m_supportedSymbianDigitalZoomFactors.contains(symbianFactor)) { + int closestIndex = -1; + int closestDiff = 1000000; // Sensible maximum + for (int i = 0; i < m_supportedSymbianDigitalZoomFactors.count(); ++i) { + int diff = abs(m_supportedSymbianDigitalZoomFactors.at(i) - symbianFactor); + if (diff < closestDiff) { + closestDiff = diff; + closestIndex = i; + } + } + if (closestIndex != -1) + symbianFactor = m_supportedSymbianDigitalZoomFactors.at(closestIndex); + else + User::Leave(KErrGeneral); + } + if (m_advancedSettings) + m_advancedSettings->SetDigitalZoom(symbianFactor); + else + User::Leave(KErrNotSupported); +#else // S60 3.1 Platform + Q_UNUSED(zoomFactor); + emit error(QCamera::NotSupportedFeatureError, tr("Settings digital zoom factor is not supported.")); +#endif // POST_31_PLATFORM +} + +// MCameraObserver2 +void S60CameraSettings::HandleAdvancedEvent(const TECAMEvent& aEvent) +{ +#ifdef POST_31_PLATFORM + + if (aEvent.iErrorCode != KErrNone) { + switch (aEvent.iErrorCode) { + case KErrECamCameraDisabled: + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + return; + case KErrECamSettingDisabled: + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + return; + case KErrECamParameterNotInRange: + emit error(QCamera::NotSupportedFeatureError, tr("Requested value is not in supported range.")); + return; + case KErrECamSettingNotSupported: + emit error(QCamera::NotSupportedFeatureError, tr("Requested setting is not supported.")); + return; + case KErrECamNotOptimalFocus: + if (m_continuousFocusing) + emit focusStatusChanged(QCamera::Searching, QCamera::LockTemporaryLost); + else + emit focusStatusChanged(QCamera::Unlocked, QCamera::LockFailed); + return; + } + + if (aEvent.iEventType == KUidECamEventCameraSettingFocusRange || + aEvent.iEventType == KUidECamEventCameraSettingAutoFocusType2) { + emit focusStatusChanged(QCamera::Unlocked, QCamera::LockFailed); + return; + } else if (aEvent.iEventType == KUidECamEventCameraSettingIsoRate) { + if (aEvent.iErrorCode == KErrNotSupported) + emit error(QCamera::NotSupportedFeatureError, tr("Requested ISO value is not supported.")); + else + emit error(QCamera::CameraError, tr("Setting ISO value failed.")); + return; + } else if (aEvent.iEventType == KUidECamEventCameraSettingAperture) { + if (aEvent.iErrorCode == KErrNotSupported) + emit error(QCamera::NotSupportedFeatureError, tr("Requested aperture value is not supported.")); + else + emit error(QCamera::CameraError, tr("Setting aperture value failed.")); + return; + } else if (aEvent.iEventType == KUidECamEventCameraSettingExposureCompensation) { + if (aEvent.iErrorCode == KErrNotSupported) + emit error(QCamera::NotSupportedFeatureError, tr("Requested exposure compensation is not supported.")); + else + emit error(QCamera::CameraError, tr("Setting exposure compensation failed.")); + return; + } else if (aEvent.iEventType == KUidECamEventCameraSettingOpticalZoom || + aEvent.iEventType == KUidECamEventCameraSettingDigitalZoom) { + if (aEvent.iErrorCode == KErrNotSupported) + return; // Discard + else { + emit error(QCamera::CameraError, tr("Setting zoom factor failed.")); + return; + } + } else if (aEvent.iEventType == KUidECamEventCameraSettingFocusMode) { + if (aEvent.iErrorCode == KErrNotSupported) + if (m_cameraEngine && m_cameraEngine->CurrentCameraIndex() != 0) + emit error(QCamera::NotSupportedFeatureError, tr("Focusing is not supported with this camera.")); + else + emit error(QCamera::NotSupportedFeatureError, tr("Requested focus mode is not supported.")); + else + emit error(QCamera::CameraError, tr("Setting focus mode failed.")); + return; + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + return; + } + } + + if (aEvent.iEventType == KUidECamEventCameraSettingExposureLock) { + if (m_advancedSettings) { + if (m_advancedSettings->ExposureLockOn()) + emit exposureStatusChanged(QCamera::Locked, QCamera::LockAcquired); + else + emit exposureStatusChanged(QCamera::Unlocked, QCamera::LockLost); + } + else + emit exposureStatusChanged(QCamera::Unlocked, QCamera::LockLost); + } + else if (aEvent.iEventType == KUidECamEventCameraSettingAperture) + emit apertureChanged(); + + else if (aEvent.iEventType == KUidECamEventCameraSettingApertureRange) + emit apertureRangeChanged(); + + else if (aEvent.iEventType == KUidECamEventCameraSettingIsoRateType) + emit isoSensitivityChanged(); + + else if (aEvent.iEventType == KUidECamEventCameraSettingShutterSpeed) + emit shutterSpeedChanged(); + + else if (aEvent.iEventType == KUidECamEventCameraSettingExposureCompensationStep) + emit evChanged(); + + else if (aEvent.iEventType == KUidECamEventFlashReady) + emit flashReady(true); + + else if (aEvent.iEventType == KUidECamEventFlashNotReady) + emit flashReady(false); + + else if (aEvent.iEventType.iUid == KUidECamEventCameraSettingsOptimalFocusUidValue) + emit focusStatusChanged(QCamera::Locked, QCamera::LockAcquired); + +#else // S60 3.1 Platform + Q_UNUSED(aEvent); +#endif // POST_31_PLATFORM +} + +bool S60CameraSettings::isFlashReady() +{ + TBool isReady = false; +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + int flashErr = m_advancedSettings->IsFlashReady(isReady); + if(flashErr != KErrNone) { + if (flashErr != KErrNotSupported) + emit error(QCamera::CameraError, tr("Unexpected error with flash.")); + return false; + } + } + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); +#endif + return isReady; +} + +QCameraExposure::MeteringMode S60CameraSettings::meteringMode() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + CCamera::CCameraAdvancedSettings::TMeteringMode mode = m_advancedSettings->MeteringMode(); + switch (mode) { + case CCamera::CCameraAdvancedSettings::EMeteringModeCenterWeighted: + return QCameraExposure::MeteringAverage; + case CCamera::CCameraAdvancedSettings::EMeteringModeEvaluative: + return QCameraExposure::MeteringMatrix; + case CCamera::CCameraAdvancedSettings::EMeteringModeSpot: + return QCameraExposure::MeteringSpot; + + default: + return QCameraExposure::MeteringAverage; + } + }else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + return QCameraExposure::MeteringAverage; + } +#else // S60 3.1 Platform + return QCameraExposure::MeteringAverage; +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::setMeteringMode(QCameraExposure::MeteringMode mode) +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + switch(mode) { + case QCameraExposure::MeteringAverage: + m_advancedSettings->SetMeteringMode(CCamera::CCameraAdvancedSettings::EMeteringModeCenterWeighted); + break; + case QCameraExposure::MeteringMatrix: + m_advancedSettings->SetMeteringMode(CCamera::CCameraAdvancedSettings::EMeteringModeEvaluative); + break; + case QCameraExposure::MeteringSpot: + m_advancedSettings->SetMeteringMode(CCamera::CCameraAdvancedSettings::EMeteringModeSpot); + break; + default: + break; + } + } + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); +#else // S60 3.1 + Q_UNUSED(mode); + emit error(QCamera::NotSupportedFeatureError, tr("Setting metering mode is not supported.")); +#endif // POST_31_PLATFORM +} + +bool S60CameraSettings::isMeteringModeSupported(QCameraExposure::MeteringMode mode) +{ +#ifdef POST_31_PLATFORM + TInt supportedModes = 0; + + if (m_advancedSettings) { + supportedModes = m_advancedSettings->SupportedMeteringModes(); + if (supportedModes == 0) + return false; + + switch (mode) { + case QCameraExposure::MeteringMatrix: + if (supportedModes & CCamera::CCameraAdvancedSettings::EMeteringModeEvaluative) + return true; + else + return false; + case QCameraExposure::MeteringAverage: + if (supportedModes & CCamera::CCameraAdvancedSettings::EMeteringModeCenterWeighted) + return true; + else + return false; + case QCameraExposure::MeteringSpot: + if (supportedModes & CCamera::CCameraAdvancedSettings::EMeteringModeSpot) + return true; + else + return false; + + default: + return false; + } + } + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); +#else // S60 3.1 + Q_UNUSED(mode); +#endif // POST_31_PLATFORM + + return false; +} + +int S60CameraSettings::isoSensitivity() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + CCamera::CCameraAdvancedSettings::TISORateType isoRateType; + TInt param = 0; + TInt isoRate = 0; + TRAPD(err, m_advancedSettings->GetISORateL(isoRateType, param, isoRate)); + if (err) + return 0; + if (isoRate != KErrNotFound) + return isoRate; + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } +#endif // POST_31_PLATFORM + return 0; +} + +QList S60CameraSettings::supportedIsoSensitivities() +{ + QList isoSentitivities; +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + RArray supportedIsoRates; + CleanupClosePushL(supportedIsoRates); + + TRAPD(err, m_advancedSettings->GetSupportedIsoRatesL(supportedIsoRates)); + if (err != KErrNone) { + if (err != KErrNotSupported) // Don's emit error if ISO is not supported + emit error(QCamera::CameraError, tr("Failure while querying supported iso sensitivities.")); + } else { + for (int i = 0; i < supportedIsoRates.Count(); ++i) + isoSentitivities << supportedIsoRates[i]; + } + CleanupStack::PopAndDestroy(); // RArray supportedIsoRates + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } + + return isoSentitivities; +#else // S60 3.1 Platform + return isoSentitivities; +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::setManualIsoSensitivity(int iso) +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + TRAPD(err, m_advancedSettings->SetISORateL(CCamera::CCameraAdvancedSettings::EISOManual, iso)); + if (err) + emit error(QCamera::CameraError, tr("Setting manual iso sensitivity failed.")); + return; + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } +#else // S60 3.1 Platform + Q_UNUSED(iso); + emit error(QCamera::NotSupportedFeatureError, tr("Setting manual iso sensitivity is not supported.")); +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::setAutoIsoSensitivity() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + TRAPD(err, m_advancedSettings->SetISORateL(CCamera::CCameraAdvancedSettings::EISOAutoUnPrioritised, 0)); + if (err) + emit error(QCamera::CameraError, tr("Setting auto iso sensitivity failed.")); + return; + } + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); +#else // S60 3.1 Platform + emit error(QCamera::NotSupportedFeatureError, tr("Setting auto iso sensitivity is not supported.")); +#endif // POST_31_PLATFORM +} + +qreal S60CameraSettings::aperture() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) + return qreal(m_advancedSettings->Aperture()) / KSymbianFineResolutionFactor; + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + return 0; +#else // S60 3.1 Platform + return 0; +#endif // POST_31_PLATFORM +} + +QList S60CameraSettings::supportedApertures() +{ + QList apertures; + +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + RArray supportedApertures; + TValueInfo info = ENotActive; + + TRAPD(err, m_advancedSettings->GetAperturesL(supportedApertures, info)); + if (err != KErrNone) + if (err != KErrNotSupported) + emit error(QCamera::CameraError, tr("Failure while querying supported apertures.")); + else { + for (int i = 0; i < supportedApertures.Count(); i++) { + qreal q = qreal(supportedApertures[i]) / KSymbianFineResolutionFactor; + apertures.append(q); + } + } + supportedApertures.Close(); + } + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + return apertures; +#else // S60 3.1 Platform + return apertures; +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::setManualAperture(qreal aperture) +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + int symbianAperture = (aperture * KSymbianFineResolutionFactor); // KSymbianFineResolutionFactor = 100 + m_advancedSettings->SetAperture(symbianAperture); + } + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); +#else // S60 3.1 + Q_UNUSED(aperture); + emit error(QCamera::NotSupportedFeatureError, tr("Setting manual aperture is not supported.")); +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::lockExposure(bool lock) +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + m_advancedSettings->SetExposureLockOn(lock); + return; + } + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); +#else // S60 3.1 + Q_UNUSED(lock); + emit error(QCamera::NotSupportedFeatureError, tr("Locking exposure is not supported.")); +#endif // POST_31_PLATFORM +} + +bool S60CameraSettings::isExposureLocked() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) + return m_advancedSettings->ExposureLockOn(); + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); +#endif // POST_31_PLATFORM + return false; +} + +qreal S60CameraSettings::shutterSpeed() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + qreal shutterSpeed = qreal(m_advancedSettings->ShutterSpeed()) / 1000000.0; + return shutterSpeed; // In seconds + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } + return 0; +#else // S60 3.1 Platform + return 0; +#endif // POST_31_PLATFORM +} + +QList S60CameraSettings::supportedShutterSpeeds() +{ + QList speeds; + +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + RArray supportedSpeeds; + TValueInfo info = ENotActive; + + TRAPD(err, m_advancedSettings->GetShutterSpeedsL(supportedSpeeds, info)); + if (err != KErrNone) + if (err != KErrNotSupported) + emit error(QCamera::CameraError, tr("Failure while querying supported shutter speeds.")); + else { + for (int i = 0; i < supportedSpeeds.Count(); i++) { + qreal q = qreal(supportedSpeeds[i]) / 1000000.0; + speeds.append(q); // In seconds + } + } + supportedSpeeds.Close(); + } + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + return speeds; +#else // S60 3.1 Platform + return speeds; +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::setManualShutterSpeed(qreal speed) +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + TInt shutterSpeed = speed * 1000000; // From seconds to microseconds + m_advancedSettings->SetShutterSpeed(shutterSpeed); + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } +#else // S60 3.1 + emit error(QCamera::NotSupportedFeatureError, tr("Setting manual shutter speed is not supported.")); + Q_UNUSED(speed); +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::setExposureCompensation(qreal ev) +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + TInt evStep = ev * KSymbianFineResolutionFactor; + m_advancedSettings->SetExposureCompensationStep(evStep); + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } +#else // S60 3.1 Platform + Q_UNUSED(ev); + emit error(QCamera::NotSupportedFeatureError, tr("Setting exposure compensation is not supported.")); +#endif // POST_31_PLATFORM +} + +qreal S60CameraSettings::exposureCompensation() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + TInt evStepSymbian = 0; + m_advancedSettings->GetExposureCompensationStep(evStepSymbian); + qreal evStep = evStepSymbian; + evStep /= KSymbianFineResolutionFactor; + return evStep; + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } + return 0; +#else // S60 3.1 Platform + return 0; +#endif // POST_31_PLATFORM +} + +QList S60CameraSettings::supportedExposureCompensationValues() +{ + QList valueList; + +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + RArray evSteps; + TValueInfo info; + TRAPD(err, m_advancedSettings->GetExposureCompensationStepsL(evSteps, info)); + if (err) { + if (err != KErrNotSupported) + emit error(QCamera::CameraError, tr("Failure while querying supported exposure compensation values.")); + return valueList; + } + + if (info == ENotActive || evSteps.Count() == 0) { + // EV not supported, return empty list + return valueList; + } + + for (int i = 0; i < evSteps.Count(); ++i) { + qreal appendValue = evSteps[i]; + appendValue /= KSymbianFineResolutionFactor; + valueList.append(appendValue); + } + } + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + return valueList; +#else // S60 3.1 Platform + return valueList; +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::setSharpeningLevel(int value) +{ +#ifdef POST_31_PLATFORM + if (m_imageProcessingSettings && isSharpeningSupported()) + m_imageProcessingSettings->SetTransformationValue(KUidECamEventImageProcessingAdjustSharpness, value); + else + emit error(QCamera::NotSupportedFeatureError, tr("Setting sharpening level is not supported.")); +#else // S60 3.1 + Q_UNUSED(value); + emit error(QCamera::NotSupportedFeatureError, tr("Setting sharpening level is not supported.")); +#endif // POST_31_PLATFORM +} + +bool S60CameraSettings::isSharpeningSupported() const +{ +#ifdef POST_31_PLATFORM + if (m_imageProcessingSettings) { + RArray suppTransforms; + TRAPD(err, m_imageProcessingSettings->GetSupportedTransformationsL(suppTransforms)); + if (err) + return false; + + if (suppTransforms.Find(KUidECamEventImageProcessingAdjustSharpness)) + return true; + } + return false; +#else // S60 3.1 Platform + return false; +#endif // POST_31_PLATFORM +} + +int S60CameraSettings::sharpeningLevel() const +{ +#ifdef POST_31_PLATFORM + if (m_imageProcessingSettings && isSharpeningSupported()) + return m_imageProcessingSettings->TransformationValue(KUidECamEventImageProcessingAdjustSharpness); + else + return 0; +#else // S60 3.1 Platform + return 0; +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::setSaturation(int value) +{ +#ifdef POST_31_PLATFORM + if (m_imageProcessingSettings) { + RArray suppTransforms; + TRAPD(err, m_imageProcessingSettings->GetSupportedTransformationsL(suppTransforms)); + if (err) + if (err != KErrNotSupported) + emit error(QCamera::CameraError, tr("Failure while querying supported transformations.")); + + if (suppTransforms.Find(KUidECamEventtImageProcessingAdjustSaturation)) + m_imageProcessingSettings->SetTransformationValue(KUidECamEventtImageProcessingAdjustSaturation, value == -1 ? 0 : value*2-100); + else + emit error(QCamera::NotSupportedFeatureError, tr("Setting saturation is not supported.")); + } + else + emit error(QCamera::NotSupportedFeatureError, tr("Setting saturation is not supported.")); +#else // S60 3.1 + Q_UNUSED(value); + emit error(QCamera::NotSupportedFeatureError, tr("Setting saturation is not supported.")); +#endif // POST_31_PLATFORM +} + +int S60CameraSettings::saturation() +{ +#ifdef POST_31_PLATFORM + if (m_imageProcessingSettings) { + RArray suppTransforms; + TRAPD(err, m_imageProcessingSettings->GetSupportedTransformationsL(suppTransforms)); + if (err) + if (err != KErrNotSupported) + emit error(QCamera::CameraError, tr("Failure while querying supported transformations.")); + + if (suppTransforms.Find(KUidECamEventtImageProcessingAdjustSaturation)) + return m_imageProcessingSettings->TransformationValue(KUidECamEventtImageProcessingAdjustSaturation); + } + return 0; +#else // S60 3.1 Platform + return 0; +#endif // POST_31_PLATFORM +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60camerasettings.h b/src/plugins/symbian/ecam/s60camerasettings.h new file mode 100644 index 000000000..4ecb131b2 --- /dev/null +++ b/src/plugins/symbian/ecam/s60camerasettings.h @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60CAMERASETTINGS_H +#define S60CAMERASETTINGS_H + +#include "qcamera.h" + +#include "s60cameraengine.h" +#include "s60cameraengineobserver.h" + +#include + +QT_USE_NAMESPACE + +/* + * Class handling CCamera AdvancedSettings and ImageProcessing operations. + */ +class S60CameraSettings : public QObject, + public MAdvancedSettingsObserver +{ + Q_OBJECT + +public: // Static Contructor & Destructor + + static S60CameraSettings* New(int &error, QObject *parent = 0, CCameraEngine *engine = 0); + ~S60CameraSettings(); + +public: // Methods + + // Focus + QCameraFocus::FocusMode focusMode(); + void setFocusMode(QCameraFocus::FocusMode mode); + QCameraFocus::FocusModes supportedFocusModes(); + void startFocusing(); + void cancelFocusing(); + + // Zoom + qreal opticalZoomFactorL() const; + void setOpticalZoomFactorL(const qreal zoomFactor); + QList supportedDigitalZoomFactors() const; + qreal digitalZoomFactorL() const; + void setDigitalZoomFactorL(const qreal zoomFactor); + + // Flash + bool isFlashReady(); + + // Exposure + void setExposureMode(QCameraExposure::ExposureMode mode); + void lockExposure(bool lock); + bool isExposureLocked(); + + // Metering Mode + QCameraExposure::MeteringMode meteringMode(); + void setMeteringMode(QCameraExposure::MeteringMode mode); + bool isMeteringModeSupported(QCameraExposure::MeteringMode mode); + + // ISO Sensitivity + int isoSensitivity(); + void setManualIsoSensitivity(int iso); + void setAutoIsoSensitivity(); + QList supportedIsoSensitivities(); + + // Aperture + qreal aperture(); + void setManualAperture(qreal aperture); + QList supportedApertures(); + + // Shutter Speed + qreal shutterSpeed(); + void setManualShutterSpeed(qreal speed); + QList supportedShutterSpeeds(); + + // ExposureCompensation + qreal exposureCompensation(); + void setExposureCompensation(qreal ev); + QList supportedExposureCompensationValues(); + + // Sharpening Level + int sharpeningLevel() const; + void setSharpeningLevel(int value); + bool isSharpeningSupported() const; + + // Saturation + int saturation(); + void setSaturation(int value); + +signals: // Notifications + + // For QCameraExposureControl + void flashReady(bool ready); + void apertureChanged(); + void apertureRangeChanged(); + void shutterSpeedChanged(); + void isoSensitivityChanged(); + void evChanged(); + + // For QCameraLocksControl + void exposureStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason); + void focusStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason); + + // Errors + void error(int, const QString&); + +protected: // Protected constructors + + S60CameraSettings(QObject *parent, CCameraEngine *engine); + void ConstructL(); + +protected: // MAdvancedSettingsObserver + + void HandleAdvancedEvent(const TECAMEvent& aEvent); + +private: // Internal + + bool queryAdvancedSettingsInfo(); + +private: // Enums + + enum EcamErrors { + KErrECamCameraDisabled = -12100, // The camera has been disabled, hence calls do not succeed + KErrECamSettingDisabled = -12101, // This parameter or operation is supported, but presently is disabled. + KErrECamParameterNotInRange = -12102, // This value is out of range. + KErrECamSettingNotSupported = -12103, // This parameter or operation is not supported. + KErrECamNotOptimalFocus = -12104 // The optimum focus is lost + }; + +private: // Data + +#ifndef S60_31_PLATFORM // Post S60 3.1 Platforms + CCamera::CCameraAdvancedSettings *m_advancedSettings; + CCamera::CCameraImageProcessing *m_imageProcessingSettings; +#endif // S60_31_PLATFORM + CCameraEngine *m_cameraEngine; + QList m_supportedSymbianDigitalZoomFactors; + bool m_continuousFocusing; +}; + +#endif // S60CAMERASETTINGS_H diff --git a/src/plugins/symbian/ecam/s60cameraviewfinderengine.cpp b/src/plugins/symbian/ecam/s60cameraviewfinderengine.cpp new file mode 100644 index 000000000..55d7cbc67 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraviewfinderengine.cpp @@ -0,0 +1,789 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "s60cameraviewfinderengine.h" +#include "s60cameraengine.h" +#include "s60cameracontrol.h" +#include "s60videowidgetcontrol.h" +#include "s60videowidgetdisplay.h" +#include "s60videorenderercontrol.h" +#include "s60videowindowcontrol.h" +#include "s60videowindowdisplay.h" +#include "s60cameraconstants.h" + +#include // CCoeEnv +#include // CCoeControl +#include + +// Helper function +TRect qRect2TRect(const QRect &qr) +{ + return TRect(TPoint(qr.left(), qr.top()), TSize(qr.width(), qr.height())); +} + + +S60CameraViewfinderEngine::S60CameraViewfinderEngine(S60CameraControl *control, + CCameraEngine *engine, + QObject *parent): + QObject(parent), + m_cameraEngine(engine), + m_cameraControl(0), + m_viewfinderOutput(0), + m_viewfinderDisplay(0), + m_viewfinderSurface(0), + m_wsSession(CCoeEnv::Static()->WsSession()), + m_screenDevice(*CCoeEnv::Static()->ScreenDevice()), + m_window(0), + m_desktopWidget(0), + m_vfState(EVFNotConnectedNotStarted), + m_viewfinderSize(KDefaultViewfinderSize), + m_actualViewFinderSize(KDefaultViewfinderSize), + m_viewfinderAspectRatio(0.0), + m_viewfinderType(OutputTypeNotSet), + m_viewfinderNativeType(EBitmapViewFinder), // Default type + m_isViewFinderVisible(true), // True by default (only QVideoWidgetControl supports being hidden) + m_uiLandscape(true), + m_vfErrorsSignalled(0) +{ + m_cameraControl = control; + + // Check whether platform supports DirectScreen ViewFinder + if (m_cameraEngine) { + if (m_cameraEngine->IsDirectViewFinderSupported()) + m_viewfinderNativeType = EDirectScreenViewFinder; + else + m_viewfinderNativeType = EBitmapViewFinder; + + MCameraViewfinderObserver *vfObserver = this; + m_cameraEngine->SetViewfinderObserver(vfObserver); + } + else + m_cameraControl->setError(KErrGeneral, tr("Unexpected camera error.")); + // From now on it is safe to assume engine exists + + // Check the UI orientation + QDesktopWidget* desktopWidget = QApplication::desktop(); + QRect screenRect = desktopWidget->screenGeometry(); + if (screenRect.width() > screenRect.height()) + m_uiLandscape = true; + else + m_uiLandscape = false; + + // Detect UI Rotations + m_desktopWidget = QApplication::desktop(); + if (m_desktopWidget) + connect(m_desktopWidget, SIGNAL(resized(int)), this, SLOT(handleDesktopResize(int))); +} + +S60CameraViewfinderEngine::~S60CameraViewfinderEngine() +{ + // No need to stop viewfinder: + // Engine has stopped it already + // Surface will be stopped by VideoRendererControl + + m_viewfinderOutput = 0; + m_viewfinderSurface = 0; +} + +void S60CameraViewfinderEngine::setNewCameraEngine(CCameraEngine *engine) +{ + m_cameraEngine = engine; + + if (m_cameraEngine) { + // And set observer to the new CameraEngine + MCameraViewfinderObserver *vfObserver = this; + m_cameraEngine->SetViewfinderObserver(vfObserver); + } +} + +void S60CameraViewfinderEngine::handleDesktopResize(int screen) +{ + Q_UNUSED(screen); + // UI Rotation is handled by the QVideoWidgetControl, thus this is needed + // only for the QVideoRendererControl + if (m_viewfinderType == OutputTypeRenderer) { + QSize newResolution(-1,-1); + if (m_viewfinderSurface) + newResolution = m_viewfinderSurface->nativeResolution(); + + if (newResolution.width() == -1 || newResolution.height() == -1) { + QDesktopWidget* desktopWidget = QApplication::desktop(); + QRect screenRect = desktopWidget->screenGeometry(); + newResolution = QSize(screenRect.width(), screenRect.height()); + } + + resetViewfinderSize(newResolution); + } + + // Rotate Camera if UI has rotated + checkAndRotateCamera(); +} + +void S60CameraViewfinderEngine::setVideoWidgetControl(QObject *viewfinderOutput) +{ + // Release old control if it has not already been done + if (m_viewfinderOutput) + releaseControl(m_viewfinderType); + + // Rotate Camera if UI has rotated + checkAndRotateCamera(); + + S60VideoWidgetControl* viewFinderWidgetControl = + qobject_cast(viewfinderOutput); + + if (viewFinderWidgetControl) { + // Check whether platform supports DirectScreen ViewFinder + if (m_cameraEngine) { + if (m_cameraEngine->IsDirectViewFinderSupported()) + m_viewfinderNativeType = EDirectScreenViewFinder; + else + m_viewfinderNativeType = EBitmapViewFinder; + } + else + return; + + m_viewfinderDisplay = viewFinderWidgetControl->display(); + + if (m_viewfinderNativeType == EDirectScreenViewFinder) { + m_viewfinderDisplay->setPaintingEnabled(false); // No Qt Painter painting - Direct rendering + connect(m_viewfinderDisplay, SIGNAL(windowHandleChanged(RWindow *)), this, SLOT(resetViewfinderDisplay())); + } else { + m_viewfinderDisplay->setPaintingEnabled(true); // Qt Painter painting - Bitmap rendering + connect(this, SIGNAL(viewFinderFrameReady(const CFbsBitmap &)), m_viewfinderDisplay, SLOT(setFrame(const CFbsBitmap &))); + } + + connect(m_viewfinderDisplay, SIGNAL(visibilityChanged(bool)), this, SLOT(handleVisibilityChange(bool))); + connect(m_viewfinderDisplay, SIGNAL(displayRectChanged(QRect, QRect)), this, SLOT(resetVideoWindowSize())); + connect(m_viewfinderDisplay, SIGNAL(windowHandleChanged(RWindow*)), this, SLOT(handleWindowChange(RWindow*))); + + m_viewfinderSize = m_viewfinderDisplay->extentRect().size(); + m_viewfinderOutput = viewfinderOutput; + m_viewfinderType = OutputTypeVideoWidget; + m_isViewFinderVisible = m_viewfinderDisplay->isVisible(); + + switch (m_vfState) { + case EVFNotConnectedNotStarted: + m_vfState = EVFIsConnectedNotStarted; + break; + case EVFNotConnectedIsStarted: + if (m_isViewFinderVisible) + m_vfState = EVFIsConnectedIsStartedIsVisible; + else + m_vfState = EVFIsConnectedIsStartedNotVisible; + break; + case EVFIsConnectedNotStarted: + case EVFIsConnectedIsStartedNotVisible: + case EVFIsConnectedIsStartedIsVisible: + // Already connected, state does not change + break; + default: + emit error(QCamera::CameraError, tr("General viewfinder error.")); + break; + } + + if (m_vfState == EVFIsConnectedIsStartedIsVisible) + startViewfinder(true); // Internal start (i.e. start if started externally) + } +} + +void S60CameraViewfinderEngine::setVideoRendererControl(QObject *viewfinderOutput) +{ + // Release old control if it has not already been done + if (m_viewfinderOutput) + releaseControl(m_viewfinderType); + + // Rotate Camera if UI has rotated + checkAndRotateCamera(); + + S60VideoRendererControl* viewFinderRenderControl = + qobject_cast(viewfinderOutput); + + if (viewFinderRenderControl) { + m_viewfinderNativeType = EBitmapViewFinder; // Always Bitmap + + connect(viewFinderRenderControl, SIGNAL(viewFinderSurfaceSet()), + this, SLOT(rendererSurfaceSet())); + + Q_ASSERT(!viewFinderRenderControl->surface()); + m_viewfinderOutput = viewfinderOutput; + m_viewfinderType = OutputTypeRenderer; + // RendererControl viewfinder is "visible" when surface is set + m_isViewFinderVisible = false; + if (EVFIsConnectedIsStartedIsVisible) + m_vfState = EVFIsConnectedIsStartedNotVisible; + + // Use display resolution as default viewfinder resolution + m_viewfinderSize = QApplication::desktop()->screenGeometry().size(); + + switch (m_vfState) { + case EVFNotConnectedNotStarted: + m_vfState = EVFIsConnectedNotStarted; + break; + case EVFNotConnectedIsStarted: + m_vfState = EVFIsConnectedIsStartedIsVisible; // GraphicsItem "always visible" (FrameWork decides to draw/not draw) + break; + case EVFIsConnectedNotStarted: + case EVFIsConnectedIsStartedNotVisible: + case EVFIsConnectedIsStartedIsVisible: + // Already connected, state does not change + break; + default: + emit error(QCamera::CameraError, tr("General viewfinder error.")); + break; + } + + if (m_vfState == EVFIsConnectedIsStartedIsVisible) + startViewfinder(true); + } +} + +void S60CameraViewfinderEngine::setVideoWindowControl(QObject *viewfinderOutput) +{ + // Release old control if it has not already been done + if (m_viewfinderOutput) + releaseControl(m_viewfinderType); + + // Rotate Camera if UI has rotated + checkAndRotateCamera(); + + S60VideoWindowControl* viewFinderWindowControl = + qobject_cast(viewfinderOutput); + + if (viewFinderWindowControl) { + // Check whether platform supports DirectScreen ViewFinder + if (m_cameraEngine) { + if (m_cameraEngine->IsDirectViewFinderSupported()) + m_viewfinderNativeType = EDirectScreenViewFinder; + else + m_viewfinderNativeType = EBitmapViewFinder; + } else { + return; + } + + m_viewfinderDisplay = viewFinderWindowControl->display(); + + if (m_viewfinderNativeType == EDirectScreenViewFinder) { + m_viewfinderDisplay->setPaintingEnabled(false); // No Qt Painter painting - Direct rendering + connect(m_viewfinderDisplay, SIGNAL(windowHandleChanged(RWindow *)), this, SLOT(resetViewfinderDisplay())); + } else { + m_viewfinderDisplay->setPaintingEnabled(true); // Qt Painter painting - Bitmap rendering + connect(this, SIGNAL(viewFinderFrameReady(const CFbsBitmap &)), m_viewfinderDisplay, SLOT(setFrame(const CFbsBitmap &))); + } + + connect(m_viewfinderDisplay, SIGNAL(displayRectChanged(QRect, QRect)), this, SLOT(resetVideoWindowSize())); + connect(m_viewfinderDisplay, SIGNAL(visibilityChanged(bool)), this, SLOT(handleVisibilityChange(bool))); + connect(m_viewfinderDisplay, SIGNAL(windowHandleChanged(RWindow*)), this, SLOT(handleWindowChange(RWindow*))); + + m_viewfinderSize = m_viewfinderDisplay->extentRect().size(); + m_viewfinderOutput = viewfinderOutput; + m_viewfinderType = OutputTypeVideoWindow; + m_isViewFinderVisible = m_viewfinderDisplay->isVisible(); + + switch (m_vfState) { + case EVFNotConnectedNotStarted: + m_vfState = EVFIsConnectedNotStarted; + break; + case EVFNotConnectedIsStarted: + if (m_isViewFinderVisible) + m_vfState = EVFIsConnectedIsStartedIsVisible; + else + m_vfState = EVFIsConnectedIsStartedNotVisible; + break; + case EVFIsConnectedNotStarted: + case EVFIsConnectedIsStartedNotVisible: + case EVFIsConnectedIsStartedIsVisible: + // Already connected, state does not change + break; + default: + emit error(QCamera::CameraError, tr("General viewfinder error.")); + break; + } + + if (m_vfState == EVFIsConnectedIsStartedIsVisible) + startViewfinder(true); // Internal start (i.e. start if started externally) + } +} + +void S60CameraViewfinderEngine::releaseControl(ViewfinderOutputType type) +{ + if (m_vfState == EVFIsConnectedIsStartedIsVisible) + stopViewfinder(true); + + if (m_viewfinderOutput) { + switch (type) { + case OutputTypeNotSet: + return; + case OutputTypeVideoWidget: + if (m_viewfinderType != OutputTypeVideoWidget) + return; + disconnect(m_viewfinderOutput); + m_viewfinderOutput->disconnect(this); + Q_ASSERT(m_viewfinderDisplay); + disconnect(m_viewfinderDisplay); + m_viewfinderDisplay->disconnect(this); + m_viewfinderDisplay = 0; + // Invalidate the extent rect + qobject_cast(m_viewfinderOutput)->setExtentRect(QRect()); + break; + case OutputTypeVideoWindow: + if (m_viewfinderType != OutputTypeVideoWindow) + return; + disconnect(m_viewfinderOutput); + m_viewfinderOutput->disconnect(this); + Q_ASSERT(m_viewfinderDisplay); + disconnect(m_viewfinderDisplay); + m_viewfinderDisplay->disconnect(this); + m_viewfinderDisplay = 0; + break; + case OutputTypeRenderer: + if (m_viewfinderType != OutputTypeRenderer) + return; + disconnect(m_viewfinderOutput); + m_viewfinderOutput->disconnect(this); + if (m_viewfinderSurface) + m_viewfinderSurface->disconnect(this); + disconnect(this, SIGNAL(viewFinderFrameReady(const CFbsBitmap &)), + this, SLOT(viewFinderBitmapReady(const CFbsBitmap &))); + break; + default: + emit error(QCamera::CameraError, tr("Unexpected viewfinder error.")); + return; + } + } + + Q_ASSERT(!m_viewfinderDisplay); + m_viewfinderOutput = 0; + m_viewfinderType = OutputTypeNotSet; + + // Update state + switch (m_vfState) { + case EVFNotConnectedNotStarted: + case EVFNotConnectedIsStarted: + // Do nothing + break; + case EVFIsConnectedNotStarted: + m_vfState = EVFNotConnectedNotStarted; + break; + case EVFIsConnectedIsStartedNotVisible: + case EVFIsConnectedIsStartedIsVisible: + m_vfState = EVFNotConnectedIsStarted; + break; + default: + emit error(QCamera::CameraError, tr("General viewfinder error.")); + break; + } +} + +void S60CameraViewfinderEngine::startViewfinder(const bool internalStart) +{ + if (!internalStart) { + switch (m_vfState) { + case EVFNotConnectedNotStarted: + m_vfState = EVFNotConnectedIsStarted; + break; + case EVFIsConnectedNotStarted: + if (m_isViewFinderVisible) + m_vfState = EVFIsConnectedIsStartedIsVisible; + else + m_vfState = EVFIsConnectedIsStartedNotVisible; + break; + case EVFNotConnectedIsStarted: + case EVFIsConnectedIsStartedNotVisible: + case EVFIsConnectedIsStartedIsVisible: + // Already started, state does not change + break; + default: + emit error(QCamera::CameraError, tr("General viewfinder error.")); + break; + } + } + + // Start viewfinder + if (m_vfState == EVFIsConnectedIsStartedIsVisible) { + + if (!m_cameraEngine) + return; + + if (m_viewfinderNativeType == EDirectScreenViewFinder) { + + if (RWindow *window = m_viewfinderDisplay ? m_viewfinderDisplay->windowHandle() : 0) { + m_window = window; + } else { + emit error(QCamera::CameraError, tr("Requesting window for viewfinder failed.")); + return; + } + + const QRect extentRect = m_viewfinderDisplay ? m_viewfinderDisplay->extentRect() : QRect(); + const QRect clipRect = m_viewfinderDisplay ? m_viewfinderDisplay->clipRect() : QRect(); + + TRect extentRectSymbian = qRect2TRect(extentRect); + TRect clipRectSymbian = qRect2TRect(clipRect); + TRAPD(err, m_cameraEngine->StartDirectViewFinderL(m_wsSession, m_screenDevice, *m_window, extentRectSymbian, clipRectSymbian)); + if (err) { + if (err == KErrNotSupported) { + emit error(QCamera::NotSupportedFeatureError, tr("Requested viewfinder size is not supported.")); + } else { + emit error(QCamera::CameraError, tr("Starting viewfinder failed.")); + } + return; + } + + m_actualViewFinderSize = QSize(extentRectSymbian.Size().iWidth, extentRectSymbian.Size().iHeight); + m_viewfinderAspectRatio = qreal(m_actualViewFinderSize.width()) / qreal(m_actualViewFinderSize.height()); + + } else { // Bitmap ViewFinder + TSize size = TSize(m_viewfinderSize.width(), m_viewfinderSize.height()); + + if( m_viewfinderType == OutputTypeRenderer && m_viewfinderSurface) { + if (!m_surfaceFormat.isValid()) { + emit error(QCamera::NotSupportedFeatureError, tr("Invalid surface format.")); + return; + } + + // Start rendering to surface with correct size and format + if (!m_viewfinderSurface->isFormatSupported(m_surfaceFormat) || + !m_viewfinderSurface->start(m_surfaceFormat)) { + emit error(QCamera::NotSupportedFeatureError, tr("Failed to start surface.")); + return; + } + + if (!m_viewfinderSurface->isActive()) + return; + } + + TRAPD(vfErr, m_cameraEngine->StartViewFinderL(size)); + if (vfErr) { + if (vfErr == KErrNotSupported) { + emit error(QCamera::NotSupportedFeatureError, tr("Requested viewfinder size is not supported.")); + } else { + emit error(QCamera::CameraError, tr("Starting viewfinder failed.")); + } + return; + } + + m_actualViewFinderSize = QSize(size.iWidth, size.iHeight); + m_viewfinderAspectRatio = qreal(m_actualViewFinderSize.width()) / qreal(m_actualViewFinderSize.height()); + + // Notify control about the frame size (triggers frame position calculation) + if (m_viewfinderDisplay) { + m_viewfinderDisplay->setNativeSize(m_actualViewFinderSize); + } else { + if (m_viewfinderType == OutputTypeRenderer && m_viewfinderSurface) { + m_viewfinderSurface->stop(); + QVideoSurfaceFormat format = m_viewfinderSurface->surfaceFormat(); + format.setFrameSize(QSize(m_actualViewFinderSize)); + format.setViewport(QRect(0, 0, m_actualViewFinderSize.width(), m_actualViewFinderSize.height())); + m_viewfinderSurface->start(format); + } + } + } + } +} + +void S60CameraViewfinderEngine::stopViewfinder(const bool internalStop) +{ + // Stop if viewfinder is started + if (m_vfState == EVFIsConnectedIsStartedIsVisible) { + if (m_viewfinderOutput && m_viewfinderType == OutputTypeRenderer && m_viewfinderSurface) { + // Stop surface if one still exists + m_viewfinderSurface->stop(); + } + + if (m_cameraEngine) + m_cameraEngine->StopViewFinder(); + } + + // Update state + if (!internalStop) { + switch (m_vfState) { + case EVFNotConnectedNotStarted: + case EVFIsConnectedNotStarted: + // Discard + break; + case EVFNotConnectedIsStarted: + m_vfState = EVFNotConnectedNotStarted; + break; + case EVFIsConnectedIsStartedNotVisible: + case EVFIsConnectedIsStartedIsVisible: + m_vfState = EVFIsConnectedNotStarted; + break; + default: + emit error(QCamera::CameraError, tr("General viewfinder error.")); + break; + } + } +} + +void S60CameraViewfinderEngine::MceoViewFinderFrameReady(CFbsBitmap& aFrame) +{ + emit viewFinderFrameReady(aFrame); + if (m_cameraEngine) + m_cameraEngine->ReleaseViewFinderBuffer(); +} + +void S60CameraViewfinderEngine::resetViewfinderSize(const QSize size) +{ + m_viewfinderSize = size; + + if(m_vfState != EVFIsConnectedIsStartedIsVisible) { + // Set native size to Window/Renderer Control + if (m_viewfinderDisplay) + m_viewfinderDisplay->setNativeSize(m_actualViewFinderSize); + return; + } + + stopViewfinder(true); + + startViewfinder(true); +} + +void S60CameraViewfinderEngine::resetVideoWindowSize() +{ + if (m_viewfinderDisplay) + resetViewfinderSize(m_viewfinderDisplay->extentRect().size()); +} + +void S60CameraViewfinderEngine::resetViewfinderDisplay() +{ + if (m_viewfinderNativeType == EDirectScreenViewFinder) { + + switch (m_viewfinderType) { + case OutputTypeVideoWidget: { + if (!m_viewfinderOutput) + return; + + // First stop viewfinder + stopViewfinder(true); + + RWindow *window = m_viewfinderDisplay->windowHandle(); + if (!window) { + return; + } + + // Then start it with the new WindowID + startViewfinder(true); + break; + } + case OutputTypeRenderer: + case OutputTypeVideoWindow: + // Do nothing + break; + + default: + // Not ViewFinder Output has been set, Discard + break; + } + } +} + +void S60CameraViewfinderEngine::rendererSurfaceSet() +{ + S60VideoRendererControl* viewFinderRenderControl = + qobject_cast(m_viewfinderOutput); + + // Reset old surface if needed + if (m_viewfinderSurface) { + handleVisibilityChange(false); + disconnect(m_viewfinderSurface); + if (viewFinderRenderControl->surface()) + stopViewfinder(true); // Temporary stop + else + stopViewfinder(); // Stop for good + m_viewfinderSize = QApplication::desktop()->screenGeometry().size(); + m_viewfinderSurface = 0; + } + + // Set new surface + m_viewfinderSurface = viewFinderRenderControl->surface(); + if (!m_viewfinderSurface) + return; + if (!m_viewfinderSurface->nativeResolution().isEmpty()) { + if (m_viewfinderSurface->nativeResolution() != m_viewfinderSize) + resetViewfinderSize(m_viewfinderSurface->nativeResolution()); + } + + connect(m_viewfinderSurface, SIGNAL(nativeResolutionChanged(const QSize&)), + this, SLOT(resetViewfinderSize(QSize))); + + // Set Surface Properties + if (m_viewfinderSurface->supportedPixelFormats().contains(QVideoFrame::Format_RGB32)) + m_surfaceFormat = QVideoSurfaceFormat(m_actualViewFinderSize, QVideoFrame::Format_RGB32); + else if (m_viewfinderSurface->supportedPixelFormats().contains(QVideoFrame::Format_ARGB32)) + m_surfaceFormat = QVideoSurfaceFormat(m_actualViewFinderSize, QVideoFrame::Format_ARGB32); + else { + return; + } + m_surfaceFormat.setFrameRate(KViewfinderFrameRate); + m_surfaceFormat.setYCbCrColorSpace(QVideoSurfaceFormat::YCbCr_Undefined); // EColor16MU (compatible with EColor16MA) + m_surfaceFormat.setPixelAspectRatio(1,1); // PAR 1:1 + + + connect(this, SIGNAL(viewFinderFrameReady(const CFbsBitmap &)), + this, SLOT(viewFinderBitmapReady(const CFbsBitmap &))); + + // Surface set, viewfinder is "visible" + handleVisibilityChange(true); +} + +void S60CameraViewfinderEngine::viewFinderBitmapReady(const CFbsBitmap &bitmap) +{ + CFbsBitmap *bitmapPtr = const_cast(&bitmap); + QPixmap pixmap = QPixmap::fromSymbianCFbsBitmap(bitmapPtr); + + QImage newImage = pixmap.toImage(); + if (newImage.format() != QImage::Format_ARGB32 && + newImage.format() != QImage::Format_RGB32) { + newImage = newImage.convertToFormat(QImage::Format_RGB32); + } + + if (!newImage.isNull()) { + QVideoFrame newFrame(newImage); + if (newFrame.isValid()) { + if (!m_viewfinderSurface->present(newFrame)) { + // Presenting may fail even if there are no errors (e.g. busy) + if (m_viewfinderSurface->error()) { + if (m_vfErrorsSignalled < KMaxVFErrorsSignalled) { + emit error(QCamera::CameraError, tr("Presenting viewfinder frame failed.")); + ++m_vfErrorsSignalled; + } + } + } + } else { + if (m_vfErrorsSignalled < KMaxVFErrorsSignalled) { + emit error(QCamera::CameraError, tr("Invalid viewfinder frame was received.")); + ++m_vfErrorsSignalled; + } + } + + } else { + if (m_vfErrorsSignalled < KMaxVFErrorsSignalled) { + emit error(QCamera::CameraError, tr("Failed to convert viewfinder frame to presentable image.")); + ++m_vfErrorsSignalled; + } + } +} + +void S60CameraViewfinderEngine::handleVisibilityChange(const bool isVisible) +{ + if (m_isViewFinderVisible == isVisible) + return; + + m_isViewFinderVisible = isVisible; + + if (m_isViewFinderVisible) { + switch (m_vfState) { + case EVFNotConnectedNotStarted: + case EVFIsConnectedNotStarted: + case EVFNotConnectedIsStarted: + case EVFIsConnectedIsStartedIsVisible: + // Discard + break; + case EVFIsConnectedIsStartedNotVisible: + m_vfState = EVFIsConnectedIsStartedIsVisible; + break; + default: + emit error(QCamera::CameraError, tr("General viewfinder error.")); + break; + } + startViewfinder(true); + } else { + // Stopping takes care of the state change + stopViewfinder(true); + } +} + +void S60CameraViewfinderEngine::handleWindowChange(RWindow *handle) +{ + stopViewfinder(true); + + if (handle) // New handle available, start viewfinder + startViewfinder(true); +} + +void S60CameraViewfinderEngine::checkAndRotateCamera() +{ + bool isUiNowLandscape = false; + QDesktopWidget* desktopWidget = QApplication::desktop(); + QRect screenRect = desktopWidget->screenGeometry(); + + if (screenRect.width() > screenRect.height()) + isUiNowLandscape = true; + else + isUiNowLandscape = false; + + // Rotate camera if possible + if (isUiNowLandscape != m_uiLandscape) { + stopViewfinder(true); + + // Request orientation reset + m_cameraControl->resetCameraOrientation(); + } + m_uiLandscape = isUiNowLandscape; +} + +void S60CameraViewfinderEngine::handleContentAspectRatioChange(const QSize& newSize) +{ + qreal newAspectRatio = qreal(newSize.width()) / qreal(newSize.height()); + // Check if aspect ratio changed + if (qFuzzyCompare(newAspectRatio, m_viewfinderAspectRatio)) + return; + + // Resize viewfinder by reducing either width or height to comply with the new aspect ratio + QSize newNativeResolution; + if (newAspectRatio > m_viewfinderAspectRatio) { // New AspectRatio is wider => Reduce height + newNativeResolution = QSize(m_actualViewFinderSize.width(), (m_actualViewFinderSize.width() / newAspectRatio)); + } else { // New AspectRatio is higher => Reduce width + newNativeResolution = QSize((m_actualViewFinderSize.height() * newAspectRatio), m_actualViewFinderSize.height()); + } + + // Notify aspect ratio change (use actual content size to notify that) + // This triggers item size/position re-calculation + if (m_viewfinderDisplay) + m_viewfinderDisplay->setNativeSize(newNativeResolution); +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60cameraviewfinderengine.h b/src/plugins/symbian/ecam/s60cameraviewfinderengine.h new file mode 100644 index 000000000..c5df760d9 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraviewfinderengine.h @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef S60CAMERAVIEWFINDERENGINE_H +#define S60CAMERAVIEWFINDERENGINE_H + +#include +#include + +#include + +#include "s60cameraengineobserver.h" + +class CCameraEngine; +class S60CameraControl; +class QAbstractVideoSurface; + +// For DirectScreen ViewFinder +class RWsSession; +class CWsScreenDevice; +class RWindowBase; +class RWindow; +class QDesktopWidget; + +class S60VideoDisplay; + +/* + * Class implementing video output selection for the viewfinder and the handler of + * all common viewfinder operations. + */ +class S60CameraViewfinderEngine : public QObject, public MCameraViewfinderObserver +{ + Q_OBJECT + +public: // Enums + + /* + * Defines whether viewfinder output backend control is of type + * QVideoWidgetControl, QVideoRendererControl or QVideoWindowControl + */ + enum ViewfinderOutputType { + OutputTypeNotSet = 0, // No viewfinder output connected + OutputTypeVideoWidget, // Using QVideoWidget + OutputTypeRenderer, // (Using QGraphicsVideoItem with) QVideoRendererControl + OutputTypeVideoWindow // Using QGraphicsVideoItem with QVideoWindow + }; + +public: // Constructor & Destructor + + S60CameraViewfinderEngine(S60CameraControl *control, + CCameraEngine *engine, + QObject *parent = 0); + ~S60CameraViewfinderEngine(); + +public: // Methods + + // Setting Viewfinder Output + void setVideoWidgetControl(QObject *viewfinderOutput); + void setVideoRendererControl(QObject *viewfinderOutput); + void setVideoWindowControl(QObject *viewfinderOutput); + void releaseControl(ViewfinderOutputType type); + + // Controls + void startViewfinder(const bool internalStart = false); + void stopViewfinder(const bool internalStop = false); + + // Start using new CameraEngine + void setNewCameraEngine(CCameraEngine *engine); + +protected: // MCameraViewfinderObserver + + void MceoViewFinderFrameReady(CFbsBitmap& aFrame); + +private: // Internal operation + + void checkAndRotateCamera(); + +signals: + + void error(int error, const QString &errorString); + void viewFinderFrameReady(const CFbsBitmap &bitmap); + +private slots: + + void resetViewfinderSize(const QSize size); + void resetVideoWindowSize(); + void resetViewfinderDisplay(); + void viewFinderBitmapReady(const CFbsBitmap &bitmap); + void handleVisibilityChange(const bool isVisible); + void handleWindowChange(RWindow *handle); + void handleDesktopResize(int screen); + void handleContentAspectRatioChange(const QSize& newSize); + void rendererSurfaceSet(); + +private: // Enums + + /* + * Defines the internal state of the viewfinder. ViewFinder will only be + * started if output is connected to Camera and Camera is started (and + * ViewFinder widget is visible in case of QVideoWidget). + */ + enum ViewFinderState { + EVFNotConnectedNotStarted = 0, // 0 - No output connected, viewfinder is not started + EVFNotConnectedIsStarted, // 1 - No output connected, viewfinder is started + EVFIsConnectedNotStarted, // 2 - Output is connected, viewfinder is not started + EVFIsConnectedIsStartedNotVisible, // 3 - Output is connected, viewfinder is started but is not visible + EVFIsConnectedIsStartedIsVisible // 4 - Output is connected, viewfinder is started and is visible + }; + + /* + * The native type of ViewFinder. DirectScreen ViewFinder is used with + * QVideoWidget if support for it is available in the platform. For + * QGraphicsVideoItem Bitmap ViewFinder is always used. + */ + enum NativeViewFinderType { + EBitmapViewFinder = 0, + EDirectScreenViewFinder + }; + +private: // Data + + CCameraEngine *m_cameraEngine; + S60CameraControl *m_cameraControl; + QObject *m_viewfinderOutput; + S60VideoDisplay *m_viewfinderDisplay; + QAbstractVideoSurface *m_viewfinderSurface; // Used only by QVideoRendererControl + RWsSession &m_wsSession; + CWsScreenDevice &m_screenDevice; + RWindowBase *m_window; + QDesktopWidget *m_desktopWidget; + ViewFinderState m_vfState; + QSize m_viewfinderSize; + // Actual viewfinder size, which may differ from requested + // (m_viewfinderSize), if the size/aspect ratio was not supported. + QSize m_actualViewFinderSize; + qreal m_viewfinderAspectRatio; + ViewfinderOutputType m_viewfinderType; + NativeViewFinderType m_viewfinderNativeType; + QVideoSurfaceFormat m_surfaceFormat; // Used only by QVideoRendererControl + bool m_isViewFinderVisible; + bool m_uiLandscape; // For detecting UI rotation + int m_vfErrorsSignalled; +}; + +#endif // S60CAMERAVIEWFINDERENGINE_H diff --git a/src/plugins/symbian/ecam/s60imagecapturesession.cpp b/src/plugins/symbian/ecam/s60imagecapturesession.cpp new file mode 100644 index 000000000..16d240c7b --- /dev/null +++ b/src/plugins/symbian/ecam/s60imagecapturesession.cpp @@ -0,0 +1,1884 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "s60imagecapturesession.h" +#include "s60videowidgetcontrol.h" +#include "s60cameraservice.h" +#include "s60cameraconstants.h" + +#include // CFbsBitmap +#include +#include // ICL Decoder (for SnapShot) & Encoder (for Bitmap Images) + +S60ImageCaptureDecoder::S60ImageCaptureDecoder(S60ImageCaptureSession *imageSession, + RFs *fileSystemAccess, + const TDesC8 *data, + const TDesC16 *fileName) : + CActive(CActive::EPriorityStandard), + m_imageSession(imageSession), + m_fs(fileSystemAccess), + m_jpegImageData(data), + m_jpegImageFile(fileName), + m_fileInput(false) +{ + CActiveScheduler::Add(this); +} + +S60ImageCaptureDecoder::~S60ImageCaptureDecoder() +{ + if (m_imageDecoder) { + delete m_imageDecoder; + m_imageDecoder = 0; + } +} + +S60ImageCaptureDecoder *S60ImageCaptureDecoder::FileNewL(S60ImageCaptureSession *imageSession, + RFs *fileSystemAccess, + const TDesC16 *fileName) +{ + S60ImageCaptureDecoder* self = new (ELeave) S60ImageCaptureDecoder(imageSession, + fileSystemAccess, + 0, + fileName); + CleanupStack::PushL(self); + self->ConstructL(true); + CleanupStack::Pop(self); + return self; +} + +S60ImageCaptureDecoder *S60ImageCaptureDecoder::DataNewL(S60ImageCaptureSession *imageSession, + RFs *fileSystemAccess, + const TDesC8 *data) +{ + S60ImageCaptureDecoder* self = new (ELeave) S60ImageCaptureDecoder(imageSession, + fileSystemAccess, + data, + 0); + CleanupStack::PushL(self); + self->ConstructL(false); + CleanupStack::Pop(self); + return self; +} + +void S60ImageCaptureDecoder::ConstructL(const bool fileInput) +{ + if (fileInput) { + if (!m_imageSession || !m_fs || !m_jpegImageFile) + User::Leave(KErrGeneral); + m_imageDecoder = CImageDecoder::FileNewL(*m_fs, *m_jpegImageFile); + } else { + if (!m_imageSession || !m_fs || !m_jpegImageData) + User::Leave(KErrGeneral); + m_imageDecoder = CImageDecoder::DataNewL(*m_fs, *m_jpegImageData); + } +} + +void S60ImageCaptureDecoder::decode(CFbsBitmap *destBitmap) +{ + if (m_imageDecoder) { + m_imageDecoder->Convert(&iStatus, *destBitmap, 0); + SetActive(); + } + else + m_imageSession->setError(KErrGeneral, QLatin1String("Preview image creation failed.")); +} + +TFrameInfo *S60ImageCaptureDecoder::frameInfo() +{ + if (m_imageDecoder) { + m_frameInfo = m_imageDecoder->FrameInfo(); + return &m_frameInfo; + } + else + return 0; +} + +void S60ImageCaptureDecoder::RunL() +{ + m_imageSession->handleImageDecoded(iStatus.Int()); +} + +void S60ImageCaptureDecoder::DoCancel() +{ + if (m_imageDecoder) + m_imageDecoder->Cancel(); +} + +TInt S60ImageCaptureDecoder::RunError(TInt aError) +{ + m_imageSession->setError(aError, QLatin1String("Preview image creation failed.")); + return KErrNone; +} + +//============================================================================= + +S60ImageCaptureEncoder::S60ImageCaptureEncoder(S60ImageCaptureSession *imageSession, + RFs *fileSystemAccess, + const TDesC16 *fileName, + TInt jpegQuality) : + CActive(CActive::EPriorityStandard), + m_imageSession(imageSession), + m_fileSystemAccess(fileSystemAccess), + m_fileName(fileName), + m_jpegQuality(jpegQuality) +{ + CActiveScheduler::Add(this); +} + +S60ImageCaptureEncoder::~S60ImageCaptureEncoder() +{ + if (m_frameImageData) { + delete m_frameImageData; + m_frameImageData = 0; + } + if (m_imageEncoder) { + delete m_imageEncoder; + m_imageEncoder = 0; + } +} + +S60ImageCaptureEncoder *S60ImageCaptureEncoder::NewL(S60ImageCaptureSession *imageSession, + RFs *fileSystemAccess, + const TDesC16 *fileName, + TInt jpegQuality) +{ + S60ImageCaptureEncoder* self = new (ELeave) S60ImageCaptureEncoder(imageSession, + fileSystemAccess, + fileName, + jpegQuality); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; +} + +void S60ImageCaptureEncoder::ConstructL() +{ + if (!m_imageSession || !m_fileSystemAccess || !m_fileName) + User::Leave(KErrGeneral); + + m_imageEncoder = CImageEncoder::FileNewL(*m_fileSystemAccess, + *m_fileName, + CImageEncoder::EOptionNone, + KImageTypeJPGUid); + CleanupStack::PushL(m_imageEncoder); + + // Set Jpeg Quality + m_frameImageData = CFrameImageData::NewL(); + CleanupStack::PushL(m_frameImageData); + + TJpegImageData* jpegFormat = new( ELeave ) TJpegImageData; + CleanupStack::PushL(jpegFormat); + + jpegFormat->iQualityFactor = m_jpegQuality; + + // jpegFormat (TJpegImageData) ownership transferred to m_frameImageData (CFrameImageData) + User::LeaveIfError( m_frameImageData->AppendImageData(jpegFormat)); + + CleanupStack::Pop(jpegFormat); + CleanupStack::Pop(m_frameImageData); + CleanupStack::Pop(m_imageEncoder); +} + +void S60ImageCaptureEncoder::encode(CFbsBitmap *sourceBitmap) +{ + if (m_imageEncoder) { + m_imageEncoder->Convert(&iStatus, *sourceBitmap, m_frameImageData); + SetActive(); + } + else + m_imageSession->setError(KErrGeneral, QLatin1String("Saving image to file failed.")); +} + +void S60ImageCaptureEncoder::RunL() +{ + m_imageSession->handleImageEncoded(iStatus.Int()); +} + +void S60ImageCaptureEncoder::DoCancel() +{ + if (m_imageEncoder) + m_imageEncoder->Cancel(); +} + +TInt S60ImageCaptureEncoder::RunError(TInt aError) +{ + m_imageSession->setError(aError, QLatin1String("Saving image to file failed.")); + return KErrNone; +} + +//============================================================================= + +S60ImageCaptureSession::S60ImageCaptureSession(QObject *parent) : + QObject(parent), + m_cameraEngine(0), + m_advancedSettings(0), + m_cameraInfo(0), + m_previewBitmap(0), + m_activeScheduler(0), + m_fileSystemAccess(0), + m_imageDecoder(0), + m_imageEncoder(0), + m_error(KErrNone), + m_activeDeviceIndex(KDefaultCameraDevice), + m_cameraStarted(false), + m_icState(EImageCaptureNotPrepared), + m_currentCodec(QString()), + m_captureSize(QSize()), + m_symbianImageQuality(QtMultimediaKit::HighQuality * KSymbianImageQualityCoefficient), + m_captureSettingsSet(false), + m_stillCaptureFileName(QString()), + m_requestedStillCaptureFileName(QString()), + m_currentImageId(0), + m_captureWhenReady(false), + m_previewDecodingOngoing(false), + m_previewInWaitLoop(false) +{ + // Define supported image codecs + m_supportedImageCodecs << "image/jpeg"; + + initializeImageCaptureSettings(); + + // Install ActiveScheduler if needed + if (!CActiveScheduler::Current()) { + m_activeScheduler = new CActiveScheduler; + CActiveScheduler::Install(m_activeScheduler); + } +} + +S60ImageCaptureSession::~S60ImageCaptureSession() +{ + // Delete AdvancedSettings (Should already be destroyed by CameraControl) + deleteAdvancedSettings(); + + m_formats.clear(); + m_supportedImageCodecs.clear(); + + if (m_imageDecoder) { + m_imageDecoder->Cancel(); + delete m_imageDecoder; + m_imageDecoder = 0; + } + if (m_imageEncoder) { + m_imageEncoder->Cancel(); + delete m_imageEncoder; + m_imageEncoder = 0; + } + + if (m_previewBitmap) { + delete m_previewBitmap; + m_previewBitmap = 0; + } + + // Uninstall ActiveScheduler if needed + if (m_activeScheduler) { + CActiveScheduler::Install(0); + delete m_activeScheduler; + m_activeScheduler = 0; + } +} + +CCamera::TFormat S60ImageCaptureSession::defaultImageFormat() +{ + // Primary Camera + if (m_activeDeviceIndex == 0) + return KDefaultImageFormatPrimaryCam; + + // Secondary Camera or other + else + return KDefaultImageFormatSecondaryCam; +} + +bool S60ImageCaptureSession::isDeviceReady() +{ +#ifdef Q_CC_NOKIAX86 // Emulator + return true; +#endif + + if (m_cameraEngine) + return m_cameraEngine->IsCameraReady(); + + return false; +} + +void S60ImageCaptureSession::deleteAdvancedSettings() +{ + if (m_advancedSettings) { + delete m_advancedSettings; + m_advancedSettings = 0; + emit advancedSettingChanged(); + } +} + +void S60ImageCaptureSession::setCameraHandle(CCameraEngine* camerahandle) +{ + if (camerahandle) { + m_cameraEngine = camerahandle; + resetSession(); + + // Set default settings + initializeImageCaptureSettings(); + } +} + +void S60ImageCaptureSession::setCurrentDevice(TInt deviceindex) +{ + m_activeDeviceIndex = deviceindex; +} + +void S60ImageCaptureSession::notifySettingsSet() +{ + m_captureSettingsSet = true; +} + +void S60ImageCaptureSession::resetSession(bool errorHandling) +{ + // Delete old AdvancedSettings + deleteAdvancedSettings(); + + m_captureWhenReady = false; + m_previewDecodingOngoing = false; + m_previewInWaitLoop = false; + m_stillCaptureFileName = QString(); + m_requestedStillCaptureFileName = QString(); + m_icState = EImageCaptureNotPrepared; + + m_error = KErrNone; + m_currentFormat = defaultImageFormat(); + + int err = KErrNone; + m_advancedSettings = S60CameraSettings::New(err, this, m_cameraEngine); + if (err == KErrNotSupported) { + m_advancedSettings = 0; +#ifndef S60_31_PLATFORM // Post S60 3.1 Platform + // Adv. settings may not be supported for other than the Primary Camera + if (m_cameraEngine->CurrentCameraIndex() == 0) + setError(err, tr("Unexpected camera error.")); +#endif // !S60_31_PLATFORM + } else if (err != KErrNone) { // Other errors + m_advancedSettings = 0; + qWarning("Failed to create camera settings handler."); + if (errorHandling) + emit cameraError(QCamera::ServiceMissingError, tr("Failed to recover from error.")); + else + setError(err, tr("Unexpected camera error.")); + return; + } + + if (m_advancedSettings) { + if (m_cameraEngine) + m_cameraEngine->SetAdvancedObserver(m_advancedSettings); + else + setError(KErrNotReady, tr("Unexpected camera error.")); + } + + updateImageCaptureFormats(); + + emit advancedSettingChanged(); +} + +S60CameraSettings* S60ImageCaptureSession::advancedSettings() +{ + return m_advancedSettings; +} + +/* + * This function can be used both internally and from Control classes using + * this session. The error notification will go to the client application + * either through QCameraImageCapture (if captureError is true) or QCamera (if + * captureError is false, default) error signal. + */ +void S60ImageCaptureSession::setError(const TInt error, + const QString &description, + const bool captureError) +{ + if (error == KErrNone) + return; + + m_error = error; + QCameraImageCapture::Error cameraError = fromSymbianErrorToQtMultimediaError(error); + + if (captureError) { + emit this->captureError(m_currentImageId, cameraError, description); + if (cameraError != QCameraImageCapture::NotSupportedFeatureError) + resetSession(true); + } else { + emit this->cameraError(cameraError, description); + if (cameraError != QCamera::NotSupportedFeatureError) + resetSession(true); + } +} + +QCameraImageCapture::Error S60ImageCaptureSession::fromSymbianErrorToQtMultimediaError(int aError) +{ + switch(aError) { + case KErrNone: + return QCameraImageCapture::NoError; // No errors have occurred + case KErrNotReady: + return QCameraImageCapture::NotReadyError; // Not ready for operation + case KErrNotSupported: + return QCameraImageCapture::NotSupportedFeatureError; // The feature is not supported + case KErrNoMemory: + return QCameraImageCapture::OutOfSpaceError; // Out of disk space + case KErrNotFound: + case KErrBadHandle: + return QCameraImageCapture::ResourceError; // No resources available + + default: + return QCameraImageCapture::ResourceError; // Other error has occurred + } +} + +int S60ImageCaptureSession::currentImageId() const +{ + return m_currentImageId; +} + +void S60ImageCaptureSession::initializeImageCaptureSettings() +{ + if (m_captureSettingsSet) + return; + + m_currentCodec = KDefaultImageCodec; + m_captureSize = QSize(-1, -1); + m_currentFormat = defaultImageFormat(); + + // Resolution + if (m_cameraEngine) { + QList resolutions = supportedCaptureSizesForCodec(imageCaptureCodec()); + foreach (QSize reso, resolutions) { + if ((reso.width() * reso.height()) > (m_captureSize.width() * m_captureSize.height())) + m_captureSize = reso; + } + } else { + m_captureSize = KDefaultImageResolution; + } + + m_symbianImageQuality = KDefaultImageQuality; +} + +/* + * This function selects proper format to be used for the captured image based + * on the requested image codec. + */ +CCamera::TFormat S60ImageCaptureSession::selectFormatForCodec(const QString &codec) +{ + CCamera::TFormat format = CCamera::EFormatMonochrome; + + if (codec == "image/jpg" || codec == "image/jpeg") { + // Primary Camera + if (m_activeDeviceIndex == 0) + format = KDefaultImageFormatPrimaryCam; + + // Secondary Camera or other + else + format = KDefaultImageFormatSecondaryCam; + + return format; + } + + setError(KErrNotSupported, tr("Failed to select color format to be used with image codec.")); + return format; +} + +int S60ImageCaptureSession::prepareImageCapture() +{ + if (m_cameraEngine) { + if (!m_cameraEngine->IsCameraReady()) { + // Reset state to make sure camera is prepared before capturing image + m_icState = EImageCaptureNotPrepared; + return KErrNotReady; + } + + // First set the quality + CCamera *camera = m_cameraEngine->Camera(); + if (camera) + camera->SetJpegQuality(m_symbianImageQuality); + else + setError(KErrNotReady, tr("Setting image quality failed."), true); + + // Then prepare with correct resolution and format + TSize captureSize = TSize(m_captureSize.width(), m_captureSize.height()); + TRAPD(symbianError, m_cameraEngine->PrepareL(captureSize, m_currentFormat)); + if (!symbianError) + m_icState = EImageCapturePrepared; + + // Check if CaptureSize was modified + if (captureSize.iWidth != m_captureSize.width() || captureSize.iHeight != m_captureSize.height()) + m_captureSize = QSize(captureSize.iWidth, captureSize.iHeight); + emit captureSizeChanged(m_captureSize); + +#ifdef ECAM_PREVIEW_API + // Subscribe previews + MCameraPreviewObserver *observer = this; + m_cameraEngine->EnablePreviewProvider(observer); +#endif // ECAM_PREVIEW_API + + return symbianError; + } + + return KErrGeneral; +} + +void S60ImageCaptureSession::releaseImageCapture() +{ + // Make sure ImageCapture is prepared the next time it is being activated + m_icState = EImageCaptureNotPrepared; + +#ifdef ECAM_PREVIEW_API + // Cancel preview subscription + m_cameraEngine->DisablePreviewProvider(); +#endif // ECAM_PREVIEW_API +} + +int S60ImageCaptureSession::capture(const QString &fileName) +{ + if (!m_cameraStarted) { + m_captureWhenReady = true; + m_requestedStillCaptureFileName = fileName; // Save name, it will be processed during actual capture + return 0; + } + + if (m_icState < EImageCapturePrepared) { + int prepareSuccess = prepareImageCapture(); + if (prepareSuccess) { + setError(prepareSuccess, tr("Failure during image capture preparation."), true); + return 0; + } + } else if (m_icState > EImageCapturePrepared) { + setError(KErrNotReady, tr("Previous operation is still ongoing."), true); + return 0; + } + + m_icState = EImageCaptureCapturing; + + // Give new ID for the new image + m_currentImageId += 1; + + emit readyForCaptureChanged(false); + + processFileName(fileName); + + if (m_cameraEngine) { + TRAPD(err, m_cameraEngine->CaptureL()); + setError(err, tr("Image capture failed."), true); + } else { + setError(KErrNotReady, tr("Unexpected camera error."), true); + } + +#ifdef Q_CC_NOKIAX86 // Emulator + QImage *snapImage = new QImage(QLatin1String("C:/Data/testimage.jpg")); + emit imageExposed(m_currentImageId); + emit imageCaptured(m_currentImageId, *snapImage); + emit imageSaved(m_currentImageId, m_stillCaptureFileName); +#endif // Q_CC_NOKIAX86 + + return m_currentImageId; +} + +void S60ImageCaptureSession::cancelCapture() +{ + if (m_icState != EImageCaptureCapturing) + return; + + if (m_cameraEngine) + m_cameraEngine->CancelCapture(); + + m_icState = EImageCapturePrepared; +} + +void S60ImageCaptureSession::processFileName(const QString &fileName) +{ + // Empty FileName - Use default file name and path (C:\Data\Images\image.jpg) + if (fileName.isEmpty()) { + // Make sure default directory exists + QDir videoDir(QDir::rootPath()); + if (!videoDir.exists(KDefaultImagePath)) + videoDir.mkpath(KDefaultImagePath); + QString defaultFile = KDefaultImagePath; + defaultFile.append("\\"); + defaultFile.append(KDefaultImageFileName); + m_stillCaptureFileName = defaultFile; + + } else { // Not empty + + QString fullFileName; + + // Relative FileName + if (!fileName.contains(":")) { + // Extract file name and path from the URL + fullFileName = KDefaultImagePath; + if (fileName.at(0) != '\\') + fullFileName.append("\\"); + fullFileName.append(QDir::toNativeSeparators(QDir::cleanPath(fileName))); + + // Absolute FileName + } else { + // Extract file name and path from the given location + fullFileName = QDir::toNativeSeparators(QDir::cleanPath(fileName)); + } + + QString fileNameOnly = fullFileName.right(fullFileName.length() - fullFileName.lastIndexOf("\\") - 1); + QString directory = fullFileName.left(fullFileName.lastIndexOf("\\")); + if (directory.lastIndexOf("\\") == (directory.length() - 1)) + directory = directory.left(directory.length() - 1); + + // URL is Absolute path, not including file name + if (!fileNameOnly.contains(".")) { + if (fileNameOnly != "") { + directory.append("\\"); + directory.append(fileNameOnly); + } + fileNameOnly = KDefaultImageFileName; + } + + // Make sure absolute directory exists + QDir imageDir(QDir::rootPath()); + if (!imageDir.exists(directory)) + imageDir.mkpath(directory); + + QString resolvedFileName = directory; + resolvedFileName.append("\\"); + resolvedFileName.append(fileNameOnly); + m_stillCaptureFileName = resolvedFileName; + } +} + +void S60ImageCaptureSession::MceoFocusComplete() +{ + emit focusStatusChanged(QCamera::Locked, QCamera::LockAcquired); +} + +void S60ImageCaptureSession::MceoCapturedDataReady(TDesC8* aData) +{ + emit imageExposed(m_currentImageId); + + m_icState = EImageCaptureWritingImage; + + TFileName path = convertImagePath(); + + // Try to save image and inform if it was succcesful + TRAPD(err, saveImageL(aData, path)); + if (err) { + if (m_previewDecodingOngoing) + m_previewDecodingOngoing = false; // Reset + + setError(err, tr("Writing captured image to a file failed."), true); + m_icState = EImageCapturePrepared; + return; + } + + m_icState = EImageCapturePrepared; + +} + +void S60ImageCaptureSession::MceoCapturedBitmapReady(CFbsBitmap* aBitmap) +{ + emit imageExposed(m_currentImageId); + + m_icState = EImageCaptureWritingImage; + + if(aBitmap) + { +#ifndef ECAM_PREVIEW_API + if (m_previewDecodingOngoing) { + m_previewInWaitLoop = true; + CActiveScheduler::Start(); // Wait for the completion of the previous Preview generation + } + + // Delete old instances if needed + if (m_imageDecoder) { + delete m_imageDecoder; + m_imageDecoder = 0; + } + if (m_previewBitmap) { + delete m_previewBitmap; + m_previewBitmap = 0; + } +#endif // ECAM_CAMERA_API + if (m_imageEncoder) { + delete m_imageEncoder; + m_imageEncoder = 0; + } + if (m_fileSystemAccess) { + m_fileSystemAccess->Close(); + delete m_fileSystemAccess; + m_fileSystemAccess = 0; + } + + TInt saveError = KErrNone; + TFileName path = convertImagePath(); + + // Create FileSystem access + m_fileSystemAccess = new RFs; + if (!m_fileSystemAccess) { + setError(KErrNoMemory, tr("Failed to write captured image to a file.")); + return; + } + saveError = m_fileSystemAccess->Connect(); + if (saveError) { + setError(saveError, tr("Failed to write captured image to a file.")); + return; + } + + TRAP(saveError, m_imageEncoder = S60ImageCaptureEncoder::NewL(this, + m_fileSystemAccess, + &path, + m_symbianImageQuality)); + if (saveError) + setError(saveError, tr("Saving captured image failed."), true); + m_previewDecodingOngoing = true; + m_imageEncoder->encode(aBitmap); + + } else { + setError(KErrBadHandle, tr("Unexpected camera error."), true); + } + + m_icState = EImageCapturePrepared; +} + +void S60ImageCaptureSession::MceoHandleError(TCameraEngineError aErrorType, TInt aError) +{ + Q_UNUSED(aErrorType); + setError(aError, tr("General camera error.")); +} + +TFileName S60ImageCaptureSession::convertImagePath() +{ + TFileName path = KNullDesC(); + + // Convert to Symbian path + TPtrC16 attachmentPath(KNullDesC); + + // Path is already included in filename + attachmentPath.Set(reinterpret_cast(QDir::toNativeSeparators(m_stillCaptureFileName).utf16())); + path.Append(attachmentPath); + + return path; +} + +/* + * Creates (asynchronously) Preview Image from Jpeg ImageBuffer and also + * writes Jpeg (synchronously) to a file. + */ +void S60ImageCaptureSession::saveImageL(TDesC8 *aData, TFileName &aPath) +{ + if (aData == 0) + setError(KErrGeneral, tr("Captured image data is not available."), true); + + if (aPath.Size() > 0) { +#ifndef ECAM_PREVIEW_API + if (m_previewDecodingOngoing) { + m_previewInWaitLoop = true; + CActiveScheduler::Start(); // Wait for the completion of the previous Preview generation + } + + // Delete old instances if needed + if (m_imageDecoder) { + delete m_imageDecoder; + m_imageDecoder = 0; + } + if (m_previewBitmap) { + delete m_previewBitmap; + m_previewBitmap = 0; + } +#endif // ECAM_PREVIEW_API + if (m_fileSystemAccess) { + m_fileSystemAccess->Close(); + delete m_fileSystemAccess; + m_fileSystemAccess = 0; + } + + RFs *fileSystemAccess = new (ELeave) RFs; + User::LeaveIfError(fileSystemAccess->Connect()); + CleanupClosePushL(*fileSystemAccess); + +#ifndef ECAM_PREVIEW_API + // Generate Thumbnail to be used as Preview + S60ImageCaptureDecoder *imageDecoder = S60ImageCaptureDecoder::DataNewL(this, fileSystemAccess, aData); + CleanupStack::PushL(imageDecoder); + + // Set proper Preview Size + TSize scaledSize((m_captureSize.width() / KSnapshotDownScaleFactor), (m_captureSize.height() / KSnapshotDownScaleFactor)); + if (scaledSize.iWidth < KSnapshotMinWidth || scaledSize.iHeight < KSnapshotMinHeight) + scaledSize.SetSize((m_captureSize.width() / (KSnapshotDownScaleFactor/2)), (m_captureSize.height() / (KSnapshotDownScaleFactor/2))); + if (scaledSize.iWidth < KSnapshotMinWidth || scaledSize.iHeight < KSnapshotMinHeight) + scaledSize.SetSize((m_captureSize.width() / (KSnapshotDownScaleFactor/4)), (m_captureSize.height() / (KSnapshotDownScaleFactor/4))); + if (scaledSize.iWidth < KSnapshotMinWidth || scaledSize.iHeight < KSnapshotMinHeight) + scaledSize.SetSize(m_captureSize.width(), m_captureSize.height()); + + TFrameInfo *info = imageDecoder->frameInfo(); + if (!info) { + setError(KErrGeneral, tr("Preview image creation failed.")); + return; + } + + CFbsBitmap *previewBitmap = new (ELeave) CFbsBitmap; + CleanupStack::PushL(previewBitmap); + TInt bitmapCreationErr = previewBitmap->Create(scaledSize, info->iFrameDisplayMode); + if (bitmapCreationErr) { + setError(bitmapCreationErr, tr("Preview creation failed.")); + return; + } + + // Jpeg conversion completes in RunL + m_previewDecodingOngoing = true; + imageDecoder->decode(previewBitmap); +#endif // ECAM_PREVIEW_API + + RFile file; + TInt fileWriteErr = KErrNone; + fileWriteErr = file.Replace(*fileSystemAccess, aPath, EFileWrite); + if (fileWriteErr) + User::Leave(fileWriteErr); + CleanupClosePushL(file); // Close if Leaves + + fileWriteErr = file.Write(*aData); + if (fileWriteErr) + User::Leave(fileWriteErr); + + CleanupStack::PopAndDestroy(&file); +#ifdef ECAM_PREVIEW_API + CleanupStack::PopAndDestroy(fileSystemAccess); +#else // !ECAM_PREVIEW_API + // Delete when Image is decoded + CleanupStack::Pop(previewBitmap); + CleanupStack::Pop(imageDecoder); + CleanupStack::Pop(fileSystemAccess); + + // Set member variables (Cannot leave any more) + m_previewBitmap = previewBitmap; + m_imageDecoder = imageDecoder; + m_fileSystemAccess = fileSystemAccess; +#endif // ECAM_PREVIEW_API + + emit imageSaved(m_currentImageId, m_stillCaptureFileName); + + // Inform that we can continue taking more pictures + emit readyForCaptureChanged(true); + + // For custom preview generation, image buffer gets released in RunL() +#ifdef ECAM_PREVIEW_API + releaseImageBuffer(); +#endif // ECAM_PREVIEW_API + + } else { + setError(KErrPathNotFound, tr("Invalid path given."), true); + } +} + +void S60ImageCaptureSession::releaseImageBuffer() +{ + if (m_cameraEngine) + m_cameraEngine->ReleaseImageBuffer(); + else + setError(KErrNotReady, tr("Unexpected camera error."), true); +} + +/* + * Queries camera properties + * Results are returned to member variable m_info + * + * @return boolean indicating if querying the info was a success + */ +bool S60ImageCaptureSession::queryCurrentCameraInfo() +{ + if (m_cameraEngine) { + m_cameraInfo = m_cameraEngine->CameraInfo(); + return true; + } + + return false; +} + +/* + * This function handles different camera status changes + */ +void S60ImageCaptureSession::cameraStatusChanged(QCamera::Status status) +{ + if (status == QCamera::ActiveStatus) { + m_cameraStarted = true; + if (m_captureWhenReady) + capture(m_requestedStillCaptureFileName); + }else if (status == QCamera::UnloadedStatus) { + m_cameraStarted = false; + m_icState = EImageCaptureNotPrepared; + } + else + m_cameraStarted = false; +} + +QSize S60ImageCaptureSession::captureSize() const +{ + return m_captureSize; +} + +QSize S60ImageCaptureSession::minimumCaptureSize() +{ + return supportedCaptureSizesForCodec(formatMap().key(m_currentFormat)).first(); +} +QSize S60ImageCaptureSession::maximumCaptureSize() +{ + return supportedCaptureSizesForCodec(formatMap().key(m_currentFormat)).last(); +} + +void S60ImageCaptureSession::setCaptureSize(const QSize &size) +{ + if (size.isNull() || + size.isEmpty() || + size == QSize(-1,-1)) { + // An empty QSize indicates the encoder should make an optimal choice based on what is + // available from the image source and the limitations of the codec. + m_captureSize = supportedCaptureSizesForCodec(formatMap().key(m_currentFormat)).last(); + } + else + m_captureSize = size; +} + +QList S60ImageCaptureSession::supportedCaptureSizesForCodec(const QString &codecName) +{ + QList list; + + // If we have CameraEngine loaded and we can update CameraInfo + if (m_cameraEngine && queryCurrentCameraInfo()) { + CCamera::TFormat format; + if (codecName == "") + format = defaultImageFormat(); + else + format = selectFormatForCodec(codecName); + + CCamera *camera = m_cameraEngine->Camera(); + TSize imageSize; + if (camera) { + for (int i = 0; i < m_cameraInfo->iNumImageSizesSupported; i++) { + camera->EnumerateCaptureSizes(imageSize, i, format); + list << QSize(imageSize.iWidth, imageSize.iHeight); // Add resolution to the list + } + } + } + +#ifdef Q_CC_NOKIAX86 // Emulator + // Add some for testing purposes + list << QSize(50, 50); + list << QSize(100, 100); + list << QSize(800,600); +#endif + + return list; +} + +QMap S60ImageCaptureSession::formatMap() +{ + QMap formats; + + // Format list copied from CCamera::TFormat (in ecam.h) + formats.insert("Monochrome", 0x0001); + formats.insert("16bitRGB444", 0x0002); + formats.insert("16BitRGB565", 0x0004); + formats.insert("32BitRGB888", 0x0008); + formats.insert("Jpeg", 0x0010); + formats.insert("Exif", 0x0020); + formats.insert("FbsBitmapColor4K", 0x0040); + formats.insert("FbsBitmapColor64K", 0x0080); + formats.insert("FbsBitmapColor16M", 0x0100); + formats.insert("UserDefined", 0x0200); + formats.insert("YUV420Interleaved", 0x0400); + formats.insert("YUV420Planar", 0x0800); + formats.insert("YUV422", 0x1000); + formats.insert("YUV422Reversed", 0x2000); + formats.insert("YUV444", 0x4000); + formats.insert("YUV420SemiPlanar", 0x8000); + formats.insert("FbsBitmapColor16MU", 0x00010000); + formats.insert("MJPEG", 0x00020000); + formats.insert("EncodedH264", 0x00040000); + + return formats; +} + +QMap S60ImageCaptureSession::codecDescriptionMap() +{ + QMap formats; + + formats.insert("image/jpg", "JPEG image codec"); + + return formats; +} + +QStringList S60ImageCaptureSession::supportedImageCaptureCodecs() +{ +#ifdef Q_CC_NOKIAX86 // Emulator + return formatMap().keys(); +#endif + + return m_supportedImageCodecs; +} + +void S60ImageCaptureSession::updateImageCaptureFormats() +{ + m_formats.clear(); + if (m_cameraEngine && queryCurrentCameraInfo()) { + TUint32 supportedFormats = m_cameraInfo->iImageFormatsSupported; + +#ifdef S60_3X_PLATFORM // S60 3.1 & 3.2 + int maskEnd = CCamera::EFormatFbsBitmapColor16MU; +#else // S60 5.0 or later + int maskEnd = CCamera::EFormatEncodedH264; +#endif // S60_3X_PLATFORM + + for (int mask = CCamera::EFormatMonochrome; mask <= maskEnd; mask <<= 1) { + if (supportedFormats & mask) + m_formats << mask; // Store mask of supported format + } + } +} + +QString S60ImageCaptureSession::imageCaptureCodec() +{ + return m_currentCodec; +} +void S60ImageCaptureSession::setImageCaptureCodec(const QString &codecName) +{ + if (!codecName.isEmpty()) { + if (supportedImageCaptureCodecs().contains(codecName, Qt::CaseInsensitive) || + codecName == "image/jpg") { + m_currentCodec = codecName; + m_currentFormat = selectFormatForCodec(m_currentCodec); + } else { + setError(KErrNotSupported, tr("Requested image codec is not supported")); + } + } else { + m_currentCodec = KDefaultImageCodec; + m_currentFormat = selectFormatForCodec(m_currentCodec); + } +} + +QString S60ImageCaptureSession::imageCaptureCodecDescription(const QString &codecName) +{ + QString description = codecDescriptionMap().value(codecName); + return description; +} + +QtMultimediaKit::EncodingQuality S60ImageCaptureSession::captureQuality() const +{ + switch (m_symbianImageQuality) { + case KJpegQualityVeryLow: + return QtMultimediaKit::VeryLowQuality; + case KJpegQualityLow: + return QtMultimediaKit::LowQuality; + case KJpegQualityNormal: + return QtMultimediaKit::NormalQuality; + case KJpegQualityHigh: + return QtMultimediaKit::HighQuality; + case KJpegQualityVeryHigh: + return QtMultimediaKit::VeryHighQuality; + + default: + // Return normal as default + return QtMultimediaKit::NormalQuality; + } +} + +void S60ImageCaptureSession::setCaptureQuality(const QtMultimediaKit::EncodingQuality &quality) +{ + // Use sensible presets + switch (quality) { + case QtMultimediaKit::VeryLowQuality: + m_symbianImageQuality = KJpegQualityVeryLow; + break; + case QtMultimediaKit::LowQuality: + m_symbianImageQuality = KJpegQualityLow; + break; + case QtMultimediaKit::NormalQuality: + m_symbianImageQuality = KJpegQualityNormal; + break; + case QtMultimediaKit::HighQuality: + m_symbianImageQuality = KJpegQualityHigh; + break; + case QtMultimediaKit::VeryHighQuality: + m_symbianImageQuality = KJpegQualityVeryHigh; + break; + + default: + m_symbianImageQuality = quality * KSymbianImageQualityCoefficient; + break; + } +} + +qreal S60ImageCaptureSession::maximumZoom() +{ + qreal maxZoomFactor = 1.0; + + if (queryCurrentCameraInfo()) { + maxZoomFactor = m_cameraInfo->iMaxZoomFactor; + + if (maxZoomFactor == 0.0 || maxZoomFactor == 1.0) { + return 1.0; // Not supported + } else { + return maxZoomFactor; + } + } else { + return 1.0; + } +} + +qreal S60ImageCaptureSession::minZoom() +{ + qreal minZoomValue = 1.0; + + if (queryCurrentCameraInfo()) { + minZoomValue = m_cameraInfo->iMinZoomFactor; + if (minZoomValue == 0.0 || minZoomValue == 1.0) + return 1.0; // Macro Zoom is not supported + else { + return minZoomValue; + } + + } else { + return 1.0; + } +} + +qreal S60ImageCaptureSession::maxDigitalZoom() +{ + qreal maxDigitalZoomFactor = 1.0; + + if (queryCurrentCameraInfo()) { + maxDigitalZoomFactor = m_cameraInfo->iMaxDigitalZoomFactor; + return maxDigitalZoomFactor; + } else { + return 1.0; + } +} + +void S60ImageCaptureSession::doSetZoomFactorL(qreal optical, qreal digital) +{ +#if !defined(USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER) & !defined(USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER) + // Convert Zoom Factor to Zoom Value if AdvSettings are not available + int digitalSymbian = (digital * m_cameraInfo->iMaxDigitalZoom) / maxDigitalZoom(); + if (m_cameraInfo->iMaxDigitalZoom != 0 && digital == 1.0) + digitalSymbian = 1; // Make sure zooming out to initial value if requested +#endif // !USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER & !USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER + + if (m_cameraEngine && !m_cameraEngine->IsCameraReady()) + return; + + if (m_cameraEngine && queryCurrentCameraInfo()) { + CCamera *camera = m_cameraEngine->Camera(); + if (camera) { + + // Optical Zoom + if (!qFuzzyCompare(optical, qreal(1.0)) && !qFuzzyCompare(optical, qreal(0.0))) { + setError(KErrNotSupported, tr("Requested optical zoom factor is not supported.")); + return; + } + + // Digital Zoom (Smooth Zoom - Zoom value set in steps) + if (digital != digitalZoomFactor()) { + if ((digital > 1.0 || qFuzzyCompare(digital, qreal(1.0))) && + digital <= m_cameraInfo->iMaxDigitalZoomFactor) { +#if defined(USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER) | defined(USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER) + if (m_advancedSettings) { + qreal currentZoomFactor = m_advancedSettings->digitalZoomFactorL(); + + QList smoothZoomSetValues; + QList factors = m_advancedSettings->supportedDigitalZoomFactors(); + if (currentZoomFactor < digital) { + for (int i = 0; i < factors.count(); ++i) { + if (factors.at(i) > currentZoomFactor && factors.at(i) < digital) + smoothZoomSetValues << factors.at(i); + } + + for (int i = 0; i < smoothZoomSetValues.count(); i = i + KSmoothZoomStep) { + m_advancedSettings->setDigitalZoomFactorL(smoothZoomSetValues[i]); // Using Zoom Factor + } + + } else { + for (int i = 0; i < factors.count(); ++i) { + if (factors.at(i) < currentZoomFactor && factors.at(i) > digital) + smoothZoomSetValues << factors.at(i); + } + + for (int i = (smoothZoomSetValues.count() - 1); i >= 0; i = i - KSmoothZoomStep) { + m_advancedSettings->setDigitalZoomFactorL(smoothZoomSetValues[i]); // Using Zoom Factor + } + } + + // Set final value + m_advancedSettings->setDigitalZoomFactorL(digital); + } + else + setError(KErrNotReady, tr("Zooming failed.")); +#else // No advanced settigns + // Define zoom steps + int currentZoomFactor = camera->DigitalZoomFactor(); + int difference = abs(currentZoomFactor - digitalSymbian); + int midZoomValue = currentZoomFactor; + + if (currentZoomFactor < digitalSymbian) { + while (midZoomValue < (digitalSymbian - KSmoothZoomStep)) { + midZoomValue = midZoomValue + KSmoothZoomStep; + camera->SetDigitalZoomFactorL(midZoomValue); + } + } else { + while (midZoomValue > (digitalSymbian + KSmoothZoomStep)) { + midZoomValue = midZoomValue - KSmoothZoomStep; + camera->SetDigitalZoomFactorL(midZoomValue); + } + } + + // Set final and emit signal + camera->SetDigitalZoomFactorL(digitalSymbian); +#endif // USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER | USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER + } else { + setError(KErrNotSupported, tr("Requested digital zoom factor is not supported.")); + return; + } + } + } + } else { + setError(KErrGeneral, tr("Unexpected camera error.")); + } +} + +qreal S60ImageCaptureSession::opticalZoomFactor() +{ + qreal factor = 1.0; + +#if defined(USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER) | defined(USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER) + if (m_advancedSettings) { + TRAPD(err, factor = m_advancedSettings->opticalZoomFactorL()); + if (err) + return 1.0; + } +#else // No advanced settigns + if (m_cameraEngine && m_cameraInfo) { + if (m_cameraEngine->Camera()) { + if (m_cameraInfo->iMaxZoom != 0) + factor = (m_cameraEngine->Camera()->ZoomFactor()* maximumZoom()) / m_cameraInfo->iMaxZoom; + else + factor = 1.0; + } + } +#endif // USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER | USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER + + if (factor == 0.0) // If not supported + factor = 1.0; + + return factor; +} + +qreal S60ImageCaptureSession::digitalZoomFactor() +{ + qreal factor = 1.0; + +#if defined(USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER) | defined(USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER) + if (m_advancedSettings) { + TRAPD(err, factor = m_advancedSettings->digitalZoomFactorL()); + if (err) + return 1.0; + } +#else // No advanced settigns + if (m_cameraEngine && m_cameraInfo) { + if (m_cameraEngine->Camera()) { + if (m_cameraInfo->iMaxDigitalZoom != 0) + factor = (m_cameraEngine->Camera()->DigitalZoomFactor()* maxDigitalZoom()) / m_cameraInfo->iMaxDigitalZoom; + else + factor = 1.0; + } + } +#endif // USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER | USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER + + if (factor == 0.0) + factor = 1.0; + + return factor; +} + +void S60ImageCaptureSession::setFlashMode(QCameraExposure::FlashModes mode) +{ + TRAPD(err, doSetFlashModeL(mode)); + setError(err, tr("Failed to set flash mode.")); +} + +void S60ImageCaptureSession::doSetFlashModeL(QCameraExposure::FlashModes mode) +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + CCamera *camera = m_cameraEngine->Camera(); + switch(mode) { + case QCameraExposure::FlashOff: + camera->SetFlashL(CCamera::EFlashNone); + break; + case QCameraExposure::FlashAuto: + camera->SetFlashL(CCamera::EFlashAuto); + break; + case QCameraExposure::FlashOn: + camera->SetFlashL(CCamera::EFlashForced); + break; + case QCameraExposure::FlashRedEyeReduction: + camera->SetFlashL(CCamera::EFlashRedEyeReduce); + break; + case QCameraExposure::FlashFill: + camera->SetFlashL(CCamera::EFlashFillIn); + break; + + default: + setError(KErrNotSupported, tr("Requested flash mode is not suported")); + break; + } + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } +} + +QCameraExposure::FlashMode S60ImageCaptureSession::flashMode() +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + CCamera *camera = m_cameraEngine->Camera(); + switch(camera->Flash()) { + case CCamera::EFlashAuto: + return QCameraExposure::FlashAuto; + case CCamera::EFlashForced: + return QCameraExposure::FlashOn; + case CCamera::EFlashRedEyeReduce: + return QCameraExposure::FlashRedEyeReduction; + case CCamera::EFlashFillIn: + return QCameraExposure::FlashFill; + case CCamera::EFlashNone: + return QCameraExposure::FlashOff; + + default: + return QCameraExposure::FlashAuto; // Most probable default + } + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } + + return QCameraExposure::FlashOff; +} + +QCameraExposure::FlashModes S60ImageCaptureSession::supportedFlashModes() +{ + QCameraExposure::FlashModes modes = QCameraExposure::FlashOff; + + if (queryCurrentCameraInfo()) { + TInt supportedModes = m_cameraInfo->iFlashModesSupported; + + if (supportedModes == 0) + return modes; + + if (supportedModes & CCamera::EFlashManual) + modes |= QCameraExposure::FlashOff; + if (supportedModes & CCamera::EFlashForced) + modes |= QCameraExposure::FlashOn; + if (supportedModes & CCamera::EFlashAuto) + modes |= QCameraExposure::FlashAuto; + if (supportedModes & CCamera::EFlashFillIn) + modes |= QCameraExposure::FlashFill; + if (supportedModes & CCamera::EFlashRedEyeReduce) + modes |= QCameraExposure::FlashRedEyeReduction; + } + + return modes; +} + +QCameraExposure::ExposureMode S60ImageCaptureSession::exposureMode() +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + CCamera* camera = m_cameraEngine->Camera(); + switch(camera->Exposure()) { + case CCamera::EExposureManual: + return QCameraExposure::ExposureManual; + case CCamera::EExposureAuto: + return QCameraExposure::ExposureAuto; + case CCamera::EExposureNight: + return QCameraExposure::ExposureNight; + case CCamera::EExposureBacklight: + return QCameraExposure::ExposureBacklight; + case CCamera::EExposureSport: + return QCameraExposure::ExposureSports; + case CCamera::EExposureSnow: + return QCameraExposure::ExposureSnow; + case CCamera::EExposureBeach: + return QCameraExposure::ExposureBeach; + + default: + return QCameraExposure::ExposureAuto; + } + } + + return QCameraExposure::ExposureAuto; +} + +bool S60ImageCaptureSession::isExposureModeSupported(QCameraExposure::ExposureMode mode) const +{ + TInt supportedModes = m_cameraInfo->iExposureModesSupported; + + if (supportedModes == 0) + return false; + + switch (mode) { + case QCameraExposure::ExposureManual: + if(supportedModes & CCamera::EExposureManual) + return true; + else + return false; + case QCameraExposure::ExposureAuto: + return true; // Always supported + case QCameraExposure::ExposureNight: + if(supportedModes & CCamera::EExposureNight) + return true; + else + return false; + case QCameraExposure::ExposureBacklight: + if(supportedModes & CCamera::EExposureBacklight) + return true; + else + return false; + case QCameraExposure::ExposureSports: + if(supportedModes & CCamera::EExposureSport) + return true; + else + return false; + case QCameraExposure::ExposureSnow: + if(supportedModes & CCamera::EExposureSnow) + return true; + else + return false; + case QCameraExposure::ExposureBeach: + if(supportedModes & CCamera::EExposureBeach) + return true; + else + return false; + + default: + return false; + } +} + +void S60ImageCaptureSession::setExposureMode(QCameraExposure::ExposureMode mode) +{ + TRAPD(err, doSetExposureModeL(mode)); + setError(err, tr("Failed to set exposure mode.")); +} + +void S60ImageCaptureSession::doSetExposureModeL( QCameraExposure::ExposureMode mode) +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + CCamera *camera = m_cameraEngine->Camera(); + switch(mode) { + case QCameraExposure::ExposureManual: + camera->SetExposureL(CCamera::EExposureManual); + break; + case QCameraExposure::ExposureAuto: + camera->SetExposureL(CCamera::EExposureAuto); + break; + case QCameraExposure::ExposureNight: + camera->SetExposureL(CCamera::EExposureNight); + break; + case QCameraExposure::ExposureBacklight: + camera->SetExposureL(CCamera::EExposureBacklight); + break; + case QCameraExposure::ExposureSports: + camera->SetExposureL(CCamera::EExposureSport); + break; + case QCameraExposure::ExposureSnow: + camera->SetExposureL(CCamera::EExposureSnow); + break; + case QCameraExposure::ExposureBeach: + camera->SetExposureL(CCamera::EExposureBeach); + break; + case QCameraExposure::ExposureLargeAperture: + case QCameraExposure::ExposureSmallAperture: + break; + case QCameraExposure::ExposurePortrait: + case QCameraExposure::ExposureSpotlight: + default: + setError(KErrNotSupported, tr("Requested exposure mode is not suported")); + break; + } + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } +} + +int S60ImageCaptureSession::contrast() const +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + return m_cameraEngine->Camera()->Contrast(); + } else { + return 0; + } +} + +void S60ImageCaptureSession::setContrast(int value) +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + TRAPD(err, m_cameraEngine->Camera()->SetContrastL(value)); + setError(err, tr("Failed to set contrast.")); + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } +} + +int S60ImageCaptureSession::brightness() const +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + return m_cameraEngine->Camera()->Brightness(); + } else { + return 0; + } +} + +void S60ImageCaptureSession::setBrightness(int value) +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + TRAPD(err, m_cameraEngine->Camera()->SetBrightnessL(value)); + setError(err, tr("Failed to set brightness.")); + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } +} + + QCameraImageProcessing::WhiteBalanceMode S60ImageCaptureSession::whiteBalanceMode() +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + CCamera::TWhiteBalance mode = m_cameraEngine->Camera()->WhiteBalance(); + switch(mode) { + case CCamera::EWBAuto: + return QCameraImageProcessing::WhiteBalanceAuto; + case CCamera::EWBDaylight: + return QCameraImageProcessing::WhiteBalanceSunlight; + case CCamera::EWBCloudy: + return QCameraImageProcessing::WhiteBalanceCloudy; + case CCamera::EWBTungsten: + return QCameraImageProcessing::WhiteBalanceTungsten; + case CCamera::EWBFluorescent: + return QCameraImageProcessing::WhiteBalanceFluorescent; + case CCamera::EWBFlash: + return QCameraImageProcessing::WhiteBalanceFlash; + case CCamera::EWBBeach: + return QCameraImageProcessing::WhiteBalanceSunset; + case CCamera::EWBManual: + return QCameraImageProcessing::WhiteBalanceManual; + case CCamera::EWBShade: + return QCameraImageProcessing::WhiteBalanceShade; + + default: + return QCameraImageProcessing::WhiteBalanceAuto; + } + } + + return QCameraImageProcessing::WhiteBalanceAuto; +} + +void S60ImageCaptureSession::setWhiteBalanceMode( QCameraImageProcessing::WhiteBalanceMode mode) +{ + TRAPD(err, doSetWhiteBalanceModeL(mode)); + setError(err, tr("Failed to set white balance mode.")); +} + +void S60ImageCaptureSession::doSetWhiteBalanceModeL( QCameraImageProcessing::WhiteBalanceMode mode) +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + CCamera* camera = m_cameraEngine->Camera(); + switch(mode) { + case QCameraImageProcessing::WhiteBalanceAuto: + camera->SetWhiteBalanceL(CCamera::EWBAuto); + break; + case QCameraImageProcessing::WhiteBalanceSunlight: + camera->SetWhiteBalanceL(CCamera::EWBDaylight); + break; + case QCameraImageProcessing::WhiteBalanceCloudy: + camera->SetWhiteBalanceL(CCamera::EWBCloudy); + break; + case QCameraImageProcessing::WhiteBalanceTungsten: + camera->SetWhiteBalanceL(CCamera::EWBTungsten); + break; + case QCameraImageProcessing::WhiteBalanceFluorescent: + camera->SetWhiteBalanceL(CCamera::EWBFluorescent); + break; + case QCameraImageProcessing::WhiteBalanceFlash: + camera->SetWhiteBalanceL(CCamera::EWBFlash); + break; + case QCameraImageProcessing::WhiteBalanceSunset: + camera->SetWhiteBalanceL(CCamera::EWBBeach); + break; + case QCameraImageProcessing::WhiteBalanceManual: + camera->SetWhiteBalanceL(CCamera::EWBManual); + break; + case QCameraImageProcessing::WhiteBalanceShade: + camera->SetWhiteBalanceL(CCamera::EWBShade); + break; + + default: + setError(KErrNotSupported, tr("Requested white balance mode is not suported")); + break; + } + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } +} + +bool S60ImageCaptureSession::isWhiteBalanceModeSupported(QCameraImageProcessing::WhiteBalanceMode mode) const +{ + if (m_cameraEngine) { + TInt supportedModes = m_cameraInfo->iWhiteBalanceModesSupported; + switch (mode) { + case QCameraImageProcessing::WhiteBalanceManual: + if (supportedModes & CCamera::EWBManual) + return true; + else + return false; + case QCameraImageProcessing::WhiteBalanceAuto: + if (supportedModes & CCamera::EWBAuto) + return true; + else + return false; + case QCameraImageProcessing::WhiteBalanceSunlight: + if (supportedModes & CCamera::EWBDaylight) + return true; + else + return false; + case QCameraImageProcessing::WhiteBalanceCloudy: + if (supportedModes & CCamera::EWBCloudy) + return true; + else + return false; + case QCameraImageProcessing::WhiteBalanceShade: + if (supportedModes & CCamera::EWBShade) + return true; + else + return false; + case QCameraImageProcessing::WhiteBalanceTungsten: + if (supportedModes & CCamera::EWBTungsten) + return true; + else + return false; + case QCameraImageProcessing::WhiteBalanceFluorescent: + if (supportedModes & CCamera::EWBFluorescent) + return true; + else + return false; + case QCameraImageProcessing::WhiteBalanceIncandescent: // Not available in Symbian + return false; + case QCameraImageProcessing::WhiteBalanceFlash: + if (supportedModes & CCamera::EWBFlash) + return true; + else + return false; + case QCameraImageProcessing::WhiteBalanceSunset: + if (supportedModes & CCamera::EWBBeach) + return true; + else + return false; + + default: + return false; + } + } + + return false; +} + +/* + * ==================== + * S60 3.1 AutoFocosing + * ==================== + */ +bool S60ImageCaptureSession::isFocusSupported() const +{ + return m_cameraEngine->IsAutoFocusSupported(); +} + +void S60ImageCaptureSession::startFocus() +{ + if (m_cameraEngine) { + TRAPD(err, m_cameraEngine->StartFocusL()); + setError(err, tr("Failed to start focusing.")); + } + else + setError(KErrNotReady, tr("Unexpected camera error.")); +} + +void S60ImageCaptureSession::cancelFocus() +{ + if (m_cameraEngine) { + TRAPD(err, m_cameraEngine->FocusCancel()); + setError(err, tr("Failed to cancel focusing.")); + } + else + setError(KErrNotReady, tr("Unexpected camera error.")); +} + +void S60ImageCaptureSession::handleImageDecoded(int error) +{ + // Delete unneeded objects + if (m_imageDecoder) { + delete m_imageDecoder; + m_imageDecoder = 0; + } + if (m_fileSystemAccess) { + m_fileSystemAccess->Close(); + delete m_fileSystemAccess; + m_fileSystemAccess = 0; + } + + // Check status of decoding + if (error != KErrNone) { + if (m_previewBitmap) { + m_previewBitmap->Reset(); + delete m_previewBitmap; + m_previewBitmap = 0; + } + releaseImageBuffer(); + if (m_previewInWaitLoop) { + CActiveScheduler::Stop(); // Notify to continue execution of next Preview Image generation + m_previewInWaitLoop = false; // Reset + } + setError(error, tr("Preview creation failed.")); + return; + } + + m_previewDecodingOngoing = false; + + QPixmap prevPixmap = QPixmap::fromSymbianCFbsBitmap(m_previewBitmap); + QImage preview = prevPixmap.toImage(); + + if (m_previewBitmap) { + m_previewBitmap->Reset(); + delete m_previewBitmap; + m_previewBitmap = 0; + } + + QT_TRYCATCH_LEAVING( emit imageCaptured(m_currentImageId, preview) ); + + // Release image resources (if not already done) + releaseImageBuffer(); + + if (m_previewInWaitLoop) { + CActiveScheduler::Stop(); // Notify to continue execution of next Preview Image generation + m_previewInWaitLoop = false; // Reset + } +} + +void S60ImageCaptureSession::handleImageEncoded(int error) +{ + // Check status of encoding + if (error != KErrNone) { + releaseImageBuffer(); + if (m_previewInWaitLoop) { + CActiveScheduler::Stop(); // Notify to continue execution of next Preview Image generation + m_previewInWaitLoop = false; // Reset + } + setError(error, tr("Saving captured image to file failed.")); + return; + } else { + QT_TRYCATCH_LEAVING( emit imageSaved(m_currentImageId, m_stillCaptureFileName) ); + } + + if (m_imageEncoder) { + delete m_imageEncoder; + m_imageEncoder = 0; + } + +#ifndef ECAM_PREVIEW_API + // Start preview generation + TInt previewError = KErrNone; + TFileName fileName = convertImagePath(); + TRAP(previewError, m_imageDecoder = S60ImageCaptureDecoder::FileNewL(this, m_fileSystemAccess, &fileName)); + if (previewError) { + setError(previewError, tr("Failed to create preview image.")); + return; + } + + // Set proper Preview Size + TSize scaledSize((m_captureSize.width() / KSnapshotDownScaleFactor), (m_captureSize.height() / KSnapshotDownScaleFactor)); + if (scaledSize.iWidth < KSnapshotMinWidth || scaledSize.iHeight < KSnapshotMinHeight) + scaledSize.SetSize((m_captureSize.width() / (KSnapshotDownScaleFactor/2)), (m_captureSize.height() / (KSnapshotDownScaleFactor/2))); + if (scaledSize.iWidth < KSnapshotMinWidth || scaledSize.iHeight < KSnapshotMinHeight) + scaledSize.SetSize((m_captureSize.width() / (KSnapshotDownScaleFactor/4)), (m_captureSize.height() / (KSnapshotDownScaleFactor/4))); + if (scaledSize.iWidth < KSnapshotMinWidth || scaledSize.iHeight < KSnapshotMinHeight) + scaledSize.SetSize(m_captureSize.width(), m_captureSize.height()); + + TFrameInfo *info = m_imageDecoder->frameInfo(); + if (!info) { + setError(KErrGeneral, tr("Preview image creation failed.")); + return; + } + + m_previewBitmap = new CFbsBitmap; + if (!m_previewBitmap) { + setError(KErrNoMemory, tr("Failed to create preview image.")); + return; + } + previewError = m_previewBitmap->Create(scaledSize, info->iFrameDisplayMode); + if (previewError) { + setError(previewError, tr("Preview creation failed.")); + return; + } + + // Jpeg decoding completes in handleImageDecoded() + m_imageDecoder->decode(m_previewBitmap); +#endif // ECAM_PREVIEW_API + + // Buffer can be released since Preview is created from file + releaseImageBuffer(); + + // Inform that we can continue taking more pictures + QT_TRYCATCH_LEAVING( emit readyForCaptureChanged(true) ); +} + +#ifdef ECAM_PREVIEW_API +void S60ImageCaptureSession::MceoPreviewReady(CFbsBitmap& aPreview) +{ + QPixmap previewPixmap = QPixmap::fromSymbianCFbsBitmap(&aPreview); + QImage preview = previewPixmap.toImage(); + + // Notify preview availability + emit imageCaptured(m_currentImageId, preview); +} +#endif // ECAM_PREVIEW_API + +// End of file + diff --git a/src/plugins/symbian/ecam/s60imagecapturesession.h b/src/plugins/symbian/ecam/s60imagecapturesession.h new file mode 100644 index 000000000..9cae05fc9 --- /dev/null +++ b/src/plugins/symbian/ecam/s60imagecapturesession.h @@ -0,0 +1,359 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60IMAGECAPTURESESSION_H +#define S60IMAGECAPTURESESSION_H + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "s60camerasettings.h" +#include "s60cameraengine.h" +#include "s60cameraengineobserver.h" +#include "s60cameraconstants.h" // Default Jpeg Quality + +#include // TFrameInfo + +QT_USE_NAMESPACE + +class S60CameraService; +class CImageDecoder; +class CImageEncoder; +class CFrameImageData; +class RFs; +class S60ImageCaptureSession; + +/* + * This class implements asynchronous image decoding service for the + * S60ImageCaptureSession. + */ +class S60ImageCaptureDecoder : public CActive +{ +public: // Static Contructor & Destructor + + static S60ImageCaptureDecoder* FileNewL(S60ImageCaptureSession *imageSession = 0, + RFs *fileSystemAccess = 0, + const TDesC16 *fileName = 0); + static S60ImageCaptureDecoder* DataNewL(S60ImageCaptureSession *imageSession = 0, + RFs *fileSystemAccess = 0, + const TDesC8 *data = 0); + ~S60ImageCaptureDecoder(); + +public: // Operations + + void decode(CFbsBitmap *destBitmap); + TFrameInfo *frameInfo(); + +protected: // CActive + + void RunL(); + void DoCancel(); + TInt RunError(TInt aError); + +protected: // Protected constructors + + S60ImageCaptureDecoder(S60ImageCaptureSession *imageSession, + RFs *fileSystemAccess, + const TDesC8 *data, + const TDesC16 *fileName); + void ConstructL(const bool fileInput = false); + +private: // Data + + S60ImageCaptureSession *m_imageSession; + CImageDecoder *m_imageDecoder; + RFs *m_fs; + const TDesC8 *m_jpegImageData; + const TDesC16 *m_jpegImageFile; + bool m_fileInput; + TFrameInfo m_frameInfo; + +}; + +//============================================================================= + +/* + * This class implements asynchronous image encoding service for the + * S60ImageCaptureSession. + */ +class S60ImageCaptureEncoder : public CActive +{ +public: // Static Contructor & Destructor + + static S60ImageCaptureEncoder* NewL(S60ImageCaptureSession *imageSession = 0, + RFs *fileSystemAccess = 0, + const TDesC16 *fileName = 0, + TInt jpegQuality = KDefaultImageQuality); + ~S60ImageCaptureEncoder(); + +public: // Operations + + void encode(CFbsBitmap *sourceBitmap); + +protected: // CActive + + void RunL(); + void DoCancel(); + TInt RunError(TInt aError); + +protected: // Protected constructors + + S60ImageCaptureEncoder(S60ImageCaptureSession *imageSession, + RFs *fileSystemAccess, + const TDesC16 *fileName, + TInt jpegQuality); + void ConstructL(); + +private: // Data + + S60ImageCaptureSession *m_imageSession; + CImageEncoder *m_imageEncoder; + RFs *m_fileSystemAccess; + const TDesC16 *m_fileName; + CFrameImageData *m_frameImageData; + TInt m_jpegQuality; + +}; + +//============================================================================= + +/* + * Session handling all image capture activities. + */ +class S60ImageCaptureSession : public QObject, +#ifdef ECAM_PREVIEW_API + public MCameraPreviewObserver, +#endif // ECAM_PREVIEW_API + public MCameraEngineImageCaptureObserver +{ + Q_OBJECT + +public: // Enums + + enum ImageCaptureState { + EImageCaptureNotPrepared = 0, // 0 - ImageCapture has not been prepared + EImageCapturePrepared, // 1 - ImageCapture has been prepared + EImageCaptureCapturing, // 2 - Image capture ongoing + EImageCaptureWritingImage // 3 - Image captured and image writing to file ongoing + }; + +public: // Constructor & Destructor + + S60ImageCaptureSession(QObject *parent = 0); + ~S60ImageCaptureSession(); + +public: // Methods + + void setError(const TInt error, const QString &description, const bool captureError = false); + int currentImageId() const; + + bool isDeviceReady(); + void setCameraHandle(CCameraEngine* camerahandle); + void setCurrentDevice(TInt deviceindex); + void notifySettingsSet(); + + // Ecam Advanced Settings + S60CameraSettings* advancedSettings(); + void deleteAdvancedSettings(); + + // Controls + int prepareImageCapture(); + void releaseImageCapture(); + int capture(const QString &fileName); + void cancelCapture(); + void releaseImageBuffer(); + + // Image Resolution + QSize captureSize() const; + QSize minimumCaptureSize(); + QSize maximumCaptureSize(); + QList supportedCaptureSizesForCodec(const QString &codecName); + void setCaptureSize(const QSize &size); + + // Image Codec + QStringList supportedImageCaptureCodecs(); + QString imageCaptureCodec(); + void setImageCaptureCodec(const QString &codecName); + QString imageCaptureCodecDescription(const QString &codecName); + + // Image Quality + QtMultimediaKit::EncodingQuality captureQuality() const; + void setCaptureQuality(const QtMultimediaKit::EncodingQuality &quality); + + // S60 3.1 Focus Control (S60 3.2 and later via S60CameraSettings class) + bool isFocusSupported() const; + void startFocus(); + void cancelFocus(); + + // Zoom Control + qreal maximumZoom(); + qreal minZoom(); + qreal maxDigitalZoom(); + void doSetZoomFactorL(qreal optical, qreal digital); + qreal opticalZoomFactor(); + qreal digitalZoomFactor(); + + // Exposure Mode Control + QCameraExposure::ExposureMode exposureMode(); + void setExposureMode(QCameraExposure::ExposureMode mode); + bool isExposureModeSupported(QCameraExposure::ExposureMode mode) const; + + // Flash Mode Control + QCameraExposure::FlashMode flashMode(); + void setFlashMode(QCameraExposure::FlashModes mode); + QCameraExposure::FlashModes supportedFlashModes(); + + // Contrast Control + int contrast() const; + void setContrast(int value); + + // Brightness Control + int brightness() const; + void setBrightness(int value); + + // White Balance Mode Control + QCameraImageProcessing::WhiteBalanceMode whiteBalanceMode(); + void setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode); + bool isWhiteBalanceModeSupported(QCameraImageProcessing::WhiteBalanceMode mode) const; + +public: // Image Decoding & Encoding Notifications + + void handleImageDecoded(int error); + void handleImageEncoded(int error); + +protected: // MCameraEngineObserver + + void MceoFocusComplete(); + void MceoCapturedDataReady(TDesC8* aData); + void MceoCapturedBitmapReady(CFbsBitmap* aBitmap); + void MceoHandleError(TCameraEngineError aErrorType, TInt aError); + +#ifdef ECAM_PREVIEW_API +protected: // MCameraPreviewObserver + + void MceoPreviewReady(CFbsBitmap& aPreview); +#endif // ECAM_PREVIEW_API + +private: // Internal + + QCameraImageCapture::Error fromSymbianErrorToQtMultimediaError(int aError); + + void initializeImageCaptureSettings(); + void resetSession(bool errorHandling = false); + + CCamera::TFormat selectFormatForCodec(const QString &codec); + CCamera::TFormat defaultImageFormat(); + bool queryCurrentCameraInfo(); + QMap formatMap(); + QMap codecDescriptionMap(); + void updateImageCaptureFormats(); + + void doSetWhiteBalanceModeL(QCameraImageProcessing::WhiteBalanceMode mode); + + void doSetFlashModeL(QCameraExposure::FlashModes mode); + void doSetExposureModeL(QCameraExposure::ExposureMode mode); + + void saveImageL(TDesC8 *aData, TFileName &aPath); + void processFileName(const QString &fileName); + TFileName convertImagePath(); + +signals: // Notifications + + void stateChanged(QCamera::State); + void advancedSettingChanged(); + void captureSizeChanged(const QSize&); + + // Error signals + void cameraError(int, const QString&); // For QCamera::error + void captureError(int, int, const QString&); // For QCameraImageCapture::error + + // Capture notifications + void readyForCaptureChanged(bool); + void imageExposed(int); + void imageCaptured(const int, const QImage&); + void imageSaved(const int, const QString&); + + // Focus notifications + void focusStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason); + +private slots: // Internal Slots + + void cameraStatusChanged(QCamera::Status); + +private: // Data + + CCameraEngine *m_cameraEngine; + S60CameraSettings *m_advancedSettings; + mutable TCameraInfo *m_cameraInfo; + CFbsBitmap *m_previewBitmap; + CActiveScheduler *m_activeScheduler; + RFs *m_fileSystemAccess; + S60ImageCaptureDecoder *m_imageDecoder; + S60ImageCaptureEncoder *m_imageEncoder; + mutable int m_error; // Symbian ErrorCode + TInt m_activeDeviceIndex; + bool m_cameraStarted; + ImageCaptureState m_icState; + QStringList m_supportedImageCodecs; + QString m_currentCodec; + CCamera::TFormat m_currentFormat; + QSize m_captureSize; + int m_symbianImageQuality; + bool m_captureSettingsSet; + QString m_stillCaptureFileName; + QString m_requestedStillCaptureFileName; + mutable int m_currentImageId; + QList m_formats; + // This indicates that image capture should be triggered right after + // camera and image setting initialization has completed + bool m_captureWhenReady; + bool m_previewDecodingOngoing; + bool m_previewInWaitLoop; +}; + +#endif // S60IMAGECAPTURESESSION_H diff --git a/src/plugins/symbian/ecam/s60imageencodercontrol.cpp b/src/plugins/symbian/ecam/s60imageencodercontrol.cpp new file mode 100644 index 000000000..bfbf8d36b --- /dev/null +++ b/src/plugins/symbian/ecam/s60imageencodercontrol.cpp @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "s60imageencodercontrol.h" +#include "s60imagecapturesession.h" + +S60ImageEncoderControl::S60ImageEncoderControl(QObject *parent) : + QImageEncoderControl(parent) +{ +} + +S60ImageEncoderControl::S60ImageEncoderControl(S60ImageCaptureSession *session, QObject *parent) : + QImageEncoderControl(parent) +{ + m_session = session; +} + +S60ImageEncoderControl::~S60ImageEncoderControl() +{ +} + +QList S60ImageEncoderControl::supportedResolutions( + const QImageEncoderSettings &settings, bool *continuous) const +{ + QList resolutions = m_session->supportedCaptureSizesForCodec(settings.codec()); + + // Discrete resolutions are returned + if (continuous) + *continuous = false; + + return resolutions; +} +QStringList S60ImageEncoderControl::supportedImageCodecs() const +{ + return m_session->supportedImageCaptureCodecs(); +} + +QString S60ImageEncoderControl::imageCodecDescription(const QString &codec) const +{ + return m_session->imageCaptureCodecDescription(codec); +} + +QImageEncoderSettings S60ImageEncoderControl::imageSettings() const +{ + // Update setting values from session + QImageEncoderSettings settings; + settings.setCodec(m_session->imageCaptureCodec()); + settings.setResolution(m_session->captureSize()); + settings.setQuality(m_session->captureQuality()); + + return settings; +} +void S60ImageEncoderControl::setImageSettings(const QImageEncoderSettings &settings) +{ + // Notify that settings have been implicitly set and there's no need to + // initialize them in case camera is changed + m_session->notifySettingsSet(); + + if (!settings.isNull()) { + if (!settings.codec().isEmpty()) { + if (settings.resolution() != QSize(-1,-1)) { // Codec, Resolution & Quality + m_session->setImageCaptureCodec(settings.codec()); + m_session->setCaptureSize(settings.resolution()); + m_session->setCaptureQuality(settings.quality()); + } else { // Codec and Quality + m_session->setImageCaptureCodec(settings.codec()); + m_session->setCaptureQuality(settings.quality()); + } + } else { + if (settings.resolution() != QSize(-1,-1)) { // Resolution & Quality + m_session->setCaptureSize(settings.resolution()); + m_session->setCaptureQuality(settings.quality()); + } + else // Only Quality + m_session->setCaptureQuality(settings.quality()); + } + + // Prepare ImageCapture with the settings and set error if needed + int prepareSuccess = m_session->prepareImageCapture(); + + // Preparation fails with KErrNotReady if camera has not been started. + // That can be ignored since settings are set internally in that case. + if (prepareSuccess != KErrNotReady && prepareSuccess != KErrNone) + m_session->setError(prepareSuccess, tr("Failure in preparation of image capture.")); + } +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60imageencodercontrol.h b/src/plugins/symbian/ecam/s60imageencodercontrol.h new file mode 100644 index 000000000..99a308286 --- /dev/null +++ b/src/plugins/symbian/ecam/s60imageencodercontrol.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60IMAGEENCODERCONTROL_H +#define S60IMAGEENCODERCONTROL_H + +#include +#include "qimageencodercontrol.h" + +QT_USE_NAMESPACE + +class S60ImageCaptureSession; + +/* + * Control for setting encoding settings for the captured image. + */ +class S60ImageEncoderControl : public QImageEncoderControl +{ + Q_OBJECT + +public: // Contructors & Destructor + + S60ImageEncoderControl(QObject *parent = 0); + S60ImageEncoderControl(S60ImageCaptureSession *session, QObject *parent = 0); + ~S60ImageEncoderControl(); + +public: // QImageEncoderControl + + // Codec + QStringList supportedImageCodecs() const; + QString imageCodecDescription(const QString &codec) const; + + // Resolution + QList supportedResolutions(const QImageEncoderSettings &settings, + bool *continuous = 0) const; + + // Settings + QImageEncoderSettings imageSettings() const; + void setImageSettings(const QImageEncoderSettings &settings); + +private: // Data + + S60ImageCaptureSession *m_session; +}; + +#endif // S60IMAGEENCODERCONTROL_H diff --git a/src/plugins/symbian/ecam/s60mediacontainercontrol.cpp b/src/plugins/symbian/ecam/s60mediacontainercontrol.cpp new file mode 100644 index 000000000..f0d20f4e3 --- /dev/null +++ b/src/plugins/symbian/ecam/s60mediacontainercontrol.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "s60mediacontainercontrol.h" +#include "s60videocapturesession.h" +#include "s60cameraconstants.h" + +S60MediaContainerControl::S60MediaContainerControl(QObject *parent): + QMediaContainerControl(parent) +{ +} + +S60MediaContainerControl::S60MediaContainerControl(S60VideoCaptureSession *session, QObject *parent): + QMediaContainerControl(parent) +{ + m_session = session; + + // Set default video container + m_supportedContainers = m_session->supportedVideoContainers(); + + if (!m_supportedContainers.isEmpty()) { + // Check if default container is supported + if (m_supportedContainers.indexOf(KMimeTypeDefaultContainer) != -1) + setContainerMimeType(KMimeTypeDefaultContainer); + // Otherwise use first in the list + else + setContainerMimeType(m_supportedContainers[0]); // First as default + } else { + m_session->setError(KErrGeneral, tr("No supported video containers found.")); + } +} + +S60MediaContainerControl::~S60MediaContainerControl() +{ + m_supportedContainers.clear(); + m_containerDescriptions.clear(); +} + +QStringList S60MediaContainerControl::supportedContainers() const +{ + return m_session->supportedVideoContainers(); +} + +QString S60MediaContainerControl::containerMimeType() const +{ + return m_session->videoContainer(); +} + +void S60MediaContainerControl::setContainerMimeType(const QString &containerMimeType) +{ + m_session->setVideoContainer(containerMimeType); +} + +QString S60MediaContainerControl::containerDescription(const QString &containerMimeType) const +{ + return m_session->videoContainerDescription(containerMimeType); +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60mediacontainercontrol.h b/src/plugins/symbian/ecam/s60mediacontainercontrol.h new file mode 100644 index 000000000..057b4bc43 --- /dev/null +++ b/src/plugins/symbian/ecam/s60mediacontainercontrol.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60MEDIACONTAINERCONTROL_H +#define S60MEDIACONTAINERCONTROL_H + +#include +#include +#include + +QT_USE_NAMESPACE + +class S60VideoCaptureSession; + +/* + * Control for setting container (file format) for video recorded using + * QMediaRecorder. + */ +class S60MediaContainerControl : public QMediaContainerControl +{ + Q_OBJECT + +public: // Contructors & Destructor + + S60MediaContainerControl(QObject *parent = 0); + S60MediaContainerControl(S60VideoCaptureSession *session, QObject *parent = 0); + virtual ~S60MediaContainerControl(); + +public: // QMediaContainerControl + + QStringList supportedContainers() const; + QString containerMimeType() const; + void setContainerMimeType(const QString &containerMimeType); + + QString containerDescription(const QString &containerMimeType) const; + +private: // Data + + S60VideoCaptureSession *m_session; + QStringList m_supportedContainers; + QMap m_containerDescriptions; +}; + +#endif // S60MEDIACONTAINERCONTROL_H diff --git a/src/plugins/symbian/ecam/s60mediarecordercontrol.cpp b/src/plugins/symbian/ecam/s60mediarecordercontrol.cpp new file mode 100644 index 000000000..2a1394fa5 --- /dev/null +++ b/src/plugins/symbian/ecam/s60mediarecordercontrol.cpp @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "s60cameraservice.h" +#include "s60mediarecordercontrol.h" +#include "s60cameracontrol.h" +#include "s60videocapturesession.h" + +S60MediaRecorderControl::S60MediaRecorderControl(QObject *parent) : + QMediaRecorderControl(parent) +{ +} + +S60MediaRecorderControl::S60MediaRecorderControl(S60CameraService *service, + S60VideoCaptureSession *session, + QObject *parent): + QMediaRecorderControl(parent), + m_state(QMediaRecorder::StoppedState) // Default RecorderState +{ + m_session = session; + m_service = service; + m_cameraControl = qobject_cast(m_service->requestControl(QCameraControl_iid)); + + // Connect signals + connect(m_session, SIGNAL(stateChanged(S60VideoCaptureSession::TVideoCaptureState)), + this, SLOT(updateState(S60VideoCaptureSession::TVideoCaptureState))); + connect(m_session, SIGNAL(positionChanged(qint64)), this, SIGNAL(durationChanged(qint64))); + connect(m_session, SIGNAL(mutedChanged(bool)), this, SIGNAL(mutedChanged(bool))); + connect(m_session, SIGNAL(error(int,const QString &)), this, SIGNAL(error(int,const QString &))); +} + +S60MediaRecorderControl::~S60MediaRecorderControl() +{ + // Release requested control + if (m_cameraControl) + m_service->releaseControl(m_cameraControl); +} + +QUrl S60MediaRecorderControl::outputLocation() const +{ + return m_session->outputLocation(); +} + +bool S60MediaRecorderControl::setOutputLocation(const QUrl& sink) +{ + // Output location can only be set in StoppedState + if (m_state == QMediaRecorder::StoppedState) + return m_session->setOutputLocation(sink); + + // Do not signal error, but notify that setting was not effective + return false; +} + +QMediaRecorder::State S60MediaRecorderControl::convertInternalStateToQtState(S60VideoCaptureSession::TVideoCaptureState aState) const +{ + QMediaRecorder::State state; + + switch (aState) { + case S60VideoCaptureSession::ERecording: + state = QMediaRecorder::RecordingState; + break; + case S60VideoCaptureSession::EPaused: + state = QMediaRecorder::PausedState; + break; + + default: + // All others + state = QMediaRecorder::StoppedState; + break; + } + + return state; +} + +void S60MediaRecorderControl::updateState(S60VideoCaptureSession::TVideoCaptureState state) +{ + QMediaRecorder::State newState = convertInternalStateToQtState(state); + + if (m_state != newState) { + m_state = newState; + emit stateChanged(m_state); + } +} + +QMediaRecorder::State S60MediaRecorderControl::state() const +{ + return m_state; +} + +qint64 S60MediaRecorderControl::duration() const +{ + return m_session->position(); +} + +/* +This method is called after encoder configuration is done. +Encoder can load necessary resources at this point, +to reduce delay before recording is started. Calling this method reduces the +latency when calling record() to start video recording. +*/ +void S60MediaRecorderControl::applySettings() +{ + m_session->applyAllSettings(); +} + +void S60MediaRecorderControl::record() +{ + if (m_state == QMediaRecorder::RecordingState) + return; + + if (m_cameraControl && m_cameraControl->captureMode() != QCamera::CaptureVideo) { + emit error(QCamera::CameraError, tr("Video capture mode is not selected.")); + return; + } + + m_session->startRecording(); +} + +void S60MediaRecorderControl::pause() +{ + if (m_state != QMediaRecorder::RecordingState) { + // Discard + return; + } + + m_session->pauseRecording(); +} + +void S60MediaRecorderControl::stop() +{ + if (m_state == QMediaRecorder::StoppedState) { + // Ignore + return; + } + + m_session->stopRecording(); +} + +bool S60MediaRecorderControl::isMuted() const +{ + return m_session->isMuted(); +} + +void S60MediaRecorderControl::setMuted(bool muted) +{ + m_session->setMuted(muted); +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60mediarecordercontrol.h b/src/plugins/symbian/ecam/s60mediarecordercontrol.h new file mode 100644 index 000000000..5db7477bd --- /dev/null +++ b/src/plugins/symbian/ecam/s60mediarecordercontrol.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60MEDIARECORDERCONTROL_H +#define S60MEDIARECORDERCONTROL_H + +#include +#include +#include + +#include "s60videocapturesession.h" + +QT_USE_NAMESPACE + +class S60VideoCaptureSession; +class S60CameraService; +class S60CameraControl; + +/* + * Control for video recording operations. + */ +class S60MediaRecorderControl : public QMediaRecorderControl +{ + Q_OBJECT + +public: // Contructors & Destructor + + S60MediaRecorderControl(QObject *parent = 0); + S60MediaRecorderControl(S60CameraService *service, + S60VideoCaptureSession *session, + QObject *parent = 0); + ~S60MediaRecorderControl(); + +public: // QMediaRecorderControl + + QUrl outputLocation() const; + bool setOutputLocation(const QUrl &sink); + + QMediaRecorder::State state() const; + + qint64 duration() const; + + bool isMuted() const; + + void applySettings(); + +/* +Q_SIGNALS: // QMediaRecorderControl + void stateChanged(QMediaRecorder::State state); + void durationChanged(qint64 position); + void mutedChanged(bool muted); + void error(int error, const QString &errorString); +*/ + +public slots: // QMediaRecorderControl + + void record(); + void pause(); + void stop(); + void setMuted(bool); + +private: + + QMediaRecorder::State convertInternalStateToQtState( + S60VideoCaptureSession::TVideoCaptureState aState) const; + +private slots: + + void updateState(S60VideoCaptureSession::TVideoCaptureState state); + +private: // Data + + S60VideoCaptureSession *m_session; + S60CameraService *m_service; + S60CameraControl *m_cameraControl; + QMediaRecorder::State m_state; + +}; + +#endif // S60MEDIARECORDERCONTROL_H diff --git a/src/plugins/symbian/ecam/s60videocapturesession.cpp b/src/plugins/symbian/ecam/s60videocapturesession.cpp new file mode 100644 index 000000000..7158f8696 --- /dev/null +++ b/src/plugins/symbian/ecam/s60videocapturesession.cpp @@ -0,0 +1,2995 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +#include "s60videocapturesession.h" +#include "s60cameraconstants.h" + +#include +#include + +#ifdef S60_DEVVIDEO_RECORDING_SUPPORTED +#include +#endif + +S60VideoCaptureSession::S60VideoCaptureSession(QObject *parent) : + QObject(parent), + m_cameraEngine(0), + m_videoRecorder(0), + m_position(0), + m_error(KErrNone), + m_cameraStarted(false), + m_captureState(ENotInitialized), // Default state + m_sink(QUrl()), + m_requestedSink(QUrl()), + m_captureSettingsSet(false), + m_container(QString()), + m_requestedContainer(QString()), + m_muted(false), + m_maxClipSize(-1), + m_videoControllerMap(QHash >()), + m_videoParametersForEncoder(QList()), + m_openWhenReady(false), + m_prepareAfterOpenComplete(false), + m_startAfterPrepareComplete(false), + m_uncommittedSettings(false), + m_commitSettingsWhenReady(false) +{ +#ifdef S60_DEVVIDEO_RECORDING_SUPPORTED + // Populate info of supported codecs, and their resolution, etc. + TRAPD(err, doPopulateVideoCodecsDataL()); + setError(err, tr("Failed to gather video codec information.")); +#endif // S60_DEVVIDEO_RECORDING_SUPPORTED + + initializeVideoCaptureSettings(); + + m_durationTimer = new QTimer; + m_durationTimer->setInterval(KDurationChangedInterval); + connect(m_durationTimer, SIGNAL(timeout()), this, SLOT(durationTimerTriggered())); +} + +S60VideoCaptureSession::~S60VideoCaptureSession() +{ + if (m_captureState >= ERecording) + m_videoRecorder->Stop(); + + if (m_captureState >= EInitialized) + m_videoRecorder->Close(); + + if (m_videoRecorder) { + delete m_videoRecorder; + m_videoRecorder = 0; + } + + if (m_durationTimer) { + delete m_durationTimer; + m_durationTimer = 0; + } + + // Clear all data structures + foreach (MaxResolutionRatesAndTypes structure, m_videoParametersForEncoder) { + structure.frameRatePictureSizePair.clear(); + structure.mimeTypes.clear(); + } + m_videoParametersForEncoder.clear(); + + m_videoCodecList.clear(); + m_audioCodecList.clear(); + + QList controllers = m_videoControllerMap.keys(); + for (int i = 0; i < controllers.size(); ++i) { + foreach(VideoFormatData data, m_videoControllerMap[controllers[i]]){ + data.supportedMimeTypes.clear(); + } + m_videoControllerMap[controllers[i]].clear(); + } + m_videoControllerMap.clear(); +} + +/* + * This function can be used both internally and from Control classes using this session. + * The error notification will go to client application through QMediaRecorder error signal. + */ +void S60VideoCaptureSession::setError(const TInt error, const QString &description) +{ + if (error == KErrNone) + return; + + m_error = error; + QMediaRecorder::Error recError = fromSymbianErrorToQtMultimediaError(m_error); + + // Stop/Close/Reset only of other than "not supported" error + if (m_error != KErrNotSupported) { + if (m_captureState >= ERecording) + m_videoRecorder->Stop(); + + if (m_captureState >= EInitialized) + m_videoRecorder->Close(); + + // Reset state + if (m_captureState != ENotInitialized) { + if (m_durationTimer->isActive()) + m_durationTimer->stop(); + m_captureState = ENotInitialized; + emit stateChanged(m_captureState); + } + } + + emit this->error(recError, description); + + // Reset only of other than "not supported" error + if (m_error != KErrNotSupported) + resetSession(true); + else + m_error = KErrNone; // Reset error +} + +QMediaRecorder::Error S60VideoCaptureSession::fromSymbianErrorToQtMultimediaError(int aError) +{ + switch(aError) { + case KErrNone: + return QMediaRecorder::NoError; // No errors have occurred + case KErrArgument: + case KErrNotSupported: + return QMediaRecorder::FormatError; // The feature/format is not supported + case KErrNoMemory: + case KErrNotFound: + case KErrBadHandle: + return QMediaRecorder::ResourceError; // Not able to use camera/recorder resources + + default: + return QMediaRecorder::ResourceError; // Other error has occurred + } +} + +/* + * This function applies all recording settings to make latency during the + * start of the recording as short as possible. After this it is not possible to + * set settings (inc. output location) before stopping the recording. + */ +void S60VideoCaptureSession::applyAllSettings() +{ + switch (m_captureState) { + case ENotInitialized: + case EInitializing: + m_commitSettingsWhenReady = true; + return; + case EInitialized: + setOutputLocation(QUrl()); + m_prepareAfterOpenComplete = true; + return; + case EOpening: + m_prepareAfterOpenComplete = true; + return; + case EOpenComplete: + // Do nothing, ready to commit + break; + case EPreparing: + m_commitSettingsWhenReady = true; + return; + case EPrepared: + // Revert state internally, since logically applying settings means going + // from OpenComplete ==> Preparing ==> Prepared. + m_captureState = EOpenComplete; + break; + case ERecording: + case EPaused: + setError(KErrNotReady, tr("Cannot apply settings while recording.")); + return; + + default: + setError(KErrGeneral, tr("Unexpected camera error.")); + return; + } + + // Commit settings - State is now OpenComplete (possibly reverted from Prepared) + commitVideoEncoderSettings(); + + // If capture state has been changed to: + // * Opening: A different media container has been requested + // * Other: Failure during the setting committing + // ==> Return + if (m_captureState != EOpenComplete) + return; + + // Start preparing + m_captureState = EPreparing; + emit stateChanged(m_captureState); + + if (m_cameraEngine->IsCameraReady()) + m_videoRecorder->Prepare(); +} + +void S60VideoCaptureSession::setCameraHandle(CCameraEngine* cameraHandle) +{ + m_cameraEngine = cameraHandle; + + // Initialize settings for the new camera + initializeVideoCaptureSettings(); + + resetSession(); +} + +void S60VideoCaptureSession::notifySettingsSet() +{ + m_captureSettingsSet = true; +} + +void S60VideoCaptureSession::doInitializeVideoRecorderL() +{ + if (m_captureState > ENotInitialized) + resetSession(); + + m_captureState = EInitializing; + emit stateChanged(m_captureState); + + // Open Dummy file to be able to query supported settings + int cameraHandle = m_cameraEngine->Camera() ? m_cameraEngine->Camera()->Handle() : 0; + + TUid controllerUid; + TUid formatUid; + selectController(m_requestedContainer, controllerUid, formatUid); + + if (m_videoRecorder) { + // File open completes in MvruoOpenComplete + TRAPD(err, m_videoRecorder->OpenFileL(KDummyVideoFile, cameraHandle, controllerUid, formatUid)); + setError(err, tr("Failed to initialize video recorder.")); + m_container = m_requestedContainer; + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } +} + +void S60VideoCaptureSession::resetSession(bool errorHandling) +{ + if (m_videoRecorder) { + delete m_videoRecorder; + m_videoRecorder = 0; + } + + if (m_captureState != ENotInitialized) { + if (m_durationTimer->isActive()) + m_durationTimer->stop(); + m_captureState = ENotInitialized; + emit stateChanged(m_captureState); + } + + // Reset error to be able to recover + m_error = KErrNone; + + // Reset flags + m_openWhenReady = false; + m_prepareAfterOpenComplete = false; + m_startAfterPrepareComplete = false; + m_uncommittedSettings = false; + m_commitSettingsWhenReady = false; + + TRAPD(err, m_videoRecorder = CVideoRecorderUtility::NewL(*this)); + if (err) { + qWarning("Failed to create video recorder."); + if (errorHandling) + emit error(QMediaRecorder::ResourceError, tr("Failed to recover from video error.")); + else + setError(err, tr("Failure in creation of video recorder device.")); + return; + } + + updateVideoCaptureContainers(); +} + +QList S60VideoCaptureSession::supportedVideoResolutions(bool *continuous) +{ + QList resolutions; + + // Secondary Camera + if (m_cameraEngine->CurrentCameraIndex() != 0) { + TCameraInfo *info = m_cameraEngine->CameraInfo(); + if (info) { + TInt videoResolutionCount = info->iNumVideoFrameSizesSupported; + CCamera *camera = m_cameraEngine->Camera(); + if (camera) { + for (TInt i = 0; i < videoResolutionCount; ++i) { + TSize checkedResolution; + camera->EnumerateVideoFrameSizes(checkedResolution, i, CCamera::EFormatYUV420Planar); + QSize qtResolution(checkedResolution.iWidth, checkedResolution.iHeight); + if (!resolutions.contains(qtResolution)) + resolutions.append(qtResolution); + } + } else { + setError(KErrGeneral, tr("Could not query supported video resolutions.")); + } + } else { + setError(KErrGeneral, tr("Could not query supported video resolutions.")); + } + + // Primary Camera + } else { + + if (m_videoParametersForEncoder.count() > 0) { + + // Also arbitrary resolutions are supported + if (continuous) + *continuous = true; + + // Append all supported resolutions to the list + foreach (MaxResolutionRatesAndTypes parameters, m_videoParametersForEncoder) + for (int i = 0; i < parameters.frameRatePictureSizePair.count(); ++i) + if (!resolutions.contains(parameters.frameRatePictureSizePair[i].frameSize)) + resolutions.append(parameters.frameRatePictureSizePair[i].frameSize); + } + } + +#ifdef Q_CC_NOKIAX86 // Emulator + resolutions << QSize(160, 120); + resolutions << QSize(352, 288); + resolutions << QSize(640,480); +#endif // Q_CC_NOKIAX86 + + return resolutions; +} + +QList S60VideoCaptureSession::supportedVideoResolutions(const QVideoEncoderSettings &settings, bool *continuous) +{ + QList supportedFrameSizes; + + // Secondary Camera + if (m_cameraEngine->CurrentCameraIndex() != 0) { + TCameraInfo *info = m_cameraEngine->CameraInfo(); + if (info) { + TInt videoResolutionCount = info->iNumVideoFrameSizesSupported; + CCamera *camera = m_cameraEngine->Camera(); + if (camera) { + for (TInt i = 0; i < videoResolutionCount; ++i) { + TSize checkedResolution; + camera->EnumerateVideoFrameSizes(checkedResolution, i, CCamera::EFormatYUV420Planar); + QSize qtResolution(checkedResolution.iWidth, checkedResolution.iHeight); + if (!supportedFrameSizes.contains(qtResolution)) + supportedFrameSizes.append(qtResolution); + } + } else { + setError(KErrGeneral, tr("Could not query supported video resolutions.")); + } + } else { + setError(KErrGeneral, tr("Could not query supported video resolutions.")); + } + + // Primary Camera + } else { + + if (settings.codec().isEmpty()) + return supportedFrameSizes; + + if (!m_videoCodecList.contains(settings.codec(), Qt::CaseInsensitive)) + return supportedFrameSizes; + + // Also arbitrary resolutions are supported + if (continuous) + *continuous = true; + + // Find maximum resolution (using defined framerate if set) + for (int i = 0; i < m_videoParametersForEncoder.count(); ++i) { + // Check if encoder supports the requested codec + if (!m_videoParametersForEncoder[i].mimeTypes.contains(settings.codec(), Qt::CaseInsensitive)) + continue; + + foreach (SupportedFrameRatePictureSize pair, m_videoParametersForEncoder[i].frameRatePictureSizePair) { + if (!supportedFrameSizes.contains(pair.frameSize)) { + QSize maxForMime = maximumResolutionForMimeType(settings.codec()); + if (settings.frameRate() != 0) { + if (settings.frameRate() <= pair.frameRate) { + if ((pair.frameSize.width() * pair.frameSize.height()) <= (maxForMime.width() * maxForMime.height())) + supportedFrameSizes.append(pair.frameSize); + } + } else { + if ((pair.frameSize.width() * pair.frameSize.height()) <= (maxForMime.width() * maxForMime.height())) + supportedFrameSizes.append(pair.frameSize); + } + } + } + } + } + +#ifdef Q_CC_NOKIAX86 // Emulator + supportedFrameSizes << QSize(160, 120); + supportedFrameSizes << QSize(352, 288); + supportedFrameSizes << QSize(640,480); +#endif + + return supportedFrameSizes; +} + +QList S60VideoCaptureSession::supportedVideoFrameRates(bool *continuous) +{ + QList supportedRatesList; + + if (m_videoParametersForEncoder.count() > 0) { + // Insert min and max to the list + supportedRatesList.append(1.0); // Use 1fps as sensible minimum + qreal foundMaxFrameRate(0.0); + + // Also arbitrary framerates are supported + if (continuous) + *continuous = true; + + // Find max framerate + foreach (MaxResolutionRatesAndTypes parameters, m_videoParametersForEncoder) { + for (int i = 0; i < parameters.frameRatePictureSizePair.count(); ++i) { + qreal maxFrameRate = parameters.frameRatePictureSizePair[i].frameRate; + if (maxFrameRate > foundMaxFrameRate) + foundMaxFrameRate = maxFrameRate; + } + } + + supportedRatesList.append(foundMaxFrameRate); + } + + // Add also other standard framerates to the list + if (!supportedRatesList.isEmpty()) { + if (supportedRatesList.last() > 30.0) { + if (!supportedRatesList.contains(30.0)) + supportedRatesList.insert(1, 30.0); + } + if (supportedRatesList.last() > 25.0) { + if (!supportedRatesList.contains(25.0)) + supportedRatesList.insert(1, 25.0); + } + if (supportedRatesList.last() > 15.0) { + if (!supportedRatesList.contains(15.0)) + supportedRatesList.insert(1, 15.0); + } + if (supportedRatesList.last() > 10.0) { + if (!supportedRatesList.contains(10)) + supportedRatesList.insert(1, 10.0); + } + } + +#ifdef Q_CC_NOKIAX86 // Emulator + supportedRatesList << 30.0 << 25.0 << 15.0 << 10.0 << 5.0; +#endif + + return supportedRatesList; +} + +QList S60VideoCaptureSession::supportedVideoFrameRates(const QVideoEncoderSettings &settings, bool *continuous) +{ + QList supportedFrameRates; + + if (settings.codec().isEmpty()) + return supportedFrameRates; + if (!m_videoCodecList.contains(settings.codec(), Qt::CaseInsensitive)) + return supportedFrameRates; + + // Also arbitrary framerates are supported + if (continuous) + *continuous = true; + + // Find maximum framerate (using defined resolution if set) + for (int i = 0; i < m_videoParametersForEncoder.count(); ++i) { + // Check if encoder supports the requested codec + if (!m_videoParametersForEncoder[i].mimeTypes.contains(settings.codec(), Qt::CaseInsensitive)) + continue; + + foreach (SupportedFrameRatePictureSize pair, m_videoParametersForEncoder[i].frameRatePictureSizePair) { + if (!supportedFrameRates.contains(pair.frameRate)) { + qreal maxRateForMime = maximumFrameRateForMimeType(settings.codec()); + if (settings.resolution().width() != 0 && settings.resolution().height() != 0) { + if((settings.resolution().width() * settings.resolution().height()) <= (pair.frameSize.width() * pair.frameSize.height())) { + if (pair.frameRate <= maxRateForMime) + supportedFrameRates.append(pair.frameRate); + } + } else { + if (pair.frameRate <= maxRateForMime) + supportedFrameRates.append(pair.frameRate); + } + } + } + } + + // Add also other standard framerates to the list + if (!supportedFrameRates.isEmpty()) { + if (supportedFrameRates.last() > 30.0) { + if (!supportedFrameRates.contains(30.0)) + supportedFrameRates.insert(1, 30.0); + } + if (supportedFrameRates.last() > 25.0) { + if (!supportedFrameRates.contains(25.0)) + supportedFrameRates.insert(1, 25.0); + } + if (supportedFrameRates.last() > 15.0) { + if (!supportedFrameRates.contains(15.0)) + supportedFrameRates.insert(1, 15.0); + } + if (supportedFrameRates.last() > 10.0) { + if (!supportedFrameRates.contains(10)) + supportedFrameRates.insert(1, 10.0); + } + } + +#ifdef Q_CC_NOKIAX86 // Emulator + supportedFrameRates << 30.0 << 25.0 << 15.0 << 10.0 << 5.0; +#endif + + return supportedFrameRates; +} + +bool S60VideoCaptureSession::setOutputLocation(const QUrl &sink) +{ + m_requestedSink = sink; + + if (m_error) + return false; + + switch (m_captureState) { + case ENotInitialized: + case EInitializing: + case EOpening: + case EPreparing: + m_openWhenReady = true; + return true; + + case EInitialized: + case EOpenComplete: + case EPrepared: + // Continue + break; + + case ERecording: + case EPaused: + setError(KErrNotReady, tr("Cannot set file name while recording.")); + return false; + + default: + setError(KErrGeneral, tr("Unexpected camera error.")); + return false; + } + + // Empty URL - Use default file name and path (C:\Data\Videos\video.mp4) + if (sink.isEmpty()) { + + // Make sure default directory exists + QDir videoDir(QDir::rootPath()); + if (!videoDir.exists(KDefaultVideoPath)) + videoDir.mkpath(KDefaultVideoPath); + QString defaultFile = KDefaultVideoPath; + defaultFile.append("\\"); + defaultFile.append(KDefaultVideoFileName); + m_sink.setUrl(defaultFile); + + } else { // Non-empty URL + + QString fullUrl = sink.scheme(); + + // Relative URL + if (sink.isRelative()) { + + // Extract file name and path from the URL + fullUrl = KDefaultVideoPath; + fullUrl.append("\\"); + fullUrl.append(QDir::toNativeSeparators(sink.path())); + + // Absolute URL + } else { + + // Extract file name and path from the URL + if (fullUrl == "file") { + fullUrl = QDir::toNativeSeparators(sink.path().right(sink.path().length() - 1)); + } else { + fullUrl.append(":"); + fullUrl.append(QDir::toNativeSeparators(sink.path())); + } + } + + QString fileName = fullUrl.right(fullUrl.length() - fullUrl.lastIndexOf("\\") - 1); + QString directory = fullUrl.left(fullUrl.lastIndexOf("\\")); + if (directory.lastIndexOf("\\") == (directory.length() - 1)) + directory = directory.left(directory.length() - 1); + + // URL is Absolute path, not including file name + if (!fileName.contains(".")) { + if (fileName != "") { + directory.append("\\"); + directory.append(fileName); + } + fileName = KDefaultVideoFileName; + } + + // Make sure absolute directory exists + QDir videoDir(QDir::rootPath()); + if (!videoDir.exists(directory)) + videoDir.mkpath(directory); + + QString resolvedURL = directory; + resolvedURL.append("\\"); + resolvedURL.append(fileName); + m_sink = QUrl(resolvedURL); + } + + // State is either Initialized, OpenComplete or Prepared, Close previously opened file + if (m_videoRecorder) + m_videoRecorder->Close(); + else + setError(KErrNotReady, tr("Unexpected camera error.")); + + // Open file + + QString fileName = QDir::toNativeSeparators(m_sink.toString()); + TPtrC16 fileSink(reinterpret_cast(fileName.utf16())); + + int cameraHandle = m_cameraEngine->Camera() ? m_cameraEngine->Camera()->Handle() : 0; + + TUid controllerUid; + TUid formatUid; + selectController(m_requestedContainer, controllerUid, formatUid); + + if (m_videoRecorder) { + // File open completes in MvruoOpenComplete + TRAPD(err, m_videoRecorder->OpenFileL(fileSink, cameraHandle, controllerUid, formatUid)); + setError(err, tr("Failed to initialize video recorder.")); + m_container = m_requestedContainer; + m_captureState = EOpening; + emit stateChanged(m_captureState); + } + else + setError(KErrNotReady, tr("Unexpected camera error.")); + + m_uncommittedSettings = true; + return true; +} + +QUrl S60VideoCaptureSession::outputLocation() const +{ + return m_sink; +} + +qint64 S60VideoCaptureSession::position() +{ + // Update position only if recording is ongoing + if ((m_captureState == ERecording) && m_videoRecorder) { + // Signal will be automatically emitted of position changes + TRAPD(err, m_position = m_videoRecorder->DurationL().Int64() / 1000); + setError(err, tr("Cannot retrieve video position.")); + } + + return m_position; +} + +S60VideoCaptureSession::TVideoCaptureState S60VideoCaptureSession::state() const +{ + return m_captureState; +} + +bool S60VideoCaptureSession::isMuted() const +{ + return m_muted; +} + +void S60VideoCaptureSession::setMuted(const bool muted) +{ + // CVideoRecorderUtility can mute/unmute only if not recording + if (m_captureState > EPrepared) { + if (muted) + setError(KErrNotSupported, tr("Muting audio is not supported during recording.")); + else + setError(KErrNotSupported, tr("Unmuting audio is not supported during recording.")); + return; + } + + // Check if request is already active + if (muted == isMuted()) + return; + + m_muted = muted; + + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::commitVideoEncoderSettings() +{ + if (m_captureState == EOpenComplete) { + + if (m_container != m_requestedContainer) { + setOutputLocation(m_requestedSink); + return; + } + + TRAPD(err, doSetCodecsL()); + if (err) { + setError(err, tr("Failed to set audio or video codec.")); + m_audioSettings.setCodec(KMimeTypeDefaultAudioCodec); + m_videoSettings.setCodec(KMimeTypeDefaultVideoCodec); + } + + doSetVideoResolution(m_videoSettings.resolution()); + doSetFrameRate(m_videoSettings.frameRate()); + doSetBitrate(m_videoSettings.bitRate()); + + // Audio/Video EncodingMode are not supported in Symbian + +#ifndef S60_31_PLATFORM + if (m_audioSettings.sampleRate() != -1 && m_audioSettings.sampleRate() != 0) { + TRAP(err, m_videoRecorder->SetAudioSampleRateL((TInt)m_audioSettings.sampleRate())); + if (err != KErrNotSupported) { + setError(err, tr("Setting audio sample rate failed.")); + } else { + setError(err, tr("Setting audio sample rate is not supported.")); + m_audioSettings.setSampleRate(KDefaultSampleRate); // Reset + } + } +#endif // S60_31_PLATFORM + + TRAP(err, m_videoRecorder->SetAudioBitRateL((TInt)m_audioSettings.bitRate())); + if (err != KErrNotSupported) { + if (err == KErrArgument) { + setError(KErrNotSupported, tr("Requested audio bitrate is not supported or previously set codec is not supported with requested bitrate.")); + int fallback = 16000; + TRAP(err, m_videoRecorder->SetAudioBitRateL(TInt(fallback))); + if (err == KErrNone) + m_audioSettings.setBitRate(fallback); + } else { + setError(err, tr("Setting audio bitrate failed.")); + } + } + +#ifndef S60_31_PLATFORM + if (m_audioSettings.channelCount() != -1) { + TRAP(err, m_videoRecorder->SetAudioChannelsL(TUint(m_audioSettings.channelCount()))); + if (err != KErrNotSupported) { + setError(err, tr("Setting audio channel count failed.")); + } else { + setError(err, tr("Setting audio channel count is not supported.")); + m_audioSettings.setChannelCount(KDefaultChannelCount); // Reset + } + } +#endif // S60_31_PLATFORM + + TBool isAudioMuted = EFalse; + TRAP(err, isAudioMuted = !m_videoRecorder->AudioEnabledL()); + if (err != KErrNotSupported && err != KErrNone) + setError(err, tr("Failure when checking if audio is enabled.")); + + if (m_muted != (bool)isAudioMuted) { + TRAP(err, m_videoRecorder->SetAudioEnabledL(TBool(!m_muted))); + if (err) { + if (err != KErrNotSupported) { + setError(err, tr("Failed to mute/unmute audio.")); + } else { + setError(err, tr("Muting/unmuting audio is not supported.")); + } + } + else + emit mutedChanged(m_muted); + } + + m_uncommittedSettings = false; // Reset + } +} + +void S60VideoCaptureSession::queryAudioEncoderSettings() +{ + if (!m_videoRecorder) + return; + + switch (m_captureState) { + case ENotInitialized: + case EInitializing: + case EOpening: + case EPreparing: + return; + + // Possible to query settings from CVideoRecorderUtility + case EInitialized: + case EOpenComplete: + case EPrepared: + case ERecording: + case EPaused: + break; + + default: + return; + } + + TInt err = KErrNone; + + // Codec + TFourCC audioCodec; + TRAP(err, audioCodec = m_videoRecorder->AudioTypeL()); + if (err) { + if (err != KErrNotSupported) + setError(err, tr("Querying audio codec failed.")); + } + QString codec = ""; + foreach (TFourCC aCodec, m_audioCodecList) { + if (audioCodec == aCodec) + codec = m_audioCodecList.key(aCodec); + } + m_audioSettings.setCodec(codec); + +#ifndef S60_31_PLATFORM + // Samplerate + TInt sampleRate = -1; + TRAP(err, sampleRate = m_videoRecorder->AudioSampleRateL()); + if (err) { + if (err != KErrNotSupported) + setError(err, tr("Querying audio sample rate failed.")); + } + m_audioSettings.setSampleRate(int(sampleRate)); +#endif // S60_31_PLATFORM + + // BitRate + TInt bitRate = -1; + TRAP(err, bitRate = m_videoRecorder->AudioBitRateL()); + if (err) { + if (err != KErrNotSupported) + setError(err, tr("Querying audio bitrate failed.")); + } + m_audioSettings.setBitRate(int(bitRate)); + +#ifndef S60_31_PLATFORM + // ChannelCount + TUint channelCount = 0; + TRAP(err, channelCount = m_videoRecorder->AudioChannelsL()); + if (err) { + if (err != KErrNotSupported) + setError(err, tr("Querying audio channel count failed.")); + } + if (channelCount != 0) + m_audioSettings.setChannelCount(int(channelCount)); + else + m_audioSettings.setChannelCount(-1); +#endif // S60_31_PLATFORM + + // EncodingMode + m_audioSettings.setEncodingMode(QtMultimediaKit::ConstantQualityEncoding); + + // IsMuted + TBool isEnabled = ETrue; + TRAP(err, isEnabled = m_videoRecorder->AudioEnabledL()); + if (err) { + if (err != KErrNotSupported) + setError(err, tr("Querying whether audio is muted failed.")); + } + m_muted = bool(!isEnabled); +} + +void S60VideoCaptureSession::queryVideoEncoderSettings() +{ + if (!m_videoRecorder) + return; + + switch (m_captureState) { + case ENotInitialized: + case EInitializing: + case EOpening: + case EPreparing: + return; + + // Possible to query settings from CVideoRecorderUtility + case EInitialized: + case EOpenComplete: + case EPrepared: + case ERecording: + case EPaused: + break; + + default: + return; + } + + TInt err = KErrNone; + + // Codec + const TDesC8 &videoMimeType = m_videoRecorder->VideoFormatMimeType(); + QString videoMimeTypeString = ""; + if (videoMimeType.Length() > 0) { + // First convert the 8-bit descriptor to Unicode + HBufC16* videoCodec; + videoCodec = CnvUtfConverter::ConvertToUnicodeFromUtf8L(videoMimeType); + CleanupStack::PushL(videoCodec); + + // Then deep copy QString from that + videoMimeTypeString = QString::fromUtf16(videoCodec->Ptr(), videoCodec->Length()); + m_videoSettings.setCodec(videoMimeTypeString); + + CleanupStack::PopAndDestroy(videoCodec); + } + + // Resolution + TSize symbianResolution; + TRAP(err, m_videoRecorder->GetVideoFrameSizeL(symbianResolution)); + if (err) { + if (err != KErrNotSupported) + setError(err, tr("Querying video resolution failed.")); + } + QSize resolution = QSize(symbianResolution.iWidth, symbianResolution.iHeight); + m_videoSettings.setResolution(resolution); + + // FrameRate + TReal32 frameRate = 0; + TRAP(err, frameRate = m_videoRecorder->VideoFrameRateL()); + if (err) { + if (err != KErrNotSupported) + setError(err, tr("Querying video framerate failed.")); + } + m_videoSettings.setFrameRate(qreal(frameRate)); + + // BitRate + TInt bitRate = -1; + TRAP(err, bitRate = m_videoRecorder->VideoBitRateL()); + if (err) { + if (err != KErrNotSupported) + setError(err, tr("Querying video bitrate failed.")); + } + m_videoSettings.setBitRate(int(bitRate)); + + // EncodingMode + m_audioSettings.setEncodingMode(QtMultimediaKit::ConstantQualityEncoding); +} + +void S60VideoCaptureSession::videoEncoderSettings(QVideoEncoderSettings &videoSettings) +{ + switch (m_captureState) { + // CVideoRecorderUtility, return requested settings + case ENotInitialized: + case EInitializing: + case EInitialized: + case EOpening: + case EOpenComplete: + case EPreparing: + break; + + // Possible to query settings from CVideoRecorderUtility + case EPrepared: + case ERecording: + case EPaused: + queryVideoEncoderSettings(); + break; + + default: + videoSettings = QVideoEncoderSettings(); + setError(KErrGeneral, tr("Unexpected video error.")); + return; + } + + videoSettings = m_videoSettings; +} + +void S60VideoCaptureSession::audioEncoderSettings(QAudioEncoderSettings &audioSettings) +{ + switch (m_captureState) { + // CVideoRecorderUtility, return requested settings + case ENotInitialized: + case EInitializing: + case EInitialized: + case EOpening: + case EOpenComplete: + case EPreparing: + break; + + // Possible to query settings from CVideoRecorderUtility + case EPrepared: + case ERecording: + case EPaused: + queryAudioEncoderSettings(); + break; + + default: + audioSettings = QAudioEncoderSettings(); + setError(KErrGeneral, tr("Unexpected video error.")); + return; + } + + audioSettings = m_audioSettings; +} + +void S60VideoCaptureSession::validateRequestedCodecs() +{ + if (!m_audioCodecList.contains(m_audioSettings.codec())) { + m_audioSettings.setCodec(KMimeTypeDefaultAudioCodec); + setError(KErrNotSupported, tr("Currently selected audio codec is not supported by the platform.")); + } + if (!m_videoCodecList.contains(m_videoSettings.codec())) { + m_videoSettings.setCodec(KMimeTypeDefaultVideoCodec); + setError(KErrNotSupported, tr("Currently selected video codec is not supported by the platform.")); + } +} + +void S60VideoCaptureSession::setVideoCaptureQuality(const QtMultimediaKit::EncodingQuality quality, + const VideoQualityDefinition mode) +{ + // Sensible presets + switch (mode) { + case ENoVideoQuality: + // Do nothing + break; + case EOnlyVideoQuality: + if (quality == QtMultimediaKit::VeryLowQuality) { + m_videoSettings.setResolution(QSize(128,96)); + m_videoSettings.setFrameRate(10); + m_videoSettings.setBitRate(64000); + } else if (quality == QtMultimediaKit::LowQuality) { + m_videoSettings.setResolution(QSize(176,144)); + m_videoSettings.setFrameRate(15); + m_videoSettings.setBitRate(64000); + } else if (quality == QtMultimediaKit::NormalQuality) { + m_videoSettings.setResolution(QSize(176,144)); + m_videoSettings.setFrameRate(15); + m_videoSettings.setBitRate(128000); + } else if (quality == QtMultimediaKit::HighQuality) { + m_videoSettings.setResolution(QSize(352,288)); + m_videoSettings.setFrameRate(15); + m_videoSettings.setBitRate(384000); + } else if (quality == QtMultimediaKit::VeryHighQuality) { + if (m_cameraEngine && m_cameraEngine->CurrentCameraIndex() == 0) + m_videoSettings.setResolution(QSize(640,480)); // Primary camera + else + m_videoSettings.setResolution(QSize(352,288)); // Other cameras + m_videoSettings.setFrameRate(15); + m_videoSettings.setBitRate(2000000); + } else { + m_videoSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported video quality.")); + return; + } + break; + case EVideoQualityAndResolution: + if (quality == QtMultimediaKit::VeryLowQuality) { + m_videoSettings.setFrameRate(10); + m_videoSettings.setBitRate(64000); + } else if (quality == QtMultimediaKit::LowQuality) { + m_videoSettings.setFrameRate(15); + m_videoSettings.setBitRate(64000); + } else if (quality == QtMultimediaKit::NormalQuality) { + m_videoSettings.setFrameRate(15); + m_videoSettings.setBitRate(128000); + } else if (quality == QtMultimediaKit::HighQuality) { + m_videoSettings.setFrameRate(15); + m_videoSettings.setBitRate(384000); + } else if (quality == QtMultimediaKit::VeryHighQuality) { + m_videoSettings.setFrameRate(15); + m_videoSettings.setBitRate(2000000); + } else { + m_videoSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported video quality.")); + return; + } + break; + case EVideoQualityAndFrameRate: + if (quality == QtMultimediaKit::VeryLowQuality) { + m_videoSettings.setResolution(QSize(128,96)); + m_videoSettings.setBitRate(64000); + } else if (quality == QtMultimediaKit::LowQuality) { + m_videoSettings.setResolution(QSize(176,144)); + m_videoSettings.setBitRate(64000); + } else if (quality == QtMultimediaKit::NormalQuality) { + m_videoSettings.setResolution(QSize(176,144)); + m_videoSettings.setBitRate(128000); + } else if (quality == QtMultimediaKit::HighQuality) { + m_videoSettings.setResolution(QSize(352,288)); + m_videoSettings.setBitRate(384000); + } else if (quality == QtMultimediaKit::VeryHighQuality) { + if (m_cameraEngine && m_cameraEngine->CurrentCameraIndex() == 0) + m_videoSettings.setResolution(QSize(640,480)); // Primary camera + else + m_videoSettings.setResolution(QSize(352,288)); // Other cameras + m_videoSettings.setBitRate(2000000); + } else { + m_videoSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported video quality.")); + return; + } + break; + case EVideoQualityAndBitRate: + if (quality == QtMultimediaKit::VeryLowQuality) { + m_videoSettings.setResolution(QSize(128,96)); + m_videoSettings.setFrameRate(10); + } else if (quality == QtMultimediaKit::LowQuality) { + m_videoSettings.setResolution(QSize(176,144)); + m_videoSettings.setFrameRate(15); + } else if (quality == QtMultimediaKit::NormalQuality) { + m_videoSettings.setResolution(QSize(176,144)); + m_videoSettings.setFrameRate(15); + } else if (quality == QtMultimediaKit::HighQuality) { + m_videoSettings.setResolution(QSize(352,288)); + m_videoSettings.setFrameRate(15); + } else if (quality == QtMultimediaKit::VeryHighQuality) { + if (m_cameraEngine && m_cameraEngine->CurrentCameraIndex() == 0) + m_videoSettings.setResolution(QSize(640,480)); // Primary camera + else + m_videoSettings.setResolution(QSize(352,288)); // Other cameras + m_videoSettings.setFrameRate(15); + } else { + m_videoSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported video quality.")); + return; + } + break; + case EVideoQualityAndResolutionAndBitRate: + if (quality == QtMultimediaKit::VeryLowQuality) { + m_videoSettings.setFrameRate(10); + } else if (quality == QtMultimediaKit::LowQuality) { + m_videoSettings.setFrameRate(15); + } else if (quality == QtMultimediaKit::NormalQuality) { + m_videoSettings.setFrameRate(15); + } else if (quality == QtMultimediaKit::HighQuality) { + m_videoSettings.setFrameRate(15); + } else if (quality == QtMultimediaKit::VeryHighQuality) { + m_videoSettings.setFrameRate(15); + } else { + m_videoSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported video quality.")); + return; + } + break; + case EVideoQualityAndResolutionAndFrameRate: + if (quality == QtMultimediaKit::VeryLowQuality) { + m_videoSettings.setBitRate(64000); + } else if (quality == QtMultimediaKit::LowQuality) { + m_videoSettings.setBitRate(64000); + } else if (quality == QtMultimediaKit::NormalQuality) { + m_videoSettings.setBitRate(128000); + } else if (quality == QtMultimediaKit::HighQuality) { + m_videoSettings.setBitRate(384000); + } else if (quality == QtMultimediaKit::VeryHighQuality) { + m_videoSettings.setBitRate(2000000); + } else { + m_videoSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported video quality.")); + return; + } + break; + case EVideoQualityAndFrameRateAndBitRate: + if (quality == QtMultimediaKit::VeryLowQuality) { + m_videoSettings.setResolution(QSize(128,96)); + } else if (quality == QtMultimediaKit::LowQuality) { + m_videoSettings.setResolution(QSize(176,144)); + } else if (quality == QtMultimediaKit::NormalQuality) { + m_videoSettings.setResolution(QSize(176,144)); + } else if (quality == QtMultimediaKit::HighQuality) { + m_videoSettings.setResolution(QSize(352,288)); + } else if (quality == QtMultimediaKit::VeryHighQuality) { + if (m_cameraEngine && m_cameraEngine->CurrentCameraIndex() == 0) + m_videoSettings.setResolution(QSize(640,480)); // Primary camera + else + m_videoSettings.setResolution(QSize(352,288)); // Other cameras + } else { + m_videoSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported video quality.")); + return; + } + break; + } + + m_videoSettings.setQuality(quality); + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::setAudioCaptureQuality(const QtMultimediaKit::EncodingQuality quality, + const AudioQualityDefinition mode) +{ + // Based on audio quality definition mode, select proper SampleRate and BitRate + switch (mode) { + case EOnlyAudioQuality: + switch (quality) { + case QtMultimediaKit::VeryLowQuality: + m_audioSettings.setBitRate(16000); + m_audioSettings.setSampleRate(-1); + break; + case QtMultimediaKit::LowQuality: + m_audioSettings.setBitRate(16000); + m_audioSettings.setSampleRate(-1); + break; + case QtMultimediaKit::NormalQuality: + m_audioSettings.setBitRate(32000); + m_audioSettings.setSampleRate(-1); + break; + case QtMultimediaKit::HighQuality: + m_audioSettings.setBitRate(64000); + m_audioSettings.setSampleRate(-1); + break; + case QtMultimediaKit::VeryHighQuality: + m_audioSettings.setBitRate(64000); + m_audioSettings.setSampleRate(-1); + break; + default: + m_audioSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported audio quality.")); + return; + } + break; + case EAudioQualityAndBitRate: + switch (quality) { + case QtMultimediaKit::VeryLowQuality: + m_audioSettings.setSampleRate(-1); + break; + case QtMultimediaKit::LowQuality: + m_audioSettings.setSampleRate(-1); + break; + case QtMultimediaKit::NormalQuality: + m_audioSettings.setSampleRate(-1); + break; + case QtMultimediaKit::HighQuality: + m_audioSettings.setSampleRate(-1); + break; + case QtMultimediaKit::VeryHighQuality: + m_audioSettings.setSampleRate(-1); + break; + default: + m_audioSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported audio quality.")); + return; + } + break; + case EAudioQualityAndSampleRate: + switch (quality) { + case QtMultimediaKit::VeryLowQuality: + m_audioSettings.setBitRate(16000); + break; + case QtMultimediaKit::LowQuality: + m_audioSettings.setBitRate(16000); + break; + case QtMultimediaKit::NormalQuality: + m_audioSettings.setBitRate(32000); + break; + case QtMultimediaKit::HighQuality: + m_audioSettings.setBitRate(64000); + break; + case QtMultimediaKit::VeryHighQuality: + m_audioSettings.setBitRate(64000); + break; + default: + m_audioSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported audio quality.")); + return; + } + break; + case ENoAudioQuality: + // No actions required, just set quality parameter + break; + + default: + setError(KErrGeneral, tr("Unexpected camera error.")); + return; + } + + m_audioSettings.setQuality(quality); + m_uncommittedSettings = true; +} + +int S60VideoCaptureSession::initializeVideoRecording() +{ + if (m_error) + return m_error; + + TRAPD(symbianError, doInitializeVideoRecorderL()); + setError(symbianError, tr("Failed to initialize video recorder.")); + + return symbianError; +} + +void S60VideoCaptureSession::releaseVideoRecording() +{ + if (m_captureState >= ERecording) { + m_videoRecorder->Stop(); + if (m_durationTimer->isActive()) + m_durationTimer->stop(); + } + + if (m_captureState >= EInitialized) + m_videoRecorder->Close(); + + // Reset state + m_captureState = ENotInitialized; + + // Reset error to be able to recover from error + m_error = KErrNone; + + // Reset flags + m_openWhenReady = false; + m_prepareAfterOpenComplete = false; + m_startAfterPrepareComplete = false; + m_uncommittedSettings = false; + m_commitSettingsWhenReady = false; +} + +void S60VideoCaptureSession::startRecording() +{ + if (m_error) { + setError(m_error, tr("Unexpected recording error.")); + return; + } + + switch (m_captureState) { + case ENotInitialized: + case EInitializing: + case EInitialized: + if (m_captureState == EInitialized) + setOutputLocation(m_requestedSink); + m_startAfterPrepareComplete = true; + return; + + case EOpening: + case EPreparing: + // Execute FileOpenL() and Prepare() asap and then start recording + m_startAfterPrepareComplete = true; + return; + case EOpenComplete: + case EPrepared: + if (m_captureState == EPrepared && !m_uncommittedSettings) + break; + + // Revert state internally, since logically applying settings means going + // from OpenComplete ==> Preparing ==> Prepared. + m_captureState = EOpenComplete; + m_startAfterPrepareComplete = true; + + // Commit settings and prepare with them + applyAllSettings(); + return; + case ERecording: + // Discard + return; + case EPaused: + // Continue + break; + + default: + setError(KErrGeneral, tr("Unexpected camera error.")); + return; + } + + // State should now be either Prepared with no Uncommitted Settings or Paused + + if (!m_cameraStarted) { + m_startAfterPrepareComplete = true; + return; + } + + if (m_cameraEngine && !m_cameraEngine->IsCameraReady()) { + setError(KErrNotReady, tr("Camera not ready to start video recording.")); + return; + } + + if (m_videoRecorder) { + m_videoRecorder->Record(); + m_captureState = ERecording; + emit stateChanged(m_captureState); + m_durationTimer->start(); + + // Reset all flags + m_openWhenReady = false; + m_prepareAfterOpenComplete = false; + m_startAfterPrepareComplete = false; + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } +} + +void S60VideoCaptureSession::pauseRecording() +{ + if (m_captureState == ERecording) { + if (m_videoRecorder) { + TRAPD(err, m_videoRecorder->PauseL()); + setError(err, tr("Pausing video recording failed.")); + m_captureState = EPaused; + emit stateChanged(m_captureState); + if (m_durationTimer->isActive()) + m_durationTimer->stop(); + + // Notify last duration + TRAP(err, m_position = m_videoRecorder->DurationL().Int64() / 1000); + setError(err, tr("Cannot retrieve video position.")); + emit positionChanged(m_position); + } + else + setError(KErrNotReady, tr("Unexpected camera error.")); + } +} + +void S60VideoCaptureSession::stopRecording(const bool reInitialize) +{ + if (m_captureState != ERecording && m_captureState != EPaused) + return; // Ignore + + if (m_videoRecorder) { + m_videoRecorder->Stop(); + m_videoRecorder->Close(); + + // Notify muting is disabled if needed + if (m_muted) + emit mutedChanged(false); + + m_captureState = ENotInitialized; + emit stateChanged(m_captureState); + + if (m_durationTimer->isActive()) + m_durationTimer->stop(); + + // VideoRecording will be re-initialized unless explicitly requested not to do so + if (reInitialize) { + if (m_cameraEngine->IsCameraReady()) + initializeVideoRecording(); + } + } + else + setError(KErrNotReady, tr("Unexpected camera error.")); +} + +void S60VideoCaptureSession::updateVideoCaptureContainers() +{ + TRAPD(err, doUpdateVideoCaptureContainersL()); + setError(err, tr("Failed to gather video container information.")); +} + +void S60VideoCaptureSession::doUpdateVideoCaptureContainersL() +{ + // Clear container data structure + QList mapControllers = m_videoControllerMap.keys(); + for (int i = 0; i < mapControllers.size(); ++i) { + foreach(VideoFormatData data, m_videoControllerMap[mapControllers[i]]){ + data.supportedMimeTypes.clear(); + } + m_videoControllerMap[mapControllers[i]].clear(); + } + m_videoControllerMap.clear(); + + // Resolve the supported video format and retrieve a list of controllers + CMMFControllerPluginSelectionParameters* pluginParameters = + CMMFControllerPluginSelectionParameters::NewLC(); + CMMFFormatSelectionParameters* format = + CMMFFormatSelectionParameters::NewLC(); + + // Set the play and record format selection parameters to be blank. + // Format support is only retrieved if requested. + pluginParameters->SetRequiredPlayFormatSupportL(*format); + pluginParameters->SetRequiredRecordFormatSupportL(*format); + + // Set the media IDs + RArray mediaIds; + CleanupClosePushL(mediaIds); + + User::LeaveIfError(mediaIds.Append(KUidMediaTypeVideo)); + + // Get plugins that support at least video + pluginParameters->SetMediaIdsL(mediaIds, + CMMFPluginSelectionParameters::EAllowOtherMediaIds); + pluginParameters->SetPreferredSupplierL(KNullDesC, + CMMFPluginSelectionParameters::EPreferredSupplierPluginsFirstInList); + + // Array to hold all the controllers support the match data + RMMFControllerImplInfoArray controllers; + CleanupResetAndDestroyPushL(controllers); + pluginParameters->ListImplementationsL(controllers); + + // Find the first controller with at least one record format available + for (TInt index = 0; index < controllers.Count(); ++index) { + + m_videoControllerMap.insert(controllers[index]->Uid().iUid, QHash()); + + const RMMFFormatImplInfoArray& recordFormats = controllers[index]->RecordFormats(); + for (TInt j = 0; j < recordFormats.Count(); ++j) { + VideoFormatData formatData; + formatData.description = QString::fromUtf16( + recordFormats[j]->DisplayName().Ptr(), + recordFormats[j]->DisplayName().Length()); + + const CDesC8Array& mimeTypes = recordFormats[j]->SupportedMimeTypes(); + for (int k = 0; k < mimeTypes.Count(); ++k) { + TPtrC8 mimeType = mimeTypes[k]; + QString type = QString::fromUtf8((char *)mimeType.Ptr(), + mimeType.Length()); + formatData.supportedMimeTypes.append(type); + } + + m_videoControllerMap[controllers[index]->Uid().iUid].insert(recordFormats[j]->Uid().iUid, formatData); + } + } + + CleanupStack::PopAndDestroy(&controllers); + CleanupStack::PopAndDestroy(&mediaIds); + CleanupStack::PopAndDestroy(format); + CleanupStack::PopAndDestroy(pluginParameters); +} + +/* + * This goes through the available controllers and selects proper one based + * on the format. Function sets proper UIDs to be used for controller and format. + */ +void S60VideoCaptureSession::selectController(const QString &format, + TUid &controllerUid, + TUid &formatUid) +{ + QList controllers = m_videoControllerMap.keys(); + QList formats; + + for (int i = 0; i < controllers.count(); ++i) { + formats = m_videoControllerMap[controllers[i]].keys(); + for (int j = 0; j < formats.count(); ++j) { + VideoFormatData formatData = m_videoControllerMap[controllers[i]][formats[j]]; + if (formatData.supportedMimeTypes.contains(format, Qt::CaseInsensitive)) { + controllerUid = TUid::Uid(controllers[i]); + formatUid = TUid::Uid(formats[j]); + } + } + } +} + +QStringList S60VideoCaptureSession::supportedVideoCaptureCodecs() +{ + return m_videoCodecList; +} + +QStringList S60VideoCaptureSession::supportedAudioCaptureCodecs() +{ + QStringList keys = m_audioCodecList.keys(); + keys.sort(); + return keys; +} + +QList S60VideoCaptureSession::supportedSampleRates(const QAudioEncoderSettings &settings, bool *continuous) +{ + QList rates; + + TRAPD(err, rates = doGetSupportedSampleRatesL(settings, continuous)); + if (err != KErrNotSupported) + setError(err, tr("Failed to query information of supported sample rates.")); + + return rates; +} + +QList S60VideoCaptureSession::doGetSupportedSampleRatesL(const QAudioEncoderSettings &settings, bool *continuous) +{ + QList sampleRates; + + if (m_captureState < EOpenComplete) + return sampleRates; + +#ifndef S60_31_PLATFORM + RArray supportedSampleRates; + CleanupClosePushL(supportedSampleRates); + + if (!settings.codec().isEmpty()) { + + TFourCC currentAudioCodec; + currentAudioCodec = m_videoRecorder->AudioTypeL(); + + TFourCC requestedAudioCodec; + if (qstrcmp(settings.codec().toLocal8Bit().constData(), "audio/aac") == 0) + requestedAudioCodec.Set(KMMFFourCCCodeAAC); + else if (qstrcmp(settings.codec().toLocal8Bit().constData(), "audio/amr") == 0) + requestedAudioCodec.Set(KMMFFourCCCodeAMR); + m_videoRecorder->SetAudioTypeL(requestedAudioCodec); + + m_videoRecorder->GetSupportedAudioSampleRatesL(supportedSampleRates); + + m_videoRecorder->SetAudioTypeL(currentAudioCodec); + } + else + m_videoRecorder->GetSupportedAudioSampleRatesL(supportedSampleRates); + + for (int i = 0; i < supportedSampleRates.Count(); ++i) + sampleRates.append(int(supportedSampleRates[i])); + + CleanupStack::PopAndDestroy(); // RArray supportedSampleRates +#else // S60 3.1 Platform + Q_UNUSED(settings); +#endif // S60_31_PLATFORM + + if (continuous) + *continuous = false; + + return sampleRates; +} + +void S60VideoCaptureSession::setAudioSampleRate(const int sampleRate) +{ + if (sampleRate != -1) + m_audioSettings.setSampleRate(sampleRate); + + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::setAudioBitRate(const int bitRate) +{ + if (bitRate != -1) + m_audioSettings.setBitRate(bitRate); + + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::setAudioChannelCount(const int channelCount) +{ + if (channelCount != -1) + m_audioSettings.setChannelCount(channelCount); + + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::setVideoCaptureCodec(const QString &codecName) +{ + if (codecName == m_videoSettings.codec()) + return; + + if (codecName.isEmpty()) + m_videoSettings.setCodec(KMimeTypeDefaultVideoCodec); // Use default + else + m_videoSettings.setCodec(codecName); + + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::setAudioCaptureCodec(const QString &codecName) +{ + if (codecName == m_audioSettings.codec()) + return; + + if (codecName.isEmpty()) { + m_audioSettings.setCodec(KMimeTypeDefaultAudioCodec); // Use default + } else { + // If information of supported codecs is already available check that + // given codec is supported + if (m_captureState >= EOpenComplete) { + if (m_audioCodecList.contains(codecName)) { + m_audioSettings.setCodec(codecName); + m_uncommittedSettings = true; + } else { + setError(KErrNotSupported, tr("Requested audio codec is not supported")); + } + } else { + m_audioSettings.setCodec(codecName); + m_uncommittedSettings = true; + } + } +} + +QString S60VideoCaptureSession::videoCaptureCodecDescription(const QString &codecName) +{ + QString codecDescription; + if (codecName.contains("video/H263-2000", Qt::CaseInsensitive)) + codecDescription.append("H.263 Video Codec"); + else if (codecName.contains("video/mp4v-es", Qt::CaseInsensitive)) + codecDescription.append("MPEG-4 Part 2 Video Codec"); + else if (codecName.contains("video/H264", Qt::CaseInsensitive)) + codecDescription.append("H.264 AVC (MPEG-4 Part 10) Video Codec"); + else + codecDescription.append("Video Codec"); + + return codecDescription; +} + +void S60VideoCaptureSession::doSetCodecsL() +{ + // Determine Profile and Level for the video codec if needed + // (MimeType/Profile-level-id contains "profile" if profile/level info is available) + if (!m_videoSettings.codec().contains(QString("profile"), Qt::CaseInsensitive)) + m_videoSettings.setCodec(determineProfileAndLevel()); + + if (m_videoRecorder) { + TPtrC16 str(reinterpret_cast(m_videoSettings.codec().utf16())); + HBufC8* videoCodec(0); + videoCodec = CnvUtfConverter::ConvertFromUnicodeToUtf8L(str); + CleanupStack::PushL(videoCodec); + + TFourCC audioCodec = m_audioCodecList[m_audioSettings.codec()]; + + TInt vErr = KErrNone; + TInt aErr = KErrNone; + TRAP(vErr, m_videoRecorder->SetVideoTypeL(*videoCodec)); + TRAP(aErr, m_videoRecorder->SetAudioTypeL(audioCodec)); + + User::LeaveIfError(vErr); + User::LeaveIfError(aErr); + + CleanupStack::PopAndDestroy(videoCodec); + } + else + setError(KErrNotReady, tr("Unexpected camera error.")); +} + +QString S60VideoCaptureSession::determineProfileAndLevel() +{ + QString determinedMimeType = m_videoSettings.codec(); + + // H.263 + if (determinedMimeType.contains(QString("video/H263-2000"), Qt::CaseInsensitive)) { + if ((m_videoSettings.resolution().width() * m_videoSettings.resolution().height()) > (176*144)) { + if (m_videoSettings.frameRate() > 15.0) + determinedMimeType.append("; profile=0; level=20"); + else + determinedMimeType.append("; profile=0; level=40"); + } else { + if (m_videoSettings.bitRate() > 64000) + determinedMimeType.append("; profile=0; level=45"); + else + determinedMimeType.append("; profile=0; level=10"); + } + + // MPEG-4 + } else if (determinedMimeType.contains(QString("video/mp4v-es"), Qt::CaseInsensitive)) { + if ((m_videoSettings.resolution().width() * m_videoSettings.resolution().height()) > (720*480)) { + determinedMimeType.append("; profile-level-id=6"); + } else if ((m_videoSettings.resolution().width() * m_videoSettings.resolution().height()) > (640*480)) { + determinedMimeType.append("; profile-level-id=5"); + } else if ((m_videoSettings.resolution().width() * m_videoSettings.resolution().height()) > (352*288)) { + determinedMimeType.append("; profile-level-id=4"); + } else if ((m_videoSettings.resolution().width() * m_videoSettings.resolution().height()) > (176*144)) { + if (m_videoSettings.frameRate() > 15.0) + determinedMimeType.append("; profile-level-id=3"); + else + determinedMimeType.append("; profile-level-id=2"); + } else { + if (m_videoSettings.bitRate() > 64000) + determinedMimeType.append("; profile-level-id=9"); + else + determinedMimeType.append("; profile-level-id=1"); + } + + // H.264 + } else if (determinedMimeType.contains(QString("video/H264"), Qt::CaseInsensitive)) { + if ((m_videoSettings.resolution().width() * m_videoSettings.resolution().height()) > (640*480)) { + determinedMimeType.append("; profile-level-id=42801F"); + } else if ((m_videoSettings.resolution().width() * m_videoSettings.resolution().height()) > (352*288)) { + determinedMimeType.append("; profile-level-id=42801E"); + } else if ((m_videoSettings.resolution().width() * m_videoSettings.resolution().height()) > (176*144)) { + if (m_videoSettings.frameRate() > 15.0) + determinedMimeType.append("; profile-level-id=428015"); + else + determinedMimeType.append("; profile-level-id=42800C"); + } else { + determinedMimeType.append("; profile-level-id=42900B"); + } + } + + return determinedMimeType; +} + +void S60VideoCaptureSession::setBitrate(const int bitrate) +{ + m_videoSettings.setBitRate(bitrate); + + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::doSetBitrate(const int &bitrate) +{ + if (bitrate != -1) { + if (m_videoRecorder) { + TRAPD(err, m_videoRecorder->SetVideoBitRateL(bitrate)); + if (err) { + if (err == KErrNotSupported || err == KErrArgument) { + setError(KErrNotSupported, tr("Requested video bitrate is not supported.")); + m_videoSettings.setBitRate(64000); // Reset + } else { + setError(err, tr("Failed to set video bitrate.")); + } + } + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } + } +} + +void S60VideoCaptureSession::setVideoResolution(const QSize &resolution) +{ + m_videoSettings.setResolution(resolution); + + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::doSetVideoResolution(const QSize &resolution) +{ + TSize size((TInt)resolution.width(), (TInt)resolution.height()); + + // Make sure resolution is not too big if main camera is not used + if (m_cameraEngine->CurrentCameraIndex() != 0) { + TCameraInfo *info = m_cameraEngine->CameraInfo(); + if (info) { + TInt videoResolutionCount = info->iNumVideoFrameSizesSupported; + TSize maxCameraVideoResolution = TSize(0,0); + CCamera *camera = m_cameraEngine->Camera(); + if (camera) { + for (TInt i = 0; i < videoResolutionCount; ++i) { + TSize checkedResolution; + // Use YUV video max frame size in the check (Through + // CVideoRecorderUtility/DevVideoRecord it is possible to + // query only encoder maximums) + camera->EnumerateVideoFrameSizes(checkedResolution, i, CCamera::EFormatYUV420Planar); + if ((checkedResolution.iWidth * checkedResolution.iHeight) > + (maxCameraVideoResolution.iWidth * maxCameraVideoResolution.iHeight)) + maxCameraVideoResolution = checkedResolution; + } + if ((maxCameraVideoResolution.iWidth * maxCameraVideoResolution.iHeight) < + (size.iWidth * size.iHeight)) { + size = maxCameraVideoResolution; + setError(KErrNotSupported, tr("Requested resolution is not supported for this camera.")); + } + } + else + setError(KErrGeneral, tr("Could not query supported video resolutions.")); + }else + setError(KErrGeneral, tr("Could not query supported video resolutions.")); + } + + if (resolution.width() != -1 && resolution.height() != -1) { + if (m_videoRecorder) { + TRAPD(err, m_videoRecorder->SetVideoFrameSizeL((TSize)size)); + if (err == KErrNotSupported || err == KErrArgument) { + setError(KErrNotSupported, tr("Requested video resolution is not supported.")); + TSize fallBack(640,480); + TRAPD(err, m_videoRecorder->SetVideoFrameSizeL(fallBack)); + if (err == KErrNone) { + m_videoSettings.setResolution(QSize(fallBack.iWidth,fallBack.iHeight)); + } else { + fallBack = TSize(176,144); + TRAPD(err, m_videoRecorder->SetVideoFrameSizeL(fallBack)); + if (err == KErrNone) + m_videoSettings.setResolution(QSize(fallBack.iWidth,fallBack.iHeight)); + } + } else { + setError(err, tr("Failed to set video resolution.")); + } + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } + } +} + +void S60VideoCaptureSession::setFrameRate(qreal rate) +{ + m_videoSettings.setFrameRate(rate); + + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::doSetFrameRate(qreal rate) +{ + if (rate != 0) { + if (m_videoRecorder) { + bool continuous = false; + QList list = supportedVideoFrameRates(&continuous); + qreal maxRate = 0.0; + foreach (qreal fRate, list) + if (fRate > maxRate) + maxRate = fRate; + if (maxRate >= rate && rate > 0) { + TRAPD(err, m_videoRecorder->SetVideoFrameRateL((TReal32)rate)); + if (err == KErrNotSupported) { + setError(KErrNotSupported, tr("Requested framerate is not supported.")); + TReal32 fallBack = 15.0; + TRAPD(err, m_videoRecorder->SetVideoFrameRateL(fallBack)); + if (err == KErrNone) + m_videoSettings.setFrameRate((qreal)fallBack); + } else { + if (err == KErrArgument) { + setError(KErrNotSupported, tr("Requested framerate is not supported.")); + m_videoSettings.setFrameRate(15.0); // Reset + } else { + setError(err, tr("Failed to set video framerate.")); + } + } + } else { + setError(KErrNotSupported, tr("Requested framerate is not supported.")); + m_videoSettings.setFrameRate(15.0); // Reset + } + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } + } +} + +void S60VideoCaptureSession::setVideoEncodingMode(const QtMultimediaKit::EncodingMode mode) +{ + // This has no effect as it has no support in Symbian + + if (mode == QtMultimediaKit::ConstantQualityEncoding) { + m_videoSettings.setEncodingMode(mode); + return; + } + + setError(KErrNotSupported, tr("Requested video encoding mode is not supported")); + + // m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::setAudioEncodingMode(const QtMultimediaKit::EncodingMode mode) +{ + // This has no effect as it has no support in Symbian + + if (mode == QtMultimediaKit::ConstantQualityEncoding) { + m_audioSettings.setEncodingMode(mode); + return; + } + + setError(KErrNotSupported, tr("Requested audio encoding mode is not supported")); + + // m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::initializeVideoCaptureSettings() +{ + // Check if user has already requested some settings + if (m_captureSettingsSet) + return; + + QSize resolution(-1, -1); + qreal frameRate(0); + int bitRate(-1); + + if (m_cameraEngine) { + + if (m_videoRecorder && m_captureState >= EInitialized) { + + // Resolution + QList resos = supportedVideoResolutions(0); + foreach (QSize reso, resos) { + if ((reso.width() * reso.height()) > (resolution.width() * resolution.height())) + resolution = reso; + } + + // Needed to query supported framerates for this codec/resolution pair + m_videoSettings.setCodec(KMimeTypeDefaultVideoCodec); + m_videoSettings.setResolution(resolution); + + // FrameRate + QList fRates = supportedVideoFrameRates(m_videoSettings, 0); + foreach (qreal rate, fRates) { + if (rate > frameRate) + frameRate = rate; + } + + // BitRate +#ifdef SYMBIAN_3_PLATFORM + if (m_cameraEngine->CurrentCameraIndex() == 0) + bitRate = KBiR_H264_PLID_42801F // 14Mbps + else + bitRate = KBiR_H264_PLID_428016 // 4Mbps +#else // Other platforms + if (m_cameraEngine->CurrentCameraIndex() == 0) + bitRate = KBiR_MPEG4_PLID_4 // 2/4Mbps + else + bitRate = KBiR_MPEG4_PLID_3 // 384kbps +#endif // SYMBIAN_3_PLATFORM + + } else { +#ifdef SYMBIAN_3_PLATFORM + if (m_cameraEngine->CurrentCameraIndex() == 0) { + // Primary camera + resolution = KResH264_PLID_42801F; // 1280x720 + frameRate = KFrR_H264_PLID_42801F; // 30fps + bitRate = KBiR_H264_PLID_42801F; // 14Mbps + } else { + // Other cameras + resolution = KResH264_PLID_42801E; // 640x480 + frameRate = KFrR_H264_PLID_428014; // 30fps + bitRate = KBiR_H264_PLID_428016; // 4Mbps + } +#else // Other platforms + if (m_cameraEngine->CurrentCameraIndex() == 0) { + // Primary camera + resolution = KResMPEG4_PLID_4; // 640x480 + frameRate = KFrR_MPEG4_PLID_4; // 15/30fps + bitRate = KBiR_MPEG4_PLID_4; // 2/4Mbps + } else { + // Other cameras + resolution = KResMPEG4_PLID_3; // 352x288 + frameRate = KFrR_MPEG4; // 15fps + bitRate = KBiR_MPEG4_PLID_3; // 384kbps + } +#endif // SYMBIAN_3_PLATFORM + } + } else { +#ifdef SYMBIAN_3_PLATFORM + resolution = KResH264_PLID_42801F; + frameRate = KFrR_H264_PLID_42801F; + bitRate = KBiR_H264_PLID_42801F; +#else // Pre-Symbian3 Platforms + resolution = KResMPEG4_PLID_4; + frameRate = KFrR_MPEG4_PLID_4; + bitRate = KBiR_MPEG4_PLID_4; +#endif // SYMBIAN_3_PLATFORM + } + + // Set specified settings (Resolution, FrameRate and BitRate) + m_videoSettings.setResolution(resolution); + m_videoSettings.setFrameRate(frameRate); + m_videoSettings.setBitRate(bitRate); + + // Video Settings: Codec, EncodingMode and Quality + m_videoSettings.setCodec(KMimeTypeDefaultVideoCodec); + m_videoSettings.setEncodingMode(QtMultimediaKit::ConstantQualityEncoding); + m_videoSettings.setQuality(QtMultimediaKit::VeryHighQuality); + + // Audio Settings + m_audioSettings.setCodec(KMimeTypeDefaultAudioCodec); + m_audioSettings.setBitRate(KDefaultBitRate); + m_audioSettings.setSampleRate(KDefaultSampleRate); + m_audioSettings.setChannelCount(KDefaultChannelCount); + m_audioSettings.setEncodingMode(QtMultimediaKit::ConstantQualityEncoding); + m_audioSettings.setQuality(QtMultimediaKit::VeryHighQuality); +} + +QSize S60VideoCaptureSession::pixelAspectRatio() +{ +#ifndef S60_31_PLATFORM + TVideoAspectRatio par; + TRAPD(err, m_videoRecorder->GetPixelAspectRatioL(par)); + if (err) + setError(err, tr("Failed to query current pixel aspect ratio.")); + return QSize(par.iNumerator, par.iDenominator); +#else // S60_31_PLATFORM + return QSize(); +#endif // !S60_31_PLATFORM +} + +void S60VideoCaptureSession::setPixelAspectRatio(const QSize par) +{ +#ifndef S60_31_PLATFORM + + const TVideoAspectRatio videoPar(par.width(), par.height()); + TRAPD(err, m_videoRecorder->SetPixelAspectRatioL(videoPar)); + if (err) + setError(err, tr("Failed to set pixel aspect ratio.")); +#else // S60_31_PLATFORM + Q_UNUSED(par); +#endif // !S60_31_PLATFORM + + m_uncommittedSettings = true; +} + +int S60VideoCaptureSession::gain() +{ + TInt gain = 0; + TRAPD(err, gain = m_videoRecorder->GainL()); + if (err) + setError(err, tr("Failed to query video gain.")); + return (int)gain; +} + +void S60VideoCaptureSession::setGain(const int gain) +{ + TRAPD(err, m_videoRecorder->SetGainL(gain)); + if (err) + setError(err, tr("Failed to set video gain.")); + + m_uncommittedSettings = true; +} + +int S60VideoCaptureSession::maxClipSizeInBytes() const +{ + return m_maxClipSize; +} + +void S60VideoCaptureSession::setMaxClipSizeInBytes(const int size) +{ + TRAPD(err, m_videoRecorder->SetMaxClipSizeL(size)); + if (err) { + setError(err, tr("Failed to set maximum video size.")); + } else + m_maxClipSize = size; + + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::MvruoOpenComplete(TInt aError) +{ + if (m_error) + return; + + if (aError == KErrNone && m_videoRecorder) { + if (m_captureState == EInitializing) { + // Dummy file open completed, initialize settings + TRAPD(err, doPopulateAudioCodecsL()); + setError(err, tr("Failed to gather information of supported audio codecs.")); + + // For DevVideoRecord codecs are populated during + // doPopulateVideoCodecsDataL() + TRAP(err, doPopulateVideoCodecsL()); + setError(err, tr("Failed to gather information of supported video codecs.")); +#ifndef S60_DEVVIDEO_RECORDING_SUPPORTED + // Max parameters needed to be populated, if not using DevVideoRecord + // Otherwise done already in constructor + doPopulateMaxVideoParameters(); +#endif // S60_DEVVIDEO_RECORDING_SUPPORTED + + m_captureState = EInitialized; + emit stateChanged(m_captureState); + + // Initialize settings if not already done + initializeVideoCaptureSettings(); + + // Validate codecs to be used + validateRequestedCodecs(); + + if (m_openWhenReady || m_prepareAfterOpenComplete || m_startAfterPrepareComplete) { + setOutputLocation(m_requestedSink); + m_openWhenReady = false; // Reset + } + if (m_commitSettingsWhenReady) { + applyAllSettings(); + m_commitSettingsWhenReady = false; // Reset + } + return; + + } else if (m_captureState == EOpening) { + // Actual file open completed + m_captureState = EOpenComplete; + emit stateChanged(m_captureState); + + // Prepare right away + if (m_startAfterPrepareComplete || m_prepareAfterOpenComplete) { + m_prepareAfterOpenComplete = false; // Reset + + // Commit settings and prepare with them + applyAllSettings(); + } + return; + + } else if (m_captureState == ENotInitialized) { + // Resources released while waiting OpenFileL to complete + m_videoRecorder->Close(); + return; + + } else { + setError(KErrGeneral, tr("Unexpected camera error.")); + return; + } + } + + m_videoRecorder->Close(); + if (aError == KErrNotFound || aError == KErrNotSupported || aError == KErrArgument) + setError(KErrGeneral, tr("Requested video container or controller is not supported.")); + else + setError(KErrGeneral, tr("Failure during video recorder initialization.")); +} + +void S60VideoCaptureSession::MvruoPrepareComplete(TInt aError) +{ + if (m_error) + return; + + if(aError == KErrNone) { + if (m_captureState == ENotInitialized) { + // Resources released while waiting for Prepare to complete + m_videoRecorder->Close(); + return; + } + + emit captureSizeChanged(m_videoSettings.resolution()); + + m_captureState = EPrepared; + emit stateChanged(EPrepared); + + // Check the actual active settings + queryAudioEncoderSettings(); + queryVideoEncoderSettings(); + + if (m_openWhenReady == true) { + setOutputLocation(m_requestedSink); + m_openWhenReady = false; // Reset + } + + if (m_commitSettingsWhenReady) { + applyAllSettings(); + m_commitSettingsWhenReady = false; // Reset + } + + if (m_startAfterPrepareComplete) { + m_startAfterPrepareComplete = false; // Reset + startRecording(); + } + } else { + m_videoRecorder->Close(); + if (aError == KErrNotSupported) + setError(aError, tr("Camera preparation for video recording failed because of unsupported setting.")); + else + setError(aError, tr("Failed to prepare camera for video recording.")); + } +} + +void S60VideoCaptureSession::MvruoRecordComplete(TInt aError) +{ + if (!m_videoRecorder) { + setError(KErrNotReady, tr("Unexpected camera error.")); + return; + } + + if((aError == KErrNone || aError == KErrCompletion)) { + m_videoRecorder->Stop(); + + // Reset state + if (m_captureState != ENotInitialized) { + m_captureState = ENotInitialized; + emit stateChanged(m_captureState); + if (m_durationTimer->isActive()) + m_durationTimer->stop(); + } + + if (m_cameraEngine->IsCameraReady()) + initializeVideoRecording(); + } + m_videoRecorder->Close(); + + // Notify muting is disabled if needed + if (m_muted) + emit mutedChanged(false); + + if (aError == KErrDiskFull) + setError(aError, tr("Not enough space for video, recording stopped.")); + else + setError(aError, tr("Recording stopped due to unexpected error.")); +} + +void S60VideoCaptureSession::MvruoEvent(const TMMFEvent& aEvent) +{ + Q_UNUSED(aEvent); +} + +#ifdef S60_DEVVIDEO_RECORDING_SUPPORTED +void S60VideoCaptureSession::MdvroReturnPicture(TVideoPicture *aPicture) +{ + // Not used + Q_UNUSED(aPicture); +} + +void S60VideoCaptureSession::MdvroSupplementalInfoSent() +{ + // Not used +} + +void S60VideoCaptureSession::MdvroNewBuffers() +{ + // Not used +} + +void S60VideoCaptureSession::MdvroFatalError(TInt aError) +{ + setError(aError, tr("Unexpected camera error.")); +} + +void S60VideoCaptureSession::MdvroInitializeComplete(TInt aError) +{ + // Not used + Q_UNUSED(aError); +} + +void S60VideoCaptureSession::MdvroStreamEnd() +{ + // Not used +} + +/* + * This populates video codec information (supported codecs, resolutions, + * framerates, etc.) using DevVideoRecord API. + */ +void S60VideoCaptureSession::doPopulateVideoCodecsDataL() +{ + RArray encoders; + CleanupClosePushL(encoders); + + CMMFDevVideoRecord *mDevVideoRecord = CMMFDevVideoRecord::NewL(*this); + CleanupStack::PushL(mDevVideoRecord); + + // Retrieve list of all encoders provided by the platform + mDevVideoRecord->GetEncoderListL(encoders); + + for (int i = 0; i < encoders.Count(); ++i ) { + + CVideoEncoderInfo *encoderInfo = mDevVideoRecord->VideoEncoderInfoLC(encoders[i]); + + // Discard encoders that are not HW accelerated and do not support direct capture + if (encoderInfo->Accelerated() == false || encoderInfo->SupportsDirectCapture() == false) { + CleanupStack::Check(encoderInfo); + CleanupStack::PopAndDestroy(encoderInfo); + continue; + } + + m_videoParametersForEncoder.append(MaxResolutionRatesAndTypes()); + int newIndex = m_videoParametersForEncoder.count() - 1; + + m_videoParametersForEncoder[newIndex].bitRate = (int)encoderInfo->MaxBitrate(); + + // Get supported MIME Types + const RPointerArray &videoFormats = encoderInfo->SupportedOutputFormats(); + for(int x = 0; x < videoFormats.Count(); ++x) { + QString codecMimeType = QString::fromUtf8((char *)videoFormats[x]->MimeType().Ptr(),videoFormats[x]->MimeType().Length()); + + m_videoParametersForEncoder[newIndex].mimeTypes.append(codecMimeType); + } + + // Get supported maximum Resolution/Framerate pairs + const RArray &ratesAndSizes = encoderInfo->MaxPictureRates(); + SupportedFrameRatePictureSize data; + for(int j = 0; j < ratesAndSizes.Count(); ++j) { + data.frameRate = ratesAndSizes[j].iPictureRate; + data.frameSize = QSize(ratesAndSizes[j].iPictureSize.iWidth, ratesAndSizes[j].iPictureSize.iHeight); + + // Save data to the hash + m_videoParametersForEncoder[newIndex].frameRatePictureSizePair.append(data); + } + + CleanupStack::Check(encoderInfo); + CleanupStack::PopAndDestroy(encoderInfo); + } + + CleanupStack::Check(mDevVideoRecord); + CleanupStack::PopAndDestroy(mDevVideoRecord); + CleanupStack::PopAndDestroy(); // RArray encoders +} +#endif // S60_DEVVIDEO_RECORDING_SUPPORTED + +QStringList S60VideoCaptureSession::supportedVideoContainers() +{ + QStringList containers; + + QList controllers = m_videoControllerMap.keys(); + for (int i = 0; i < controllers.count(); ++i) { + foreach (VideoFormatData formatData, m_videoControllerMap[controllers[i]]) { + for (int j = 0; j < formatData.supportedMimeTypes.count(); ++j) { + if (containers.contains(formatData.supportedMimeTypes[j], Qt::CaseInsensitive) == false) + containers.append(formatData.supportedMimeTypes[j]); + } + } + } + + return containers; +} + +bool S60VideoCaptureSession::isSupportedVideoContainer(const QString &containerName) +{ + return supportedVideoContainers().contains(containerName, Qt::CaseInsensitive); +} + +QString S60VideoCaptureSession::videoContainer() const +{ + return m_container; +} + +void S60VideoCaptureSession::setVideoContainer(const QString &containerName) +{ + if (containerName == m_requestedContainer) + return; + + if (containerName.isEmpty()) { + m_requestedContainer = KMimeTypeDefaultContainer; // Use default + } else { + if (supportedVideoContainers().contains(containerName)) { + m_requestedContainer = containerName; + } else { + setError(KErrNotSupported, tr("Requested video container is not supported.")); + m_requestedContainer = KMimeTypeDefaultContainer; // Reset to default + } + } + + m_uncommittedSettings = true; +} + +QString S60VideoCaptureSession::videoContainerDescription(const QString &containerName) +{ + QList formats; + QList encoders = m_videoControllerMap.keys(); + for (int i = 0; i < encoders.count(); ++i) { + formats = m_videoControllerMap[encoders[i]].keys(); + for (int j = 0; j < formats.count(); ++j) { + if (m_videoControllerMap[encoders[i]][formats[j]].supportedMimeTypes.contains(containerName, Qt::CaseInsensitive)) + return m_videoControllerMap[encoders[i]][formats[j]].description; + } + } + + return QString(); +} + +void S60VideoCaptureSession::cameraStatusChanged(QCamera::Status status) +{ + if (status == QCamera::ActiveStatus) { + m_cameraStarted = true; + + // Continue preparation or start recording if previously requested + if (m_captureState == EInitialized + && (m_openWhenReady || m_prepareAfterOpenComplete || m_startAfterPrepareComplete)) { + setOutputLocation(m_requestedSink); + m_openWhenReady = false; // Reset + } else if ((m_captureState == EOpenComplete || m_captureState == EPrepared) + && (m_prepareAfterOpenComplete || m_startAfterPrepareComplete)) { + startRecording(); + m_prepareAfterOpenComplete = false; // Reset + } + + } else if (status == QCamera::UnloadedStatus) { + m_cameraStarted = false; + releaseVideoRecording(); + } else { + m_cameraStarted = false; + } +} + +void S60VideoCaptureSession::durationTimerTriggered() +{ + // Update position only if recording is ongoing + if ((m_captureState == ERecording) && m_videoRecorder) { + // Signal will be automatically emitted of position changes + TRAPD(err, m_position = m_videoRecorder->DurationL().Int64() / 1000); + setError(err, tr("Cannot retrieve video position.")); + + emit positionChanged(m_position); + } +} + +void S60VideoCaptureSession::doPopulateAudioCodecsL() +{ + if (m_captureState == EInitializing) { + m_audioCodecList.clear(); + + RArray audioTypes; + CleanupClosePushL(audioTypes); + + if (m_videoRecorder) + m_videoRecorder->GetSupportedAudioTypesL(audioTypes); + else + setError(KErrNotReady, tr("Unexpected camera error.")); + + for (TInt i = 0; i < audioTypes.Count(); i++) { + TUint32 codec = audioTypes[i].FourCC(); + + if (codec == KMMFFourCCCodeAMR) + m_audioCodecList.insert(QString("audio/amr"), KMMFFourCCCodeAMR); + if (codec == KMMFFourCCCodeAAC) + m_audioCodecList.insert(QString("audio/aac"), KMMFFourCCCodeAAC); + } + CleanupStack::PopAndDestroy(&audioTypes); + } +} + +void S60VideoCaptureSession::doPopulateVideoCodecsL() +{ + if (m_captureState == EInitializing) { + m_videoCodecList.clear(); + + CDesC8ArrayFlat* videoTypes = new (ELeave) CDesC8ArrayFlat(10); + CleanupStack::PushL(videoTypes); + + if (m_videoRecorder) + m_videoRecorder->GetSupportedVideoTypesL(*videoTypes); + else + setError(KErrNotReady, tr("Unexpected camera error.")); + + for (TInt i = 0; i < videoTypes->Count(); i++) { + TPtrC8 videoType = videoTypes->MdcaPoint(i); + QString codecMimeType = QString::fromUtf8((char *)videoType.Ptr(), videoType.Length()); +#ifdef S60_DEVVIDEO_RECORDING_SUPPORTED + for (int j = 0; j < m_videoParametersForEncoder.size(); ++j) { + if (m_videoParametersForEncoder[j].mimeTypes.contains(codecMimeType, Qt::CaseInsensitive)) { + m_videoCodecList << codecMimeType; + break; + } + } +#else // CVideoRecorderUtility + m_videoCodecList << codecMimeType; +#endif // S60_DEVVIDEO_RECORDING_SUPPORTED + } + CleanupStack::PopAndDestroy(videoTypes); + } +} + +#ifndef S60_DEVVIDEO_RECORDING_SUPPORTED +/* + * Maximum resolution, framerate and bitrate can not be queried via MMF or + * ECam, but needs to be set according to the definitions of the video + * standard in question. In video standards, the values often depend on each + * other, but the below function defines constant maximums. + */ +void S60VideoCaptureSession::doPopulateMaxVideoParameters() +{ + m_videoParametersForEncoder.append(MaxResolutionRatesAndTypes()); // For H.263 + m_videoParametersForEncoder.append(MaxResolutionRatesAndTypes()); // For MPEG-4 + m_videoParametersForEncoder.append(MaxResolutionRatesAndTypes()); // For H.264 + + for (int i = 0; i < m_videoCodecList.count(); ++i) { + + // Use all lower case for comparisons + QString codec = m_videoCodecList[i].toLower(); + + if (codec.contains("video/h263-2000", Qt::CaseInsensitive)) { + // H.263 + if (codec == "video/h263-2000" || + codec == "video/h263-2000; profile=0" || + codec == "video/h263-2000; profile=0; level=10" || + codec == "video/h263-2000; profile=3") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(176,144))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 64000) + m_videoParametersForEncoder[0].bitRate = 64000; + continue; + } else if (codec == "video/h263-2000; profile=0; level=20") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 128000) + m_videoParametersForEncoder[0].bitRate = 128000; + continue; + } else if (codec == "video/h263-2000; profile=0; level=30") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(30.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 384000) + m_videoParametersForEncoder[0].bitRate = 384000; + continue; + } else if (codec == "video/h263-2000; profile=0; level=40") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(30.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 2048000) + m_videoParametersForEncoder[0].bitRate = 2048000; + continue; + } else if (codec == "video/h263-2000; profile=0; level=45") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(176,144))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 128000) + m_videoParametersForEncoder[0].bitRate = 128000; + continue; + } else if (codec == "video/h263-2000; profile=0; level=50") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 4096000) + m_videoParametersForEncoder[0].bitRate = 4096000; + continue; + } + + } else if (codec.contains("video/mp4v-es", Qt::CaseInsensitive)) { + // Mpeg-4 + if (codec == "video/mp4v-es" || + codec == "video/mp4v-es; profile-level-id=1" || + codec == "video/mp4v-es; profile-level-id=8") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(176,144))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 64000) + m_videoParametersForEncoder[0].bitRate = 64000; + continue; + } else if (codec == "video/mp4v-es; profile-level-id=2" || + codec == "video/mp4v-es; profile-level-id=9") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 128000) + m_videoParametersForEncoder[0].bitRate = 128000; + continue; + } else if (codec == "video/mp4v-es; profile-level-id=3") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(30.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 384000) + m_videoParametersForEncoder[0].bitRate = 384000; + continue; + } else if (codec == "video/mp4v-es; profile-level-id=4") { +#if (defined(S60_31_PLATFORM) | defined(S60_32_PLATFORM)) + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(640,480))); +#else // S60 5.0 and later platforms + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(30.0, QSize(640,480))); +#endif + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 4000000) + m_videoParametersForEncoder[0].bitRate = 4000000; + continue; + } else if (codec == "video/mp4v-es; profile-level-id=5") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(25.0, QSize(720,576))); + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(30.0, QSize(720,480))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 8000000) + m_videoParametersForEncoder[0].bitRate = 8000000; + continue; + } else if (codec == "video/mp4v-es; profile-level-id=6") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(30.0, QSize(1280,720))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 12000000) + m_videoParametersForEncoder[0].bitRate = 12000000; + continue; + } + + } else if (codec.contains("video/h264", Qt::CaseInsensitive)) { + // H.264 + if (codec == "video/h264" || + codec == "video/h264; profile-level-id=42800a") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(176,144))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 64000) + m_videoParametersForEncoder[0].bitRate = 64000; + continue; + } else if (codec == "video/h264; profile-level-id=42900b") { // BP, L1b + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(176,144))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 128000) + m_videoParametersForEncoder[0].bitRate = 128000; + continue; + } else if (codec == "video/h264; profile-level-id=42800b") { // BP, L1.1 + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(7.5, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 192000) + m_videoParametersForEncoder[0].bitRate = 192000; + continue; + } else if (codec == "video/h264; profile-level-id=42800c") { // BP, L1.2 + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 384000) + m_videoParametersForEncoder[0].bitRate = 384000; + continue; + } else if (codec == "video/h264; profile-level-id=42800d") { // BP, L1.3 + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(30.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 768000) + m_videoParametersForEncoder[0].bitRate = 768000; + continue; + } else if (codec == "video/h264; profile-level-id=428014") { // BP, L2 + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(30.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 2000000) + m_videoParametersForEncoder[0].bitRate = 2000000; + continue; + } else if (codec == "video/h264; profile-level-id=428015") { // BP, L2.1 + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(50.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 4000000) + m_videoParametersForEncoder[0].bitRate = 4000000; + continue; + } else if (codec == "video/h264; profile-level-id=428016") { // BP, L2.2 + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(16.9, QSize(640,480))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 4000000) + m_videoParametersForEncoder[0].bitRate = 4000000; + continue; + } else if (codec == "video/h264; profile-level-id=42801e") { // BP, L3 + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(33.8, QSize(640,480))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 10000000) + m_videoParametersForEncoder[0].bitRate = 10000000; + continue; + } else if (codec == "video/h264; profile-level-id=42801f") { // BP, L3.1 + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(30.0, QSize(1280,720))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 14000000) + m_videoParametersForEncoder[0].bitRate = 14000000; + continue; + } + } + } +} +#endif // S60_DEVVIDEO_RECORDING_SUPPORTED + +/* + * This function returns the maximum resolution defined by the video standards + * for different MIME Types. + */ +QSize S60VideoCaptureSession::maximumResolutionForMimeType(const QString &mimeType) const +{ + QSize maxSize(-1,-1); + // Use all lower case for comparisons + QString lowerMimeType = mimeType.toLower(); + + if (lowerMimeType == "video/h263-2000") { + maxSize = KResH263; + } else if (lowerMimeType == "video/h263-2000; profile=0") { + maxSize = KResH263_Profile0; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=10") { + maxSize = KResH263_Profile0_Level10; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=20") { + maxSize = KResH263_Profile0_Level20; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=30") { + maxSize = KResH263_Profile0_Level30; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=40") { + maxSize = KResH263_Profile0_Level40; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=45") { + maxSize = KResH263_Profile0_Level45; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=50") { + maxSize = KResH263_Profile0_Level50; + } else if (lowerMimeType == "video/h263-2000; profile=3") { + maxSize = KResH263_Profile3; + } else if (lowerMimeType == "video/mp4v-es") { + maxSize = KResMPEG4; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=1") { + maxSize = KResMPEG4_PLID_1; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=2") { + maxSize = KResMPEG4_PLID_2; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=3") { + maxSize = KResMPEG4_PLID_3; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=4") { + maxSize = KResMPEG4_PLID_4; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=5") { + maxSize = KResMPEG4_PLID_5; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=6") { + maxSize = KResMPEG4_PLID_6; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=8") { + maxSize = KResMPEG4_PLID_8; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=9") { + maxSize = KResMPEG4_PLID_9; + } else if (lowerMimeType == "video/h264") { + maxSize = KResH264; + } else if (lowerMimeType == "video/h264; profile-level-id=42800a" || + lowerMimeType == "video/h264; profile-level-id=4d400a" || + lowerMimeType == "video/h264; profile-level-id=64400a") { // L1 + maxSize = KResH264_PLID_42800A; + } else if (lowerMimeType == "video/h264; profile-level-id=42900b" || + lowerMimeType == "video/h264; profile-level-id=4d500b" || + lowerMimeType == "video/h264; profile-level-id=644009") { // L1.b + maxSize = KResH264_PLID_42900B; + } else if (lowerMimeType == "video/h264; profile-level-id=42800b" || + lowerMimeType == "video/h264; profile-level-id=4d400b" || + lowerMimeType == "video/h264; profile-level-id=64400b") { // L1.1 + maxSize = KResH264_PLID_42800B; + } else if (lowerMimeType == "video/h264; profile-level-id=42800c" || + lowerMimeType == "video/h264; profile-level-id=4d400c" || + lowerMimeType == "video/h264; profile-level-id=64400c") { // L1.2 + maxSize = KResH264_PLID_42800C; + } else if (lowerMimeType == "video/h264; profile-level-id=42800d" || + lowerMimeType == "video/h264; profile-level-id=4d400d" || + lowerMimeType == "video/h264; profile-level-id=64400d") { // L1.3 + maxSize = KResH264_PLID_42800D; + } else if (lowerMimeType == "video/h264; profile-level-id=428014" || + lowerMimeType == "video/h264; profile-level-id=4d4014" || + lowerMimeType == "video/h264; profile-level-id=644014") { // L2 + maxSize = KResH264_PLID_428014; + } else if (lowerMimeType == "video/h264; profile-level-id=428015" || + lowerMimeType == "video/h264; profile-level-id=4d4015" || + lowerMimeType == "video/h264; profile-level-id=644015") { // L2.1 + maxSize = KResH264_PLID_428015; + } else if (lowerMimeType == "video/h264; profile-level-id=428016" || + lowerMimeType == "video/h264; profile-level-id=4d4016" || + lowerMimeType == "video/h264; profile-level-id=644016") { // L2.2 + maxSize = KResH264_PLID_428016; + } else if (lowerMimeType == "video/h264; profile-level-id=42801e" || + lowerMimeType == "video/h264; profile-level-id=4d401e" || + lowerMimeType == "video/h264; profile-level-id=64401e") { // L3 + maxSize = KResH264_PLID_42801E; + } else if (lowerMimeType == "video/h264; profile-level-id=42801f" || + lowerMimeType == "video/h264; profile-level-id=4d401f" || + lowerMimeType == "video/h264; profile-level-id=64401f") { // L3.1 + maxSize = KResH264_PLID_42801F; + } else if (lowerMimeType == "video/h264; profile-level-id=428020" || + lowerMimeType == "video/h264; profile-level-id=4d4020" || + lowerMimeType == "video/h264; profile-level-id=644020") { // L3.2 + maxSize = KResH264_PLID_428020; + } else if (lowerMimeType == "video/h264; profile-level-id=428028" || + lowerMimeType == "video/h264; profile-level-id=4d4028" || + lowerMimeType == "video/h264; profile-level-id=644028") { // L4 + maxSize = KResH264_PLID_428028; + } + + return maxSize; +} + +/* + * This function returns the maximum framerate defined by the video standards + * for different MIME Types. + */ + +qreal S60VideoCaptureSession::maximumFrameRateForMimeType(const QString &mimeType) const +{ + qreal maxRate(-1.0); + // Use all lower case for comparisons + QString lowerMimeType = mimeType.toLower(); + + if (lowerMimeType == "video/h263-2000") { + maxRate = KFrR_H263; + } else if (lowerMimeType == "video/h263-2000; profile=0") { + maxRate = KFrR_H263_Profile0; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=10") { + maxRate = KFrR_H263_Profile0_Level10; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=20") { + maxRate = KFrR_H263_Profile0_Level20; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=30") { + maxRate = KFrR_H263_Profile0_Level30; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=40") { + maxRate = KFrR_H263_Profile0_Level40; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=45") { + maxRate = KFrR_H263_Profile0_Level45; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=50") { + maxRate = KFrR_H263_Profile0_Level50; + } else if (lowerMimeType == "video/h263-2000; profile=3") { + maxRate = KFrR_H263_Profile3; + } else if (lowerMimeType == "video/mp4v-es") { + maxRate = KFrR_MPEG4; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=1") { + maxRate = KFrR_MPEG4_PLID_1; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=2") { + maxRate = KFrR_MPEG4_PLID_2; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=3") { + maxRate = KFrR_MPEG4_PLID_3; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=4") { + maxRate = KFrR_MPEG4_PLID_4; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=5") { + maxRate = KFrR_MPEG4_PLID_5; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=6") { + maxRate = KFrR_MPEG4_PLID_6; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=8") { + maxRate = KFrR_MPEG4_PLID_8; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=9") { + maxRate = KFrR_MPEG4_PLID_9; + } else if (lowerMimeType == "video/h264") { + maxRate = KFrR_H264; + } else if (lowerMimeType == "video/h264; profile-level-id=42800a" || + lowerMimeType == "video/h264; profile-level-id=4d400a" || + lowerMimeType == "video/h264; profile-level-id=64400a") { // L1 + maxRate = KFrR_H264_PLID_42800A; + } else if (lowerMimeType == "video/h264; profile-level-id=42900b" || + lowerMimeType == "video/h264; profile-level-id=4d500b" || + lowerMimeType == "video/h264; profile-level-id=644009") { // L1.b + maxRate = KFrR_H264_PLID_42900B; + } else if (lowerMimeType == "video/h264; profile-level-id=42800b" || + lowerMimeType == "video/h264; profile-level-id=4d400b" || + lowerMimeType == "video/h264; profile-level-id=64400b") { // L1.1 + maxRate = KFrR_H264_PLID_42800B; + } else if (lowerMimeType == "video/h264; profile-level-id=42800c" || + lowerMimeType == "video/h264; profile-level-id=4d400c" || + lowerMimeType == "video/h264; profile-level-id=64400c") { // L1.2 + maxRate = KFrR_H264_PLID_42800C; + } else if (lowerMimeType == "video/h264; profile-level-id=42800d" || + lowerMimeType == "video/h264; profile-level-id=4d400d" || + lowerMimeType == "video/h264; profile-level-id=64400d") { // L1.3 + maxRate = KFrR_H264_PLID_42800D; + } else if (lowerMimeType == "video/h264; profile-level-id=428014" || + lowerMimeType == "video/h264; profile-level-id=4d4014" || + lowerMimeType == "video/h264; profile-level-id=644014") { // L2 + maxRate = KFrR_H264_PLID_428014; + } else if (lowerMimeType == "video/h264; profile-level-id=428015" || + lowerMimeType == "video/h264; profile-level-id=4d4015" || + lowerMimeType == "video/h264; profile-level-id=644015") { // L2.1 + maxRate = KFrR_H264_PLID_428015; + } else if (lowerMimeType == "video/h264; profile-level-id=428016" || + lowerMimeType == "video/h264; profile-level-id=4d4016" || + lowerMimeType == "video/h264; profile-level-id=644016") { // L2.2 + maxRate = KFrR_H264_PLID_428016; + } else if (lowerMimeType == "video/h264; profile-level-id=42801e" || + lowerMimeType == "video/h264; profile-level-id=4d401e" || + lowerMimeType == "video/h264; profile-level-id=64401e") { // L3 + maxRate = KFrR_H264_PLID_42801E; + } else if (lowerMimeType == "video/h264; profile-level-id=42801f" || + lowerMimeType == "video/h264; profile-level-id=4d401f" || + lowerMimeType == "video/h264; profile-level-id=64401f") { // L3.1 + maxRate = KFrR_H264_PLID_42801F; + } else if (lowerMimeType == "video/h264; profile-level-id=428020" || + lowerMimeType == "video/h264; profile-level-id=4d4020" || + lowerMimeType == "video/h264; profile-level-id=644020") { // L3.2 + maxRate = KFrR_H264_PLID_428020; + } else if (lowerMimeType == "video/h264; profile-level-id=428028" || + lowerMimeType == "video/h264; profile-level-id=4d4028" || + lowerMimeType == "video/h264; profile-level-id=644028") { // L4 + maxRate = KFrR_H264_PLID_428028; + } + + return maxRate; +} + +/* + * This function returns the maximum bitrate defined by the video standards + * for different MIME Types. + */ +int S60VideoCaptureSession::maximumBitRateForMimeType(const QString &mimeType) const +{ + int maxRate(-1.0); + // Use all lower case for comparisons + QString lowerMimeType = mimeType.toLower(); + + if (lowerMimeType == "video/h263-2000") { + maxRate = KBiR_H263; + } else if (lowerMimeType == "video/h263-2000; profile=0") { + maxRate = KBiR_H263_Profile0; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=10") { + maxRate = KBiR_H263_Profile0_Level10; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=20") { + maxRate = KBiR_H263_Profile0_Level20; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=30") { + maxRate = KBiR_H263_Profile0_Level30; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=40") { + maxRate = KBiR_H263_Profile0_Level40; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=45") { + maxRate = KBiR_H263_Profile0_Level45; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=50") { + maxRate = KBiR_H263_Profile0_Level50; + } else if (lowerMimeType == "video/h263-2000; profile=3") { + maxRate = KBiR_H263_Profile3; + } else if (lowerMimeType == "video/mp4v-es") { + maxRate = KBiR_MPEG4; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=1") { + maxRate = KBiR_MPEG4_PLID_1; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=2") { + maxRate = KBiR_MPEG4_PLID_2; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=3") { + maxRate = KBiR_MPEG4_PLID_3; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=4") { + maxRate = KBiR_MPEG4_PLID_4; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=5") { + maxRate = KBiR_MPEG4_PLID_5; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=6") { + maxRate = KBiR_MPEG4_PLID_6; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=8") { + maxRate = KBiR_MPEG4_PLID_8; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=9") { + maxRate = KBiR_MPEG4_PLID_9; + } else if (lowerMimeType == "video/h264") { + maxRate = KBiR_H264; + } else if (lowerMimeType == "video/h264; profile-level-id=42800a" || + lowerMimeType == "video/h264; profile-level-id=4d400a" || + lowerMimeType == "video/h264; profile-level-id=64400a") { // L1 + maxRate = KBiR_H264_PLID_42800A; + } else if (lowerMimeType == "video/h264; profile-level-id=42900b" || + lowerMimeType == "video/h264; profile-level-id=4d500b" || + lowerMimeType == "video/h264; profile-level-id=644009") { // L1.b + maxRate = KBiR_H264_PLID_42900B; + } else if (lowerMimeType == "video/h264; profile-level-id=42800b" || + lowerMimeType == "video/h264; profile-level-id=4d400b" || + lowerMimeType == "video/h264; profile-level-id=64400b") { // L1.1 + maxRate = KBiR_H264_PLID_42800B; + } else if (lowerMimeType == "video/h264; profile-level-id=42800c" || + lowerMimeType == "video/h264; profile-level-id=4d400c" || + lowerMimeType == "video/h264; profile-level-id=64400c") { // L1.2 + maxRate = KBiR_H264_PLID_42800C; + } else if (lowerMimeType == "video/h264; profile-level-id=42800d" || + lowerMimeType == "video/h264; profile-level-id=4d400d" || + lowerMimeType == "video/h264; profile-level-id=64400d") { // L1.3 + maxRate = KBiR_H264_PLID_42800D; + } else if (lowerMimeType == "video/h264; profile-level-id=428014" || + lowerMimeType == "video/h264; profile-level-id=4d4014" || + lowerMimeType == "video/h264; profile-level-id=644014") { // L2 + maxRate = KBiR_H264_PLID_428014; + } else if (lowerMimeType == "video/h264; profile-level-id=428015" || + lowerMimeType == "video/h264; profile-level-id=4d4015" || + lowerMimeType == "video/h264; profile-level-id=644015") { // L2.1 + maxRate = KBiR_H264_PLID_428015; + } else if (lowerMimeType == "video/h264; profile-level-id=428016" || + lowerMimeType == "video/h264; profile-level-id=4d4016" || + lowerMimeType == "video/h264; profile-level-id=644016") { // L2.2 + maxRate = KBiR_H264_PLID_428016; + } else if (lowerMimeType == "video/h264; profile-level-id=42801e" || + lowerMimeType == "video/h264; profile-level-id=4d401e" || + lowerMimeType == "video/h264; profile-level-id=64401e") { // L3 + maxRate = KBiR_H264_PLID_42801E; + } else if (lowerMimeType == "video/h264; profile-level-id=42801f" || + lowerMimeType == "video/h264; profile-level-id=4d401f" || + lowerMimeType == "video/h264; profile-level-id=64401f") { // L3.1 + maxRate = KBiR_H264_PLID_42801F; + } else if (lowerMimeType == "video/h264; profile-level-id=428020" || + lowerMimeType == "video/h264; profile-level-id=4d4020" || + lowerMimeType == "video/h264; profile-level-id=644020") { // L3.2 + maxRate = KBiR_H264_PLID_428020; + } else if (lowerMimeType == "video/h264; profile-level-id=428028" || + lowerMimeType == "video/h264; profile-level-id=4d4028" || + lowerMimeType == "video/h264; profile-level-id=644028") { // L4 + maxRate = KBiR_H264_PLID_428028; + } + + return maxRate; +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60videocapturesession.h b/src/plugins/symbian/ecam/s60videocapturesession.h new file mode 100644 index 000000000..cfa101f57 --- /dev/null +++ b/src/plugins/symbian/ecam/s60videocapturesession.h @@ -0,0 +1,414 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60VIDEOCAPTURESESSION_H +#define S60VIDEOCAPTURESESSION_H + +#include +#include + +#include +#include +#include + +#include "s60cameraengine.h" + +#include +#include // CVideoRecorderUtility +#ifdef S60_DEVVIDEO_RECORDING_SUPPORTED +#include +#endif // S60_DEVVIDEO_RECORDING_SUPPORTED + +QT_USE_NAMESPACE + +class QTimer; + +/* + * VideoSession is the main class handling all video recording related + * operations. It uses mainly CVideoRecorderUtility to do it's tasks, but if + * DevVideoRecord is available it is used to provide more detailed + * information of the supported video settings. + */ +class S60VideoCaptureSession : public QObject, + public MVideoRecorderUtilityObserver +#ifdef S60_DEVVIDEO_RECORDING_SUPPORTED + ,public MMMFDevVideoRecordObserver +#endif // S60_DEVVIDEO_RECORDING_SUPPORTED +{ + Q_OBJECT + Q_ENUMS(Error) + Q_ENUMS(EcamErrors) + Q_ENUMS(TVideoCaptureState) + +public: // Enums + + enum TVideoCaptureState + { + ENotInitialized = 0, // 0 - VideoRecording is not initialized, instance may or may not be created + EInitializing, // 1 - Initialization is ongoing + EInitialized, // 2 - VideoRecording is initialized, OpenFile is called with dummy file + EOpening, // 3 - OpenFile called with actual output location, waiting completion + EOpenComplete, // 4 - OpenFile completed with the actual output location + EPreparing, // 5 - Preparing VideoRecording to use set video settings + EPrepared, // 6 - VideoRecording is prepared with the set settings, ready to record + ERecording, // 7 - Video recording is ongoing + EPaused // 8 - Video recording has been started and paused + }; + + enum AudioQualityDefinition + { + ENoAudioQuality = 0, // 0 - Both BitRate and SampleRate settings available + EOnlyAudioQuality, // 1 - No BitRate or SampleRate settings available, use Quality to set them + EAudioQualityAndBitRate, // 2 - BitRate setting available, use Quality to set SampleRate + EAudioQualityAndSampleRate, // 3 - SampleRate setting available, use Quality to set BitRate + }; + + enum VideoQualityDefinition + { + ENoVideoQuality = 0, // 0 - All, Resolution, FrameRate and BitRate available + EOnlyVideoQuality, // 1 - None available, use Quality to set Resolution, FrameRate and BitRate + EVideoQualityAndResolution, // 2 - Only Resolution available, use Quality to set FrameRate and BitRate + EVideoQualityAndFrameRate, // 3 - Only FrameRate available, use Quality to set Resolution and BitRate + EVideoQualityAndBitRate, // 4 - Only BitRate available, use Quality to set Resolution and FrameRate + EVideoQualityAndResolutionAndBitRate, // 5 - No FrameRate available, use Quality to set it + EVideoQualityAndResolutionAndFrameRate, // 6 - No BitRate available, use Quality to set it + EVideoQualityAndFrameRateAndBitRate // 7 - No Resolution available, use Quality to set it + }; + +public: // Constructor & Destructor + + S60VideoCaptureSession(QObject *parent = 0); + ~S60VideoCaptureSession(); + +public: // MVideoRecorderUtilityObserver + + void MvruoOpenComplete(TInt aError); + void MvruoPrepareComplete(TInt aError); + void MvruoRecordComplete(TInt aError); + void MvruoEvent(const TMMFEvent& aEvent); + +#ifdef S60_DEVVIDEO_RECORDING_SUPPORTED +public: // MMMFDevVideoRecordObserver + void MdvroReturnPicture(TVideoPicture *aPicture); + void MdvroSupplementalInfoSent(); + void MdvroNewBuffers(); + void MdvroFatalError(TInt aError); + void MdvroInitializeComplete(TInt aError); + void MdvroStreamEnd(); +#endif // S60_DEVVIDEO_RECORDING_SUPPORTED + +public: // Methods + + void setError(const TInt error, const QString &description); + void setCameraHandle(CCameraEngine* cameraHandle); + void notifySettingsSet(); + + qint64 position(); + TVideoCaptureState state() const; + bool isMuted() const; + + // Controls + int initializeVideoRecording(); + void releaseVideoRecording(); + void applyAllSettings(); + + void startRecording(); + void pauseRecording(); + void stopRecording(const bool reInitialize = true); + void setMuted(const bool muted); + + // Output Location + bool setOutputLocation(const QUrl &sink); + QUrl outputLocation() const; + + // Resolution + void setVideoResolution(const QSize &resolution); + QList supportedVideoResolutions(bool *continuous); + QList supportedVideoResolutions(const QVideoEncoderSettings &settings, bool *continuous); + + // Framerate + void setFrameRate(const qreal rate); + QList supportedVideoFrameRates(bool *continuous); + QList supportedVideoFrameRates(const QVideoEncoderSettings &settings, bool *continuous); + + // Other Video Settings + void setBitrate(const int bitrate); + void setVideoEncodingMode(const QtMultimediaKit::EncodingMode mode); + + // Video Codecs + void setVideoCaptureCodec(const QString &codecName); + QStringList supportedVideoCaptureCodecs(); + QString videoCaptureCodecDescription(const QString &codecName); + + // Audio Codecs + void setAudioCaptureCodec(const QString &codecName); + QStringList supportedAudioCaptureCodecs(); + + // Encoder Settings + void videoEncoderSettings(QVideoEncoderSettings &videoSettings); + void audioEncoderSettings(QAudioEncoderSettings &audioSettings); + + // Quality + void setVideoCaptureQuality(const QtMultimediaKit::EncodingQuality quality, + const VideoQualityDefinition mode); + void setAudioCaptureQuality(const QtMultimediaKit::EncodingQuality quality, + const AudioQualityDefinition mode); + + // Video Containers + QString videoContainer() const; + void setVideoContainer(const QString &containerName); + QStringList supportedVideoContainers(); + bool isSupportedVideoContainer(const QString &containerName); + QString videoContainerDescription(const QString &containerName); + + // Audio Settings + QList supportedSampleRates(const QAudioEncoderSettings &settings, bool *continuous); + void setAudioSampleRate(const int sampleRate); + void setAudioBitRate(const int bitRate); + void setAudioChannelCount(const int channelCount); + void setAudioEncodingMode(const QtMultimediaKit::EncodingMode mode); + + // Video Options + QSize pixelAspectRatio(); + void setPixelAspectRatio(const QSize par); + int gain(); + void setGain(const int gain); + int maxClipSizeInBytes() const; + void setMaxClipSizeInBytes(const int size); + +private: // Internal + + QMediaRecorder::Error fromSymbianErrorToQtMultimediaError(int aError); + + void initializeVideoCaptureSettings(); + void doInitializeVideoRecorderL(); + void commitVideoEncoderSettings(); + void queryAudioEncoderSettings(); + void queryVideoEncoderSettings(); + void validateRequestedCodecs(); + void resetSession(bool errorHandling = false); + + void doSetCodecsL(); + QString determineProfileAndLevel(); + void doSetVideoResolution(const QSize &resolution); + void doSetFrameRate(qreal rate); + void doSetBitrate(const int &bitrate); + + void updateVideoCaptureContainers(); + void doUpdateVideoCaptureContainersL(); + void selectController(const QString &format, + TUid &controllerUid, + TUid &formatUid); + + void doPopulateVideoCodecsDataL(); + void doPopulateVideoCodecsL(); +#ifndef S60_DEVVIDEO_RECORDING_SUPPORTED + void doPopulateMaxVideoParameters(); +#endif // S60_DEVVIDEO_RECORDING_SUPPORTED + void doPopulateAudioCodecsL(); + + QList doGetSupportedSampleRatesL(const QAudioEncoderSettings &settings, + bool *continuous); + QSize maximumResolutionForMimeType(const QString &mimeType) const; + qreal maximumFrameRateForMimeType(const QString &mimeType) const; + int maximumBitRateForMimeType(const QString &mimeType) const; + +signals: // Notification Signals + + void stateChanged(S60VideoCaptureSession::TVideoCaptureState); + void positionChanged(qint64); + void mutedChanged(bool); + void captureSizeChanged(const QSize&); + void error(int, const QString&); + +private slots: // Internal Slots + + void cameraStatusChanged(QCamera::Status); + void durationTimerTriggered(); + +private: // Structs + + /* + * This structure holds the information of supported video mime types for + * the format and also description for it. + */ + struct VideoFormatData { + QString description; + QStringList supportedMimeTypes; + }; + + /* + * This structure is used to define supported resolutions and framerate + * (depending on each other) for each supported encoder mime type (defining + * encoder, profile and level) + */ + struct SupportedFrameRatePictureSize { + SupportedFrameRatePictureSize() {} + SupportedFrameRatePictureSize(qreal rate, QSize size): + frameRate(rate), + frameSize(size) {} + qreal frameRate; + QSize frameSize; + }; + + /* + * This structure defines supported resolution/framerate pairs and maximum + * bitrate for a single encodec device. It also the supported mime types + * (codec, profile and level) of the encoder device. + * + * Structure defines 2 contructors: + * - First with no attributes + * - Second, which will construct the sructure appending one + * resolution/framerate pair to the list of + * SupportedFrameRatePictureSizes and setting the given bitrate as + * maximum. This second constructor is for convenience. + * + * This struct is used in m_videoParametersForEncoder (QList). + * + * Here's a visualization of an example strcuture: + * STRUCT: + * |-- Resolution/FrameRate Pairs: + * | |- VGA / 30fps + * | |- 720p / 25fps + * | |- Etc. + * | + * |-- MimeTypes: + * | |- video/mp4v-es; profile-level-id=1 + * | |- video/mp4v-es; profile-level-id=2 + * | |- Etc. + * | + * |-- Max BitRate: 1Mbps + */ + struct MaxResolutionRatesAndTypes { + MaxResolutionRatesAndTypes() {} + MaxResolutionRatesAndTypes(QSize size, qreal fRate, int bRate): + bitRate(bRate) + { + frameRatePictureSizePair.append(SupportedFrameRatePictureSize(fRate,size)); + } + QList frameRatePictureSizePair; + QStringList mimeTypes; + int bitRate; + }; + +private: // Data + + CCameraEngine *m_cameraEngine; + CVideoRecorderUtility *m_videoRecorder; + QTimer *m_durationTimer; + qint64 m_position; + // Symbian ErrorCode + mutable int m_error; + // This defines whether Camera is in ActiveStatus or not + bool m_cameraStarted; + // Internal state of the video recorder + TVideoCaptureState m_captureState; + // Actual output file name/path + QUrl m_sink; + // Requested output file name/path, this may be different from m_sink if + // asynchronous operation was ongoing in the CVideoRecorderUtility when new + // outputLocation was set. + QUrl m_requestedSink; + // Requested videoSettings. The may not be active settings before those are + // committed (with commitVideoEncoderSettings()) + QVideoEncoderSettings m_videoSettings; + // Requested audioSettings. The may not be active settings before those are + // committed (with commitVideoEncoderSettings()) + QAudioEncoderSettings m_audioSettings; + // Tells whether settings should be initialized when changing the camera + bool m_captureSettingsSet; + // Active container + QString m_container; + // Requested container, this may be different from m_container if + // asynchronous operation was ongoing in the CVideoRecorderUtility when new + // container was set. + QString m_requestedContainer; + // Requested muted value. This may not be active value before settings are + // committed (with commitVideoEncoderSettings()) + bool m_muted; + // Maximum ClipSize in Bytes + int m_maxClipSize; + // List of supported video codec mime types + QStringList m_videoCodecList; + // Hash of supported video codec mime types and corresponding FourCC codes + QHash m_audioCodecList; + // Map of video capture controllers information. It is populated during + // doUpdateVideoCaptureContainersL(). + // + // Here's a visualization of an example strcuture: + // m_videoControllerMap(HASH): + // | + // |-- Controller 1 : HASH + // | |- Container 1 (UID) : FormatData + // | | |- Description + // | | |- List of supported MimeTypes + // | |- Container 2 (UID) : FormatData + // | | |- Description + // | | |- List of supported MimeTypes + // | |- Etc. + // | + // |-- Controller 2: HASH + // | |- Container 1 (UID) : FormatData + // | | |- Description + // | | |- List of supported MimeTypes + // | |- Etc. + // + QHash > m_videoControllerMap; + // List of Encoder information. If DevVideoRecord is available info is + // gathered during doPopulateVideoCodecsDataL() for each encoder (hw + // accelerated and supporting camera input) found. If DevVideoRecord is not + // available, the info is set in doPopulateMaxVideoParameters() based on + // supported codec list received from CVideoRecorderUtility. + QList m_videoParametersForEncoder; + // Set if OpenFileL should be executed when currently ongoing operation + // is completed. + bool m_openWhenReady; + // Set if video capture should be prepared after OpenFileL has completed + bool m_prepareAfterOpenComplete; + // Set if video capture should be started when Prepare has completed + bool m_startAfterPrepareComplete; + // Tells if settings have been set after last Prepare() + bool m_uncommittedSettings; + // Tells if settings need to be applied after ongoing operation has finished + bool m_commitSettingsWhenReady; +}; + +#endif // S60VIDEOCAPTURESESSION_H diff --git a/src/plugins/symbian/ecam/s60videodevicecontrol.cpp b/src/plugins/symbian/ecam/s60videodevicecontrol.cpp new file mode 100644 index 000000000..3d55d3110 --- /dev/null +++ b/src/plugins/symbian/ecam/s60videodevicecontrol.cpp @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "s60videodevicecontrol.h" +#include "s60cameracontrol.h" +#include "s60cameraconstants.h" + +S60VideoDeviceControl::S60VideoDeviceControl(QObject *parent) : + QVideoDeviceControl(parent) +{ +} + +S60VideoDeviceControl::S60VideoDeviceControl(S60CameraControl *control, QObject *parent) : + QVideoDeviceControl(parent), + m_selectedDevice(KDefaultCameraDevice) +{ + m_control = control; + connect(m_control, SIGNAL(devicesChanged()), this, SIGNAL(devicesChanged())); +} + +S60VideoDeviceControl::~S60VideoDeviceControl() +{ +} + +int S60VideoDeviceControl::deviceCount() const +{ + return S60CameraControl::deviceCount(); +} + +QString S60VideoDeviceControl::deviceName(int index) const +{ + return S60CameraControl::name(index); +} + +QString S60VideoDeviceControl::deviceDescription(int index) const +{ + return S60CameraControl::description(index); +} + +QIcon S60VideoDeviceControl::deviceIcon(int index) const +{ + Q_UNUSED(index); + return QIcon(); +} + +int S60VideoDeviceControl::defaultDevice() const +{ + return KDefaultCameraDevice; +} + +int S60VideoDeviceControl::selectedDevice() const +{ + return m_selectedDevice; +} + +void S60VideoDeviceControl::setSelectedDevice(int index) +{ + // Inform that we selected new device + if (m_selectedDevice != index) { + m_control->setSelectedDevice(index); + m_selectedDevice = index; + emit selectedDeviceChanged(m_selectedDevice); + emit selectedDeviceChanged(deviceName(m_selectedDevice)); + } +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60videodevicecontrol.h b/src/plugins/symbian/ecam/s60videodevicecontrol.h new file mode 100644 index 000000000..03249441a --- /dev/null +++ b/src/plugins/symbian/ecam/s60videodevicecontrol.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60VIDEODEVICECONTROL_H +#define S60VIDEODEVICECONTROL_H + +#include "qvideodevicecontrol.h" + +QT_USE_NAMESPACE + +class S60CameraControl; +class QString; +class QIcon; + +/* + * Control for providing information of the video device (r. camera) and to + * enable other camera device (e.g. secondary camera if one exists). + */ +class S60VideoDeviceControl : public QVideoDeviceControl +{ + Q_OBJECT + +public: // Constructors & Destructor + + S60VideoDeviceControl(QObject *parent); + S60VideoDeviceControl(S60CameraControl *control, QObject *parent = 0); + virtual ~S60VideoDeviceControl(); + +public: // QVideoDeviceControl + + int deviceCount() const; + + QString deviceName(int index) const; + QString deviceDescription(int index) const; + QIcon deviceIcon(int index) const; + + int defaultDevice() const; + int selectedDevice() const; + +public slots: // QVideoDeviceControl + + void setSelectedDevice(int index); + +/* +Q_SIGNALS: +void selectedDeviceChanged(int index); +void selectedDeviceChanged(const QString &deviceName); +void devicesChanged(); +*/ + +private: // Data + + S60CameraControl *m_control; + int m_selectedDevice; +}; + +#endif // S60VIDEODEVICECONTROL_H diff --git a/src/plugins/symbian/ecam/s60videoencodercontrol.cpp b/src/plugins/symbian/ecam/s60videoencodercontrol.cpp new file mode 100644 index 000000000..34b28e28e --- /dev/null +++ b/src/plugins/symbian/ecam/s60videoencodercontrol.cpp @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "s60videoencodercontrol.h" +#include "s60videocapturesession.h" + +S60VideoEncoderControl::S60VideoEncoderControl(QObject *parent) : + QVideoEncoderControl(parent) +{ +} + +S60VideoEncoderControl::S60VideoEncoderControl(S60VideoCaptureSession *session, QObject *parent) : + QVideoEncoderControl(parent) +{ + m_session = session; +} + +S60VideoEncoderControl::~S60VideoEncoderControl() +{ +} + +QStringList S60VideoEncoderControl::supportedVideoCodecs() const +{ + return m_session->supportedVideoCaptureCodecs(); +} + +QString S60VideoEncoderControl::videoCodecDescription(const QString &codecName) const +{ + return m_session->videoCaptureCodecDescription(codecName); +} + +QList S60VideoEncoderControl::supportedFrameRates(const QVideoEncoderSettings &settings, bool *continuous) const +{ + if (!settings.isNull()) + return m_session->supportedVideoFrameRates(settings, continuous); + return m_session->supportedVideoFrameRates(continuous); +} + +QList S60VideoEncoderControl::supportedResolutions(const QVideoEncoderSettings &settings, bool *continuous) const +{ + if (!settings.isNull()) + return m_session->supportedVideoResolutions(settings, continuous); + return m_session->supportedVideoResolutions(continuous); +} + +QStringList S60VideoEncoderControl::supportedEncodingOptions(const QString &codec) const +{ + // Possible settings: EncodingMode, Codec, Resolution, FrameRate, BitRate, Quality + // Possible (codec specific) options: PixelAspectRatio, Gain, MaxClipSizeInBytes + + // Following options are valid for all codecs + Q_UNUSED(codec); + + QStringList options; + options.append("pixelAspectRatio"); + options.append("gain"); + options.append("maxClipSizeInBytes"); + + return options; +} + +QVariant S60VideoEncoderControl::encodingOption(const QString &codec, const QString &name) const +{ + Q_UNUSED(codec); + + // Possible settings: EncodingMode, Codec, Resolution, FrameRate, BitRate, Quality + // Possible (codec specific) options: PixelAspectRatio, Gain, MaxClipSizeInBytes + + QVariant returnValue; + + if (qstrcmp(name.toLocal8Bit().constData(), "pixelAspectRatio") == 0) + returnValue.setValue(m_session->pixelAspectRatio()); + else if (qstrcmp(name.toLocal8Bit().constData(), "gain") == 0) + returnValue.setValue((int)m_session->gain()); + else if (qstrcmp(name.toLocal8Bit().constData(), "maxClipSizeInBytes") == 0) + returnValue.setValue(m_session->maxClipSizeInBytes()); + + return returnValue; +} + +void S60VideoEncoderControl::setEncodingOption( + const QString &codec, const QString &name, const QVariant &value) +{ + // Set the codec first if not already set + m_session->setVideoCaptureCodec(codec); + + if (qstrcmp(name.toLocal8Bit().constData(), "pixelAspectRatio") == 0) + m_session->setPixelAspectRatio(value.toSize()); + else if (qstrcmp(name.toLocal8Bit().constData(), "gain") == 0) + m_session->setGain(value.toInt()); + else if (qstrcmp(name.toLocal8Bit().constData(), "maxClipSizeInBytes") == 0) + m_session->setMaxClipSizeInBytes(value.toInt()); + else + m_session->setError(KErrNotSupported, tr("Requested encoding option is not supported")); +} + +QVideoEncoderSettings S60VideoEncoderControl::videoSettings() const +{ + QVideoEncoderSettings settings; + m_session->videoEncoderSettings(settings); + + return settings; +} + +void S60VideoEncoderControl::setVideoSettings(const QVideoEncoderSettings &settings) +{ + // Notify that settings have been implicitly set and there's no need to + // initialize them in case camera is changed + m_session->notifySettingsSet(); + + if (settings.codec().isEmpty() + || (settings.resolution() == QSize(-1,-1) && settings.frameRate() == 0 && settings.bitRate() == -1)) { + if (!settings.codec().isEmpty()) + m_session->setVideoCaptureCodec(settings.codec()); + m_session->setVideoEncodingMode(settings.encodingMode()); + m_session->setVideoCaptureQuality(settings.quality(), S60VideoCaptureSession::EOnlyVideoQuality); + } else if (settings.resolution() != QSize(-1,-1) && settings.frameRate() == 0 && settings.bitRate() == -1) { // Only Resolution + m_session->setVideoCaptureCodec(settings.codec()); + m_session->setVideoEncodingMode(settings.encodingMode()); + m_session->setVideoResolution(settings.resolution()); + m_session->setVideoCaptureQuality(settings.quality(), S60VideoCaptureSession::EVideoQualityAndResolution); + + } else if (settings.resolution() == QSize(-1,-1) && settings.frameRate() != 0 && settings.bitRate() == -1) { // Only Framerate + m_session->setVideoCaptureCodec(settings.codec()); + m_session->setVideoEncodingMode(settings.encodingMode()); + m_session->setFrameRate(settings.frameRate()); + m_session->setVideoCaptureQuality(settings.quality(), S60VideoCaptureSession::EVideoQualityAndFrameRate); + + } else if (settings.resolution() == QSize(-1,-1) && settings.frameRate() == 0 && settings.bitRate() != -1) { // Only BitRate + m_session->setVideoCaptureCodec(settings.codec()); + m_session->setVideoEncodingMode(settings.encodingMode()); + m_session->setBitrate(settings.bitRate()); + m_session->setVideoCaptureQuality(settings.quality(), S60VideoCaptureSession::EVideoQualityAndBitRate); + + } else if (settings.resolution() != QSize(-1,-1) && settings.frameRate() != 0 && settings.bitRate() == -1) { // Resolution and FrameRate + m_session->setVideoCaptureCodec(settings.codec()); + m_session->setVideoEncodingMode(settings.encodingMode()); + m_session->setVideoResolution(settings.resolution()); + m_session->setFrameRate(settings.frameRate()); + m_session->setVideoCaptureQuality(settings.quality(), S60VideoCaptureSession::EVideoQualityAndResolutionAndFrameRate); + + } else if (settings.resolution() != QSize(-1,-1) && settings.frameRate() == 0 && settings.bitRate() != -1) { // Resolution and BitRate + m_session->setVideoCaptureCodec(settings.codec()); + m_session->setVideoEncodingMode(settings.encodingMode()); + m_session->setVideoResolution(settings.resolution()); + m_session->setBitrate(settings.bitRate()); + m_session->setVideoCaptureQuality(settings.quality(), S60VideoCaptureSession::EVideoQualityAndResolutionAndBitRate); + + } else if (settings.resolution() == QSize(-1,-1) && settings.frameRate() != 0 && settings.bitRate() != -1) { // FrameRate and BitRate + m_session->setVideoCaptureCodec(settings.codec()); + m_session->setVideoEncodingMode(settings.encodingMode()); + m_session->setFrameRate(settings.frameRate()); + m_session->setBitrate(settings.bitRate()); + m_session->setVideoCaptureQuality(settings.quality(), S60VideoCaptureSession::EVideoQualityAndFrameRateAndBitRate); + + } else { // All: Resolution, BitRate and FrameRate + m_session->setVideoCaptureCodec(settings.codec()); + m_session->setVideoEncodingMode(settings.encodingMode()); + m_session->setVideoResolution(settings.resolution()); + m_session->setFrameRate(settings.frameRate()); + m_session->setBitrate(settings.bitRate()); + m_session->setVideoCaptureQuality(settings.quality(), S60VideoCaptureSession::ENoVideoQuality); + } +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60videoencodercontrol.h b/src/plugins/symbian/ecam/s60videoencodercontrol.h new file mode 100644 index 000000000..4554d9291 --- /dev/null +++ b/src/plugins/symbian/ecam/s60videoencodercontrol.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60VIDEOENCODERCONTROL_H +#define S60VIDEOENCODERCONTROL_H + +#include +#include + +#include "qvideoencodercontrol.h" + +QT_USE_NAMESPACE + +class S60VideoCaptureSession; + +/* + * Control for video settings when recording video using QMediaRecorder. + */ +class S60VideoEncoderControl : public QVideoEncoderControl +{ + Q_OBJECT + +public: // Contructors & Destructor + + S60VideoEncoderControl(QObject *parent = 0); + S60VideoEncoderControl(S60VideoCaptureSession *session, QObject *parent = 0); + virtual ~S60VideoEncoderControl(); + +public: // QVideoEncoderControl + + // Resolution + QList supportedResolutions(const QVideoEncoderSettings &settings, bool *continuous = 0) const; + + // Framerate + QList supportedFrameRates(const QVideoEncoderSettings &settings, bool *continuous = 0) const; + + // Video Codec + QStringList supportedVideoCodecs() const; + QString videoCodecDescription(const QString &codecName) const; + + // Video Settings + QVideoEncoderSettings videoSettings() const; + void setVideoSettings(const QVideoEncoderSettings &settings); + + // Encoding Options + QStringList supportedEncodingOptions(const QString &codec) const; + QVariant encodingOption(const QString &codec, const QString &name) const; + void setEncodingOption(const QString &codec, const QString &name, const QVariant &value); + +private: // Data + + S60VideoCaptureSession* m_session; + +}; + +#endif // S60VIDEOENCODERCONTROL_H diff --git a/src/plugins/symbian/ecam/s60videorenderercontrol.cpp b/src/plugins/symbian/ecam/s60videorenderercontrol.cpp new file mode 100644 index 000000000..8cc3546b5 --- /dev/null +++ b/src/plugins/symbian/ecam/s60videorenderercontrol.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "s60videorenderercontrol.h" + +S60VideoRendererControl::S60VideoRendererControl(QObject *parent) : + QVideoRendererControl(parent), + m_surface(0) +{ +} + +S60VideoRendererControl::~S60VideoRendererControl() +{ + // Stop surface if still active + if (m_surface) + if (m_surface->isActive()) + m_surface->stop(); +} + +QAbstractVideoSurface *S60VideoRendererControl::surface() const +{ + return m_surface; +} + +void S60VideoRendererControl::setSurface(QAbstractVideoSurface *surface) +{ + if (surface == 0) { + // Stop current surface if needed + if (m_surface) + if (m_surface->isActive()) + m_surface->stop(); + } + + m_surface = surface; + emit viewFinderSurfaceSet(); +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60videorenderercontrol.h b/src/plugins/symbian/ecam/s60videorenderercontrol.h new file mode 100644 index 000000000..b35433f86 --- /dev/null +++ b/src/plugins/symbian/ecam/s60videorenderercontrol.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60VIDEORENDERERCONTROL_H +#define S60VIDEORENDERERCONTROL_H + +#include + +/* + * Control for QGraphicsVideoItem. Viewfinder frames are streamed to a surface + * which is drawn to the display by the Qt Graphics Vide Framework. + * VideoRendererControl uses only Bitmap Viewfinder. + */ +class S60VideoRendererControl : public QVideoRendererControl +{ + Q_OBJECT + +public: // Constructor & Destructor + + S60VideoRendererControl(QObject *parent = 0); + virtual ~S60VideoRendererControl(); + +public: // S60VideoRendererControl + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + +signals: // Internal Signals + + void viewFinderSurfaceSet(); + +private: // Data + + QAbstractVideoSurface *m_surface; + +}; + +#endif // S60VIDEORENDERERCONTROL_H diff --git a/src/plugins/symbian/mmf/audiosource/audiosource_s60.pri b/src/plugins/symbian/mmf/audiosource/audiosource_s60.pri new file mode 100644 index 000000000..7732600fa --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/audiosource_s60.pri @@ -0,0 +1,31 @@ +INCLUDEPATH += $$PWD + +DEFINES += AUDIOSOURCEUSED + +symbian:LIBS += -lmediaclientaudio \ + -lmmfcontrollerframework \ + -lefsrv \ + -lbafl \ + +!contains(S60_VERSION, 3.1) { + contains(audiorouting_s60_enabled,yes) { + #We use audioinputrouting.lib for recording audio from different sources -lmediaclientaudioinputstream \ -lcone \ + DEFINES += AUDIOINPUT_ROUTING + message("Audio Input Routing enabled onwards 3.2 SDK") + LIBS += -laudioinputrouting + } +} + +HEADERS += $$PWD/s60audioencodercontrol.h \ + $$PWD/s60audiomediarecordercontrol.h \ + $$PWD/s60audioendpointselector.h \ + $$PWD/s60audiocaptureservice.h \ + $$PWD/s60audiocapturesession.h \ + $$PWD/S60audiocontainercontrol.h + +SOURCES += $$PWD/s60audioencodercontrol.cpp \ + $$PWD/s60audiomediarecordercontrol.cpp \ + $$PWD/s60audioendpointselector.cpp \ + $$PWD/s60audiocaptureservice.cpp \ + $$PWD/s60audiocapturesession.cpp \ + $$PWD/S60audiocontainercontrol.cpp diff --git a/src/plugins/symbian/mmf/audiosource/s60audiocaptureservice.cpp b/src/plugins/symbian/mmf/audiosource/s60audiocaptureservice.cpp new file mode 100644 index 000000000..742ac8f82 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audiocaptureservice.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DebugMacros.h" +#include + +#include "s60audiocaptureservice.h" +#include "s60audiocapturesession.h" +#include "s60audioendpointselector.h" +#include "s60audioencodercontrol.h" +#include "s60audiomediarecordercontrol.h" +#include "s60audiocontainercontrol.h" + +S60AudioCaptureService::S60AudioCaptureService(QObject *parent): + QMediaService(parent) +{ + DP0("S60AudioCaptureService::S60AudioCaptureService +++"); + + m_session = new S60AudioCaptureSession(this); + m_encoderControl = new S60AudioEncoderControl(m_session,this); + m_recorderControl = new S60AudioMediaRecorderControl(m_session,this); + m_endpointSelector = new S60AudioEndpointSelector(m_session,this); + m_containerControl = new S60AudioContainerControl(m_session, this); + + DP0("S60AudioCaptureService::S60AudioCaptureService ---"); +} + +S60AudioCaptureService::~S60AudioCaptureService() +{ + DP0("S60AudioCaptureService::~S60AudioCaptureService +++"); + DP0("S60AudioCaptureService::~S60AudioCaptureService ---"); +} + +QMediaControl *S60AudioCaptureService::requestControl(const char *name) +{ + DP0("S60AudioCaptureService::requestControl"); + + if (qstrcmp(name,QMediaRecorderControl_iid) == 0) + return m_recorderControl; + + if (qstrcmp(name,QAudioEncoderControl_iid) == 0) + return m_encoderControl; + + if (qstrcmp(name,QAudioEndpointSelector_iid) == 0) + return m_endpointSelector; + + if (qstrcmp(name,QMediaContainerControl_iid) == 0) + return m_containerControl; + + return 0; +} + +void S60AudioCaptureService::releaseControl(QMediaControl *control) +{ + DP0("S60AudioCaptureService::releaseControl +++"); + + Q_UNUSED(control) + + DP0("S60AudioCaptureService::releaseControl ---"); +} diff --git a/src/plugins/symbian/mmf/audiosource/s60audiocaptureservice.h b/src/plugins/symbian/mmf/audiosource/s60audiocaptureservice.h new file mode 100644 index 000000000..86d71a994 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audiocaptureservice.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60AUDIOCAPTURESERVICE_H +#define S60AUDIOCAPTURESERVICE_H + +#include + +#include + +QT_USE_NAMESPACE + +class S60AudioCaptureSession; +class S60AudioEncoderControl; +class S60AudioMediaRecorderControl; +class S60AudioEndpointSelector; +class S60AudioContainerControl; + + +class S60AudioCaptureService : public QMediaService +{ + Q_OBJECT +public: + S60AudioCaptureService(QObject *parent = 0); + ~S60AudioCaptureService(); + + QMediaControl *requestControl(const char *name); + void releaseControl(QMediaControl *control); +private: + S60AudioCaptureSession *m_session; + S60AudioEncoderControl *m_encoderControl; + S60AudioEndpointSelector *m_endpointSelector; + S60AudioMediaRecorderControl *m_recorderControl; + S60AudioContainerControl *m_containerControl; +}; + +#endif // S60AUDIOCAPTURESERVICE_H diff --git a/src/plugins/symbian/mmf/audiosource/s60audiocapturesession.cpp b/src/plugins/symbian/mmf/audiosource/s60audiocapturesession.cpp new file mode 100644 index 000000000..79b6a53a0 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audiocapturesession.cpp @@ -0,0 +1,937 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DebugMacros.h" + +#include "s60audiocapturesession.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef AUDIOINPUT_ROUTING +const QString S60AudioCaptureSession::microPhone("Microphone"); +const QString S60AudioCaptureSession::voiceCall("Voice Call"); +const QString S60AudioCaptureSession::fmRadio("FM Radio"); +#endif + +S60AudioCaptureSession::S60AudioCaptureSession(QObject *parent): + QObject(parent) + , m_recorderUtility(NULL) + , m_captureState(ENotInitialized) + , m_controllerIdMap(QHash()) + , m_audioCodeclist(QHash()) + , m_error(QMediaRecorder::NoError) + , m_isMuted(false) +{ + DP0("S60AudioCaptureSession::S60AudioCaptureSession +++"); +#ifdef AUDIOINPUT_ROUTING + m_audioInput = NULL; + m_setActiveEndPoint = FALSE; + m_audioEndpoint = S60AudioCaptureSession::microPhone; +#endif //AUDIOINPUT_ROUTING + TRAPD(err, initializeSessionL()); + setError(err); + + DP0("S60AudioCaptureSession::S60AudioCaptureSession ---"); +} + +void S60AudioCaptureSession::initializeSessionL() +{ + DP0("S60AudioCaptureSession::initializeSessionL +++"); + + m_recorderUtility = CMdaAudioRecorderUtility::NewL(*this, 0, EMdaPriorityNormal, EMdaPriorityPreferenceTimeAndQuality); + updateAudioContainersL(); + populateAudioCodecsDataL(); + setDefaultSettings(); +#ifdef AUDIOINPUT_ROUTING + initAudioInputs(); +#endif + User::LeaveIfError(m_fsSession.Connect()); + m_captureState = EInitialized; + emit stateChanged(m_captureState); + + DP0("S60AudioCaptureSession::initializeSessionL ---"); +} + +void S60AudioCaptureSession::setError(TInt aError) +{ + DP0("S60AudioCaptureSession::setError +++"); + + DP1("S60AudioCaptureSession::setError:", aError); + + if (aError == KErrNone) + return; + + m_error = aError; + QMediaRecorder::Error recorderError = fromSymbianErrorToMultimediaError(m_error); + + // TODO: fix to user friendly string at some point + // These error string are only dev usable + QString symbianError; + symbianError.append("Symbian:"); + symbianError.append(QString::number(m_error)); + stop(); + emit error(recorderError, symbianError); + + DP0("S60AudioCaptureSession::setError ---"); +} + +QMediaRecorder::Error S60AudioCaptureSession::fromSymbianErrorToMultimediaError(int error) +{ + DP0("S60AudioCaptureSession::fromSymbianErrorToMultimediaError +++"); + + DP1("S60AudioCaptureSession::fromSymbianErrorToMultimediaError:", error); + + switch(error) { + case KErrNoMemory: + case KErrNotFound: + case KErrBadHandle: + case KErrAbort: + case KErrCorrupt: + case KErrGeneral: + case KErrPathNotFound: + case KErrUnknown: + case KErrNotReady: + case KErrInUse: + case KErrAccessDenied: + case KErrLocked: + case KErrPermissionDenied: + case KErrAlreadyExists: + return QMediaRecorder::ResourceError; + case KErrNotSupported: + case KErrArgument: + return QMediaRecorder::FormatError; + case KErrNone: + default: + DP0("S60AudioCaptureSession::fromSymbianErrorToMultimediaError: ---"); + return QMediaRecorder::NoError; + } +} + +S60AudioCaptureSession::~S60AudioCaptureSession() +{ + DP0("S60AudioCaptureSession::~S60AudioCaptureSession +++"); + //stop the utility before deleting it + stop(); + if (m_recorderUtility) + delete m_recorderUtility; + m_fsSession.Close(); + DP0("S60AudioCaptureSession::~S60AudioCaptureSession ---"); +} + +QAudioFormat S60AudioCaptureSession::format() const +{ + DP0("S60AudioCaptureSession::format"); + + return m_format; +} + +bool S60AudioCaptureSession::setFormat(const QAudioFormat &format) +{ + DP0("S60AudioCaptureSession::setFormat +++"); + + m_format = format; + + DP0("S60AudioCaptureSession::setFormat ---"); + + return true; +} + +QAudioEncoderSettings S60AudioCaptureSession::settings() const +{ + DP0("S60AudioCaptureSession::settings"); + + return m_audioEncoderSettings; +} + +bool S60AudioCaptureSession::setEncoderSettings(const QAudioEncoderSettings &setting) +{ + DP0("S60AudioCaptureSession::setEncoderSettings +++"); + + m_audioEncoderSettings = setting; + + DP0("S60AudioCaptureSession::setEncoderSettings ---"); + + return true; +} + +QStringList S60AudioCaptureSession::supportedAudioCodecs() const +{ + DP0("S60AudioCaptureSession::supportedAudioCodecs"); + + return m_audioCodeclist.keys(); +} + +QStringList S60AudioCaptureSession::supportedAudioContainers() const +{ + DP0("S60AudioCaptureSession::supportedAudioContainers"); + + return m_controllerIdMap.keys(); +} + +QString S60AudioCaptureSession::codecDescription(const QString &codecName) +{ + DP0("S60AudioCaptureSession::codecDescription +++"); + + if (m_audioCodeclist.keys().contains(codecName)) { + + DP0("S60AudioCaptureSession::codecDescription ---"); + return m_audioCodeclist.value(codecName).codecDescription; + } + else { + DP0("S60AudioCaptureSession::codecDescription ---"); + + return QString(); + } +} + +QString S60AudioCaptureSession::audioContainerDescription(const QString &containerName) +{ + DP0("S60AudioCaptureSession::audioContainerDescription +++"); + + if (m_controllerIdMap.keys().contains(containerName)) { + DP0("S60AudioCaptureSession::audioContainerDescription ---"); + + return m_controllerIdMap.value(containerName).destinationFormatDescription; + } + else { + DP0("S60AudioCaptureSession::audioContainerDescription ---"); + + return QString(); + } +} + +bool S60AudioCaptureSession::setAudioCodec(const QString &codecName) +{ + DP0("S60AudioCaptureSession::setAudioCodec"); + + QStringList codecs = supportedAudioCodecs(); + if(codecs.contains(codecName)) { + m_format.setCodec(codecName); + return true; + } + return false; +} + +bool S60AudioCaptureSession::setAudioContainer(const QString &containerMimeType) +{ + DP0("S60AudioCaptureSession::setAudioContainer"); + + QStringList containers = supportedAudioContainers(); + if (containerMimeType == "audio/mpeg") + { + m_container = "audio/mp4"; + return true; + } + if(containers.contains(containerMimeType)) { + m_container = containerMimeType; + return true; + } + return false; +} + +QString S60AudioCaptureSession::audioCodec() const +{ + DP0("S60AudioCaptureSession::audioCodec"); + + return m_format.codec(); +} + +QString S60AudioCaptureSession::audioContainer() const +{ + DP0("S60AudioCaptureSession::audioContainer"); + + return m_container; +} + +QUrl S60AudioCaptureSession::outputLocation() const +{ + DP0("S60AudioCaptureSession::outputLocation"); + + return m_sink; +} + +bool S60AudioCaptureSession::setOutputLocation(const QUrl& sink) +{ + DP0("S60AudioCaptureSession::setOutputLocation"); + + QString filename = QDir::toNativeSeparators(sink.toString()); + TPtrC16 path(reinterpret_cast(filename.utf16())); + TRAPD(err, BaflUtils::EnsurePathExistsL(m_fsSession,path)); + if (err == KErrNone) { + m_sink = sink; + setError(err); + return true; + }else { + setError(err); + return false; + } +} + +qint64 S60AudioCaptureSession::position() const +{ + DP0("S60AudioCaptureSession::position"); + + if ((m_captureState != ERecording) || !m_recorderUtility) + return 0; + + return m_recorderUtility->Duration().Int64() / 1000; +} + +void S60AudioCaptureSession::prepareSinkL() +{ + DP0("S60AudioCaptureSession::prepareSinkL +++"); + + /* If m_outputLocation is null, set a default location */ + if (m_sink.isEmpty()) { + QDir outputDir(QDir::rootPath()); + int lastImage = 0; + int fileCount = 0; + foreach(QString fileName, outputDir.entryList(QStringList() << "recordclip_*")) { + int imgNumber = fileName.mid(5, fileName.size() - 9).toInt(); + lastImage = qMax(lastImage, imgNumber); + if (outputDir.exists(fileName)) + fileCount += 1; + } + lastImage += fileCount; + m_sink = QUrl(QDir::toNativeSeparators(outputDir.canonicalPath() + QString("/recordclip_%1").arg(lastImage + 1, 4, 10, QLatin1Char('0')))); + } + + QString sink = QDir::toNativeSeparators(m_sink.toString()); + TPtrC16 path(reinterpret_cast(sink.utf16())); + if (BaflUtils::FileExists(m_fsSession, path)) + BaflUtils::DeleteFile(m_fsSession, path); + + int index = sink.lastIndexOf('.'); + if (index != -1) + sink.chop(sink.length()-index); + + sink.append(m_controllerIdMap.value(m_container).fileExtension); + m_sink.setUrl(sink); + + DP0("S60AudioCaptureSession::prepareSinkL ---"); +} + +void S60AudioCaptureSession::record() +{ + DP0("S60AudioCaptureSession::record +++"); + + if (!m_recorderUtility) + return; + + if (m_captureState == EInitialized || m_captureState == ERecordComplete) { + prepareSinkL(); + QString filename = m_sink.toString(); + TPtrC16 sink(reinterpret_cast(filename.utf16())); + TUid controllerUid(TUid::Uid(m_controllerIdMap.value(m_container).controllerUid)); + TUid formatUid(TUid::Uid(m_controllerIdMap.value(m_container).destinationFormatUid)); + + TRAPD(err,m_recorderUtility->OpenFileL(sink)); + setError(err); + }else if (m_captureState == EPaused) { + m_recorderUtility->SetPosition(m_pausedPosition); + TRAPD(error, m_recorderUtility->RecordL()); + setError(error); + m_captureState = ERecording; + emit stateChanged(m_captureState); + } + + DP0("S60AudioCaptureSession::record ---"); +} + +void S60AudioCaptureSession::mute(bool muted) +{ + DP0("S60AudioCaptureSession::mute +++"); + + if (!m_recorderUtility) + return; + + if (muted) + m_recorderUtility->SetGain(0); + else + m_recorderUtility->SetGain(m_recorderUtility->MaxGain()); + + m_isMuted = muted; + + DP0("S60AudioCaptureSession::mute ---"); +} + +bool S60AudioCaptureSession::muted() +{ + DP0("S60AudioCaptureSession::muted"); + + return m_isMuted; +} + +void S60AudioCaptureSession::setDefaultSettings() +{ + DP0("S60AudioCaptureSession::setDefaultSettings +++"); + + // Setting AMR to default format if supported + if (m_controllerIdMap.count() > 0) { + if ( m_controllerIdMap.contains("audio/amr")) + m_container = QString("audio/amr"); + else + m_container = m_controllerIdMap.keys()[0]; + } + if (m_audioCodeclist.keys().count() > 0) { + if (m_audioCodeclist.keys().contains("AMR")) { + m_format.setSampleSize(8); + m_format.setChannels(1); + m_format.setFrequency(8000); + m_format.setSampleType(QAudioFormat::SignedInt); + m_format.setCodec("AMR"); + }else + m_format.setCodec(m_audioCodeclist.keys()[0]); + } + + DP0("S60AudioCaptureSession::setDefaultSettings ---"); +} + +void S60AudioCaptureSession::pause() +{ + DP0("S60AudioCaptureSession::pause +++"); + + if (!m_recorderUtility) + return; + + m_pausedPosition = m_recorderUtility->Position(); + m_recorderUtility->Stop(); + m_captureState = EPaused; + emit stateChanged(m_captureState); + + DP0("S60AudioCaptureSession::pause ---"); +} + +void S60AudioCaptureSession::stop() +{ + DP0("S60AudioCaptureSession::stop +++"); + + if (!m_recorderUtility) + return; + + m_recorderUtility->Stop(); + +#ifdef AUDIOINPUT_ROUTING + //delete audio input instance before closing the utility. + if (m_audioInput) + { + delete m_audioInput; + m_audioInput = NULL; + } +#endif //AUDIOINPUT_ROUTING + + m_recorderUtility->Close(); + m_captureState = ERecordComplete; + emit stateChanged(m_captureState); +} + +#ifdef AUDIOINPUT_ROUTING + +void S60AudioCaptureSession::initAudioInputs() +{ + DP0(" S60AudioCaptureSession::initAudioInputs +++"); + + m_audioInputs[S60AudioCaptureSession::microPhone] = QString("Microphone associated with the currently active speaker."); + m_audioInputs[S60AudioCaptureSession::voiceCall] = QString("Audio stream associated with the current phone call."); + m_audioInputs[S60AudioCaptureSession::fmRadio] = QString("Audio of the currently tuned FM radio station."); + + DP0(" S60AudioCaptureSession::initAudioInputs ---"); +} + +#endif //AUDIOINPUT_ROUTING + +void S60AudioCaptureSession::setActiveEndpoint(const QString& audioEndpoint) +{ + DP0(" S60AudioCaptureSession::setActiveEndpoint +++"); + + if (!m_audioInputs.keys().contains(audioEndpoint)) + return; + + if (activeEndpoint().compare(audioEndpoint) != 0) { + m_audioEndpoint = audioEndpoint; +#ifdef AUDIOINPUT_ROUTING + m_setActiveEndPoint = TRUE; +#endif + } + + DP0(" S60AudioCaptureSession::setActiveEndpoint ---"); +} + +QList S60AudioCaptureSession::availableEndpoints() const +{ + DP0(" S60AudioCaptureSession::availableEndpoints"); + + return m_audioInputs.keys(); +} + +QString S60AudioCaptureSession::endpointDescription(const QString& name) const +{ + DP0(" S60AudioCaptureSession::endpointDescription +++"); + + if (m_audioInputs.keys().contains(name)) + return m_audioInputs.value(name); + return QString(); +} + +QString S60AudioCaptureSession::activeEndpoint() const +{ + DP0(" S60AudioCaptureSession::activeEndpoint"); + + QString inputSourceName = NULL; +#ifdef AUDIOINPUT_ROUTING + if (m_audioInput) { + CAudioInput::TAudioInputArray input = m_audioInput->AudioInput(); + inputSourceName = qStringFromTAudioInputPreference(input[0]); + } +#endif //AUDIOINPUT_ROUTING + return inputSourceName; +} + +QString S60AudioCaptureSession::defaultEndpoint() const +{ + DP0(" S60AudioCaptureSession::defaultEndpoint"); + +#ifdef AUDIOINPUT_ROUTING + return QString(S60AudioCaptureSession::microPhone); +#else + return NULL; +#endif +} + +#ifdef AUDIOINPUT_ROUTING + +void S60AudioCaptureSession::doSetAudioInputL(const QString& name) +{ + DP0(" S60AudioCaptureSession::doSetAudioInputL +++"); + DP1(" S60AudioCaptureSession::doSetAudioInputL:", name); + TInt err(KErrNone); + + if (!m_recorderUtility) + return; + + CAudioInput::TAudioInputPreference input = CAudioInput::EDefaultMic; + + if (name.compare(S60AudioCaptureSession::voiceCall) == 0) + input = CAudioInput::EVoiceCall; +// commented because they are not supported on 9.2 + else if (name.compare(S60AudioCaptureSession::fmRadio) == 0) + input = CAudioInput::EFMRadio; + else // S60AudioCaptureSession::microPhone + input = CAudioInput::EDefaultMic; + + RArray inputArray; + inputArray.Append(input); + + if (m_audioInput){ + TRAP(err,m_audioInput->SetAudioInputL(inputArray.Array())); + + if (err == KErrNone) { + emit activeEndpointChanged(name); + } + else{ + setError(err); + } + } + inputArray.Close(); + + DP0(" S60AudioCaptureSession::doSetAudioInputL ---"); +} + + +QString S60AudioCaptureSession::qStringFromTAudioInputPreference(CAudioInput::TAudioInputPreference input) const +{ + DP0(" S60AudioCaptureSession::qStringFromTAudioInputPreference"); + + if (input == CAudioInput::EVoiceCall) + return S60AudioCaptureSession::voiceCall; + else if (input == CAudioInput::EFMRadio) + return S60AudioCaptureSession::fmRadio; + else + return S60AudioCaptureSession::microPhone; // CAudioInput::EDefaultMic +} +#endif //AUDIOINPUT_ROUTING + + +void S60AudioCaptureSession::MoscoStateChangeEvent(CBase* aObject, + TInt aPreviousState, TInt aCurrentState, TInt aErrorCode) +{ + DP0("S60AudioCaptureSession::MoscoStateChangeEvent +++"); + + if (aErrorCode==KErrNone) { + TRAPD(err, MoscoStateChangeEventL(aObject, aPreviousState, aCurrentState, NULL)); + setError(err); + } + else { + setError(aErrorCode); + } + DP1("S60AudioCaptureSession::MoscoStateChangeEvent, aErrorCode:", aErrorCode); + DP0("S60AudioCaptureSession::MoscoStateChangeEvent ---"); +} + +void S60AudioCaptureSession::MoscoStateChangeEventL(CBase* aObject, + TInt aPreviousState, TInt aCurrentState, TInt aErrorCode) +{ + DP0("S60AudioCaptureSession::MoscoStateChangeEventL +++"); + + DP5("S60AudioCaptureSession::MoscoStateChangeEventL - aPreviousState:", aPreviousState, + "aCurrentState:", aCurrentState, "aErrorCode:", aErrorCode); + if (aObject != m_recorderUtility) + return; + + switch(aCurrentState) { + case CMdaAudioClipUtility::EOpen: { + if(aPreviousState == CMdaAudioClipUtility::ENotReady) { + applyAudioSettingsL(); + m_recorderUtility->SetGain(m_recorderUtility->MaxGain()); + TRAPD(err, m_recorderUtility->RecordL()); + setError(err); + m_captureState = EOpenCompelete; + emit stateChanged(m_captureState); + } + break; + } + case CMdaAudioClipUtility::ENotReady: { + m_captureState = EInitialized; + emit stateChanged(m_captureState); + break; + } + case CMdaAudioClipUtility::ERecording: { + m_captureState = ERecording; + emit stateChanged(m_captureState); + break; + } + default: { + break; + } + } + + DP0("S60AudioCaptureSession::MoscoStateChangeEventL ---"); +} + +void S60AudioCaptureSession::updateAudioContainersL() +{ + DP0("S60AudioCaptureSession::updateAudioContainersL +++"); + + CMMFControllerPluginSelectionParameters* pluginParameters = + CMMFControllerPluginSelectionParameters::NewLC(); + CMMFFormatSelectionParameters* formatParameters = + CMMFFormatSelectionParameters::NewLC(); + + pluginParameters->SetRequiredRecordFormatSupportL(*formatParameters); + + RArray ids; + CleanupClosePushL(ids); + User::LeaveIfError(ids.Append(KUidMediaTypeAudio)); + + pluginParameters->SetMediaIdsL(ids, + CMMFPluginSelectionParameters::EAllowOnlySuppliedMediaIds); + + RMMFControllerImplInfoArray controllers; + CleanupResetAndDestroyPushL(controllers); + + //Get all audio record controllers/formats that are supported + pluginParameters->ListImplementationsL(controllers); + + for (TInt index=0; indexRecordFormats(); + for (TInt j=0; jSupportedMimeTypes(); + const CDesC8Array& fileExtensions = recordFormats[j]->SupportedFileExtensions(); + TInt mimeCount = mimeTypes.Count(); + TInt fileExtCount = fileExtensions.Count(); + + if (mimeCount > 0 && fileExtCount > 0) { + TPtrC8 extension = fileExtensions[0]; + TPtrC8 mimeType = mimeTypes[0]; + QString type = QString::fromUtf8((char *)mimeType.Ptr(), mimeType.Length()); + + if (type != "audio/basic") { + ControllerData data; + data.controllerUid = controllers[index]->Uid().iUid; + data.destinationFormatUid = recordFormats[j]->Uid().iUid; + data.destinationFormatDescription = QString::fromUtf16( + recordFormats[j]->DisplayName().Ptr(), + recordFormats[j]->DisplayName().Length()); + data.fileExtension = QString::fromUtf8((char *)extension.Ptr(), extension.Length()); + m_controllerIdMap[type] = data; + } + } + } + } + CleanupStack::PopAndDestroy(4);//controllers, ids, formatParameters, pluginParameters + + DP0("S60AudioCaptureSession::updateAudioContainersL ---"); +} + +void S60AudioCaptureSession::retrieveSupportedAudioSampleRatesL() +{ + DP0("S60AudioCaptureSession::retrieveSupportedAudioSampleRatesL +++"); + + if (!m_recorderUtility) { + DP0("No RecorderUtility"); + return; + } + + m_supportedSampleRates.clear(); + + RArray supportedSampleRates; + CleanupClosePushL(supportedSampleRates); + m_recorderUtility->GetSupportedSampleRatesL(supportedSampleRates); + for (TInt j = 0; j < supportedSampleRates.Count(); j++ ) + m_supportedSampleRates.append(supportedSampleRates[j]); + + CleanupStack::PopAndDestroy(&supportedSampleRates); + + DP0("S60AudioCaptureSession::retrieveSupportedAudioSampleRatesL ---"); +} + +QList S60AudioCaptureSession::supportedAudioSampleRates(const QAudioEncoderSettings &settings) const +{ + DP0("S60AudioCaptureSession::supportedAudioSampleRates +++"); + + QList supportedSampleRates; + + if (!settings.codec().isEmpty()) { + if (settings.codec() == "AMR") + supportedSampleRates.append(8000); + else + supportedSampleRates = m_supportedSampleRates; + }else + supportedSampleRates = m_supportedSampleRates; + + DP0("S60AudioCaptureSession::supportedAudioSampleRates ---"); + + return supportedSampleRates; +} + +void S60AudioCaptureSession::populateAudioCodecsDataL() +{ + DP0("S60AudioCaptureSession::populateAudioCodecsDataL +++"); + + if (!m_recorderUtility) { + DP0("No RecorderUtility"); + + return; + } + + if (m_controllerIdMap.contains("audio/amr")) { + CodecData data; + data.codecDescription = QString("GSM AMR Codec"); + m_audioCodeclist[QString("AMR")]=data; + } + if (m_controllerIdMap.contains("audio/basic")) { + CodecData data; + data.fourCC = KMMFFourCCCodeALAW; + data.codecDescription = QString("Sun/Next ""Au"" audio codec"); + m_audioCodeclist[QString("AULAW")]=data; + } + if (m_controllerIdMap.contains("audio/wav")) { + CodecData data; + data.fourCC = KMMFFourCCCodePCM16; + data.codecDescription = QString("Pulse code modulation"); + m_audioCodeclist[QString("PCM")]=data; + } + if (m_controllerIdMap.contains("audio/mp4")) { + CodecData data; + data.fourCC = KMMFFourCCCodeAAC; + data.codecDescription = QString("Advanced Audio Codec"); + m_audioCodeclist[QString("AAC")]=data; + } + + // default samplerates + m_supportedSampleRates << 96000 << 88200 << 64000 << 48000 << 44100 << 32000 << 24000 << 22050 << 16000 << 12000 << 11025 << 8000; + + DP0("S60AudioCaptureSession::populateAudioCodecsDataL ---"); +} + +void S60AudioCaptureSession::applyAudioSettingsL() +{ + DP0("S60AudioCaptureSession::applyAudioSettingsL +++"); + + if (!m_recorderUtility) + return; + +#ifdef AUDIOINPUT_ROUTING + //CAudioInput needs to be re-initialized every time recording starts + if (m_audioInput) { + delete m_audioInput; + m_audioInput = NULL; + } + + if (m_setActiveEndPoint) { + m_audioInput = CAudioInput::NewL(*m_recorderUtility); + doSetAudioInputL(m_audioEndpoint); + } +#endif //AUDIOINPUT_ROUTING + + if (m_format.codec() == "AMR") + return; + + TFourCC fourCC = m_audioCodeclist.value(m_format.codec()).fourCC; + + if (m_format.codec() == "PCM") + fourCC = determinePCMFormat(); + + RArray supportedDataTypes; + CleanupClosePushL(supportedDataTypes); + TRAPD(err,m_recorderUtility->GetSupportedDestinationDataTypesL(supportedDataTypes)); + TInt num = supportedDataTypes.Count(); + if (num > 0 ) { + supportedDataTypes.SortUnsigned(); + int index = supportedDataTypes.Find(fourCC.FourCC()); + if (index != KErrNotFound) { + TRAPD(err,m_recorderUtility->SetDestinationDataTypeL(supportedDataTypes[index])); + } + } + + supportedDataTypes.Reset(); + CleanupStack::PopAndDestroy(&supportedDataTypes); + + if (m_recorderUtility->DestinationSampleRateL() != m_format.frequency()) { + + RArray supportedSampleRates; + CleanupClosePushL(supportedSampleRates); + m_recorderUtility->GetSupportedSampleRatesL(supportedSampleRates); + for (TInt i = 0; i < supportedSampleRates.Count(); i++ ) { + TUint supportedSampleRate = supportedSampleRates[i]; + if (supportedSampleRate == m_format.frequency()) { + m_recorderUtility->SetDestinationSampleRateL(m_format.frequency()); + break; + } + } + supportedSampleRates.Reset(); + CleanupStack::PopAndDestroy(&supportedSampleRates); + } + + /* If requested channel setting is different than current one */ + if (m_recorderUtility->DestinationNumberOfChannelsL() != m_format.channels()) { + RArray supportedChannels; + CleanupClosePushL(supportedChannels); + m_recorderUtility->GetSupportedNumberOfChannelsL(supportedChannels); + for (TInt l = 0; l < supportedChannels.Count(); l++ ) { + if (supportedChannels[l] == m_format.channels()) { + m_recorderUtility->SetDestinationNumberOfChannelsL(m_format.channels()); + break; + } + } + supportedChannels.Reset(); + CleanupStack::PopAndDestroy(&supportedChannels); + } + + if (!(m_format.codec().compare("pcm",Qt::CaseInsensitive) == 0)) { + if (m_recorderUtility->DestinationBitRateL() != m_audioEncoderSettings.bitRate()) { + RArray supportedBitRates; + CleanupClosePushL(supportedBitRates); + m_recorderUtility->GetSupportedBitRatesL(supportedBitRates); + for (TInt l = 0; l < supportedBitRates.Count(); l++ ) { + if (supportedBitRates[l] == m_audioEncoderSettings.bitRate()) { + m_recorderUtility->SetDestinationBitRateL(m_audioEncoderSettings.bitRate()); + break; + } + } + supportedBitRates.Reset(); + CleanupStack::PopAndDestroy(&supportedBitRates); + } + } + + DP0("S60AudioCaptureSession::applyAudioSettingsL ---"); +} + +TFourCC S60AudioCaptureSession::determinePCMFormat() +{ + DP0("S60AudioCaptureSession::determinePCMFormat +++"); + + TFourCC fourCC; + + if (m_format.sampleSize() == 8) { + // 8 bit + switch (m_format.sampleType()) { + case QAudioFormat::SignedInt: { + fourCC.Set(KMMFFourCCCodePCM8); + break; + } + case QAudioFormat::UnSignedInt: { + fourCC.Set(KMMFFourCCCodePCMU8); + break; + } + case QAudioFormat::Float: + case QAudioFormat::Unknown: + default: { + fourCC.Set(KMMFFourCCCodePCM8); + break; + } + } + } else if (m_format.sampleSize() == 16) { + // 16 bit + switch (m_format.sampleType()) { + case QAudioFormat::SignedInt: { + fourCC.Set(m_format.byteOrder()==QAudioFormat::BigEndian? + KMMFFourCCCodePCM16B:KMMFFourCCCodePCM16); + break; + } + case QAudioFormat::UnSignedInt: { + fourCC.Set(m_format.byteOrder()==QAudioFormat::BigEndian? + KMMFFourCCCodePCMU16B:KMMFFourCCCodePCMU16); + break; + } + default: { + fourCC.Set(KMMFFourCCCodePCM16); + break; + } + } + } + + DP0("S60AudioCaptureSession::determinePCMFormat ---"); + + return fourCC; +} diff --git a/src/plugins/symbian/mmf/audiosource/s60audiocapturesession.h b/src/plugins/symbian/mmf/audiosource/s60audiocapturesession.h new file mode 100644 index 000000000..a541446e9 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audiocapturesession.h @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60AUDIOCAPTURESESSION_H +#define S60AUDIOCAPTURESESSION_H + +#include +#include +#include +#include +#include +#include +#include +#include "qaudioformat.h" +#include + +#include +#include +#include +#include +#include + +#ifdef AUDIOINPUT_ROUTING +#include +#endif //AUDIOINPUT_ROUTING + +QT_BEGIN_NAMESPACE +struct ControllerData +{ + int controllerUid; + int destinationFormatUid; + QString destinationFormatDescription; + QString fileExtension; +}; + +struct CodecData +{ + TFourCC fourCC; + QString codecDescription; +}; +QT_END_NAMESPACE + +QT_USE_NAMESPACE + +class S60AudioCaptureSession : public QObject, public MMdaObjectStateChangeObserver +{ + Q_OBJECT + Q_PROPERTY(qint64 position READ position NOTIFY positionChanged) + Q_ENUMS(TAudioCaptureState) +public: + + enum TAudioCaptureState + { + ENotInitialized = 0, + EInitialized, + EOpenCompelete, + ERecording, + EPaused, + ERecordComplete + }; + + S60AudioCaptureSession(QObject *parent = 0); + ~S60AudioCaptureSession(); + + QAudioFormat format() const; + bool setFormat(const QAudioFormat &format); + QAudioEncoderSettings settings() const; + bool setEncoderSettings(const QAudioEncoderSettings &setting); + QStringList supportedAudioCodecs() const; + QString codecDescription(const QString &codecName); + bool setAudioCodec(const QString &codecName); + QString audioCodec() const; + QString audioContainer() const; + QStringList supportedAudioContainers() const; + bool setAudioContainer(const QString &containerMimeType); + QString audioContainerDescription(const QString &containerName); + QList supportedAudioSampleRates(const QAudioEncoderSettings &settings) const; + QUrl outputLocation() const; + bool setOutputLocation(const QUrl& sink); + qint64 position() const; + void record(); + void pause(); + void stop(); + void mute(bool muted); + bool muted(); + + QString activeEndpoint() const; + QString defaultEndpoint() const; + QList availableEndpoints() const; + QString endpointDescription(const QString& name) const; + +#ifdef AUDIOINPUT_ROUTING + static const QString microPhone; + static const QString voiceCall; + static const QString fmRadio; +#endif //AUDIOINPUT_ROUTING +private: + void initializeSessionL(); + void setError(TInt aError); + QMediaRecorder::Error fromSymbianErrorToMultimediaError(int error); + void prepareSinkL(); + void updateAudioContainersL(); + void populateAudioCodecsDataL(); + void retrieveSupportedAudioSampleRatesL(); + void applyAudioSettingsL(); + TFourCC determinePCMFormat(); + void setDefaultSettings(); + // MMdaObjectStateChangeObserver + void MoscoStateChangeEvent(CBase* aObject, TInt aPreviousState, + TInt aCurrentState, TInt aErrorCode); + void MoscoStateChangeEventL(CBase* aObject, TInt aPreviousState, + TInt aCurrentState, TInt aErrorCode); + +#ifdef AUDIOINPUT_ROUTING + QString qStringFromTAudioInputPreference(CAudioInput::TAudioInputPreference input) const; + void initAudioInputs(); + void doSetAudioInputL(const QString& name); +#endif //AUDIOINPUT_ROUTING + +public Q_SLOTS: + void setActiveEndpoint(const QString& audioEndpoint); + + +Q_SIGNALS: + void stateChanged(S60AudioCaptureSession::TAudioCaptureState); + void positionChanged(qint64 position); + void error(int error, const QString &errorString); + void activeEndpointChanged(const QString &audioEndpoint); +private: + QString m_container; + QUrl m_sink; + TTimeIntervalMicroSeconds m_pausedPosition; + CMdaAudioRecorderUtility *m_recorderUtility; + TAudioCaptureState m_captureState; + QAudioFormat m_format; + QAudioEncoderSettings m_audioEncoderSettings; + QHash m_controllerIdMap; + QHash m_audioCodeclist; + QList m_supportedSampleRates; + int m_error; + bool m_isMuted; + RFs m_fsSession; + +#ifdef AUDIOINPUT_ROUTING + bool m_setActiveEndPoint; + CAudioInput *m_audioInput; + +#endif //AUDIOINPUT_ROUTING + QMap m_audioInputs; + QString m_audioEndpoint; + + +}; + +#endif // S60AUDIOCAPTURESESSION_H diff --git a/src/plugins/symbian/mmf/audiosource/s60audiocontainercontrol.cpp b/src/plugins/symbian/mmf/audiosource/s60audiocontainercontrol.cpp new file mode 100644 index 000000000..d6c2d5db2 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audiocontainercontrol.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DebugMacros.h" + +#include "s60audiocontainercontrol.h" +#include "s60audiocapturesession.h" +#include + +S60AudioContainerControl::S60AudioContainerControl(QObject *parent) + : QMediaContainerControl(parent) +{ + DP0("S60AudioContainerControl::S60AudioContainerControl(QObject *parent) +++"); + + DP0("S60AudioContainerControl::S60AudioContainerControl(QObject *parent) ---"); + +} + +S60AudioContainerControl::S60AudioContainerControl(QObject *session, QObject *parent) + : QMediaContainerControl(parent) +{ + DP0("S60AudioContainerControl::S60AudioContainerControl(QObject *session, QObject *parent) +++"); + + m_session = qobject_cast(session); + + DP0("S60AudioContainerControl::S60AudioContainerControl(QObject *session, QObject *parent) ---"); +} + +QStringList S60AudioContainerControl::supportedContainers() const +{ + DP0("S60AudioContainerControl::supportedContainers"); + + return m_session->supportedAudioContainers(); +} + +QString S60AudioContainerControl::containerMimeType() const +{ + DP0("S60AudioContainerControl::containerMimeType"); + + return m_session->audioContainer(); +} + +void S60AudioContainerControl::setContainerMimeType(const QString &containerMimeType) +{ + DP0("S60AudioContainerControl::setContainerMimeType +++"); + + m_session->setAudioContainer(containerMimeType); + + DP0("S60AudioContainerControl::setContainerMimeType ---"); +} + +QString S60AudioContainerControl::containerDescription(const QString &containerMimeType) const +{ + DP0("S60AudioContainerControl::containerDescription"); + + return m_session->audioContainerDescription(containerMimeType); +} + diff --git a/src/plugins/symbian/mmf/audiosource/s60audiocontainercontrol.h b/src/plugins/symbian/mmf/audiosource/s60audiocontainercontrol.h new file mode 100644 index 000000000..4c3498d0f --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audiocontainercontrol.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60AUDIOFORMATCONTROL_H +#define S60AUDIOFORMATCONTROL_H + +#include "qmediacontainercontrol.h" +#include + + +QT_USE_NAMESPACE + +class S60AudioCaptureSession; + +class S60AudioContainerControl : public QMediaContainerControl +{ +Q_OBJECT +public: + S60AudioContainerControl(QObject *parent = 0); + S60AudioContainerControl(QObject *session, QObject *parent = 0); + virtual ~S60AudioContainerControl() {}; + + QStringList supportedContainers() const; + QString containerMimeType() const; + void setContainerMimeType(const QString &containerMimeType); + QString containerDescription(const QString &containerMimeType) const; + +private: + S60AudioCaptureSession* m_session; +}; + +#endif // S60AUDIOFORMATCONTROL_H diff --git a/src/plugins/symbian/mmf/audiosource/s60audioencodercontrol.cpp b/src/plugins/symbian/mmf/audiosource/s60audioencodercontrol.cpp new file mode 100644 index 000000000..b3d02a94a --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audioencodercontrol.cpp @@ -0,0 +1,235 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DebugMacros.h" + +#include "s60audioencodercontrol.h" +#include "s60audiocapturesession.h" + +#include "qaudioformat.h" + +#include + +S60AudioEncoderControl::S60AudioEncoderControl(QObject *session, QObject *parent) + :QAudioEncoderControl(parent), m_quality(QtMultimediaKit::NormalQuality) +{ + DP0("S60AudioEncoderControl::S60AudioEncoderControl +++"); + + m_session = qobject_cast(session); + QAudioFormat fmt = m_session->format(); + // medium, 22050Hz mono S16 + fmt.setSampleType(QAudioFormat::SignedInt); + if (fmt.codec().compare("PCM", Qt::CaseInsensitive) == 0) { + fmt.setSampleSize(16); + fmt.setFrequency(22050); + } + fmt.setChannels(1); + m_session->setFormat(fmt); + m_settings.setChannelCount(fmt.channels()); + m_settings.setCodec(fmt.codec()); + m_settings.setSampleRate(fmt.sampleRate()); + + DP0("S60AudioEncoderControl::S60AudioEncoderControl ---"); +} + +S60AudioEncoderControl::~S60AudioEncoderControl() +{ + DP0("S60AudioEncoderControl::~S60AudioEncoderControl +++"); + + DP0("S60AudioEncoderControl::~S60AudioEncoderControl ---"); +} + +QStringList S60AudioEncoderControl::supportedAudioCodecs() const +{ + DP0("S60AudioEncoderControl::supportedAudioCodecs"); + + return m_session->supportedAudioCodecs(); +} + +QString S60AudioEncoderControl::codecDescription(const QString &codecName) const +{ + DP0("S60AudioEncoderControl::codecDescription"); + + return m_session->codecDescription(codecName); +} + +QtMultimediaKit::EncodingQuality S60AudioEncoderControl::quality() const +{ + DP0("S60AudioEncoderControl::quality"); + + return m_quality; +} + +void S60AudioEncoderControl::setQuality(QtMultimediaKit::EncodingQuality value, QAudioFormat &fmt) +{ + DP0("S60AudioEncoderControl::setQuality +++"); + + switch (value) { + case QtMultimediaKit::VeryLowQuality: + case QtMultimediaKit::LowQuality: + // low, 8000Hz mono U8 + fmt.setSampleType(QAudioFormat::UnSignedInt); + fmt.setSampleSize(8); + fmt.setFrequency(8000); + fmt.setChannels(1); + break; + case QtMultimediaKit::NormalQuality: + // medium, 22050Hz mono S16 + fmt.setSampleType(QAudioFormat::SignedInt); + fmt.setSampleSize(16); + fmt.setFrequency(22050); + fmt.setChannels(1); + break; + case QtMultimediaKit::HighQuality: + case QtMultimediaKit::VeryHighQuality: + // high, 44100Hz mono S16 + fmt.setSampleType(QAudioFormat::SignedInt); + fmt.setSampleSize(16); + fmt.setFrequency(44100); + fmt.setChannels(2); + break; + default: + break; + } + + DP0("S60AudioEncoderControl::setQuality ---"); +} + +QStringList S60AudioEncoderControl::supportedEncodingOptions(const QString &codec) const +{ + DP0("S60AudioEncoderControl::supportedEncodingOptions"); + + Q_UNUSED(codec) + QStringList list; + if (codec == "PCM") + list << "quality" << "channels" << "samplerate"; + return list; +} + +QVariant S60AudioEncoderControl::encodingOption(const QString &codec, const QString &name) const +{ + DP0("S60AudioEncoderControl::encodingOption"); + + if (codec == "PCM") { + QAudioFormat fmt = m_session->format(); + + if(qstrcmp(name.toLocal8Bit().constData(), "quality") == 0) { + return QVariant(quality()); + } + else if(qstrcmp(name.toLocal8Bit().constData(), "channels") == 0) { + return QVariant(fmt.channels()); + } + else if(qstrcmp(name.toLocal8Bit().constData(), "samplerate") == 0) { + return QVariant(fmt.frequency()); + } + } + return QVariant(); +} + +void S60AudioEncoderControl::setEncodingOption( + const QString &codec, const QString &name, const QVariant &value) +{ + DP0("S60AudioEncoderControl::setEncodingOption +++"); + + if (codec == "PCM") { + QAudioFormat fmt = m_session->format(); + + if(qstrcmp(name.toLocal8Bit().constData(), "quality") == 0) { + setQuality((QtMultimediaKit::EncodingQuality)value.toInt(), fmt); + } else if(qstrcmp(name.toLocal8Bit().constData(), "channels") == 0) { + fmt.setChannels(value.toInt()); + } else if(qstrcmp(name.toLocal8Bit().constData(), "samplerate") == 0) { + fmt.setFrequency(value.toInt()); + } + m_session->setFormat(fmt); + } + + DP0("S60AudioEncoderControl::setEncodingOption ---"); +} + +QList S60AudioEncoderControl::supportedSampleRates(const QAudioEncoderSettings &settings, bool *continuous) const +{ + DP0("S60AudioEncoderControl::supportedSampleRates"); + + if (continuous) + *continuous = false; + + return m_session->supportedAudioSampleRates(settings); +} + +QAudioEncoderSettings S60AudioEncoderControl::audioSettings() const +{ + DP0("S60AudioEncoderControl::audioSettings"); + + return m_settings; +} + +void S60AudioEncoderControl::setAudioSettings(const QAudioEncoderSettings &settings) +{ + DP0("S60AudioEncoderControl::setAudioSettings +++"); + + QAudioFormat fmt = m_session->format(); + if (settings.encodingMode() == QtMultimediaKit::ConstantQualityEncoding) { + fmt.setCodec(settings.codec()); + setQuality(settings.quality(), fmt); + if (settings.sampleRate() > 0) { + fmt.setFrequency(settings.sampleRate()); + } + if (settings.channelCount() > 0) + fmt.setChannels(settings.channelCount()); + }else { + if (settings.sampleRate() == 8000) { + fmt.setSampleType(QAudioFormat::UnSignedInt); + fmt.setSampleSize(8); + } else { + fmt.setSampleType(QAudioFormat::SignedInt); + fmt.setSampleSize(16); + } + fmt.setCodec(settings.codec()); + fmt.setFrequency(settings.sampleRate()); + fmt.setChannels(settings.channelCount()); + } + m_session->setFormat(fmt); + m_session->setEncoderSettings(settings); + m_settings = settings; + + DP0("S60AudioEncoderControl::setAudioSettings ---"); +} diff --git a/src/plugins/symbian/mmf/audiosource/s60audioencodercontrol.h b/src/plugins/symbian/mmf/audiosource/s60audioencodercontrol.h new file mode 100644 index 000000000..236d7d522 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audioencodercontrol.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AUDIOENCODERCONTROL_H +#define AUDIOENCODERCONTROL_H + +#include +#include +#include "qaudioformat.h" + +QT_USE_NAMESPACE + +class S60AudioCaptureSession; + +class S60AudioEncoderControl : public QAudioEncoderControl +{ + Q_OBJECT +public: + S60AudioEncoderControl(QObject *session, QObject *parent = 0); + virtual ~S60AudioEncoderControl(); + + QStringList supportedAudioCodecs() const; + QString codecDescription(const QString &codecName) const; + + QList supportedSampleRates(const QAudioEncoderSettings &settings, bool *continuous = 0) const; + + QAudioEncoderSettings audioSettings() const; + void setAudioSettings(const QAudioEncoderSettings&); + + QStringList supportedEncodingOptions(const QString &codec) const; + QVariant encodingOption(const QString &codec, const QString &name) const; + void setEncodingOption(const QString &codec, const QString &name, const QVariant &value); + +private: + QtMultimediaKit::EncodingQuality quality() const; + void setQuality(QtMultimediaKit::EncodingQuality, QAudioFormat &format); + +private: + S60AudioCaptureSession* m_session; + QAudioEncoderSettings m_settings; + QtMultimediaKit::EncodingQuality m_quality; +}; + +#endif diff --git a/src/plugins/symbian/mmf/audiosource/s60audioendpointselector.cpp b/src/plugins/symbian/mmf/audiosource/s60audioendpointselector.cpp new file mode 100644 index 000000000..a2f909316 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audioendpointselector.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DebugMacros.h" + +#include "s60audiocapturesession.h" +#include "s60audioendpointselector.h" + +#include + +S60AudioEndpointSelector::S60AudioEndpointSelector(QObject *session, QObject *parent) + :QAudioEndpointSelector(parent) +{ + DP0("S60AudioEndpointSelector::S60AudioEndpointSelector +++"); + m_session = qobject_cast(session); + + connect(m_session, SIGNAL(activeEndpointChanged(const QString &)), this, SIGNAL(activeEndpointChanged(const QString &))); + + DP0("S60AudioEndpointSelector::S60AudioEndpointSelector ---"); +} + +S60AudioEndpointSelector::~S60AudioEndpointSelector() +{ + DP0("S60AudioEndpointSelector::~S60AudioEndpointSelector +++"); + + DP0("S60AudioEndpointSelector::~S60AudioEndpointSelector ---"); +} + +QList S60AudioEndpointSelector::availableEndpoints() const +{ + DP0("S60AudioEndpointSelector::availableEndpoints"); + + return m_session->availableEndpoints(); +} + +QString S60AudioEndpointSelector::endpointDescription(const QString& name) const +{ + DP0("S60AudioEndpointSelector::endpointDescription"); + + return m_session->endpointDescription(name); +} + +QString S60AudioEndpointSelector::defaultEndpoint() const +{ + DP0("S60AudioEndpointSelector::defaultEndpoint"); + + return m_session->defaultEndpoint(); +} + +QString S60AudioEndpointSelector::activeEndpoint() const +{ + DP0("S60AudioEndpointSelector::activeEndpoint"); + + return m_session->activeEndpoint(); +} + +void S60AudioEndpointSelector::setActiveEndpoint(const QString& name) +{ + DP0("S60AudioEndpointSelector::setActiveEndpoint +++"); + m_session->setActiveEndpoint(name); + DP0("S60AudioEndpointSelector::setActiveEndpoint ---"); +} diff --git a/src/plugins/symbian/mmf/audiosource/s60audioendpointselector.h b/src/plugins/symbian/mmf/audiosource/s60audioendpointselector.h new file mode 100644 index 000000000..d89ce8765 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audioendpointselector.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60AUDIOENDPOINTSELECTOR_H +#define S60AUDIOENDPOINTSELECTOR_H + +#include + +#include + +QT_USE_NAMESPACE + +class S60AudioCaptureSession; + +class S60AudioEndpointSelector : public QAudioEndpointSelector +{ + +Q_OBJECT + +public: + S60AudioEndpointSelector(QObject *session, QObject *parent = 0); + ~S60AudioEndpointSelector(); + + QList availableEndpoints() const; + QString endpointDescription(const QString& name) const; + QString defaultEndpoint() const; + QString activeEndpoint() const; + + +public Q_SLOTS: + void setActiveEndpoint(const QString& name); + +private: + + S60AudioCaptureSession* m_session; +}; + +#endif // S60AUDIOENDPOINTSELECTOR_H diff --git a/src/plugins/symbian/mmf/audiosource/s60audiomediarecordercontrol.cpp b/src/plugins/symbian/mmf/audiosource/s60audiomediarecordercontrol.cpp new file mode 100644 index 000000000..5d80033b3 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audiomediarecordercontrol.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DebugMacros.h" + +#include "s60audiomediarecordercontrol.h" +#include "s60audiocapturesession.h" + +#include + +S60AudioMediaRecorderControl::S60AudioMediaRecorderControl(QObject *session, QObject *parent) + :QMediaRecorderControl(parent), m_state(QMediaRecorder::StoppedState) +{ + DP0("S60AudioMediaRecorderControl::S60AudioMediaRecorderControl +++"); + + m_session = qobject_cast(session); + connect(m_session, SIGNAL(positionChanged(qint64)), this, SIGNAL(durationChanged(qint64))); + connect(m_session, SIGNAL(stateChanged(S60AudioCaptureSession::TAudioCaptureState)), this, SLOT(updateState(S60AudioCaptureSession::TAudioCaptureState))); + connect(m_session,SIGNAL(error(int,const QString &)),this,SIGNAL(error(int,const QString &))); + + DP0("S60AudioMediaRecorderControl::S60AudioMediaRecorderControl ---"); +} + +S60AudioMediaRecorderControl::~S60AudioMediaRecorderControl() +{ + DP0("S60AudioMediaRecorderControl::~S60AudioMediaRecorderControl +++"); + + DP0("S60AudioMediaRecorderControl::~S60AudioMediaRecorderControl - - "); +} + +QUrl S60AudioMediaRecorderControl::outputLocation() const +{ + DP0("S60AudioMediaRecorderControl::outputLocation"); + + return m_session->outputLocation(); +} + +bool S60AudioMediaRecorderControl::setOutputLocation(const QUrl& sink) +{ + DP0("S60AudioMediaRecorderControl::setOutputLocation"); + + return m_session->setOutputLocation(sink); +} + +QMediaRecorder::State S60AudioMediaRecorderControl::convertState(S60AudioCaptureSession::TAudioCaptureState aState) const +{ + DP0("S60AudioMediaRecorderControl::convertState +++"); + + QMediaRecorder::State state = QMediaRecorder::StoppedState;; + switch (aState) { + case S60AudioCaptureSession::ERecording: + state = QMediaRecorder::RecordingState; + break; + case S60AudioCaptureSession::EPaused: + state = QMediaRecorder::PausedState; + break; + case S60AudioCaptureSession::ERecordComplete: + case S60AudioCaptureSession::ENotInitialized: + case S60AudioCaptureSession::EOpenCompelete: + case S60AudioCaptureSession::EInitialized: + state = QMediaRecorder::StoppedState; + break; + } + + DP1("S60AudioMediaRecorderControl::convertState:", state); + + DP0("S60AudioMediaRecorderControl::convertState ---"); + + return state; +} + +void S60AudioMediaRecorderControl::updateState(S60AudioCaptureSession::TAudioCaptureState aState) +{ + DP0("S60AudioMediaRecorderControl::updateState +++"); + + QMediaRecorder::State newState = convertState(aState); + if (m_state != newState) { + m_state = newState; + emit stateChanged(m_state); + } + + DP0("S60AudioMediaRecorderControl::updateState ---"); +} + +QMediaRecorder::State S60AudioMediaRecorderControl::state() const +{ + DP0("S60AudioMediaRecorderControl::state"); + + return m_state; +} + +qint64 S60AudioMediaRecorderControl::duration() const +{ + // DP0("S60AudioMediaRecorderControl::duration +++"); + + return m_session->position(); +} + +void S60AudioMediaRecorderControl::record() +{ + DP0("S60AudioMediaRecorderControl::record +++"); + + m_session->record(); + + DP0("S60AudioMediaRecorderControl::record ---"); +} + +void S60AudioMediaRecorderControl::pause() +{ + DP0("S60AudioMediaRecorderControl::pause +++"); + + m_session->pause(); + + DP0("S60AudioMediaRecorderControl::pause ---"); +} + +void S60AudioMediaRecorderControl::stop() +{ + DP0("S60AudioMediaRecorderControl::stop +++"); + + m_session->stop(); + + DP0("S60AudioMediaRecorderControl::stop ---"); +} + +bool S60AudioMediaRecorderControl::isMuted() const +{ + DP0("S60AudioMediaRecorderControl::isMuted"); + + return m_session->muted(); +} + +void S60AudioMediaRecorderControl::setMuted(bool muted) +{ + DP0("S60AudioMediaRecorderControl::setMuted +++"); + + DP1("S60AudioMediaRecorderControl::setMuted:", muted); + + m_session->mute(muted); + + DP0("S60AudioMediaRecorderControl::setMuted +++"); +} diff --git a/src/plugins/symbian/mmf/audiosource/s60audiomediarecordercontrol.h b/src/plugins/symbian/mmf/audiosource/s60audiomediarecordercontrol.h new file mode 100644 index 000000000..78e8f4870 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audiomediarecordercontrol.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60AUDIOMEDIARECORDERCONTROL_H +#define S60AUDIOMEDIARECORDERCONTROL_H + +#include +#include + +#include "qmediarecorder.h" +#include "qmediarecordercontrol.h" + +#include "s60audiocapturesession.h" + +QT_USE_NAMESPACE + +//class S60AudioCaptureSession; + +class S60AudioMediaRecorderControl : public QMediaRecorderControl +{ + Q_OBJECT +public: + S60AudioMediaRecorderControl(QObject *session,QObject *parent = 0); + ~S60AudioMediaRecorderControl(); + + QUrl outputLocation() const; + bool setOutputLocation(const QUrl &sink); + + QMediaRecorder::State state() const; + + qint64 duration() const; + + bool isMuted() const; + + void applySettings() {} + +private: + QMediaRecorder::State convertState(S60AudioCaptureSession::TAudioCaptureState aState) const; + +public slots: + void record(); + void pause(); + void stop(); + void setMuted(bool); + +private slots: + void updateState(S60AudioCaptureSession::TAudioCaptureState aState); + +private: + S60AudioCaptureSession* m_session; + QMediaRecorder::State m_state; +}; + +#endif diff --git a/src/plugins/symbian/mmf/inc/DebugMacros.h b/src/plugins/symbian/mmf/inc/DebugMacros.h new file mode 100644 index 000000000..449bef088 --- /dev/null +++ b/src/plugins/symbian/mmf/inc/DebugMacros.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#ifndef __DEBUGMACROS_H__ +#define __DEBUGMACROS_H__ + +// MACROS +#ifdef _DEBUG +#define DP0(string) qDebug()< +#include + +/*! + Constructs the CMdaAudioPlayerUtility object with given \a parent QObject. + + And Registers for Audio Loading Notifications. + +*/ + +S60AudioPlayerSession::S60AudioPlayerSession(QObject *parent) + : S60MediaPlayerSession(parent) + , m_player(0) + , m_audioEndpoint("Default") +{ + DP0("S60AudioPlayerSession::S60AudioPlayerSession +++"); + +#ifdef HAS_AUDIOROUTING + m_audioOutput = 0; +#endif //HAS_AUDIOROUTING + QT_TRAP_THROWING(m_player = CAudioPlayer::NewL(*this, 0, EMdaPriorityPreferenceNone)); + m_player->RegisterForAudioLoadingNotification(*this); + + DP0("S60AudioPlayerSession::S60AudioPlayerSession ---"); +} + + +/*! + Destroys the CMdaAudioPlayerUtility object. + + And Unregister the observer. + +*/ + +S60AudioPlayerSession::~S60AudioPlayerSession() +{ + DP0("S60AudioPlayerSession::~S60AudioPlayerSession +++"); +#ifdef HAS_AUDIOROUTING + if (m_audioOutput) + m_audioOutput->UnregisterObserver(*this); + delete m_audioOutput; +#endif + m_player->Close(); + delete m_player; + + DP0("S60AudioPlayerSession::~S60AudioPlayerSession ---"); +} + +/*! + + Opens the a file from \a path. + +*/ + +void S60AudioPlayerSession::doLoadL(const TDesC &path) +{ + DP0("S60AudioPlayerSession::doLoadL +++"); + +#ifdef HAS_AUDIOROUTING + // m_audioOutput needs to be reinitialized after MapcInitComplete + if (m_audioOutput) + m_audioOutput->UnregisterObserver(*this); + delete m_audioOutput; + m_audioOutput = NULL; +#endif //HAS_AUDIOROUTING + m_player->OpenFileL(path); + + DP0("S60AudioPlayerSession::doLoadL ---"); +} + +/*! + + Returns the duration of the audio sample in microseconds. + +*/ + +qint64 S60AudioPlayerSession::doGetDurationL() const +{ + // DP0("S60AudioPlayerSession::doGetDurationL"); + + return m_player->Duration().Int64() / qint64(1000); +} + +/*! + * Returns the current playback position in microseconds from the start of the clip. + +*/ + +qint64 S60AudioPlayerSession::doGetPositionL() const +{ + // DP0("S60AudioPlayerSession::doGetPositionL"); + + TTimeIntervalMicroSeconds ms = 0; + m_player->GetPosition(ms); + return ms.Int64() / qint64(1000); +} + +/*! + Returns TRUE if Video available or else FALSE + */ + +bool S60AudioPlayerSession::isVideoAvailable() +{ + DP0("S60AudioPlayerSession::isVideoAvailable"); + + return false; +} + +/*! + Returns TRUE if Audio available or else FALSE + */ +bool S60AudioPlayerSession::isAudioAvailable() +{ + DP0("S60AudioPlayerSession::isAudioAvailable"); + + return true; // this is a bit happy scenario, but we do emit error that we can't play +} + +/*! + Starts loading Media and sets media status to Buffering. + + */ + +void S60AudioPlayerSession::MaloLoadingStarted() +{ + DP0("S60AudioPlayerSession::MaloLoadingStarted +++"); + + buffering(); + + DP0("S60AudioPlayerSession::MaloLoadingStarted ---"); +} + + +/*! + Indicates loading Media is completed. + + And sets media status to Buffered. + + */ + +void S60AudioPlayerSession::MaloLoadingComplete() +{ + DP0("S60AudioPlayerSession::MaloLoadingComplete +++"); + + buffered(); + + DP0("S60AudioPlayerSession::MaloLoadingComplete ---"); +} + +/*! + Start or resume playing the current source. +*/ + +void S60AudioPlayerSession::doPlay() +{ + DP0("S60AudioPlayerSession::doPlay +++"); + + // For some reason loading progress callback are not called on emulator + // Same is the case with hardware. Will be fixed as part of QTMOBILITY-782. + + //#ifdef __WINSCW__ + buffering(); + //#endif + m_player->Play(); + //#ifdef __WINSCW__ + buffered(); + //#endif + + DP0("S60AudioPlayerSession::doPlay ---"); +} + + +/*! + Pause playing the current source. +*/ + + +void S60AudioPlayerSession::doPauseL() +{ + DP0("S60AudioPlayerSession::doPauseL +++"); + + m_player->Pause(); + + DP0("S60AudioPlayerSession::doPauseL ---"); +} + + +/*! + + Stop playing, and reset the play position to the beginning. +*/ + +void S60AudioPlayerSession::doStop() +{ + DP0("S60AudioPlayerSession::doStop +++"); + + m_player->Stop(); + + DP0("S60AudioPlayerSession::doStop ---"); +} + +/*! + Closes the current audio clip (allowing another clip to be opened) +*/ + +void S60AudioPlayerSession::doClose() +{ + DP0("S60AudioPlayerSession::doClose +++"); + +#ifdef HAS_AUDIOROUTING + if (m_audioOutput) { + m_audioOutput->UnregisterObserver(*this); + delete m_audioOutput; + m_audioOutput = NULL; + } +#endif + m_player->Close(); + + DP0("S60AudioPlayerSession::doClose ---"); +} + +/*! + + Changes the current playback volume to specified \a value. +*/ + +void S60AudioPlayerSession::doSetVolumeL(int volume) +{ + DP0("S60AudioPlayerSession::doSetVolumeL +++"); + + DP1("S60AudioPlayerSession::doSetVolumeL, Volume:", volume); + + m_player->SetVolume(volume * m_player->MaxVolume() / 100); + + DP0("S60AudioPlayerSession::doSetVolumeL ---"); +} + +/*! + Sets the current playback position to \a microSeconds from the start of the clip. +*/ + +void S60AudioPlayerSession::doSetPositionL(qint64 microSeconds) +{ + DP0("S60AudioPlayerSession::doSetPositionL +++"); + + DP1("S60AudioPlayerSession::doSetPositionL, Microseconds:", microSeconds); + + m_player->SetPosition(TTimeIntervalMicroSeconds(microSeconds)); + + DP0("S60AudioPlayerSession::doSetPositionL ---"); +} + +/*! + + Updates meta data entries in the current audio clip. +*/ + +void S60AudioPlayerSession::updateMetaDataEntriesL() +{ + DP0("S60AudioPlayerSession::updateMetaDataEntriesL +++"); + + metaDataEntries().clear(); + int numberOfMetaDataEntries = 0; + + //User::LeaveIfError(m_player->GetNumberOfMetaDataEntries(numberOfMetaDataEntries)); + m_player->GetNumberOfMetaDataEntries(numberOfMetaDataEntries); + + for (int i = 0; i < numberOfMetaDataEntries; i++) { + CMMFMetaDataEntry *entry = NULL; + entry = m_player->GetMetaDataEntryL(i); + metaDataEntries().insert(QString::fromUtf16(entry->Name().Ptr(), entry->Name().Length()), QString::fromUtf16(entry->Value().Ptr(), entry->Value().Length())); + delete entry; + } + emit metaDataChanged(); + + DP0("S60AudioPlayerSession::updateMetaDataEntriesL ---"); +} + +/*! + Sets the playbackRate with \a rate. +*/ + +void S60AudioPlayerSession::setPlaybackRate(qreal rate) +{ + DP0("S60AudioPlayerSession::setPlaybackRate +++"); + DP1("S60AudioPlayerSession::setPlaybackRate, Rate:", rate); + /*Since AudioPlayerUtility doesn't support set playback rate hence + * setPlaybackRate emits playbackRateChanged signal for 1.0x ie normal playback. + * For all other playBackRates it sets and emits error signal. + */ + if (rate == 1.0) { + emit playbackRateChanged(rate); + return; + } else { + int err = KErrNotSupported; + setAndEmitError(err); + } + DP0("S60AudioPlayerSession::setPlaybackRate ---"); +} + +/*! + + Returns the percentage of the audio clip loaded. +*/ + +int S60AudioPlayerSession::doGetBufferStatusL() const +{ + DP0("S60AudioPlayerSession::doGetBufferStatusL +++"); + + int progress = 0; + m_player->GetAudioLoadingProgressL(progress); + + DP0("S60AudioPlayerSession::doGetBufferStatusL ---"); + + return progress; +} + +/*! + + Defines required client behaviour when an attempt to open and initialise an audio sample has completed, + successfully or not. + + \a aError if KErrNone the sample is ready to play or else system wide error. + + \a aDuration The duration of the audio sample. +*/ + +#ifdef S60_DRM_SUPPORTED +void S60AudioPlayerSession::MdapcInitComplete(TInt aError, const TTimeIntervalMicroSeconds& aDuration) +#else +void S60AudioPlayerSession::MapcInitComplete(TInt aError, const TTimeIntervalMicroSeconds& aDuration) +#endif +{ + DP0("S60AudioPlayerSession::MdapcInitComplete +++"); + + DP1("S60AudioPlayerSession::MdapcInitComplete - aError", aError); + + Q_UNUSED(aDuration); + setError(aError); + if (KErrNone != aError) + return; +#ifdef HAS_AUDIOROUTING + TRAPD(err, + m_audioOutput = CAudioOutput::NewL(*m_player); + m_audioOutput->RegisterObserverL(*this); + ); + setActiveEndpoint(m_audioEndpoint); + setError(err); +#endif //HAS_AUDIOROUTING + if (KErrNone == aError) + loaded(); + + DP0("S60AudioPlayerSession::MdapcInitComplete ---"); +} + +/*! + Defines required client behaviour when an attempt to playback an audio sample has completed, + successfully or not. + + \a aError if KErrNone the playback completed or else system wide error. +*/ + + +#ifdef S60_DRM_SUPPORTED +void S60AudioPlayerSession::MdapcPlayComplete(TInt aError) +#else +void S60AudioPlayerSession::MapcPlayComplete(TInt aError) +#endif +{ + DP0("S60AudioPlayerSession::MdapcPlayComplete +++"); + + DP1("S60AudioPlayerSession::MdapcPlayComplete", aError); + + if (KErrNone == aError) + endOfMedia(); + else + setError(aError); + + DP0("S60AudioPlayerSession::MdapcPlayComplete ---"); +} + +/*! + Defiens which Audio End point to use. + + \a audioEndpoint audioEndpoint name. +*/ + +void S60AudioPlayerSession::doSetAudioEndpoint(const QString& audioEndpoint) +{ + DP0("S60AudioPlayerSession::doSetAudioEndpoint +++"); + + DP1("S60AudioPlayerSession::doSetAudioEndpoint - ", audioEndpoint); + + m_audioEndpoint = audioEndpoint; + + DP0("S60AudioPlayerSession::doSetAudioEndpoint ---"); +} + +/*! + + Returns audioEndpoint name. +*/ + +QString S60AudioPlayerSession::activeEndpoint() const +{ + DP0("S60AudioPlayerSession::activeEndpoint +++"); + + QString outputName = QString("Default"); +#ifdef HAS_AUDIOROUTING + if (m_audioOutput) { + CAudioOutput::TAudioOutputPreference output = m_audioOutput->AudioOutput(); + outputName = qStringFromTAudioOutputPreference(output); + } +#endif + DP1("S60AudioPlayerSession::activeEndpoint is :", outputName); + + DP0("S60AudioPlayerSession::activeEndpoint ---"); + return outputName; +} + +/*! + * Returns default Audio End point in use. +*/ + +QString S60AudioPlayerSession::defaultEndpoint() const +{ + DP0("S60AudioPlayerSession::defaultEndpoint +++"); + + QString outputName = QString("Default"); +#ifdef HAS_AUDIOROUTING + if (m_audioOutput) { + CAudioOutput::TAudioOutputPreference output = m_audioOutput->DefaultAudioOutput(); + outputName = qStringFromTAudioOutputPreference(output); + } +#endif + DP1("S60AudioPlayerSession::defaultEndpoint is :", outputName); + + DP0("S60AudioPlayerSession::defaultEndpoint ---"); + return outputName; +} + +/*! + Sets active end \a name as an Audio End point. +*/ + +void S60AudioPlayerSession::setActiveEndpoint(const QString& name) +{ + DP0("S60AudioPlayerSession::setActiveEndpoint +++"); + + DP1("S60AudioPlayerSession::setActiveEndpoint - ", name); + +#ifdef HAS_AUDIOROUTING + CAudioOutput::TAudioOutputPreference output = CAudioOutput::ENoPreference; + + if (name == QString("Default")) + output = CAudioOutput::ENoPreference; + else if (name == QString("All")) + output = CAudioOutput::EAll; + else if (name == QString("None")) + output = CAudioOutput::ENoOutput; + else if (name == QString("Earphone")) + output = CAudioOutput::EPrivate; + else if (name == QString("Speaker")) + output = CAudioOutput::EPublic; + + if (m_audioOutput) { + TRAPD(err, m_audioOutput->SetAudioOutputL(output)); + setError(err); + } +#endif + + DP0("S60AudioPlayerSession::setActiveEndpoint ---"); +} + +/*! + The default audio output has been changed. + + \a aAudioOutput Audio Output object. + + \a aNewDefault is CAudioOutput::TAudioOutputPreference. +*/ + + +#ifdef HAS_AUDIOROUTING +void S60AudioPlayerSession::DefaultAudioOutputChanged(CAudioOutput& aAudioOutput, + CAudioOutput::TAudioOutputPreference aNewDefault) +{ + DP0("S60AudioPlayerSession::DefaultAudioOutputChanged +++"); + + // Emit already implemented in setActiveEndpoint function + Q_UNUSED(aAudioOutput) + Q_UNUSED(aNewDefault) + + DP0("S60AudioPlayerSession::DefaultAudioOutputChanged ---"); +} + + +/*! + Converts CAudioOutput::TAudioOutputPreference enum to QString. + + \a output is CAudioOutput::TAudioOutputPreference enum value. + +*/ + +QString S60AudioPlayerSession::qStringFromTAudioOutputPreference(CAudioOutput::TAudioOutputPreference output) const +{ + DP0("S60AudioPlayerSession::qStringFromTAudioOutputPreference"); + + if (output == CAudioOutput::ENoPreference) + return QString("Default"); + else if (output == CAudioOutput::EAll) + return QString("All"); + else if (output == CAudioOutput::ENoOutput) + return QString("None"); + else if (output == CAudioOutput::EPrivate) + return QString("Earphone"); + else if (output == CAudioOutput::EPublic) + return QString("Speaker"); + return QString("Default"); +} +#endif + +/*! + Return True if its Seekable or else False. +*/ + +bool S60AudioPlayerSession::getIsSeekable() const +{ + DP0("S60AudioPlayerSession::getIsSeekable"); + + return ETrue; +} + diff --git a/src/plugins/symbian/mmf/mediaplayer/s60audioplayersession.h b/src/plugins/symbian/mmf/mediaplayer/s60audioplayersession.h new file mode 100644 index 000000000..80228ef0a --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60audioplayersession.h @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60AUDIOPLAYERSESSION_H +#define S60AUDIOPLAYERSESSION_H + +#include +#include "s60mediaplayersession.h" + +#ifdef S60_DRM_SUPPORTED +#include +typedef CDrmPlayerUtility CAudioPlayer; +typedef MDrmAudioPlayerCallback MAudioPlayerObserver; +#else +#include +typedef CMdaAudioPlayerUtility CAudioPlayer; +typedef MMdaAudioPlayerCallback MAudioPlayerObserver; +#endif + +#ifdef HAS_AUDIOROUTING +#include +#include +#endif //HAS_AUDIOROUTING + +class S60AudioPlayerSession : public S60MediaPlayerSession + , public MAudioPlayerObserver + , public MAudioLoadingObserver +#ifdef HAS_AUDIOROUTING + , public MAudioOutputObserver +#endif +{ + Q_OBJECT +public: + S60AudioPlayerSession(QObject *parent); + ~S60AudioPlayerSession(); + + //From S60MediaPlayerSession + bool isVideoAvailable(); + bool isAudioAvailable(); + + // From MAudioLoadingObserver + void MaloLoadingStarted(); + void MaloLoadingComplete(); + +#ifdef HAS_AUDIOROUTING + // From MAudioOutputObserver + void DefaultAudioOutputChanged( CAudioOutput& aAudioOutput, + CAudioOutput::TAudioOutputPreference aNewDefault ); +#endif //HAS_AUDIOROUTING + +public: + // From S60MediaPlayerAudioEndpointSelector + QString activeEndpoint() const; + QString defaultEndpoint() const; + void setPlaybackRate(qreal rate); +public Q_SLOTS: + void setActiveEndpoint(const QString& name); + +protected: + //From S60MediaPlayerSession + void doLoadL(const TDesC &path); + void doLoadUrlL(const TDesC &path){Q_UNUSED(path)/*empty implementation*/} + void doPlay(); + void doStop(); + void doClose(); + void doPauseL(); + void doSetVolumeL(int volume); + qint64 doGetPositionL() const; + void doSetPositionL(qint64 microSeconds); + void updateMetaDataEntriesL(); + int doGetBufferStatusL() const; + qint64 doGetDurationL() const; + void doSetAudioEndpoint(const QString& audioEndpoint); + bool getIsSeekable() const; +private: +#ifdef S60_DRM_SUPPORTED + // From MMdaAudioPlayerCallback + void MdapcInitComplete(TInt aError, const TTimeIntervalMicroSeconds& aDuration); + void MdapcPlayComplete(TInt aError); +#else + // From MDrmAudioPlayerCallback + void MapcInitComplete(TInt aError, const TTimeIntervalMicroSeconds& aDuration); + void MapcPlayComplete(TInt aError); +#endif + +#ifdef HAS_AUDIOROUTING + QString qStringFromTAudioOutputPreference(CAudioOutput::TAudioOutputPreference output) const; +#endif //HAS_AUDIOROUTING + +private: + CAudioPlayer *m_player; +#ifdef HAS_AUDIOROUTING + CAudioOutput *m_audioOutput; +#endif //HAS_AUDIOROUTING + QString m_audioEndpoint; +}; + +#endif diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediametadataprovider.cpp b/src/plugins/symbian/mmf/mediaplayer/s60mediametadataprovider.cpp new file mode 100644 index 000000000..85bfe65a3 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediametadataprovider.cpp @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DebugMacros.h" + +#include "s60mediametadataprovider.h" +#include "s60mediaplayercontrol.h" +#include "s60mediaplayersession.h" +#include + +/*! + * Typecasts the \a control object to S60MediaPlayerControl object. +*/ +S60MediaMetaDataProvider::S60MediaMetaDataProvider(QObject *control, QObject *parent) + : QMetaDataReaderControl(parent) + , m_control(NULL) +{ + DP0("S60MediaMetaDataProvider::S60MediaMetaDataProvider +++"); + + m_control = qobject_cast(control); + + DP0("S60MediaMetaDataProvider::S60MediaMetaDataProvider ---"); +} + +/*! + * Destructor +*/ + +S60MediaMetaDataProvider::~S60MediaMetaDataProvider() +{ + DP0("S60MediaMetaDataProvider::~S60MediaMetaDataProvider +++"); + DP0("S60MediaMetaDataProvider::~S60MediaMetaDataProvider ---"); +} + +/*! + * Returns TRUE if MetaData is Available or else FALSE. +*/ + +bool S60MediaMetaDataProvider::isMetaDataAvailable() const +{ + DP0("S60MediaMetaDataProvider::isMetaDataAvailable"); + + if (m_control->session()) + return m_control->session()->isMetadataAvailable(); + return false; +} + +/*! + * Always returns FLASE. +*/ +bool S60MediaMetaDataProvider::isWritable() const +{ + DP0("S60MediaMetaDataProvider::isWritable"); + + return false; +} + +/*! + * Returns when \a key meta data is found in metaData. +*/ + +QVariant S60MediaMetaDataProvider::metaData(QtMultimediaKit::MetaData key) const +{ + DP0("S60MediaMetaDataProvider::metaData"); + + if (m_control->session()) + return m_control->session()->metaData(key); + return QVariant(); +} + +/*! + * Returns available metaData. +*/ + +QList S60MediaMetaDataProvider::availableMetaData() const +{ + DP0("S60MediaMetaDataProvider::availableMetaData"); + + if (m_control->session()) + return m_control->session()->availableMetaData(); + return QList(); +} + +/*! + * Returns when \a key string is found in extended metaData. +*/ + +QVariant S60MediaMetaDataProvider::extendedMetaData(const QString &key) const +{ + DP0("S60MediaMetaDataProvider::extendedMetaData"); + + if (m_control->session()) + return m_control->session()->metaData(key); + return QVariant(); +} + +/*! + * Returns available Extended MetaData. +*/ + +QStringList S60MediaMetaDataProvider::availableExtendedMetaData() const +{ + DP0("S60MediaMetaDataProvider::availableExtendedMetaData"); + + if (m_control->session()) + return m_control->session()->availableExtendedMetaData(); + return QStringList(); +} diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediametadataprovider.h b/src/plugins/symbian/mmf/mediaplayer/s60mediametadataprovider.h new file mode 100644 index 000000000..eb995080d --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediametadataprovider.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60MEDIAMETADATAPROVIDER_H +#define S60MEDIAMETADATAPROVIDER_H + +#include +#include "s60mediaplayercontrol.h" + +QT_USE_NAMESPACE + +class S60MediaPlayerControl; + +class S60MediaMetaDataProvider : public QMetaDataReaderControl +{ + Q_OBJECT + +public: + S60MediaMetaDataProvider(QObject *control, QObject *parent = 0); + ~S60MediaMetaDataProvider(); + + bool isMetaDataAvailable() const; + bool isWritable() const; + + QVariant metaData(QtMultimediaKit::MetaData key) const; + QList availableMetaData() const; + QVariant extendedMetaData(const QString &key) const ; + QStringList availableExtendedMetaData() const; + +private: + S60MediaPlayerControl *m_control; +}; + +#endif // S60VIDEOMETADATAPROVIDER_H diff --git a/src/plugins/symbian/mmf/mediaplayer/s60medianetworkaccesscontrol.cpp b/src/plugins/symbian/mmf/mediaplayer/s60medianetworkaccesscontrol.cpp new file mode 100644 index 000000000..dad69a691 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60medianetworkaccesscontrol.cpp @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "s60medianetworkaccesscontrol.h" + +#define KBuffersize 512 + +S60MediaNetworkAccessControl::S60MediaNetworkAccessControl(QObject *parent) + : QMediaNetworkAccessControl(parent) + , m_iapId(KUseDefaultIap) + , m_currentIndex(0) +{ +} + +void S60MediaNetworkAccessControl::accessPointChanged(int id) +{ + if (!m_IapIdList.isEmpty()) + m_NetworkObject = m_NetworkObjectList.at(m_IapIdList.indexOf(id)); + emit configurationChanged(m_NetworkObject); +} + +S60MediaNetworkAccessControl::~S60MediaNetworkAccessControl() +{ + m_NetworkObjectList.clear(); + m_IapIdList.clear(); +} + +void S60MediaNetworkAccessControl::resetIndex() +{ + m_currentIndex = 0; +} + +void S60MediaNetworkAccessControl::setConfigurations(const QList &configurations) +{ + if (!configurations.isEmpty()) { + m_currentIndex =0; + TRAPD(error, retriveAccesspointIDL(configurations)); + if (error != KErrNone) { + m_NetworkObjectList.clear(); + m_IapIdList.clear(); + } + } +} + +TBool S60MediaNetworkAccessControl::isLastAccessPoint() +{ + if (m_currentIndex == m_NetworkObjectList.size()) + return TRUE; + else + return FALSE; +} + +int S60MediaNetworkAccessControl::accessPointId() +{ + if (m_IapIdList.isEmpty()) + return m_iapId; + + m_iapId = m_IapIdList.at(m_currentIndex); + + if (isLastAccessPoint()) + m_currentIndex = 0; + else + m_currentIndex ++; + + return m_iapId; +} + +QNetworkConfiguration S60MediaNetworkAccessControl::currentConfiguration() const +{ + return m_NetworkObject; +} + +void S60MediaNetworkAccessControl::retriveAccesspointIDL(const QList &configurationList) +{ + m_NetworkObjectList.clear(); + m_IapIdList.clear(); + TBuf iapName; + TUint32 iapId; + TInt err; + + // open the IAP communications database + CCommsDatabase* commDB = CCommsDatabase::NewL(); + CleanupStack::PushL(commDB); + + // Open the IAP table + CCommsDbTableView* view = commDB->OpenTableLC(TPtrC(IAP)); + + for (int i=0;i<=configurationList.size()- 1;i++) { + QString accesspointname = configurationList.at(i).name(); + TBuf accesspointbuffer(accesspointname.utf16()); + // Point to the first entry + if (view->GotoFirstRecord() == KErrNone) { + do { + view->ReadTextL(TPtrC(COMMDB_NAME), iapName); + view->ReadUintL(TPtrC(COMMDB_ID), iapId); + if (accesspointbuffer == iapName) { + m_NetworkObjectList<GotoNextRecord(), err == KErrNone); + } + } + CleanupStack::PopAndDestroy(); // view + CleanupStack::PopAndDestroy(); // commDB +} diff --git a/src/plugins/symbian/mmf/mediaplayer/s60medianetworkaccesscontrol.h b/src/plugins/symbian/mmf/mediaplayer/s60medianetworkaccesscontrol.h new file mode 100644 index 000000000..aea4dcab5 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60medianetworkaccesscontrol.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60MEDIANETWORKACCESSCONTROL_H_ +#define S60MEDIANETWORKACCESSCONTROL_H_ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "s60mediaplayercontrol.h" + +QT_BEGIN_NAMESPACE +class QMediaPlayerControl; +class QMediaNetworkAccessControl; +class QNetworkConfiguration; +QT_END_NAMESPACE + +class S60MediaNetworkAccessControl : public QMediaNetworkAccessControl +{ + Q_OBJECT + +public: + + S60MediaNetworkAccessControl(QObject *parent = 0); + ~S60MediaNetworkAccessControl(); + + virtual void setConfigurations(const QList &configurations); + virtual QNetworkConfiguration currentConfiguration() const; + int accessPointId(); + TBool isLastAccessPoint(); + void resetIndex(); + +public Q_SLOTS: + void accessPointChanged(int); + +private: + void retriveAccesspointIDL(const QList &); + QList m_IapIdList; + QList m_NetworkObjectList; + QNetworkConfiguration m_NetworkObject; + int m_iapId; + int m_currentIndex; +}; +#endif /* S60MEDIANETWORKACCESSCONTROL_H_ */ diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediaplayeraudioendpointselector.cpp b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayeraudioendpointselector.cpp new file mode 100644 index 000000000..3ad64ef3b --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayeraudioendpointselector.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DebugMacros.h" + +#include "s60mediaplayercontrol.h" +#include "s60mediaplayersession.h" +#include "s60mediaplayeraudioendpointselector.h" + +#include +#include + +/*! + Constructs a new audio endpoint selector with the given \a parent. +*/ + +S60MediaPlayerAudioEndpointSelector::S60MediaPlayerAudioEndpointSelector(QObject *control, QObject *parent) + :QAudioEndpointSelector(parent) + , m_control(0) +{ + DP0("S60MediaPlayerAudioEndpointSelector::S60MediaPlayerAudioEndpointSelector +++"); + + m_control = qobject_cast(control); + m_audioEndpointNames.append("Default"); + m_audioEndpointNames.append("All"); + m_audioEndpointNames.append("None"); + m_audioEndpointNames.append("Earphone"); + m_audioEndpointNames.append("Speaker"); + + DP0("S60MediaPlayerAudioEndpointSelector::S60MediaPlayerAudioEndpointSelector ---"); +} + +/*! + Destroys an audio endpoint selector. +*/ + +S60MediaPlayerAudioEndpointSelector::~S60MediaPlayerAudioEndpointSelector() +{ + DP0("S60MediaPlayerAudioEndpointSelector::~S60MediaPlayerAudioEndpointSelector +++"); + DP0("S60MediaPlayerAudioEndpointSelector::~S60MediaPlayerAudioEndpointSelector ---"); +} + +/*! + \return a list of available audio endpoints. +*/ + +QList S60MediaPlayerAudioEndpointSelector::availableEndpoints() const +{ + DP0("S60MediaPlayerAudioEndpointSelector::availableEndpoints"); + + return m_audioEndpointNames; +} + +/*! + \return the description of the endpoint name. +*/ + +QString S60MediaPlayerAudioEndpointSelector::endpointDescription(const QString& name) const +{ + DP0("S60MediaPlayerAudioEndpointSelector::endpointDescription"); + + if (name == QString("Default")) //ENoPreference + return QString("Used to indicate that the playing audio can be routed to" + "any speaker. This is the default value for audio."); + else if (name == QString("All")) //EAll + return QString("Used to indicate that the playing audio should be routed to all speakers."); + else if (name == QString("None")) //ENoOutput + return QString("Used to indicate that the playing audio should not be routed to any output."); + else if (name == QString("Earphone")) //EPrivate + return QString("Used to indicate that the playing audio should be routed to" + "the default private speaker. A private speaker is one that can only" + "be heard by one person."); + else if (name == QString("Speaker")) //EPublic + return QString("Used to indicate that the playing audio should be routed to" + "the default public speaker. A public speaker is one that can " + "be heard by multiple people."); + + return QString(); +} + +/*! + \return the name of the currently selected audio endpoint. +*/ + +QString S60MediaPlayerAudioEndpointSelector::activeEndpoint() const +{ + DP0("S60MediaPlayerAudioEndpointSelector::activeEndpoint"); + + if (m_control->session()) { + DP1("S60MediaPlayerAudioEndpointSelector::activeEndpoint - ", + m_control->session()->activeEndpoint()); + return m_control->session()->activeEndpoint(); + } + else { + DP1("S60MediaPlayerAudioEndpointSelector::activeEndpoint - ", + m_control->mediaControlSettings().audioEndpoint()); + return m_control->mediaControlSettings().audioEndpoint(); + } +} + +/*! + \return the name of the default audio endpoint. +*/ + +QString S60MediaPlayerAudioEndpointSelector::defaultEndpoint() const +{ + DP0("S60MediaPlayerAudioEndpointSelector::defaultEndpoint"); + + if (m_control->session()) { + DP1("S60MediaPlayerAudioEndpointSelector::defaultEndpoint - ", + m_control->session()->defaultEndpoint()); + return m_control->session()->defaultEndpoint(); + } + else { + DP1("S60MediaPlayerAudioEndpointSelector::defaultEndpoint - ", + m_control->mediaControlSettings().audioEndpoint()); + return m_control->mediaControlSettings().audioEndpoint(); + } +} + +/*! + Set the audio endpoint to \a name. +*/ + +void S60MediaPlayerAudioEndpointSelector::setActiveEndpoint(const QString& name) +{ + DP0("S60MediaPlayerAudioEndpointSelector::setActiveEndpoin +++"); + + DP1("S60MediaPlayerAudioEndpointSelector::setActiveEndpoint - ", name); + + QString oldEndpoint = m_control->mediaControlSettings().audioEndpoint(); + + if (name != oldEndpoint && (name == QString("Default") || name == QString("All") || + name == QString("None") || name == QString("Earphone") || name == QString("Speaker"))) { + + if (m_control->session()) { + m_control->session()->setActiveEndpoint(name); + emit activeEndpointChanged(name); + } + m_control->setAudioEndpoint(name); + } + + DP0("S60MediaPlayerAudioEndpointSelector::setActiveEndpoin ---"); +} diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediaplayeraudioendpointselector.h b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayeraudioendpointselector.h new file mode 100644 index 000000000..eff49d47a --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayeraudioendpointselector.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60MEDIAPLAYERAUDIOENDPOINTSELECTOR_H +#define S60MEDIAPLAYERAUDIOENDPOINTSELECTOR_H + +#include + +#include + +QT_USE_NAMESPACE + +class S60MediaPlayerControl; +class S60MediaPlayerSession; + +class S60MediaPlayerAudioEndpointSelector : public QAudioEndpointSelector +{ + +Q_OBJECT + +public: + S60MediaPlayerAudioEndpointSelector(QObject *control, QObject *parent = 0); + ~S60MediaPlayerAudioEndpointSelector(); + + QList availableEndpoints() const ; + QString endpointDescription(const QString& name) const; + QString defaultEndpoint() const; + QString activeEndpoint() const; + +public Q_SLOTS: + void setActiveEndpoint(const QString& name); + +private: + S60MediaPlayerControl* m_control; + QString m_audioInput; + QList m_audioEndpointNames; +}; + +#endif // S60MEDIAPLAYERAUDIOENDPOINTSELECTOR_H diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediaplayercontrol.cpp b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayercontrol.cpp new file mode 100644 index 000000000..2eeceedd8 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayercontrol.cpp @@ -0,0 +1,518 @@ + +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DebugMacros.h" + +#include "s60mediaplayercontrol.h" +#include "s60mediaplayersession.h" + +#include +#include +#include + +/*! + Constructs a new media player control with the given \a parent. +*/ + +S60MediaPlayerControl::S60MediaPlayerControl(MS60MediaPlayerResolver& mediaPlayerResolver, QObject *parent) + : QMediaPlayerControl(parent), + m_mediaPlayerResolver(mediaPlayerResolver), + m_session(NULL), + m_stream(NULL) +{ + DP0("S60MediaPlayerControl::S60MediaPlayerControl +++"); + + DP0("S60MediaPlayerControl::S60MediaPlayerControl ---"); + +} + +/*! + Destroys a media player control. +*/ + +S60MediaPlayerControl::~S60MediaPlayerControl() +{ + DP0("S60MediaPlayerControl::~S60MediaPlayerControl +++"); + DP0("S60MediaPlayerControl::~S60MediaPlayerControl ---"); +} + +/*! + \return the current playback position in milliseconds. +*/ + +qint64 S60MediaPlayerControl::position() const +{ + // DP0("S60MediaPlayerControl::position"); + + if (m_session) + return m_session->position(); + return 0; +} + +/*! + \return the duration of the current media in milliseconds. +*/ + +qint64 S60MediaPlayerControl::duration() const +{ + // DP0("S60MediaPlayerControl::duration"); + + if (m_session) + return m_session->duration(); + return -1; +} + +/*! + \return the state of a player control. +*/ + +QMediaPlayer::State S60MediaPlayerControl::state() const +{ + DP0("S60MediaPlayerControl::state"); + + if (m_session) + return m_session->state(); + return QMediaPlayer::StoppedState; +} + +/*! + \return the status of the current media. +*/ + +QMediaPlayer::MediaStatus S60MediaPlayerControl::mediaStatus() const +{ + DP0("QMediaPlayer::mediaStatus"); + + if (m_session) + return m_session->mediaStatus(); + return m_mediaSettings.mediaStatus(); +} + +/*! + \return the buffering progress of the current media. Progress is measured in the percentage + of the buffer filled. +*/ + +int S60MediaPlayerControl::bufferStatus() const +{ + // DP0("S60MediaPlayerControl::bufferStatus"); + + if (m_session) + return m_session->bufferStatus(); + return 0; +} + +/*! + \return the audio volume of a player control. +*/ + +int S60MediaPlayerControl::volume() const +{ + DP0("S60MediaPlayerControl::volume"); + + if (m_session) + return m_session->volume(); + return m_mediaSettings.volume(); +} + +/*! + \return the mute state of a player control. +*/ + +bool S60MediaPlayerControl::isMuted() const +{ + DP0("S60MediaPlayerControl::isMuted"); + + if (m_session) + return m_session->isMuted(); + return m_mediaSettings.isMuted(); +} + +/*! + Identifies if the current media is seekable. + + \return true if it possible to seek within the current media, and false otherwise. +*/ + +bool S60MediaPlayerControl::isSeekable() const +{ + DP0("S60MediaPlayerControl::isSeekable"); + + if (m_session) + return m_session->isSeekable(); + return false; +} + +/*! + \return a range of times in milliseconds that can be played back. + + Usually for local files this is a continuous interval equal to [0..duration()] + or an empty time range if seeking is not supported, but for network sources + it refers to the buffered parts of the media. +*/ + +QMediaTimeRange S60MediaPlayerControl::availablePlaybackRanges() const +{ + DP0("S60MediaPlayerControl::availablePlaybackRanges"); + + QMediaTimeRange ranges; + + if(m_session && m_session->isSeekable()) + ranges.addInterval(0, m_session->duration()); + + return ranges; +} + +/*! + \return the rate of playback. +*/ + +qreal S60MediaPlayerControl::playbackRate() const +{ + DP0("S60MediaPlayerControl::playbackRate"); + + return m_mediaSettings.playbackRate(); +} + +/*! + Sets the \a rate of playback. +*/ + +void S60MediaPlayerControl::setPlaybackRate(qreal rate) +{ + DP0("S60MediaPlayerControl::setPlaybackRate +++"); + + DP1("S60MediaPlayerControl::setPlaybackRate - ", rate); + + //getting the current playbackrate + qreal currentPBrate = m_mediaSettings.playbackRate(); + //checking if we need to change the Playback rate + if (!qFuzzyCompare(currentPBrate,rate)) + { + if(m_session) + m_session->setPlaybackRate(rate); + + m_mediaSettings.setPlaybackRate(rate); + } + + DP0("S60MediaPlayerControl::setPlaybackRate ---"); +} + +/*! + Sets the playback \a pos of the current media. This will initiate a seek and it may take + some time for playback to reach the position set. +*/ + +void S60MediaPlayerControl::setPosition(qint64 pos) +{ + DP0("S60MediaPlayerControl::setPosition +++"); + + DP1("S60MediaPlayerControl::setPosition, Position:", pos); + + if (m_session) + m_session->setPosition(pos); + + DP0("S60MediaPlayerControl::setPosition ---"); +} + +/*! + Starts playback of the current media. + + If successful the player control will immediately enter the \l {QMediaPlayer::PlayingState} + {playing} state. +*/ + +void S60MediaPlayerControl::play() +{ + DP0("S60MediaPlayerControl::play +++"); + + if (m_session) + m_session->play(); + + DP0("S60MediaPlayerControl::play ---"); +} + +/*! + Pauses playback of the current media. + + If sucessful the player control will immediately enter the \l {QMediaPlayer::PausedState} + {paused} state. +*/ + +void S60MediaPlayerControl::pause() +{ + DP0("S60MediaPlayerControl::pause +++"); + + if (m_session) + m_session->pause(); + + DP0("S60MediaPlayerControl::pause ---"); +} + +/*! + Stops playback of the current media. + + If successful the player control will immediately enter the \l {QMediaPlayer::StoppedState} + {stopped} state. +*/ + +void S60MediaPlayerControl::stop() +{ + DP0("S60MediaPlayerControl::stop +++"); + + if (m_session) + m_session->stop(); + + DP0("S60MediaPlayerControl::stop ---"); +} + +/*! + Sets the audio \a volume of a player control. +*/ + +void S60MediaPlayerControl::setVolume(int volume) +{ + DP0("S60MediaPlayerControl::setVolume +++"); + + DP1("S60MediaPlayerControl::setVolume", volume); + + int boundVolume = qBound(0, volume, 100); + if (boundVolume == m_mediaSettings.volume()) + return; + + m_mediaSettings.setVolume(boundVolume); + + if (m_session) + m_session->setVolume(boundVolume); + + DP0("S60MediaPlayerControl::setVolume ---"); +} + +/*! + Sets the \a muted state of a player control. +*/ + +void S60MediaPlayerControl::setMuted(bool muted) +{ + DP0("S60MediaPlayerControl::setMuted +++"); + + DP1("S60MediaPlayerControl::setMuted - ", muted); + + if (m_mediaSettings.isMuted() == muted) + return; + + m_mediaSettings.setMuted(muted); + + if (m_session) + m_session->setMuted(muted); + + DP0("S60MediaPlayerControl::setMuted ---"); +} + +/*! + * \return the current media source. +*/ + +QMediaContent S60MediaPlayerControl::media() const +{ + DP0("S60MediaPlayerControl::media"); + + return m_currentResource; +} + +/*! + \return the current media stream. This is only a valid if a stream was passed to setMedia(). + + \sa setMedia() +*/ + +const QIODevice *S60MediaPlayerControl::mediaStream() const +{ + DP0("S60MediaPlayerControl::mediaStream"); + + return m_stream; +} + +/*! + Sets the current \a source media source. If a \a stream is supplied; data will be read from that + instead of attempting to resolve the media source. The media source may still be used to + supply media information such as mime type. + + Setting the media to a null QMediaContent will cause the control to discard all + information relating to the current media source and to cease all I/O operations related + to that media. +*/ + +void S60MediaPlayerControl::setMedia(const QMediaContent &source, QIODevice *stream) +{ + DP0("S60MediaPlayerControl::setMedia +++"); + + Q_UNUSED(stream) + + if ((m_session && m_currentResource == source) && m_session->isStreaming()) + { + m_session->load(source); + return; + } + + // we don't want to set & load media again when it is already loaded + if (m_session && m_currentResource == source) + return; + + // store to variable as session is created based on the content type. + m_currentResource = source; + S60MediaPlayerSession *newSession = m_mediaPlayerResolver.PlayerSession(); + m_mediaSettings.setMediaStatus(QMediaPlayer::UnknownMediaStatus); + + if (m_session) + m_session->reset(); + else { + emit mediaStatusChanged(QMediaPlayer::UnknownMediaStatus); + emit error(QMediaPlayer::NoError, QString()); + } + + m_session = newSession; + + if (m_session) + m_session->load(source); + else { + QMediaPlayer::MediaStatus status = (source.isNull()) ? QMediaPlayer::NoMedia : QMediaPlayer::InvalidMedia; + m_mediaSettings.setMediaStatus(status); + emit stateChanged(QMediaPlayer::StoppedState); + emit error((source.isNull()) ? QMediaPlayer::NoError : QMediaPlayer::ResourceError, + (source.isNull()) ? "" : tr("Media couldn't be resolved")); + emit mediaStatusChanged(status); + } + emit mediaChanged(m_currentResource); + + DP0("S60MediaPlayerControl::setMedia ---"); +} + +/*! + * \return media player session. +*/ +S60MediaPlayerSession* S60MediaPlayerControl::session() +{ + DP0("S60MediaPlayerControl::session"); + + return m_session; +} + +/*! + * Sets \a output as a VideoOutput. +*/ + +void S60MediaPlayerControl::setVideoOutput(QObject *output) +{ + DP0("S60MediaPlayerControl::setVideoOutput +++"); + + m_mediaPlayerResolver.VideoPlayerSession()->setVideoRenderer(output); + + DP0("S60MediaPlayerControl::setVideoOutput ---"); +} + +/*! + * \return TRUE if Audio available or else FALSE. +*/ + +bool S60MediaPlayerControl::isAudioAvailable() const +{ + DP0("S60MediaPlayerControl::isAudioAvailable"); + + if (m_session) + return m_session->isAudioAvailable(); + return false; +} + +/*! + * \return TRUE if Video available or else FALSE. +*/ + +bool S60MediaPlayerControl::isVideoAvailable() const +{ + DP0("S60MediaPlayerControl::isVideoAvailable"); + + if (m_session) + return m_session->isVideoAvailable(); + return false; +} + +/*! + * \return media settings. + * + * Media Settings include volume, muted, playbackRate, mediaStatus, audioEndpoint. +*/ +const S60MediaSettings& S60MediaPlayerControl::mediaControlSettings() const +{ + DP0("S60MediaPlayerControl::mediaControlSettings"); + return m_mediaSettings; +} + +/*! + * Set the audio endpoint to \a name. +*/ + +void S60MediaPlayerControl::setAudioEndpoint(const QString& name) +{ + DP0("S60MediaPlayerControl::setAudioEndpoint +++"); + + DP1("S60MediaPlayerControl::setAudioEndpoint - ", name); + + m_mediaSettings.setAudioEndpoint(name); + + DP0("S60MediaPlayerControl::setAudioEndpoint ---"); +} + +/*! + * Sets media type \a type as Unknown, Video, Audio, Data. +*/ + +void S60MediaPlayerControl::setMediaType(S60MediaSettings::TMediaType type) +{ + DP0("S60MediaPlayerControl::setMediaType +++"); + + DP1("S60MediaPlayerControl::setMediaType - ", type); + + m_mediaSettings.setMediaType(type); + + DP0("S60MediaPlayerControl::setMediaType ---"); +} diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediaplayercontrol.h b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayercontrol.h new file mode 100644 index 000000000..caf6631a8 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayercontrol.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60MEDIAPLAYERCONTROL_H +#define S60MEDIAPLAYERCONTROL_H + +#include + +#include + +#include "ms60mediaplayerresolver.h" +#include + +QT_BEGIN_NAMESPACE +class QMediaPlayer; +class QMediaTimeRange; +class QMediaContent; +QT_END_NAMESPACE + +QT_USE_NAMESPACE + +class S60MediaPlayerSession; +class S60MediaPlayerService; + +class S60MediaSettings +{ + +public: + S60MediaSettings() + : m_volume(30) + , m_muted(false) + , m_playbackRate(0) + , m_mediaStatus(QMediaPlayer::NoMedia) + , m_audioEndpoint(QString("Default")) + { + } + + enum TMediaType {Unknown, Video, Audio, Data}; + + void setVolume(int volume) { m_volume = volume; } + void setMuted(bool muted) { m_muted = muted; } + void setPlaybackRate(qreal rate) { m_playbackRate = rate; } + void setMediaStatus(QMediaPlayer::MediaStatus status) {m_mediaStatus=status;} + void setAudioEndpoint(const QString& audioEndpoint) { m_audioEndpoint = audioEndpoint; } + void setMediaType(S60MediaSettings::TMediaType type) { m_mediaType = type; } + + int volume() const { return m_volume; } + bool isMuted() const { return m_muted; } + qreal playbackRate() const { return m_playbackRate; } + QMediaPlayer::MediaStatus mediaStatus() const {return m_mediaStatus;} + QString audioEndpoint() const { return m_audioEndpoint; } + S60MediaSettings::TMediaType mediaType() const { return m_mediaType; } + +private: + int m_volume; + bool m_muted; + qreal m_playbackRate; + QMediaPlayer::MediaStatus m_mediaStatus; + QString m_audioEndpoint; + S60MediaSettings::TMediaType m_mediaType; +}; + +class S60MediaPlayerControl : public QMediaPlayerControl +{ + Q_OBJECT + +public: + S60MediaPlayerControl(MS60MediaPlayerResolver& mediaPlayerResolver, QObject *parent = 0); + ~S60MediaPlayerControl(); + + // from QMediaPlayerControl + virtual QMediaPlayer::State state() const; + virtual QMediaPlayer::MediaStatus mediaStatus() const; + virtual qint64 duration() const; + virtual qint64 position() const; + virtual void setPosition(qint64 pos); + virtual int volume() const; + virtual void setVolume(int volume); + virtual bool isMuted() const; + virtual void setMuted(bool muted); + virtual int bufferStatus() const; + virtual bool isAudioAvailable() const; + virtual bool isVideoAvailable() const; + virtual bool isSeekable() const; + virtual QMediaTimeRange availablePlaybackRanges() const; + virtual qreal playbackRate() const; + virtual void setPlaybackRate(qreal rate); + virtual QMediaContent media() const; + virtual const QIODevice *mediaStream() const; + virtual void setMedia(const QMediaContent&, QIODevice *); + virtual void play(); + virtual void pause(); + virtual void stop(); + + // Own methods + S60MediaPlayerSession* session(); + void setVideoOutput(QObject *output); + const S60MediaSettings& mediaControlSettings() const; + void setAudioEndpoint(const QString& name); + void setMediaType(S60MediaSettings::TMediaType type); + +private: + MS60MediaPlayerResolver &m_mediaPlayerResolver; + S60MediaPlayerSession *m_session; + QMediaContent m_currentResource; + QIODevice *m_stream; + S60MediaSettings m_mediaSettings; +}; + +#endif diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediaplayerservice.cpp b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayerservice.cpp new file mode 100644 index 000000000..a1aabef90 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayerservice.cpp @@ -0,0 +1,326 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DebugMacros.h" + +#include +#include +#include + +#include "s60mediaplayerservice.h" +#include "s60mediaplayercontrol.h" +#include "s60videoplayersession.h" +#include "s60audioplayersession.h" +#include "s60mediametadataprovider.h" +#include "s60mediarecognizer.h" +#include "s60videowidgetcontrol.h" +#include "s60videowindowcontrol.h" +#ifdef HAS_VIDEORENDERERCONTROL_IN_VIDEOPLAYER +#include "s60videorenderer.h" +#endif +#include "s60mediaplayeraudioendpointselector.h" +#include "s60medianetworkaccesscontrol.h" +#include "s60mediastreamcontrol.h" + +#include +#include + +/*! + Construct a media service with the given \a parent. +*/ + +S60MediaPlayerService::S60MediaPlayerService(QObject *parent) + : QMediaService(parent) + , m_control(NULL) + , m_videoPlayerSession(NULL) + , m_audioPlayerSession(NULL) + , m_metaData(NULL) + , m_audioEndpointSelector(NULL) + , m_streamControl(NULL) + , m_networkAccessControl(NULL) + , m_videoOutput(NULL) +{ + DP0("S60MediaPlayerService::S60MediaPlayerService +++"); + + m_control = new S60MediaPlayerControl(*this, this); + m_metaData = new S60MediaMetaDataProvider(m_control, this); + m_audioEndpointSelector = new S60MediaPlayerAudioEndpointSelector(m_control, this); + m_streamControl = new S60MediaStreamControl(m_control, this); + m_networkAccessControl = new S60MediaNetworkAccessControl(this); + + DP0("S60MediaPlayerService::S60MediaPlayerService ---"); +} + +/*! + Destroys a media service. +*/ + +S60MediaPlayerService::~S60MediaPlayerService() +{ + DP0("S60MediaPlayerService::~S60MediaPlayerService +++"); + DP0("S60MediaPlayerService::~S60MediaPlayerService ---"); +} + +/*! + \return a pointer to the media control, which matches the controller \a name. + + If the service does not implement the control, or if it is unavailable a + null pointer is returned instead. + + Controls must be returned to the service when no longer needed using the + releaseControl() function. +*/ + +QMediaControl *S60MediaPlayerService::requestControl(const char *name) +{ + DP0("S60MediaPlayerService::requestControl"); + + if (qstrcmp(name, QMediaPlayerControl_iid) == 0) + return m_control; + + if (qstrcmp(name, QMediaNetworkAccessControl_iid) == 0) + return m_networkAccessControl; + + if (qstrcmp(name, QMetaDataReaderControl_iid) == 0) + return m_metaData; + + if (qstrcmp(name, QAudioEndpointSelector_iid) == 0) + return m_audioEndpointSelector; + + if (qstrcmp(name, QMediaStreamsControl_iid) == 0) + return m_streamControl; + + if (!m_videoOutput) { + if (qstrcmp(name, QVideoWidgetControl_iid) == 0) { + m_videoOutput = new S60VideoWidgetControl(this); + } +#ifdef HAS_VIDEORENDERERCONTROL_IN_VIDEOPLAYER + else if (qstrcmp(name, QVideoRendererControl_iid) == 0) { + m_videoOutput = new S60VideoRenderer(this); + } +#endif /* HAS_VIDEORENDERERCONTROL_IN_VIDEOPLAYER */ + else if (qstrcmp(name, QVideoWindowControl_iid) == 0) { + m_videoOutput = new S60VideoWindowControl(this); + } + + if (m_videoOutput) { + m_control->setVideoOutput(m_videoOutput); + return m_videoOutput; + } + }else { + if (qstrcmp(name, QVideoWidgetControl_iid) == 0 || +#ifdef HAS_VIDEORENDERERCONTROL_IN_VIDEOPLAYER + qstrcmp(name, QVideoRendererControl_iid) == 0 || +#endif /* HAS_VIDEORENDERERCONTROL_IN_VIDEOPLAYER */ + qstrcmp(name, QVideoWindowControl_iid) == 0){ + return m_videoOutput; + } + } + return 0; +} + +/*! + Releases a \a control back to the service. +*/ + +void S60MediaPlayerService::releaseControl(QMediaControl *control) +{ + DP0("S60MediaPlayerService::releaseControl ++"); + + if (control == m_videoOutput) { + m_videoOutput = 0; + m_control->setVideoOutput(m_videoOutput); + } + + DP0("S60MediaPlayerService::releaseControl --"); +} + +/*! + * \return media player session(audio playersesion/video playersession) + * by recognizing whether media is audio or video and sets it on media type. +*/ +S60MediaPlayerSession* S60MediaPlayerService::PlayerSession() +{ + DP0("S60MediaPlayerService::PlayerSession"); + + QUrl url = m_control->media().canonicalUrl(); + + if (url.isEmpty() == true) { + return NULL; + } + + QScopedPointer mediaRecognizer(new S60MediaRecognizer); + S60MediaRecognizer::MediaType mediaType = mediaRecognizer->mediaType(url); + mediaRecognizer.reset(); + + switch (mediaType) { + case S60MediaRecognizer::Video: + case S60MediaRecognizer::Url: { + m_control->setMediaType(S60MediaSettings::Video); + return VideoPlayerSession(); + } + case S60MediaRecognizer::Audio: { + m_control->setMediaType(S60MediaSettings::Audio); + return AudioPlayerSession(); + } + default: + m_control->setMediaType(S60MediaSettings::Unknown); + break; + } + + return NULL; +} + +/*! + * \return media playersession (videoplayersession). + * constructs the videoplayersession object and connects all the respective signals and slots. + * and initialises all the media settings. +*/ + +S60MediaPlayerSession* S60MediaPlayerService::VideoPlayerSession() +{ + DP0("S60MediaPlayerService::VideoPlayerSession +++"); + + if (!m_videoPlayerSession) { + m_videoPlayerSession = new S60VideoPlayerSession(this, m_networkAccessControl); + + connect(m_videoPlayerSession, SIGNAL(positionChanged(qint64)), + m_control, SIGNAL(positionChanged(qint64))); + connect(m_videoPlayerSession, SIGNAL(playbackRateChanged(qreal)), + m_control, SIGNAL(playbackRateChanged(qreal))); + connect(m_videoPlayerSession, SIGNAL(volumeChanged(int)), + m_control, SIGNAL(volumeChanged(int))); + connect(m_videoPlayerSession, SIGNAL(mutedChanged(bool)), + m_control, SIGNAL(mutedChanged(bool))); + connect(m_videoPlayerSession, SIGNAL(durationChanged(qint64)), + m_control, SIGNAL(durationChanged(qint64))); + connect(m_videoPlayerSession, SIGNAL(stateChanged(QMediaPlayer::State)), + m_control, SIGNAL(stateChanged(QMediaPlayer::State))); + connect(m_videoPlayerSession, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + m_control, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(m_videoPlayerSession,SIGNAL(bufferStatusChanged(int)), + m_control, SIGNAL(bufferStatusChanged(int))); + connect(m_videoPlayerSession, SIGNAL(videoAvailableChanged(bool)), + m_control, SIGNAL(videoAvailableChanged(bool))); + connect(m_videoPlayerSession, SIGNAL(audioAvailableChanged(bool)), + m_control, SIGNAL(audioAvailableChanged(bool))); + connect(m_videoPlayerSession, SIGNAL(seekableChanged(bool)), + m_control, SIGNAL(seekableChanged(bool))); + connect(m_videoPlayerSession, SIGNAL(availablePlaybackRangesChanged(const QMediaTimeRange&)), + m_control, SIGNAL(availablePlaybackRangesChanged(const QMediaTimeRange&))); + connect(m_videoPlayerSession, SIGNAL(error(int, const QString &)), + m_control, SIGNAL(error(int, const QString &))); + connect(m_videoPlayerSession, SIGNAL(metaDataChanged()), + m_metaData, SIGNAL(metaDataChanged())); + connect(m_videoPlayerSession, SIGNAL(activeEndpointChanged(const QString&)), + m_audioEndpointSelector, SIGNAL(activeEndpointChanged(const QString&))); + connect(m_videoPlayerSession, SIGNAL(mediaChanged()), + m_streamControl, SLOT(handleStreamsChanged())); + connect(m_videoPlayerSession, SIGNAL(accessPointChanged(int)), + m_networkAccessControl, SLOT(accessPointChanged(int))); + + } + + m_videoPlayerSession->setVolume(m_control->mediaControlSettings().volume()); + m_videoPlayerSession->setMuted(m_control->mediaControlSettings().isMuted()); + m_videoPlayerSession->setAudioEndpoint(m_control->mediaControlSettings().audioEndpoint()); + + DP0("S60MediaPlayerService::VideoPlayerSession ---"); + + return m_videoPlayerSession; +} + +/*! + * \return media playersession (audioplayersession). + * constructs the audioplayersession object and connects all the respective signals and slots. + * and initialises all the media settings. +*/ + +S60MediaPlayerSession* S60MediaPlayerService::AudioPlayerSession() +{ + DP0("S60MediaPlayerService::AudioPlayerSession +++"); + + if (!m_audioPlayerSession) { + m_audioPlayerSession = new S60AudioPlayerSession(this); + + connect(m_audioPlayerSession, SIGNAL(positionChanged(qint64)), + m_control, SIGNAL(positionChanged(qint64))); + connect(m_audioPlayerSession, SIGNAL(playbackRateChanged(qreal)), + m_control, SIGNAL(playbackRateChanged(qreal))); + connect(m_audioPlayerSession, SIGNAL(volumeChanged(int)), + m_control, SIGNAL(volumeChanged(int))); + connect(m_audioPlayerSession, SIGNAL(mutedChanged(bool)), + m_control, SIGNAL(mutedChanged(bool))); + connect(m_audioPlayerSession, SIGNAL(durationChanged(qint64)), + m_control, SIGNAL(durationChanged(qint64))); + connect(m_audioPlayerSession, SIGNAL(stateChanged(QMediaPlayer::State)), + m_control, SIGNAL(stateChanged(QMediaPlayer::State))); + connect(m_audioPlayerSession, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + m_control, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(m_audioPlayerSession,SIGNAL(bufferStatusChanged(int)), + m_control, SIGNAL(bufferStatusChanged(int))); + connect(m_audioPlayerSession, SIGNAL(videoAvailableChanged(bool)), + m_control, SIGNAL(videoAvailableChanged(bool))); + connect(m_audioPlayerSession, SIGNAL(audioAvailableChanged(bool)), + m_control, SIGNAL(audioAvailableChanged(bool))); + connect(m_audioPlayerSession, SIGNAL(seekableChanged(bool)), + m_control, SIGNAL(seekableChanged(bool))); + connect(m_audioPlayerSession, SIGNAL(availablePlaybackRangesChanged(const QMediaTimeRange&)), + m_control, SIGNAL(availablePlaybackRangesChanged(const QMediaTimeRange&))); + connect(m_audioPlayerSession, SIGNAL(error(int, const QString &)), + m_control, SIGNAL(error(int, const QString &))); + connect(m_audioPlayerSession, SIGNAL(metaDataChanged()), + m_metaData, SIGNAL(metaDataChanged())); + connect(m_audioPlayerSession, SIGNAL(activeEndpointChanged(const QString&)), + m_audioEndpointSelector, SIGNAL(activeEndpointChanged(const QString&))); + connect(m_audioPlayerSession, SIGNAL(mediaChanged()), + m_streamControl, SLOT(handleStreamsChanged())); + + } + + m_audioPlayerSession->setVolume(m_control->mediaControlSettings().volume()); + m_audioPlayerSession->setMuted(m_control->mediaControlSettings().isMuted()); + m_audioPlayerSession->setAudioEndpoint(m_control->mediaControlSettings().audioEndpoint()); + + DP0("S60MediaPlayerService::AudioPlayerSession ---"); + + return m_audioPlayerSession; +} diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediaplayerservice.h b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayerservice.h new file mode 100644 index 000000000..d45ad45cc --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayerservice.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60VIDEOPLAYERSERVICE_H +#define S60VIDEOPLAYERSERVICE_H + +#include +#include + +#include "ms60mediaplayerresolver.h" +#include "s60mediaplayeraudioendpointselector.h" + +QT_BEGIN_NAMESPACE +class QMediaMetaData; +class QMediaPlayerControl; +class QMediaPlaylist; +QT_END_NAMESPACE + +QT_USE_NAMESPACE + +class S60VideoPlayerSession; +class S60AudioPlayerSession; +class S60MediaPlayerControl; +class S60MediaMetaDataProvider; +class S60MediaStreamControl; +class S60MediaRecognizer; + +class QMediaPlaylistNavigator; +class S60MediaNetworkAccessControl; + +class S60MediaPlayerService : public QMediaService, public MS60MediaPlayerResolver +{ + Q_OBJECT + +public: + + S60MediaPlayerService(QObject *parent = 0); + ~S60MediaPlayerService(); + + QMediaControl *requestControl(const char *name); + void releaseControl(QMediaControl *control); + +protected: // From MS60MediaPlayerResolver + S60MediaPlayerSession* PlayerSession(); + S60MediaPlayerSession* VideoPlayerSession(); + S60MediaPlayerSession* AudioPlayerSession(); + +private: + S60MediaPlayerControl *m_control; + S60VideoPlayerSession *m_videoPlayerSession; + S60AudioPlayerSession *m_audioPlayerSession; + S60MediaMetaDataProvider *m_metaData; + S60MediaPlayerAudioEndpointSelector *m_audioEndpointSelector; + S60MediaStreamControl *m_streamControl; + S60MediaNetworkAccessControl *m_networkAccessControl; + QMediaControl *m_videoOutput; +}; + +#endif diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediaplayersession.cpp b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayersession.cpp new file mode 100644 index 000000000..49a840a2d --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayersession.cpp @@ -0,0 +1,1054 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DebugMacros.h" + +#include "s60mediaplayersession.h" + +#include +#include +#include +#include +#include +#include + +/*! + Construct a media playersession with the given \a parent. +*/ + +S60MediaPlayerSession::S60MediaPlayerSession(QObject *parent) + : QObject(parent) + , m_stream(false) + , m_playbackRate(0) + , m_muted(false) + , m_volume(0) + , m_state(QMediaPlayer::StoppedState) + , m_mediaStatus(QMediaPlayer::NoMedia) + , m_progressTimer(new QTimer(this)) + , m_stalledTimer(new QTimer(this)) + , m_error(KErrNone) + , m_play_requested(false) + , m_seekable(true) +{ + DP0("S60MediaPlayerSession::S60MediaPlayerSession +++"); + + connect(m_progressTimer, SIGNAL(timeout()), this, SLOT(tick())); + connect(m_stalledTimer, SIGNAL(timeout()), this, SLOT(stalled())); + + DP0("S60MediaPlayerSession::S60MediaPlayerSession ---"); +} + +/*! + Destroys a media playersession. +*/ + +S60MediaPlayerSession::~S60MediaPlayerSession() +{ + DP0("S60MediaPlayerSession::~S60MediaPlayerSession +++"); + DP0("S60MediaPlayerSession::~S60MediaPlayerSession ---"); +} + +/*! + * \return the audio volume of a player session. +*/ +int S60MediaPlayerSession::volume() const +{ + DP1("S60MediaPlayerSession::volume", m_volume); + + return m_volume; +} + +/*! + Sets the audio \a volume of a player session. +*/ + +void S60MediaPlayerSession::setVolume(int volume) +{ + DP0("S60MediaPlayerSession::setVolume +++"); + + DP1("S60MediaPlayerSession::setVolume - ", volume); + + if (m_volume == volume) + return; + + m_volume = volume; + emit volumeChanged(m_volume); + + // Dont set symbian players volume until media loaded. + // Leaves with KerrNotReady although documentation says otherwise. + if (!m_muted && + ( mediaStatus() == QMediaPlayer::LoadedMedia + || (mediaStatus() == QMediaPlayer::StalledMedia && state() != QMediaPlayer::StoppedState) + || mediaStatus() == QMediaPlayer::BufferingMedia + || mediaStatus() == QMediaPlayer::BufferedMedia + || mediaStatus() == QMediaPlayer::EndOfMedia)) { + TRAPD(err, doSetVolumeL(m_volume)); + setError(err); + } + DP0("S60MediaPlayerSession::setVolume ---"); +} + +/*! + \return the mute state of a player session. +*/ + +bool S60MediaPlayerSession::isMuted() const +{ + DP1("S60MediaPlayerSession::isMuted", m_muted); + + return m_muted; +} + +/*! + Identifies if the current media is seekable. + + \return true if it possible to seek within the current media, and false otherwise. +*/ + +bool S60MediaPlayerSession::isSeekable() const +{ + DP1("S60MediaPlayerSession::isSeekable", m_seekable); + + return m_seekable; +} + +/*! + Sets the \a status of the current media. +*/ + +void S60MediaPlayerSession::setMediaStatus(QMediaPlayer::MediaStatus status) +{ + DP0("S60MediaPlayerSession::setMediaStatus +++"); + + if (m_mediaStatus == status) + return; + + m_mediaStatus = status; + + emit mediaStatusChanged(m_mediaStatus); + + if (m_play_requested && m_mediaStatus == QMediaPlayer::LoadedMedia) + play(); + + DP0("S60MediaPlayerSession::setMediaStatus ---"); +} + +/*! + Sets the \a state on media player. +*/ + +void S60MediaPlayerSession::setState(QMediaPlayer::State state) +{ + DP0("S60MediaPlayerSession::setState +++"); + + if (m_state == state) + return; + + m_state = state; + emit stateChanged(m_state); + + DP0("S60MediaPlayerSession::setState ---"); +} + +/*! + \return the state of a player session. +*/ + +QMediaPlayer::State S60MediaPlayerSession::state() const +{ + DP1("S60MediaPlayerSession::state", m_state); + + return m_state; +} + +/*! + \return the status of the current media. +*/ + +QMediaPlayer::MediaStatus S60MediaPlayerSession::mediaStatus() const +{ + DP1("S60MediaPlayerSession::mediaStatus", m_mediaStatus); + + return m_mediaStatus; +} + +/*! + * Loads the \a url for playback. + * If \a url is local file then it loads audio playersesion if its audio file. + * If it is a local video file then loads the video playersession. +*/ + +void S60MediaPlayerSession::load(const QMediaContent source) +{ + DP0("S60MediaPlayerSession::load +++"); + + m_source = source; + setMediaStatus(QMediaPlayer::LoadingMedia); + startStalledTimer(); + m_stream = (source.canonicalUrl().scheme() == "file")?false:true; + m_UrlPath = source.canonicalUrl(); + TRAPD(err, + if (m_stream) + doLoadUrlL(QString2TPtrC(source.canonicalUrl().toString())); + else + doLoadL(QString2TPtrC(QDir::toNativeSeparators(source.canonicalUrl().toLocalFile())))); + setError(err); + + DP0("S60MediaPlayerSession::load ---"); +} + +TBool S60MediaPlayerSession::isStreaming() +{ + return m_stream; +} + +/*! + Start or resume playing the current source. +*/ +void S60MediaPlayerSession::play() +{ + DP0("S60MediaPlayerSession::play +++"); + + if ( (state() == QMediaPlayer::PlayingState && m_play_requested == false) + || mediaStatus() == QMediaPlayer::UnknownMediaStatus + || mediaStatus() == QMediaPlayer::NoMedia + || mediaStatus() == QMediaPlayer::InvalidMedia) + return; + + setState(QMediaPlayer::PlayingState); + + if (mediaStatus() == QMediaPlayer::LoadingMedia || + (mediaStatus() == QMediaPlayer::StalledMedia && + state() == QMediaPlayer::StoppedState)) + { + m_play_requested = true; + return; + } + + m_play_requested = false; + m_duration = duration(); + setVolume(m_volume); + setMuted(m_muted); + startProgressTimer(); + doPlay(); + + DP0("S60MediaPlayerSession::play ---"); +} + +/*! + Pause playing the current source. +*/ + +void S60MediaPlayerSession::pause() +{ + DP0("S60MediaPlayerSession::pause +++"); + + if (state() != QMediaPlayer::PlayingState) + return; + + if (mediaStatus() == QMediaPlayer::NoMedia || + mediaStatus() == QMediaPlayer::InvalidMedia) + return; + + setState(QMediaPlayer::PausedState); + stopProgressTimer(); + TRAP_IGNORE(doPauseL()); + m_play_requested = false; + + DP0("S60MediaPlayerSession::pause ---"); +} + +/*! + Stop playing, and reset the play position to the beginning. +*/ + +void S60MediaPlayerSession::stop() +{ + DP0("S60MediaPlayerSession::stop +++"); + + if (state() == QMediaPlayer::StoppedState) + return; + + m_play_requested = false; + m_state = QMediaPlayer::StoppedState; + if (mediaStatus() == QMediaPlayer::BufferingMedia || + mediaStatus() == QMediaPlayer::BufferedMedia || + mediaStatus() == QMediaPlayer::StalledMedia) + setMediaStatus(QMediaPlayer::LoadedMedia); + if (mediaStatus() == QMediaPlayer::LoadingMedia) + setMediaStatus(QMediaPlayer::UnknownMediaStatus); + stopProgressTimer(); + stopStalledTimer(); + doStop(); + emit positionChanged(0); + emit stateChanged(m_state); + + DP0("S60MediaPlayerSession::stop ---"); +} + +/*! + * Stops the playback and closes the controllers. + * And resets all the flags and status, state to default values. +*/ + +void S60MediaPlayerSession::reset() +{ + DP0("S60MediaPlayerSession::reset +++"); + + m_play_requested = false; + setError(KErrNone, QString(), true); + stopProgressTimer(); + stopStalledTimer(); + doStop(); + doClose(); + setState(QMediaPlayer::StoppedState); + setMediaStatus(QMediaPlayer::UnknownMediaStatus); + setPosition(0); + + DP0("S60MediaPlayerSession::reset ---"); +} + +/*! + * Sets \a renderer as video renderer. +*/ + +void S60MediaPlayerSession::setVideoRenderer(QObject *renderer) +{ + DP0("S60MediaPlayerSession::setVideoRenderer +++"); + + Q_UNUSED(renderer); + + DP0("S60MediaPlayerSession::setVideoRenderer ---"); +} + +/*! + * the percentage of the temporary buffer filled before playback begins. + + When the player object is buffering; this property holds the percentage of + the temporary buffer that is filled. The buffer will need to reach 100% + filled before playback can resume, at which time the MediaStatus will be + BufferedMedia. + + \sa mediaStatus() +*/ + +int S60MediaPlayerSession::bufferStatus() +{ + DP0("S60MediaPlayerSession::bufferStatus"); + + if (state() ==QMediaPlayer::StoppedState) + return 0; + + if( mediaStatus() == QMediaPlayer::LoadingMedia + || mediaStatus() == QMediaPlayer::UnknownMediaStatus + || mediaStatus() == QMediaPlayer::NoMedia + || mediaStatus() == QMediaPlayer::InvalidMedia) + return 0; + + int progress = 0; + TRAPD(err, progress = doGetBufferStatusL()); + // If buffer status query not supported by codec return 100 + // do not set error + if(err == KErrNotSupported) + return 100; + + setError(err); + return progress; +} + +/*! + * return TRUE if Meta data is available in current media source. +*/ + +bool S60MediaPlayerSession::isMetadataAvailable() const +{ + DP0("S60MediaPlayerSession::isMetadataAvailable"); + + return !m_metaDataMap.isEmpty(); +} + +/*! + * \return the \a key meta data. +*/ +QVariant S60MediaPlayerSession::metaData(const QString &key) const +{ + DP0("S60MediaPlayerSession::metaData (const QString &key) const"); + + return m_metaDataMap.value(key); +} + +/*! + * \return the \a key meta data as QString. +*/ + +QVariant S60MediaPlayerSession::metaData(QtMultimediaKit::MetaData key) const +{ + DP0("S60MediaPlayerSession::metaData (QtMultimediaKit::MetaData key) const"); + + return metaData(metaDataKeyAsString(key)); +} + +/*! + * \return List of all available meta data from current media source. +*/ + +QList S60MediaPlayerSession::availableMetaData() const +{ + DP0("S60MediaPlayerSession::availableMetaData +++"); + + QList metaDataTags; + if (isMetadataAvailable()) { + for (int i = QtMultimediaKit::Title; i <= QtMultimediaKit::ThumbnailImage; i++) { + QString metaDataItem = metaDataKeyAsString((QtMultimediaKit::MetaData)i); + if (!metaDataItem.isEmpty()) { + if (!metaData(metaDataItem).isNull()) { + metaDataTags.append((QtMultimediaKit::MetaData)i); + } + } + } + } + + DP0("S60MediaPlayerSession::availableMetaData ---"); + + return metaDataTags; +} + +/*! + * \return all available extended meta data of current media source. +*/ + +QStringList S60MediaPlayerSession::availableExtendedMetaData() const +{ + DP0("S60MediaPlayerSession::availableExtendedMetaData"); + + return m_metaDataMap.keys(); +} + +/*! + * \return meta data \a key as QString. +*/ + +QString S60MediaPlayerSession::metaDataKeyAsString(QtMultimediaKit::MetaData key) const +{ + DP1("S60MediaPlayerSession::metaDataKeyAsString", key); + + switch(key) { + case QtMultimediaKit::Title: return "title"; + case QtMultimediaKit::AlbumArtist: return "artist"; + case QtMultimediaKit::Comment: return "comment"; + case QtMultimediaKit::Genre: return "genre"; + case QtMultimediaKit::Year: return "year"; + case QtMultimediaKit::Copyright: return "copyright"; + case QtMultimediaKit::AlbumTitle: return "album"; + case QtMultimediaKit::Composer: return "composer"; + case QtMultimediaKit::TrackNumber: return "albumtrack"; + case QtMultimediaKit::AudioBitRate: return "audiobitrate"; + case QtMultimediaKit::VideoBitRate: return "videobitrate"; + case QtMultimediaKit::Duration: return "duration"; + case QtMultimediaKit::MediaType: return "contenttype"; + case QtMultimediaKit::CoverArtImage: return "attachedpicture"; + case QtMultimediaKit::SubTitle: // TODO: Find the matching metadata keys + case QtMultimediaKit::Description: + case QtMultimediaKit::Category: + case QtMultimediaKit::Date: + case QtMultimediaKit::UserRating: + case QtMultimediaKit::Keywords: + case QtMultimediaKit::Language: + case QtMultimediaKit::Publisher: + case QtMultimediaKit::ParentalRating: + case QtMultimediaKit::RatingOrganisation: + case QtMultimediaKit::Size: + case QtMultimediaKit::AudioCodec: + case QtMultimediaKit::AverageLevel: + case QtMultimediaKit::ChannelCount: + case QtMultimediaKit::PeakValue: + case QtMultimediaKit::SampleRate: + case QtMultimediaKit::Author: + case QtMultimediaKit::ContributingArtist: + case QtMultimediaKit::Conductor: + case QtMultimediaKit::Lyrics: + case QtMultimediaKit::Mood: + case QtMultimediaKit::TrackCount: + case QtMultimediaKit::CoverArtUrlSmall: + case QtMultimediaKit::CoverArtUrlLarge: + case QtMultimediaKit::Resolution: + case QtMultimediaKit::PixelAspectRatio: + case QtMultimediaKit::VideoFrameRate: + case QtMultimediaKit::VideoCodec: + case QtMultimediaKit::PosterUrl: + case QtMultimediaKit::ChapterNumber: + case QtMultimediaKit::Director: + case QtMultimediaKit::LeadPerformer: + case QtMultimediaKit::Writer: + case QtMultimediaKit::CameraManufacturer: + case QtMultimediaKit::CameraModel: + case QtMultimediaKit::Event: + case QtMultimediaKit::Subject: + default: + break; + } + + return QString(); +} + +/*! + Sets the \a muted state of a player session. +*/ + +void S60MediaPlayerSession::setMuted(bool muted) +{ + DP0("S60MediaPlayerSession::setMuted +++"); + DP1("S60MediaPlayerSession::setMuted - ", muted); + + m_muted = muted; + emit mutedChanged(m_muted); + + if( m_mediaStatus == QMediaPlayer::LoadedMedia + || (m_mediaStatus == QMediaPlayer::StalledMedia && state() != QMediaPlayer::StoppedState) + || m_mediaStatus == QMediaPlayer::BufferingMedia + || m_mediaStatus == QMediaPlayer::BufferedMedia + || m_mediaStatus == QMediaPlayer::EndOfMedia) { + TRAPD(err, doSetVolumeL((m_muted)?0:m_volume)); + setError(err); + } + DP0("S60MediaPlayerSession::setMuted ---"); +} + +/*! + \return the duration of the current media in milliseconds. +*/ + +qint64 S60MediaPlayerSession::duration() const +{ + // DP0("S60MediaPlayerSession::duration"); + + if( mediaStatus() == QMediaPlayer::LoadingMedia + || mediaStatus() == QMediaPlayer::UnknownMediaStatus + || mediaStatus() == QMediaPlayer::NoMedia + || (mediaStatus() == QMediaPlayer::StalledMedia && state() == QMediaPlayer::StoppedState) + || mediaStatus() == QMediaPlayer::InvalidMedia) + return -1; + + qint64 pos = 0; + TRAP_IGNORE(pos = doGetDurationL()); + return pos; +} + +/*! + \return the current playback position in milliseconds. +*/ + +qint64 S60MediaPlayerSession::position() const +{ + // DP0("S60MediaPlayerSession::position"); + + if( mediaStatus() == QMediaPlayer::LoadingMedia + || mediaStatus() == QMediaPlayer::UnknownMediaStatus + || mediaStatus() == QMediaPlayer::NoMedia + || (mediaStatus() == QMediaPlayer::StalledMedia && state() == QMediaPlayer::StoppedState) + || mediaStatus() == QMediaPlayer::InvalidMedia) + return 0; + + qint64 pos = 0; + TRAP_IGNORE(pos = doGetPositionL()); + if (!m_play_requested && pos ==0 + && mediaStatus() != QMediaPlayer::LoadedMedia) + return m_duration; + return pos; +} + +/*! + Sets the playback \a pos of the current media. This will initiate a seek and it may take + some time for playback to reach the position set. +*/ + +void S60MediaPlayerSession::setPosition(qint64 pos) +{ + DP0("S60MediaPlayerSession::setPosition +++"); + + DP1("S60MediaPlayerSession::setPosition - ", pos); + + if (position() == pos) + return; + + QMediaPlayer::State originalState = state(); + + if (originalState == QMediaPlayer::PlayingState) + pause(); + + TRAPD(err, doSetPositionL(pos * 1000)); + setError(err); + + if (err == KErrNone) { + if (mediaStatus() == QMediaPlayer::EndOfMedia) + setMediaStatus(QMediaPlayer::LoadedMedia); + } + else if (err == KErrNotSupported) { + m_seekable = false; + emit seekableChanged(m_seekable); + } + + if (originalState == QMediaPlayer::PlayingState) + play(); + + emit positionChanged(position()); + + DP0("S60MediaPlayerSession::setPosition ---"); +} + +/*! + * Set the audio endpoint to \a audioEndpoint. +*/ + +void S60MediaPlayerSession::setAudioEndpoint(const QString& audioEndpoint) +{ + DP0("S60MediaPlayerSession::setAudioEndpoint +++"); + + DP1("S60MediaPlayerSession::setAudioEndpoint - ", audioEndpoint); + + doSetAudioEndpoint(audioEndpoint); + + DP0("S60MediaPlayerSession::setAudioEndpoint ---"); +} + +/*! + * Loading of media source is completed. + * And ready for playback. Updates all the media status, state, settings etc. + * And emits the signals. +*/ + +void S60MediaPlayerSession::loaded() +{ + DP0("S60MediaPlayerSession::loaded +++"); + + stopStalledTimer(); + if (m_error == KErrNone || m_error == KErrMMPartialPlayback) { + setMediaStatus(QMediaPlayer::LoadedMedia); + TRAPD(err, updateMetaDataEntriesL()); + setError(err); + emit durationChanged(duration()); + emit positionChanged(0); + emit videoAvailableChanged(isVideoAvailable()); + emit audioAvailableChanged(isAudioAvailable()); + emit mediaChanged(); + + m_seekable = getIsSeekable(); + } + + DP0("S60MediaPlayerSession::loaded ---"); +} + +/*! + * Playback is completed as medai source reached end of media. +*/ +void S60MediaPlayerSession::endOfMedia() +{ + DP0("S60MediaPlayerSession::endOfMedia +++"); + + m_state = QMediaPlayer::StoppedState; + setMediaStatus(QMediaPlayer::EndOfMedia); + //there is a chance that user might have called play from EOF callback + //if we are already in playing state, do not send state change callback + if(m_state == QMediaPlayer::StoppedState) + emit stateChanged(QMediaPlayer::StoppedState); + emit positionChanged(m_duration); + + DP0("S60MediaPlayerSession::endOfMedia ---"); +} + +/*! + * The percentage of the temporary buffer filling before playback begins. + + When the player object is buffering; this property holds the percentage of + the temporary buffer that is filled. The buffer will need to reach 100% + filled before playback can resume, at which time the MediaStatus will be + BufferedMedia. + + \sa mediaStatus() +*/ + +void S60MediaPlayerSession::buffering() +{ + DP0("S60MediaPlayerSession::buffering +++"); + + startStalledTimer(); + setMediaStatus(QMediaPlayer::BufferingMedia); + +//Buffering cannot happen in stopped state. Hence update the state + if (state() == QMediaPlayer::StoppedState) + setState(QMediaPlayer::PausedState); + + DP0("S60MediaPlayerSession::buffering ---"); +} + +/*! + * Buffer is filled with data and to for continuing/start playback. +*/ + +void S60MediaPlayerSession::buffered() +{ + DP0("S60MediaPlayerSession::buffered +++"); + + stopStalledTimer(); + setMediaStatus(QMediaPlayer::BufferedMedia); + + DP0("S60MediaPlayerSession::buffered ---"); +} + +/*! + * Sets media status as stalled as waiting for the buffer to be filled to start playback. +*/ + +void S60MediaPlayerSession::stalled() +{ + DP0("S60MediaPlayerSession::stalled +++"); + + setMediaStatus(QMediaPlayer::StalledMedia); + + DP0("S60MediaPlayerSession::stalled ---"); +} + +/*! + * \return all the meta data entries in the current media source. +*/ + +QMap& S60MediaPlayerSession::metaDataEntries() +{ + DP0("S60MediaPlayerSession::metaDataEntries"); + + return m_metaDataMap; +} + +/*! + * \return Error by converting Symbian specific error to Multimedia error. +*/ + +QMediaPlayer::Error S60MediaPlayerSession::fromSymbianErrorToMultimediaError(int error) +{ + DP0("S60MediaPlayerSession::fromSymbianErrorToMultimediaError"); + + DP1("S60MediaPlayerSession::fromSymbianErrorToMultimediaError - ", error); + + switch(error) { + case KErrNoMemory: + case KErrNotFound: + case KErrBadHandle: + case KErrAbort: + case KErrNotSupported: + case KErrCorrupt: + case KErrGeneral: + case KErrArgument: + case KErrPathNotFound: + case KErrDied: + case KErrServerTerminated: + case KErrServerBusy: + case KErrCompletion: + case KErrBadPower: + case KErrMMInvalidProtocol: + case KErrMMInvalidURL: + return QMediaPlayer::ResourceError; + + case KErrMMPartialPlayback: + return QMediaPlayer::FormatError; + + case KErrMMAudioDevice: + case KErrMMVideoDevice: + case KErrMMDecoder: + case KErrUnknown: + return QMediaPlayer::ServiceMissingError; + + case KErrMMNotEnoughBandwidth: + case KErrMMSocketServiceNotFound: + case KErrMMNetworkRead: + case KErrMMNetworkWrite: + case KErrMMServerSocket: + case KErrMMServerNotSupported: + case KErrMMUDPReceive: + case KErrMMMulticast: + case KErrMMProxyServer: + case KErrMMProxyServerNotSupported: + case KErrMMProxyServerConnect: + case KErrCouldNotConnect: + return QMediaPlayer::NetworkError; + + case KErrNotReady: + case KErrInUse: + case KErrAccessDenied: + case KErrLocked: + case KErrMMDRMNotAuthorized: + case KErrPermissionDenied: + case KErrCancel: + case KErrAlreadyExists: + return QMediaPlayer::AccessDeniedError; + + case KErrNone: + return QMediaPlayer::NoError; + + default: + return QMediaPlayer::ResourceError; + } +} + +/*! + * \return error. + */ + +int S60MediaPlayerSession::error() const +{ + DP1("S60MediaPlayerSession::error", m_error); + + return m_error; +} + +/*! + * Sets the error. + * * If playback complete/prepare complete ..., etc with successful then sets error as ZERO + * else Multimedia error. +*/ + +void S60MediaPlayerSession::setError(int error, const QString &errorString, bool forceReset) +{ + DP0("S60MediaPlayerSession::setError +++"); + + DP5("S60MediaPlayerSession::setError - error:", error,"errorString:", errorString, "forceReset:", forceReset); + + if( forceReset ) { + m_error = KErrNone; + emit this->error(QMediaPlayer::NoError, QString()); + return; + } + + // If error does not change and m_error is reseted without forceReset flag + if (error == m_error || + (m_error != KErrNone && error == KErrNone)) + return; + + m_error = error; + QMediaPlayer::Error mediaError = fromSymbianErrorToMultimediaError(m_error); + QString symbianError = QString(errorString); + + if (mediaError != QMediaPlayer::NoError) { + // TODO: fix to user friendly string at some point + // These error string are only dev usable + symbianError.append("Symbian:"); + symbianError.append(QString::number(m_error)); + } + + emit this->error(mediaError, symbianError); + + if (m_error == KErrInUse) { + pause(); + } else if (mediaError != QMediaPlayer::NoError) { + m_play_requested = false; + setMediaStatus(QMediaPlayer::InvalidMedia); + stop(); + } +} + +void S60MediaPlayerSession::setAndEmitError(int error) +{ + m_error = error; + QMediaPlayer::Error rateError = fromSymbianErrorToMultimediaError(error); + QString symbianError; + symbianError.append("Symbian:"); + symbianError.append(QString::number(error)); + emit this->error(rateError, symbianError); + + DP0("S60MediaPlayerSession::setError ---"); +} + +/*! + * emits the signal if there is a changes in position and buffering status. + */ + +void S60MediaPlayerSession::tick() +{ + DP0("S60MediaPlayerSession::tick +++"); + + emit positionChanged(position()); + + if (bufferStatus() < 100) + emit bufferStatusChanged(bufferStatus()); + + DP0("S60MediaPlayerSession::tick ---"); +} + +/*! + * Starts the timer once the media source starts buffering. +*/ + +void S60MediaPlayerSession::startProgressTimer() +{ + DP0("S60MediaPlayerSession::startProgressTimer +++"); + + m_progressTimer->start(500); + + DP0("S60MediaPlayerSession::startProgressTimer ---"); +} + +/*! + * Stops the timer once the media source finished buffering. +*/ + +void S60MediaPlayerSession::stopProgressTimer() +{ + DP0("S60MediaPlayerSession::stopProgressTimer +++"); + + m_progressTimer->stop(); + + DP0("S60MediaPlayerSession::stopProgressTimer ---"); +} + +/*! + * Starts the timer while waiting for some events to happen like source buffering or call backs etc. + * So that if the events doesn't occur before stalled timer stops, it'll set the error/media status etc. +*/ + +void S60MediaPlayerSession::startStalledTimer() +{ + DP0("S60MediaPlayerSession::startStalledTimer +++"); + + m_stalledTimer->start(30000); + + DP0("S60MediaPlayerSession::startStalledTimer ---"); +} + +/*! + * Stops the timer when some events occurred while waiting for them. + * media source started buffering or call back is received etc. +*/ + +void S60MediaPlayerSession::stopStalledTimer() +{ + DP0("S60MediaPlayerSession::stopStalledTimer +++"); + + m_stalledTimer->stop(); + + DP0("S60MediaPlayerSession::stopStalledTimer ---"); +} + +/*! + * \return Converted Symbian specific Descriptor to QString. +*/ + +QString S60MediaPlayerSession::TDesC2QString(const TDesC& aDescriptor) +{ + DP0("S60MediaPlayerSession::TDesC2QString"); + + return QString::fromUtf16(aDescriptor.Ptr(), aDescriptor.Length()); +} + +/*! + * \return Converted QString to non-modifiable pointer Descriptor. +*/ + +TPtrC S60MediaPlayerSession::QString2TPtrC( const QString& string ) +{ + DP0("S60MediaPlayerSession::QString2TPtrC"); + + // Returned TPtrC is valid as long as the given parameter is valid and unmodified + return TPtrC16(static_cast(string.utf16()), string.length()); +} + +/*! + * \return Converted Symbian TRect object to QRect object. +*/ + +QRect S60MediaPlayerSession::TRect2QRect(const TRect& tr) +{ + DP0("S60MediaPlayerSession::TRect2QRect"); + + return QRect(tr.iTl.iX, tr.iTl.iY, tr.Width(), tr.Height()); +} + +/*! + * \return converted QRect object to Symbian specific TRec object. + */ + +TRect S60MediaPlayerSession::QRect2TRect(const QRect& qr) +{ + DP0("S60MediaPlayerSession::QRect2TRect"); + + return TRect(TPoint(qr.left(), qr.top()), TSize(qr.width(), qr.height())); +} + +/*! + \fn bool S60MediaPlayerSession::isVideoAvailable(); + + + Returns TRUE if Video is available. +*/ + +/*! + \fn bool S60MediaPlayerSession::isAudioAvailable(); + + + Returns TRUE if Audio is available. +*/ + +/*! + \fn void S60MediaPlayerSession::setPlaybackRate (qreal rate); + + + Sets \a rate play back rate on media source. getIsSeekable +*/ + +/*! + \fn bool S60MediaPlayerSession::getIsSeekable () const; + + + \return TRUE if Seekable possible on current media source else FALSE. +*/ + +/*! + \fn QString S60MediaPlayerSession::activeEndpoint () const; + + + \return active end point name.. +*/ + +/*! + \fn QString S60MediaPlayerSession::defaultEndpoint () const; + + + \return default end point name. +*/ + diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediaplayersession.h b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayersession.h new file mode 100644 index 000000000..e6889d101 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayersession.h @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60MEDIAPLAYERSESSION_H +#define S60MEDIAPLAYERSESSION_H + +#include +#include +#include +#include +#include // for TDesC +#include +#include "s60mediaplayerservice.h" + + +_LIT( KSeekable, "Seekable" ); +_LIT( KFalse, "0"); + +QT_BEGIN_NAMESPACE +class QMediaTimeRange; +QT_END_NAMESPACE + +class QTimer; + +class S60MediaPlayerSession : public QObject +{ + Q_OBJECT + +public: + S60MediaPlayerSession(QObject *parent); + virtual ~S60MediaPlayerSession(); + + // for player control interface to use + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + qint64 duration() const; + qint64 position() const; + void setPosition(qint64 pos); + int volume() const; + void setVolume(int volume); + bool isMuted() const; + void setMuted(bool muted); + virtual bool isVideoAvailable() = 0; + virtual bool isAudioAvailable() = 0; + bool isSeekable() const; + void play(); + void pause(); + void stop(); + void reset(); + bool isMetadataAvailable() const; + QVariant metaData(const QString &key) const; + QVariant metaData(QtMultimediaKit::MetaData key) const; + QList availableMetaData() const; + QStringList availableExtendedMetaData() const; + QString metaDataKeyAsString(QtMultimediaKit::MetaData key) const; + void load(const QMediaContent source); + int bufferStatus(); + virtual void setVideoRenderer(QObject *renderer); + void setMediaStatus(QMediaPlayer::MediaStatus); + void setState(QMediaPlayer::State state); + void setAudioEndpoint(const QString& audioEndpoint); + virtual void setPlaybackRate(qreal rate) = 0; + virtual bool getIsSeekable() const { return ETrue; } + TBool isStreaming(); + +protected: + virtual void doLoadL(const TDesC &path) = 0; + virtual void doLoadUrlL(const TDesC &path) = 0; + virtual void doPlay() = 0; + virtual void doStop() = 0; + virtual void doClose() = 0; + virtual void doPauseL() = 0; + virtual void doSetVolumeL(int volume) = 0; + virtual void doSetPositionL(qint64 microSeconds) = 0; + virtual qint64 doGetPositionL() const = 0; + virtual void updateMetaDataEntriesL() = 0; + virtual int doGetBufferStatusL() const = 0; + virtual qint64 doGetDurationL() const = 0; + virtual void doSetAudioEndpoint(const QString& audioEndpoint) = 0; + +public: + // From S60MediaPlayerAudioEndpointSelector + virtual QString activeEndpoint() const = 0; + virtual QString defaultEndpoint() const = 0; +public Q_SLOTS: + virtual void setActiveEndpoint(const QString& name) = 0; + +protected: + int error() const; + void setError(int error, const QString &errorString = QString(), bool forceReset = false); + void setAndEmitError(int error); + void loaded(); + void buffering(); + void buffered(); + void endOfMedia(); + QMap& metaDataEntries(); + QMediaPlayer::Error fromSymbianErrorToMultimediaError(int error); + void startProgressTimer(); + void stopProgressTimer(); + void startStalledTimer(); + void stopStalledTimer(); + QString TDesC2QString(const TDesC& aDescriptor); + TPtrC QString2TPtrC( const QString& string ); + QRect TRect2QRect(const TRect& tr); + TRect QRect2TRect(const QRect& qr); + +protected slots: + void tick(); + void stalled(); + +signals: + void durationChanged(qint64 duration); + void positionChanged(qint64 position); + void stateChanged(QMediaPlayer::State state); + void mediaStatusChanged(QMediaPlayer::MediaStatus mediaStatus); + void videoAvailableChanged(bool videoAvailable); + void audioAvailableChanged(bool audioAvailable); + void bufferStatusChanged(int percentFilled); + void seekableChanged(bool); + void availablePlaybackRangesChanged(const QMediaTimeRange&); + void metaDataChanged(); + void error(int error, const QString &errorString); + void activeEndpointChanged(const QString &name); + void mediaChanged(); + void playbackRateChanged(qreal rate); + void volumeChanged(int volume); + void mutedChanged(bool muted); + +protected: + QUrl m_UrlPath; + bool m_stream; + QMediaContent m_source; + +private: + qreal m_playbackRate; + QMap m_metaDataMap; + bool m_muted; + int m_volume; + QMediaPlayer::State m_state; + QMediaPlayer::MediaStatus m_mediaStatus; + QTimer *m_progressTimer; + QTimer *m_stalledTimer; + int m_error; + bool m_play_requested; + bool m_seekable; + qint64 m_duration; +}; + +#endif diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediarecognizer.cpp b/src/plugins/symbian/mmf/mediaplayer/s60mediarecognizer.cpp new file mode 100644 index 000000000..48b565c34 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediarecognizer.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DebugMacros.h" + +#include "s60mediarecognizer.h" +#include +#include +#include +#include +#include + +#include + +static const TInt KMimeTypePrefixLength = 6; // "audio/" or "video/" + +_LIT(KMimeTypePrefixAudio, "audio/"); +_LIT(KMimeTypePrefixVideo, "video/"); +_LIT(KMimeTypeRingingTone, "application/vnd.nokia.ringing-tone"); + +/*! + Construct a media Recognizer with the given \a parent. +*/ + +S60MediaRecognizer::S60MediaRecognizer(QObject *parent) : QObject(parent) +{ + DP0("S60MediaRecognizer::S60MediaRecognizer +++"); + DP0("S60MediaRecognizer::S60MediaRecognizer ---"); +} + +/*! + Destroys a media Recognizer. +*/ + +S60MediaRecognizer::~S60MediaRecognizer() +{ + DP0("S60MediaRecognizer::~S60MediaRecognizer +++"); + + m_file.Close(); + m_fileServer.Close(); + m_recognizer.Close(); + + DP0("S60MediaRecognizer::~S60MediaRecognizer ---"); +} + +/*! + * \return media type of \a url. + * \a url may be a streaming link or a local file. + * If \a url is local file then identifies the media type and returns it. +*/ + +S60MediaRecognizer::MediaType S60MediaRecognizer::mediaType(const QUrl &url) +{ + DP0("S60MediaRecognizer::mediaType"); + + bool isStream = (url.scheme() == "file")?false:true; + + if (isStream) + return Url; + else + return identifyMediaType(QDir::cleanPath(url.toLocalFile())); +} + +/*! + * \return Media type of \a file name by recognizing its mimetype whether its audio or video. +*/ + +S60MediaRecognizer::MediaType S60MediaRecognizer::identifyMediaType(const QString& fileName) +{ + DP0("S60MediaRecognizer::identifyMediaType +++"); + + DP1("S60MediaRecognizer::identifyMediaType - ", fileName); + + S60MediaRecognizer::MediaType result = Video; // default to videoplayer + bool recognizerOpened = false; + + TInt err = m_recognizer.Connect(); + if (err == KErrNone) { + recognizerOpened = true; + } + + err = m_fileServer.Connect(); + if (err == KErrNone) { + recognizerOpened = true; + } + + // This is needed for sharing file handles for the recognizer + err = m_fileServer.ShareProtected(); + if (err == KErrNone) { + recognizerOpened = true; + } + + if (recognizerOpened) { + m_file.Close(); + err = m_file.Open(m_fileServer, QString2TPtrC(QDir::toNativeSeparators(fileName)), EFileRead | + EFileShareReadersOnly); + + if (err == KErrNone) { + TDataRecognitionResult recognizerResult; + err = m_recognizer.RecognizeData(m_file, recognizerResult); + if (err == KErrNone) { + const TPtrC mimeType = recognizerResult.iDataType.Des(); + + if (mimeType.Left(KMimeTypePrefixLength).Compare(KMimeTypePrefixAudio) == 0 || + mimeType.Compare(KMimeTypeRingingTone) == 0) { + result = Audio; + } else if (mimeType.Left(KMimeTypePrefixLength).Compare(KMimeTypePrefixVideo) == 0) { + result = Video; + } + } + } + } + + DP0("S60MediaRecognizer::identifyMediaType ---"); + + return result; +} + +/*! + * \return Symbian modifiable pointer descriptor from a QString \a string. + */ + +TPtrC S60MediaRecognizer::QString2TPtrC( const QString& string ) +{ + DP1("S60MediaRecognizer::QString2TPtrC - ", string); + + // Returned TPtrC is valid as long as the given parameter is valid and unmodified + return TPtrC16(static_cast(string.utf16()), string.length()); +} diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediarecognizer.h b/src/plugins/symbian/mmf/mediaplayer/s60mediarecognizer.h new file mode 100644 index 000000000..bdd0caabe --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediarecognizer.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60MEDIARECOGNIZER_H_ +#define S60MEDIARECOGNIZER_H_ + +#include + +#include +#include + +class QUrl; + +class S60MediaRecognizer : public QObject +{ + Q_OBJECT + +public: + enum MediaType { + Audio, + Video, + Url, + NotSupported = -1 + }; + + S60MediaRecognizer(QObject *parent = 0); + ~S60MediaRecognizer(); + + S60MediaRecognizer::MediaType mediaType(const QUrl &url); + S60MediaRecognizer::MediaType identifyMediaType(const QString& fileName); + +protected: + TPtrC QString2TPtrC( const QString& string ); + +private: + RApaLsSession m_recognizer; + RFile m_file; + RFs m_fileServer; +}; + +#endif /* S60MEDIARECOGNIZER_H_ */ diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediastreamcontrol.cpp b/src/plugins/symbian/mmf/mediaplayer/s60mediastreamcontrol.cpp new file mode 100644 index 000000000..9a2ce5c02 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediastreamcontrol.cpp @@ -0,0 +1,201 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DebugMacros.h" + +#include "s60mediastreamcontrol.h" +#include "s60mediaplayersession.h" +#include "s60mediaplayercontrol.h" +#include + +#include +#include +#include + +/*! + Constructs a new media streams control with the given \a control. +*/ + +S60MediaStreamControl::S60MediaStreamControl(QObject *control, QObject *parent) + : QMediaStreamsControl(parent) + , m_control(NULL) + , m_mediaType(S60MediaSettings::Unknown) +{ + DP0("S60MediaStreamControl::S60MediaStreamControl +++"); + + m_control = qobject_cast(control); + m_mediaType = m_control->mediaControlSettings().mediaType(); + + DP0("S60MediaStreamControl::S60MediaStreamControl ---"); +} + +/*! + Destroys a media streams control. +*/ + +S60MediaStreamControl::~S60MediaStreamControl() +{ + DP0("S60MediaStreamControl::~S60MediaStreamControl +++"); + DP0("S60MediaStreamControl::~S60MediaStreamControl ---"); +} + +/*! + \return the number of media streams. +*/ + +int S60MediaStreamControl::streamCount() +{ + DP0("S60MediaStreamControl::streamCount"); + + int streamCount = 0; + if (m_control->isAudioAvailable()) + streamCount++; + if (m_control->isVideoAvailable()) + streamCount++; + DP1("S60MediaStreamControl::streamCount", streamCount); + + return streamCount; +} + +/*! + \return the type of a media \a streamNumber. +*/ + +QMediaStreamsControl::StreamType S60MediaStreamControl::streamType(int streamNumber) +{ + DP0("S60MediaStreamControl::streamType +++"); + + DP1("S60MediaStreamControl::streamType - ", streamNumber); + + Q_UNUSED(streamNumber); + + QMediaStreamsControl::StreamType type = QMediaStreamsControl::UnknownStream; + + if (m_control->mediaControlSettings().mediaType() == S60MediaSettings::Video) + type = QMediaStreamsControl::VideoStream; + else + type = QMediaStreamsControl::AudioStream; + + DP0("S60MediaStreamControl::streamType ---"); + + return type; +} + +/*! + \return the meta-data value of \a key for a given \a streamNumber. + + Useful metadata keya are QtMultimediaKit::Title, QtMultimediaKit::Description and QtMultimediaKit::Language. +*/ + +QVariant S60MediaStreamControl::metaData(int streamNumber, QtMultimediaKit::MetaData key) +{ + DP0("S60MediaStreamControl::metaData"); + + Q_UNUSED(streamNumber); + + if (m_control->session()) { + if (m_control->session()->isMetadataAvailable()) + return m_control->session()->metaData(key); + } + return QVariant(); +} + +/*! + \return true if the media \a streamNumber is active else false. +*/ + +bool S60MediaStreamControl::isActive(int streamNumber) +{ + DP0("S60MediaStreamControl::isActive +++"); + + DP1("S60MediaStreamControl::isActive - ", streamNumber); + + if (m_control->mediaControlSettings().mediaType() == S60MediaSettings::Video) { + switch (streamNumber) { + case 1: + return m_control->isVideoAvailable(); + case 2: + return m_control->isAudioAvailable(); + default: + break; + } + } + + DP0("S60MediaStreamControl::isActive ---"); + + return m_control->isAudioAvailable(); +} + +/*! + Sets the active \a streamNumber of a media \a state. + + Symbian MMF does not support enabling or disabling specific media streams. + + Setting the active state of a media stream to true will activate it. If any other stream + of the same type was previously active it will be deactivated. Setting the active state fo a + media stream to false will deactivate it. +*/ + +void S60MediaStreamControl::setActive(int streamNumber, bool state) +{ + DP0("S60MediaStreamControl::setActive +++"); + + DP2("S60MediaStreamControl::setActive - ", streamNumber, state); + + Q_UNUSED(streamNumber); + Q_UNUSED(state); + // Symbian MMF does not support enabling or disabling specific media streams + + DP0("S60MediaStreamControl::setActive ---"); +} + +/*! + The signal is emitted when the available streams list is changed. +*/ + +void S60MediaStreamControl::handleStreamsChanged() +{ + DP0("S60MediaStreamControl::handleStreamsChanged +++"); + + emit streamsChanged(); + + DP0("S60MediaStreamControl::handleStreamsChanged ---"); +} diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediastreamcontrol.h b/src/plugins/symbian/mmf/mediaplayer/s60mediastreamcontrol.h new file mode 100644 index 000000000..702ebc7b2 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediastreamcontrol.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60MEDIASTREAMCONTROL_H +#define S60MEDIASTREAMCONTROL_H + +#include + +#include "s60mediaplayercontrol.h" + +#include +#include + +QT_USE_NAMESPACE + +class S60MediaPlayerControl; +class S60MediaSettings; + +class S60MediaStreamControl : public QMediaStreamsControl +{ + Q_OBJECT +public: + S60MediaStreamControl(QObject *session, QObject *parent = 0); + ~S60MediaStreamControl(); + + // from QMediaStreamsControl + int streamCount(); + QMediaStreamsControl::StreamType streamType(int streamNumber); + QVariant metaData(int streamNumber, QtMultimediaKit::MetaData key); + bool isActive(int streamNumber); + void setActive(int streamNumber, bool state); + +public Q_SLOTS: + void handleStreamsChanged(); + +private: + S60MediaPlayerControl *m_control; + S60MediaSettings::TMediaType m_mediaType; +}; + +#endif //S60MEDIASTREAMCONTROL_H diff --git a/src/plugins/symbian/mmf/mediaplayer/s60videooutputinterface.h b/src/plugins/symbian/mmf/mediaplayer/s60videooutputinterface.h new file mode 100644 index 000000000..f5388dbbc --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60videooutputinterface.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60VIDEOOUTPUTINTERFACE_H +#define S60VIDEOOUTPUTINTERFACE_H + +#include +#include +#include + +class S60VideoOutputInterface +{ +public: + RWindow *videoWindowHandle() const { return videoWinId() ? static_cast(videoWinId()->DrawableWindow()) : 0 ; } + virtual WId videoWinId() const = 0; + // If VIDEOOUTPUT_GRAPHICS_SURFACES is defined, the return value is the video + // rectangle relative to the video window. If not, the return value is the + // absolute screen rectangle. + virtual QRect videoDisplayRect() const = 0; + virtual Qt::AspectRatioMode videoAspectRatio() const = 0; +}; + +#endif // S60VIDEOOUTPUTINTERFACE_H + diff --git a/src/plugins/symbian/mmf/mediaplayer/s60videoplayersession.cpp b/src/plugins/symbian/mmf/mediaplayer/s60videoplayersession.cpp new file mode 100644 index 000000000..49d511ca2 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60videoplayersession.cpp @@ -0,0 +1,1124 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DebugMacros.h" + +#include "s60videoplayersession.h" +#include "s60mediaplayerservice.h" +#include "s60videowidgetcontrol.h" +#include "s60videowidgetdisplay.h" +#include "s60videowindowcontrol.h" +#include "s60videowindowdisplay.h" + +#include +#include +#include +#include +#include + +#include +#include // For CCoeEnv +#include +#include +#include +#include +#ifdef HTTP_COOKIES_ENABLED +#include +#endif + +const QString DefaultAudioEndpoint = QLatin1String("Default"); +const TUid KHelixUID = {0x101F8514}; + +//Hard-coding the command to support older versions. +const TInt KMMFROPControllerEnablePausedLoadingStatus = 7; + +TVideoRotation videoRotation(qreal angle) +{ + // Convert to clockwise + angle = 360.0f - angle; + while (angle >= 360.0f) + angle -= 360.0f; + TVideoRotation result = EVideoRotationNone; + if (angle >= 45.0f && angle < 135.0f) + result = EVideoRotationClockwise90; + else if (angle >= 135.0f && angle < 225.0f) + result = EVideoRotationClockwise180; + else if (angle >= 225.0f && angle < 315.0f) + result = EVideoRotationClockwise270; + return result; +} + +S60VideoPlayerEventHandler *S60VideoPlayerEventHandler::m_instance = 0; +QCoreApplication::EventFilter S60VideoPlayerEventHandler::m_eventFilter = 0; +QList S60VideoPlayerEventHandler::m_applicationFocusObservers; + +S60VideoPlayerEventHandler *S60VideoPlayerEventHandler::instance() +{ + if (!m_instance) + m_instance = new S60VideoPlayerEventHandler(); + return m_instance; +} + +S60VideoPlayerEventHandler::S60VideoPlayerEventHandler() +{ + m_eventFilter = QCoreApplication::instance()->setEventFilter(filterEvent); +} + +S60VideoPlayerEventHandler::~S60VideoPlayerEventHandler() +{ + QCoreApplication::instance()->setEventFilter(m_eventFilter); +} + +void S60VideoPlayerEventHandler::addApplicationFocusObserver(ApplicationFocusObserver *observer) +{ + m_applicationFocusObservers.append(observer); +} + +void S60VideoPlayerEventHandler::removeApplicationFocusObserver(ApplicationFocusObserver *observer) +{ + m_applicationFocusObservers.removeAt(m_applicationFocusObservers.indexOf(observer)); + if (m_applicationFocusObservers.count() == 0) { + delete m_instance; + m_instance = 0; + } +} + +bool S60VideoPlayerEventHandler::filterEvent(void *message, long *result) +{ + if (const QSymbianEvent *symbianEvent = reinterpret_cast(message)) { + switch (symbianEvent->type()) { + case QSymbianEvent::WindowServerEvent: + { + const TWsEvent *wsEvent = symbianEvent->windowServerEvent(); + if (EEventFocusLost == wsEvent->Type() || EEventFocusGained == wsEvent->Type()) { + for (QList::const_iterator it = m_applicationFocusObservers.constBegin(); + it != m_applicationFocusObservers.constEnd(); ++it) { + if (EEventFocusLost == wsEvent->Type()) + (*it)->applicationLostFocus(); + else if (EEventFocusGained == wsEvent->Type()) + (*it)->applicationGainedFocus(); + } + } + } + break; + default: + break; + } + } + bool ret = false; + if (m_eventFilter) + ret = m_eventFilter(message, result); + return ret; +} + +/*! + Constructs the CVideoPlayerUtility2 object with given \a service and \a object. + And Registers for Video Loading Notifications. +*/ +S60VideoPlayerSession::S60VideoPlayerSession(QMediaService *service, S60MediaNetworkAccessControl *object) + : S60MediaPlayerSession(service) + , m_accessPointId(0) + , m_wsSession(&CCoeEnv::Static()->WsSession()) + , m_screenDevice(CCoeEnv::Static()->ScreenDevice()) + , m_service(service) + , m_player(0) +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + , m_dsaActive(false) + , m_dsaStopped(false) +#endif + , m_videoOutputControl(0) + , m_videoOutputDisplay(0) + , m_displayWindow(0) +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + , m_audioOutput(0) +#endif + , m_audioEndpoint(DefaultAudioEndpoint) + , m_pendingChanges(0) + , m_backendInitiatedPause(false) +#ifdef HTTP_COOKIES_ENABLED + , m_destinationPckg(KUidInterfaceMMFControllerSessionInfo) +#endif +{ + DP0("S60VideoPlayerSession::S60VideoPlayerSession +++"); + + m_networkAccessControl = object; +#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES + QT_TRAP_THROWING(m_player = CVideoPlayerUtility2::NewL( + *this, + 0, + EMdaPriorityPreferenceNone + )); + m_player->RegisterForVideoLoadingNotification(*this); +#else + RWindow *window = 0; + QRect extentRect; + QWidget *widget = QApplication::activeWindow(); + if (!widget) + widget = QApplication::allWidgets().at(0); + Q_ASSERT(widget); + WId wid = widget->effectiveWinId(); + if (!wid) + wid = widget->winId(); + window = static_cast(wid->DrawableWindow()); + extentRect = QRect(widget->mapToGlobal(widget->pos()), widget->size()); + TRect clipRect = QRect2TRect(extentRect); + const TRect desktopRect = QRect2TRect(QApplication::desktop()->screenGeometry()); + clipRect.Intersection(desktopRect); + QT_TRAP_THROWING(m_player = CVideoPlayerUtility::NewL( + *this, + 0, + EMdaPriorityPreferenceNone, + *m_wsSession, + *m_screenDevice, + *window, + QRect2TRect(extentRect), + clipRect)); + m_dsaActive = true; + m_player->RegisterForVideoLoadingNotification(*this); +#endif // VIDEOOUTPUT_GRAPHICS_SURFACES + S60VideoPlayerEventHandler::instance()->addApplicationFocusObserver(this); + DP0("S60VideoPlayerSession::S60VideoPlayerSession ---"); +} + +/*! + Destroys the CVideoPlayerUtility2 object. + + And Unregister the observer. +*/ + +S60VideoPlayerSession::~S60VideoPlayerSession() +{ + DP0("S60VideoPlayerSession::~S60VideoPlayerSession +++"); + S60VideoPlayerEventHandler::instance()->removeApplicationFocusObserver(this); +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + if (m_audioOutput) + m_audioOutput->UnregisterObserver(*this); + delete m_audioOutput; +#endif + m_player->Close(); + delete m_player; + + DP0("S60VideoPlayerSession::~S60VideoPlayerSession ---"); +} + +void S60VideoPlayerSession::applicationGainedFocus() +{ + if (m_backendInitiatedPause) { + m_backendInitiatedPause = false; + play(); + } + if (QMediaPlayer::PausedState == state()) { + TRAPD(err, m_player->RefreshFrameL()); + setError(err); + } +} + +void S60VideoPlayerSession::applicationLostFocus() +{ + if (QMediaPlayer::PlayingState == state()) { + m_backendInitiatedPause = true; + pause(); + } +} + +/*! + + Opens the a file from \a path. +*/ + +void S60VideoPlayerSession::doLoadL(const TDesC &path) +{ + DP0("S60VideoPlayerSession::doLoadL +++"); + +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + // m_audioOutput needs to be reinitialized after MapcInitComplete + if (m_audioOutput) + m_audioOutput->UnregisterObserver(*this); + delete m_audioOutput; + m_audioOutput = NULL; +#endif + m_player->OpenFileL(path, KHelixUID); + + DP0("S60VideoPlayerSession::doLoadL ---"); +} + +/*! + Sets the playbackRate with \a rate. +*/ + +void S60VideoPlayerSession::setPlaybackRate(qreal rate) +{ + DP0("S60VideoPlayerSession::setPlaybackRate +++"); + + DP1("S60VideoPlayerSession::setPlaybackRate - ", rate); + + /* + * setPlaybackRate is not supported in S60 3.1 and 3.2 + * This flag will be defined for 3.1 and 3.2 + */ +#ifndef PLAY_RATE_NOT_SUPPORTED + //setPlayVelocity requires rate in the form of + //50 = 0.5x ;100 = 1.x ; 200 = 2.x ; 300 = 3.x + //so multiplying rate with 100 + TRAPD(err, m_player->SetPlayVelocityL((TInt)(rate*100))); + if (KErrNone == err) + emit playbackRateChanged(rate); + else + setError(err); +#endif + + DP0("S60VideoPlayerSession::setPlaybackRate ---"); +} + +/*! + + Opens the a Url from \a path for streaming the source. +*/ + +void S60VideoPlayerSession::doLoadUrlL(const TDesC &path) +{ + DP0("S60VideoPlayerSession::doLoadUrlL +++"); + +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + // m_audioOutput needs to be reinitialized after MapcInitComplete + if (m_audioOutput) + m_audioOutput->UnregisterObserver(*this); + delete m_audioOutput; + m_audioOutput = NULL; +#endif + m_accessPointId = m_networkAccessControl->accessPointId(); + m_player->OpenUrlL(path, m_accessPointId, KNullDesC8, KHelixUID); + + DP0("S60VideoPlayerSession::doLoadUrlL ---"); +} + +/*! + + Returns the percentage of the video clip loaded. +*/ + +int S60VideoPlayerSession::doGetBufferStatusL() const +{ + // DP0("S60VideoPlayerSession::doGetBufferStatusL +++"); + + int progress = 0; + m_player->GetVideoLoadingProgressL(progress); + + // DP0("S60VideoPlayerSession::doGetBufferStatusL ---"); + + return progress; +} + +/*! + Returns the duration of the video sample in microseconds. +*/ + +qint64 S60VideoPlayerSession::doGetDurationL() const +{ + // DP0("S60VideoPlayerSession::doGetDurationL"); + + return m_player->DurationL().Int64() / qint64(1000); +} + +/*! + * Sets the \a videooutput for video rendering. +*/ + +void S60VideoPlayerSession::setVideoRenderer(QObject *videoOutput) +{ + DP0("S60VideoPlayerSession::setVideoRenderer +++"); + if (videoOutput != m_videoOutputControl) { + if (m_videoOutputDisplay) { + disconnect(m_videoOutputDisplay); + m_videoOutputDisplay->disconnect(this); + m_videoOutputDisplay = 0; + } + if (videoOutput) { + if (S60VideoWidgetControl *control = qobject_cast(videoOutput)) + m_videoOutputDisplay = control->display(); + if (!m_videoOutputDisplay) + return; + m_videoOutputDisplay->setNativeSize(m_nativeSize); + connect(this, SIGNAL(nativeSizeChanged(QSize)), m_videoOutputDisplay, SLOT(setNativeSize(QSize))); + connect(m_videoOutputDisplay, SIGNAL(windowHandleChanged(RWindow *)), this, SLOT(windowHandleChanged())); + connect(m_videoOutputDisplay, SIGNAL(displayRectChanged(QRect, QRect)), this, SLOT(displayRectChanged())); + connect(m_videoOutputDisplay, SIGNAL(aspectRatioModeChanged(Qt::AspectRatioMode)), this, SLOT(aspectRatioChanged())); + connect(m_videoOutputDisplay, SIGNAL(rotationChanged(qreal)), this, SLOT(rotationChanged())); +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + connect(m_videoOutputDisplay, SIGNAL(beginVideoWindowNativePaint()), this, SLOT(suspendDirectScreenAccess())); + connect(m_videoOutputDisplay, SIGNAL(endVideoWindowNativePaint()), this, SLOT(resumeDirectScreenAccess())); +#endif + } + m_videoOutputControl = videoOutput; + windowHandleChanged(); + } + + DP0("S60VideoPlayerSession::setVideoRenderer ---"); +} + +/*! + * Apply the pending changes for window. +*/ +void S60VideoPlayerSession::applyPendingChanges(bool force) +{ + DP0("S60VideoPlayerSession::applyPendingChanges +++"); + + if ( force + || QMediaPlayer::LoadedMedia == mediaStatus() + || QMediaPlayer::StalledMedia == mediaStatus() + || QMediaPlayer::BufferingMedia == mediaStatus() + || QMediaPlayer::BufferedMedia == mediaStatus() + || QMediaPlayer::EndOfMedia == mediaStatus()) { + int error = KErrNone; + RWindow *const window = m_videoOutputDisplay ? m_videoOutputDisplay->windowHandle() : 0; + const QRect extentRect = m_videoOutputDisplay ? m_videoOutputDisplay->extentRect() : QRect(); + const QRect clipRect = m_videoOutputDisplay ? m_videoOutputDisplay->clipRect() : QRect(); +#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES + if (m_pendingChanges & WindowHandle) { + if (m_displayWindow) { + m_player->RemoveDisplayWindow(*m_displayWindow); + m_displayWindow = 0; + } + if (window) { + TRAP(error, m_player->AddDisplayWindowL(*m_wsSession, *m_screenDevice, + *window, + QRect2TRect(extentRect), + QRect2TRect(clipRect))); + if (KErrNone == error) + m_displayWindow = window; + } + m_pendingChanges = ScaleFactors; + } + if (KErrNone == error && (m_pendingChanges & DisplayRect) && m_displayWindow) { + TRAP(error, m_player->SetVideoExtentL(*m_displayWindow, QRect2TRect(extentRect))); + if (KErrNone == error) + TRAP(error, m_player->SetWindowClipRectL(*m_displayWindow, QRect2TRect(clipRect))); + m_pendingChanges ^= DisplayRect; + m_pendingChanges |= ScaleFactors; + } +#else + if (m_pendingChanges & WindowHandle || m_pendingChanges & DisplayRect) { + if (window) { + TRAP(error, m_player->SetDisplayWindowL(*m_wsSession, *m_screenDevice, + *window, + QRect2TRect(extentRect), + QRect2TRect(clipRect))); + if (KErrNone == error) + m_displayWindow = window; + } + m_dsaActive = (KErrNone == error); + m_dsaStopped = false; + m_pendingChanges = ScaleFactors; + } + +#endif // VIDEOOUTPUT_GRAPHICS_SURFACES + if (KErrNone == error && (m_pendingChanges & ScaleFactors) && m_displayWindow && m_videoOutputDisplay) { + const TVideoRotation rotation = videoRotation(m_videoOutputDisplay->rotation()); + const bool swap = (rotation == EVideoRotationClockwise90 || rotation == EVideoRotationClockwise270); + const QSize extentSize = swap ? QSize(extentRect.height(), extentRect.width()) : extentRect.size(); + QSize scaled = m_nativeSize; + if (m_videoOutputDisplay->aspectRatioMode() == Qt::IgnoreAspectRatio) + scaled.scale(extentSize, Qt::IgnoreAspectRatio); + else if (m_videoOutputDisplay->aspectRatioMode() == Qt::KeepAspectRatio) + scaled.scale(extentSize, Qt::KeepAspectRatio); + else if (m_videoOutputDisplay->aspectRatioMode() == Qt::KeepAspectRatioByExpanding) + scaled.scale(extentSize, Qt::KeepAspectRatioByExpanding); + const qreal width = qreal(scaled.width()) / qreal(m_nativeSize.width()) * qreal(100); + const qreal height = qreal(scaled.height()) / qreal(m_nativeSize.height()) * qreal(100); +#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES + TRAP(error, m_player->SetScaleFactorL(*m_displayWindow, width, height)); +#else + static const TBool antialias = ETrue; + TRAP(error, m_player->SetScaleFactorL(width, height, antialias)); +#endif // VIDEOOUTPUT_GRAPHICS_SURFACES + m_pendingChanges ^= ScaleFactors; + } + if (KErrNone == error && (m_pendingChanges && Rotation) && m_displayWindow && m_videoOutputDisplay) { + const TVideoRotation rotation = videoRotation(m_videoOutputDisplay->rotation()); +#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES + TRAP(error, m_player->SetRotationL(*m_displayWindow, rotation)); +#else + TRAP(error, m_player->SetRotationL(rotation)); +#endif // VIDEOOUTPUT_GRAPHICS_SURFACES + m_pendingChanges ^= Rotation; + } + setError(error); + } + + DP0("S60VideoPlayerSession::applyPendingChanges ---"); +} + +/*! + * \return TRUE if video is available. +*/ + +bool S60VideoPlayerSession::isVideoAvailable() +{ + DP0("S60VideoPlayerSession::isVideoAvailable"); + +#ifdef PRE_S60_50_PLATFORM + return true; // this is not supported in pre 5th platforms +#else + if ( mediaStatus() == QMediaPlayer::LoadingMedia + || mediaStatus() == QMediaPlayer::UnknownMediaStatus + || mediaStatus() == QMediaPlayer::NoMedia + || (mediaStatus() == QMediaPlayer::StalledMedia && state() == QMediaPlayer::StoppedState) + || mediaStatus() == QMediaPlayer::InvalidMedia) + return false; + + if (m_player) { + bool videoAvailable = false; + TRAPD(err, videoAvailable = m_player->VideoEnabledL()); + setError(err); + return videoAvailable; + } else { + return false; + } +#endif + +} + +/*! + * \return TRUE if Audio available. +*/ + +bool S60VideoPlayerSession::isAudioAvailable() +{ + DP0("S60VideoPlayerSession::isAudioAvailable"); + + if ( mediaStatus() == QMediaPlayer::LoadingMedia + || mediaStatus() == QMediaPlayer::UnknownMediaStatus + || mediaStatus() == QMediaPlayer::NoMedia + || (mediaStatus() == QMediaPlayer::StalledMedia && state() == QMediaPlayer::StoppedState) + || mediaStatus() == QMediaPlayer::InvalidMedia) + return false; + + if (m_player) { + bool audioAvailable = false; + TRAPD(err, audioAvailable = m_player->AudioEnabledL()); + setError(err); + return audioAvailable; + } else { + return false; + } +} + +/*! + Start or resume playing the current source. +*/ + +void S60VideoPlayerSession::doPlay() +{ + DP0("S60VideoPlayerSession::doPlay +++"); + + m_player->Play(); + + DP0("S60VideoPlayerSession::doPlay ---"); +} + +/*! + Pause playing the current source. +*/ + +void S60VideoPlayerSession::doPauseL() +{ + DP0("S60VideoPlayerSession::doPauseL +++"); + + m_player->PauseL(); + + DP0("S60VideoPlayerSession::doPauseL ---"); +} + +/*! + + Stop playing, and reset the play position to the beginning. +*/ + +void S60VideoPlayerSession::doStop() +{ + DP0("S60VideoPlayerSession::doStop +++"); + + if (m_stream) + m_networkAccessControl->resetIndex(); + + m_player->Stop(); + + DP0("S60VideoPlayerSession::doStop ---"); +} + +/*! + Closes the current audio clip (allowing another clip to be opened) +*/ + +void S60VideoPlayerSession::doClose() +{ + DP0("S60VideoPlayerSession::doClose +++"); + +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + if (m_audioOutput) { + m_audioOutput->UnregisterObserver(*this); + delete m_audioOutput; + m_audioOutput = NULL; + } +#endif + + m_player->Close(); + +// close will remove the window handle in media clint video. +// So mark it in pending changes. + m_pendingChanges |= WindowHandle; + + DP0("S60VideoPlayerSession::doClose ---"); +} + +/*! + * Returns the current playback position in microseconds from the start of the clip. + +*/ + +qint64 S60VideoPlayerSession::doGetPositionL() const +{ + // DP0("S60VideoPlayerSession::doGetPositionL"); + + return m_player->PositionL().Int64() / qint64(1000); +} + +/*! + Sets the current playback position to \a microSeconds from the start of the clip. +*/ + +void S60VideoPlayerSession::doSetPositionL(qint64 microSeconds) +{ + // DP0("S60VideoPlayerSession::doSetPositionL"); + + m_player->SetPositionL(TTimeIntervalMicroSeconds(microSeconds)); +} + +/*! + + Changes the current playback volume to specified \a value. +*/ + +void S60VideoPlayerSession::doSetVolumeL(int volume) +{ + DP0("S60VideoPlayerSession::doSetVolumeL +++"); + + DP1("S60VideoPlayerSession::doSetVolumeL - ", volume); + + m_player->SetVolumeL(volume * m_player->MaxVolume() / 100); + + DP0("S60VideoPlayerSession::doSetVolumeL ---"); +} + +/*! + * Notification to the client that the opening of the video clip has completed. + * If successful then an \a aError will be ZERO else system wide error. +*/ + +void S60VideoPlayerSession::MvpuoOpenComplete(TInt aError) +{ + DP0("S60VideoPlayerSession::MvpuoOpenComplete +++"); + + DP1("S60VideoPlayerSession::MvpuoOpenComplete - aError:", aError); + + setError(aError); +#ifdef HTTP_COOKIES_ENABLED + if (KErrNone == aError) { + TInt err(KErrNone); + const QByteArray userAgentString("User-Agent"); + TInt uasize = m_source.canonicalRequest().rawHeader(userAgentString).size(); + TPtrC8 userAgent((const unsigned char*)(m_source.canonicalRequest().rawHeader(userAgentString).constData()), uasize); + if (userAgent.Length()) { + err = m_player->CustomCommandSync(m_destinationPckg, EMMFSetSessionInfo, _L8("User-Agent"), userAgent); + if (err != KErrNone) { + setError(err); + return; + } + } + const QByteArray refererString("Referer"); + TInt refsize = m_source.canonicalRequest().rawHeader(refererString).size(); + TPtrC8 referer((const unsigned char*)m_source.canonicalRequest().rawHeader(refererString).constData(),refsize); + if (referer.Length()) { + err = m_player->CustomCommandSync(m_destinationPckg, EMMFSetSessionInfo, _L8("Referer"), referer); + if (err != KErrNone) { + setError(err); + return; + } + } + const QByteArray cookieString("Cookie"); + TInt cksize = m_source.canonicalRequest().rawHeader(cookieString).size(); + TPtrC8 cookie((const unsigned char*)m_source.canonicalRequest().rawHeader(cookieString).constData(),cksize); + if (cookie.Length()) { + err = m_player->CustomCommandSync(m_destinationPckg, EMMFSetSessionInfo, _L8("Cookie"), cookie); + if (err != KErrNone) { + setError(err); + return; + } + } + m_player->Prepare(); + } +#else + if (KErrNone == aError) + m_player->Prepare(); +#endif + const TMMFMessageDestinationPckg dest( KUidInterfaceMMFROPController ); + TRAP_IGNORE(m_player->CustomCommandSync(dest, KMMFROPControllerEnablePausedLoadingStatus, KNullDesC8, KNullDesC8)); + + DP0("S60VideoPlayerSession::MvpuoOpenComplete ---"); +} + +/*! + * Notification to the client that the opening of the video clip has been preapred. + * If successful then an \a aError will be ZERO else system wide error. +*/ + +void S60VideoPlayerSession::MvpuoPrepareComplete(TInt aError) +{ + DP0("S60VideoPlayerSession::MvpuoPrepareComplete +++"); + + DP1("S60VideoPlayerSession::MvpuoPrepareComplete - aError:", aError); + + if (KErrNone == aError && m_stream) { + emit accessPointChanged(m_accessPointId); + } + if (KErrCouldNotConnect == aError && !(m_networkAccessControl->isLastAccessPoint())) { + load(m_source); + return; + } + TInt error = aError; + if (KErrNone == error || KErrMMPartialPlayback == error) { + TSize originalSize; + TRAP(error, m_player->VideoFrameSizeL(originalSize)); + if (KErrNone == error) { + m_nativeSize = QSize(originalSize.iWidth, originalSize.iHeight); + emit nativeSizeChanged(m_nativeSize); + m_pendingChanges |= ScaleFactors; +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + Q_ASSERT(!m_audioOutput); + TRAP(error, m_audioOutput = CAudioOutput::NewL(*m_player)); + if (KErrNone == error) { + TRAP(error, m_audioOutput->RegisterObserverL(*this)); + if (KErrNone == error) + setActiveEndpoint(m_audioEndpoint); + } +#endif + } + if (KErrNone == error) { + applyPendingChanges(true); // force apply even though state is not Loaded + if (KErrNone == this->error()) // applyPendingChanges() can call setError() + loaded(); + } + } else { + setError(error); + } + + DP0("S60VideoPlayerSession::MvpuoPrepareComplete ---"); +} + +/*! + * Notification that frame requested by a call to GetFrameL is ready. +*/ + +void S60VideoPlayerSession::MvpuoFrameReady(CFbsBitmap &aFrame, TInt aError) +{ + DP0("S60VideoPlayerSession::MvpuoFrameReady +++"); + + Q_UNUSED(aFrame); + Q_UNUSED(aError); + + DP0("S60VideoPlayerSession::MvpuoFrameReady ---"); +} + +/*! + * Notification that video playback has completed. + * If successful then \a aError will be ZERO else system wide error. + * This not called if playback is explicitly stopped by calling stop. +*/ + +void S60VideoPlayerSession::MvpuoPlayComplete(TInt aError) +{ + DP0("S60VideoPlayerSession::MvpuoPlayComplete +++"); + + DP1("S60VideoPlayerSession::MvpuoPlayComplete - aError", aError); + + if (m_stream) + m_networkAccessControl->resetIndex(); + + if (aError != KErrNone) { + setError(aError); + doClose(); + } else { + endOfMedia(); + } + + DP0("S60VideoPlayerSession::MvpuoPlayComplete ---"); +} + + +/*! + * General \a event notification from controller. + * These events are specified by the supplier of the controller. +*/ + +void S60VideoPlayerSession::MvpuoEvent(const TMMFEvent &aEvent) +{ + DP0("S60VideoPlayerSession::MvpuoEvent +++"); + + Q_UNUSED(aEvent); + + DP0("S60VideoPlayerSession::MvpuoEvent ---"); +} + +/*! + + Updates meta data entries in the current video clip. +*/ + +void S60VideoPlayerSession::updateMetaDataEntriesL() +{ + DP0("S60VideoPlayerSession::updateMetaDataEntriesL +++"); + + metaDataEntries().clear(); + int numberOfMetaDataEntries = 0; + numberOfMetaDataEntries = m_player->NumberOfMetaDataEntriesL(); + for (int i = 0; i < numberOfMetaDataEntries; i++) { + CMMFMetaDataEntry *entry = NULL; + entry = m_player->MetaDataEntryL(i); + metaDataEntries().insert(TDesC2QString(entry->Name()), TDesC2QString(entry->Value())); + delete entry; + } + emit metaDataChanged(); + + DP0("S60VideoPlayerSession::updateMetaDataEntriesL ---"); +} + +/*! + * Apply the window changes when window handle changes. +*/ + +void S60VideoPlayerSession::windowHandleChanged() +{ + DP0("S60VideoPlayerSession::windowHandleChanged +++"); + + m_pendingChanges |= WindowHandle; + applyPendingChanges(); + + DP0("S60VideoPlayerSession::windowHandleChanged ---"); +} + +/*! + * Apply the window changes when display Rect changes. +*/ + +void S60VideoPlayerSession::displayRectChanged() +{ + DP0("S60VideoPlayerSession::displayRectChanged +++"); + + m_pendingChanges |= DisplayRect; + applyPendingChanges(); + + DP0("S60VideoPlayerSession::displayRectChanged ---"); +} + +/*! + * Apply the window changes when aspect Ratio changes. +*/ + +void S60VideoPlayerSession::aspectRatioChanged() +{ + DP0("S60VideoPlayerSession::aspectRatioChanged +++"); + + m_pendingChanges |= ScaleFactors; + applyPendingChanges(); + + DP0("S60VideoPlayerSession::aspectRatioChanged ---"); +} + +void S60VideoPlayerSession::rotationChanged() +{ + m_pendingChanges |= ScaleFactors; + m_pendingChanges |= Rotation; + applyPendingChanges(); +} + +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES +void S60VideoPlayerSession::suspendDirectScreenAccess() +{ + DP0("S60VideoPlayerSession::suspendDirectScreenAccess +++"); + + m_dsaStopped = stopDirectScreenAccess(); + + DP0("S60VideoPlayerSession::suspendDirectScreenAccess ---"); +} + +void S60VideoPlayerSession::resumeDirectScreenAccess() +{ + DP0("S60VideoPlayerSession::resumeDirectScreenAccess +++"); + + if (!m_dsaStopped) + return; + startDirectScreenAccess(); + m_dsaStopped = false; + + DP0("S60VideoPlayerSession::resumeDirectScreenAccess ---"); +} + +void S60VideoPlayerSession::startDirectScreenAccess() +{ + DP0("S60VideoPlayerSession::startDirectScreenAccess +++"); + + if (m_dsaActive) + return; + TRAPD(err, m_player->StartDirectScreenAccessL()); + if (err == KErrNone) + m_dsaActive = true; + setError(err); + + DP0("S60VideoPlayerSession::startDirectScreenAccess ---"); +} + +bool S60VideoPlayerSession::stopDirectScreenAccess() +{ + DP0("S60VideoPlayerSession::stopDirectScreenAccess"); + + if (!m_dsaActive) + return false; + TRAPD(err, m_player->StopDirectScreenAccessL()); + if (err == KErrNone) + m_dsaActive = false; + setError(err); + return true; +} +#endif + +/*! + * The percentage of the temporary buffer filling before playback begins. +*/ + +void S60VideoPlayerSession::MvloLoadingStarted() +{ + DP0("S60VideoPlayerSession::MvloLoadingStarted +++"); + + buffering(); + + DP0("S60VideoPlayerSession::MvloLoadingStarted ---"); +} + +/*! + * Buffer is filled with data and to for continuing/start playback. +*/ + +void S60VideoPlayerSession::MvloLoadingComplete() +{ + DP0("S60VideoPlayerSession::MvloLoadingComplete +++"); + + buffered(); + + DP0("S60VideoPlayerSession::MvloLoadingComplete ---"); +} + +/*! + Defiens which Audio End point to use. + + \a audioEndpoint audioEndpoint name. +*/ + +void S60VideoPlayerSession::doSetAudioEndpoint(const QString& audioEndpoint) +{ + DP0("S60VideoPlayerSession::doSetAudioEndpoint +++"); + + DP1("S60VideoPlayerSession::doSetAudioEndpoint - ", audioEndpoint); + + m_audioEndpoint = audioEndpoint; + + DP0("S60VideoPlayerSession::doSetAudioEndpoint ---"); +} + +/*! + + Returns audioEndpoint name. +*/ + +QString S60VideoPlayerSession::activeEndpoint() const +{ + DP0("S60VideoPlayerSession::activeEndpoint +++"); + + QString outputName = m_audioEndpoint; +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + if (m_audioOutput) { + CAudioOutput::TAudioOutputPreference output = m_audioOutput->AudioOutput(); + outputName = qStringFromTAudioOutputPreference(output); + } +#endif + + DP1("S60VideoPlayerSession::activeEndpoint- outputName:", outputName); + DP0("S60VideoPlayerSession::activeEndpoint ---"); + return outputName; +} + +/*! + * Returns default Audio End point in use. +*/ + +QString S60VideoPlayerSession::defaultEndpoint() const +{ + DP0("S60VideoPlayerSession::defaultEndpoint +++"); + + QString outputName = DefaultAudioEndpoint; +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + if (m_audioOutput) { + CAudioOutput::TAudioOutputPreference output = m_audioOutput->DefaultAudioOutput(); + outputName = qStringFromTAudioOutputPreference(output); + } +#endif + + DP1("S60VideoPlayerSession::defaultEndpoint, outputName:", outputName); + DP0("S60VideoPlayerSession::defaultEndpoint ---"); + + return outputName; +} + +/*! + Sets active end \a name as an Audio End point. +*/ + +void S60VideoPlayerSession::setActiveEndpoint(const QString& name) +{ + DP0("S60VideoPlayerSession::setActiveEndpoint +++"); + + DP1("S60VideoPlayerSession::setActiveEndpoint - ", name); + +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + CAudioOutput::TAudioOutputPreference output = CAudioOutput::ENoPreference; + if (name == DefaultAudioEndpoint) + output = CAudioOutput::ENoPreference; + else if (name == QString("All")) + output = CAudioOutput::EAll; + else if (name == QString("None")) + output = CAudioOutput::ENoOutput; + else if (name == QString("Earphone")) + output = CAudioOutput::EPrivate; + else if (name == QString("Speaker")) + output = CAudioOutput::EPublic; + if (m_audioOutput) { + TRAPD(err, m_audioOutput->SetAudioOutputL(output)); + setError(err); + } +#endif + + DP0("S60VideoPlayerSession::setActiveEndpoint ---"); +} + +/*! + The default Audio output has been changed. + + \a aAudioOutput Audio Output object. + + \a aNewDefault is CAudioOutput::TAudioOutputPreference. +*/ + +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER +void S60VideoPlayerSession::DefaultAudioOutputChanged( CAudioOutput& aAudioOutput, + CAudioOutput::TAudioOutputPreference aNewDefault) +{ + DP0("S60VideoPlayerSession::DefaultAudioOutputChanged +++"); + + // Emit already implemented in setActiveEndpoint function + Q_UNUSED(aAudioOutput) + Q_UNUSED(aNewDefault) + + DP0("S60VideoPlayerSession::DefaultAudioOutputChanged ---"); +} + +/*! + * \return CAudioOutput::ENoOutput by converting it to QString. +*/ + +QString S60VideoPlayerSession::qStringFromTAudioOutputPreference(CAudioOutput::TAudioOutputPreference output) const +{ + DP0("S60VideoPlayerSession::qStringFromTAudioOutputPreference"); + + if (output == CAudioOutput::ENoPreference) + return QString("Default"); + else if (output == CAudioOutput::EAll) + return QString("All"); + else if (output == CAudioOutput::ENoOutput) + return QString("None"); + else if (output == CAudioOutput::EPrivate) + return QString("Earphone"); + else if (output == CAudioOutput::EPublic) + return QString("Speaker"); + return QString("Default"); +} +#endif //HAS_AUDIOROUTING_IN_VIDEOPLAYER) + +/*! + * \return TRUE if video is Seekable else FALSE. +*/ + +bool S60VideoPlayerSession::getIsSeekable() const +{ + DP0("S60VideoPlayerSession::getIsSeekable +++"); + + bool seekable = ETrue; + int numberOfMetaDataEntries = 0; + + TRAPD(err, numberOfMetaDataEntries = m_player->NumberOfMetaDataEntriesL()); + if (err) + return seekable; + + for (int i = 0; i < numberOfMetaDataEntries; i++) { + CMMFMetaDataEntry *entry = NULL; + TRAP(err, entry = m_player->MetaDataEntryL(i)); + + if (err) + return seekable; + + if (!entry->Name().Compare(KSeekable)) { + if (!entry->Value().Compare(KFalse)) + seekable = EFalse; + break; + } + } + DP0("S60VideoPlayerSession::getIsSeekable ---"); + + return seekable; +} diff --git a/src/plugins/symbian/mmf/mediaplayer/s60videoplayersession.h b/src/plugins/symbian/mmf/mediaplayer/s60videoplayersession.h new file mode 100644 index 000000000..f73683af8 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60videoplayersession.h @@ -0,0 +1,218 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60VIDEOPLAYERSESSION_H +#define S60VIDEOPLAYERSESSION_H + +#include "s60mediaplayersession.h" +#include "s60mediaplayeraudioendpointselector.h" +#include "s60medianetworkaccesscontrol.h" +#include "s60videodisplay.h" + +#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES +#include +#else +#include +#endif // VIDEOOUTPUT_GRAPHICS_SURFACES + +#include +#include +#include + +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER +#include +#include +#endif // HAS_AUDIOROUTING_IN_VIDEOPLAYER + +class QTimer; +class S60MediaNetworkAccessControl; +class S60VideoDisplay; + +// Helper classes to pass Symbian events from WServ to the S60VideoPlayerSession +// so it can control video player on certain events if required + +class ApplicationFocusObserver +{ +public: + virtual void applicationGainedFocus() = 0; + virtual void applicationLostFocus() = 0; +}; + +class S60VideoPlayerEventHandler : public QObject +{ +public: + static S60VideoPlayerEventHandler *instance(); + static bool filterEvent(void *message, long *result); + void addApplicationFocusObserver(ApplicationFocusObserver* observer); + void removeApplicationFocusObserver(ApplicationFocusObserver* observer); +private: + S60VideoPlayerEventHandler(); + ~S60VideoPlayerEventHandler(); +private: + static S60VideoPlayerEventHandler *m_instance; + static QList m_applicationFocusObservers; + static QCoreApplication::EventFilter m_eventFilter; +}; + +class S60VideoPlayerSession : public S60MediaPlayerSession + , public MVideoPlayerUtilityObserver + , public MVideoLoadingObserver +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + , public MAudioOutputObserver +#endif // HAS_AUDIOROUTING_IN_VIDEOPLAYER + , public ApplicationFocusObserver +{ + Q_OBJECT +public: + S60VideoPlayerSession(QMediaService *service, S60MediaNetworkAccessControl *object); + ~S60VideoPlayerSession(); + + // From S60MediaPlayerSession + bool isVideoAvailable(); + bool isAudioAvailable(); + void setVideoRenderer(QObject *renderer); + + // From MVideoLoadingObserver + void MvloLoadingStarted(); + void MvloLoadingComplete(); + void setPlaybackRate(qreal rate); +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + // From MAudioOutputObserver + void DefaultAudioOutputChanged(CAudioOutput& aAudioOutput, + CAudioOutput::TAudioOutputPreference aNewDefault); +#endif + + // From S60MediaPlayerAudioEndpointSelector + QString activeEndpoint() const; + QString defaultEndpoint() const; + + // ApplicationFocusObserver + void applicationGainedFocus(); + void applicationLostFocus(); + +signals: + void nativeSizeChanged(QSize); + +public Q_SLOTS: + void setActiveEndpoint(const QString& name); + +signals: + void accessPointChanged(int); + +protected: + // From S60MediaPlayerSession + void doLoadL(const TDesC &path); + void doLoadUrlL(const TDesC &path); + void doPlay(); + void doStop(); + void doClose(); + void doPauseL(); + void doSetVolumeL(int volume); + qint64 doGetPositionL() const; + void doSetPositionL(qint64 microSeconds); + void updateMetaDataEntriesL(); + int doGetBufferStatusL() const; + qint64 doGetDurationL() const; + void doSetAudioEndpoint(const QString& audioEndpoint); + bool getIsSeekable() const; + +private slots: + void windowHandleChanged(); + void displayRectChanged(); + void aspectRatioChanged(); + void rotationChanged(); +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + void suspendDirectScreenAccess(); + void resumeDirectScreenAccess(); +#endif + +private: + void applyPendingChanges(bool force = false); +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + void startDirectScreenAccess(); + bool stopDirectScreenAccess(); +#endif +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + QString qStringFromTAudioOutputPreference(CAudioOutput::TAudioOutputPreference output) const; +#endif + + // From MVideoPlayerUtilityObserver + void MvpuoOpenComplete(TInt aError); + void MvpuoPrepareComplete(TInt aError); + void MvpuoFrameReady(CFbsBitmap &aFrame, TInt aError); + void MvpuoPlayComplete(TInt aError); + void MvpuoEvent(const TMMFEvent &aEvent); + +private: + int m_accessPointId; + S60MediaNetworkAccessControl* m_networkAccessControl; + RWsSession *const m_wsSession; + CWsScreenDevice *const m_screenDevice; + QMediaService *const m_service; +#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES + CVideoPlayerUtility2 *m_player; +#else + CVideoPlayerUtility *m_player; + bool m_dsaActive; + bool m_dsaStopped; +#endif // VIDEOOUTPUT_GRAPHICS_SURFACES + QObject *m_videoOutputControl; + S60VideoDisplay *m_videoOutputDisplay; + RWindow *m_displayWindow; + QSize m_nativeSize; +#ifdef HTTP_COOKIES_ENABLED + TMMFMessageDestinationPckg m_destinationPckg; +#endif +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + CAudioOutput *m_audioOutput; +#endif + QString m_audioEndpoint; + enum Parameter { + WindowHandle = 0x1, + DisplayRect = 0x2, + ScaleFactors = 0x4, + Rotation = 0x8 + }; + QFlags m_pendingChanges; + bool m_backendInitiatedPause; +}; + +#endif diff --git a/src/plugins/symbian/mmf/mediaplayer/s60videorenderer.cpp b/src/plugins/symbian/mmf/mediaplayer/s60videorenderer.cpp new file mode 100644 index 000000000..2de6896a0 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60videorenderer.cpp @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DebugMacros.h" + +#include "s60videorenderer.h" + +#include +#include + +/*! + Constructs a new video renderer media end point with the given \a parent. +*/ + +S60VideoRenderer::S60VideoRenderer(QObject *parent) + : QVideoRendererControl(parent) +{ + DP0("S60VideoRenderer::S60VideoRenderer +++"); + + DP0("S60VideoRenderer::S60VideoRenderer ---"); + +} + +/*! + Destroys a video renderer media end point. +*/ + +S60VideoRenderer::~S60VideoRenderer() +{ + DP0("S60VideoRenderer::~S60VideoRenderer +++"); + DP0("S60VideoRenderer::~S60VideoRenderer ---"); +} + +/*! + \return the surface a video producer renders to. +*/ + +QAbstractVideoSurface *S60VideoRenderer::surface() const +{ + DP0("S60VideoRenderer::surface"); + + return m_surface; +} + +/*! + Sets the \a surface a video producer renders to. +*/ + +void S60VideoRenderer::setSurface(QAbstractVideoSurface *surface) +{ + DP0("S60VideoRenderer::setSurface +++"); + + m_surface = surface; + + DP0("S60VideoRenderer::setSurface ---"); +} + diff --git a/src/plugins/symbian/mmf/mediaplayer/s60videorenderer.h b/src/plugins/symbian/mmf/mediaplayer/s60videorenderer.h new file mode 100644 index 000000000..6e90d42c3 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60videorenderer.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60VIDEORENDERER_H +#define S60VIDEORENDERER_H + +#include +#include + +QT_USE_NAMESPACE + +class S60VideoRenderer : public QVideoRendererControl +{ + Q_OBJECT + +public: + S60VideoRenderer(QObject *parent = 0); + virtual ~S60VideoRenderer(); + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + +private: + + QAbstractVideoSurface *m_surface; +}; + +#endif // S60VIDEORENDERER_H diff --git a/src/plugins/symbian/mmf/mediaplayer/s60videosurface.cpp b/src/plugins/symbian/mmf/mediaplayer/s60videosurface.cpp new file mode 100644 index 000000000..563d33b40 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60videosurface.cpp @@ -0,0 +1,372 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DebugMacros.h" + +#include + +#include "s60videosurface.h" +/*! + * Constructs a video surface with the given \a parent. +*/ + +S60VideoSurface::S60VideoSurface(QObject *parent) + : QAbstractVideoSurface(parent) + , m_winId(0) +{ + DP0("S60VideoSurface::S60VideoSurface +++"); + DP0("S60VideoSurface::S60VideoSurface ---"); +} + +/*! + * Destroys video surface. +*/ + +S60VideoSurface::~S60VideoSurface() +{ + DP0("S60VideoSurface::~S60VideoSurface +++"); + DP0("S60VideoSurface::~S60VideoSurface ---"); +} + +/*! + \return the ID of the window a video surface end point renders to. +*/ + +WId S60VideoSurface::winId() const +{ + DP0("S60VideoSurface::winId"); + + return m_winId; +} + +/*! + Sets the \a id of the window a video surface end point renders to. +*/ + +void S60VideoSurface::setWinId(WId id) +{ + DP0("S60VideoSurface::setWinId +++"); + + m_winId = id; + + DP0("S60VideoSurface::setWinId ---"); +} + +/*! + \return the sub-rect of a window where video is displayed. +*/ + +QRect S60VideoSurface::displayRect() const +{ + DP0("S60VideoSurface::displayRect"); + + return m_displayRect; +} + +/*! + Sets the sub-\a rect of a window where video is displayed. +*/ + +void S60VideoSurface::setDisplayRect(const QRect &rect) +{ + DP0("S60VideoSurface::setDisplayRect +++"); + + m_displayRect = rect; + + DP0("S60VideoSurface::setDisplayRect ---"); +} + +/*! + \return the brightness adjustment applied to a video surface. + + Valid brightness values range between -100 and 100, the default is 0. +*/ + +int S60VideoSurface::brightness() const +{ + DP0("S60VideoSurface::brightness"); + + return 0; +} + +/*! + Sets a \a brightness adjustment for a video surface. + + Valid brightness values range between -100 and 100, the default is 0. +*/ + +void S60VideoSurface::setBrightness(int brightness) +{ + DP0("S60VideoSurface::setBrightness +++"); + + DP1("S60VideoSurface::setBrightness - brightness:", brightness); + + Q_UNUSED(brightness); + + DP0("S60VideoSurface::setBrightness ---"); +} + +/*! + \return the contrast adjustment applied to a video surface. + + Valid contrast values range between -100 and 100, the default is 0. +*/ + +int S60VideoSurface::contrast() const +{ + DP0("S60VideoSurface::contrast"); + + return 0; +} + +/*! + Sets the \a contrast adjustment for a video surface. + + Valid contrast values range between -100 and 100, the default is 0. +*/ + +void S60VideoSurface::setContrast(int contrast) +{ + DP0("S60VideoSurface::setContrast +++"); + + DP1("S60VideoSurface::setContrast - ", contrast); + + Q_UNUSED(contrast); + + DP0("S60VideoSurface::setContrast ---"); +} + +/*! + \return the hue adjustment applied to a video surface. + + Value hue values range between -100 and 100, the default is 0. +*/ + +int S60VideoSurface::hue() const +{ + DP0("S60VideoSurface::hue"); + + return 0; +} + +/*! + Sets a \a hue adjustment for a video surface. + + Valid hue values range between -100 and 100, the default is 0. +*/ + +void S60VideoSurface::setHue(int hue) +{ + DP0("S60VideoSurface::setHue +++"); + + DP1("S60VideoSurface::setHue - ", hue); + + Q_UNUSED(hue); + + DP0("S60VideoSurface::setHue ---"); +} + +/*! + \return the saturation adjustment applied to a video surface. + + Value saturation values range between -100 and 100, the default is 0. +*/ + +int S60VideoSurface::saturation() const +{ + DP0("S60VideoSurface::saturation"); + + return 0; +} + +/*! + Sets a \a saturation adjustment for a video surface. + + Valid saturation values range between -100 and 100, the default is 0. +*/ + +void S60VideoSurface::setSaturation(int saturation) +{ + DP0("S60VideoSurface::setSaturation +++"); + + DP1("S60VideoSurface::setSaturation - ", saturation); + + Q_UNUSED(saturation); + + DP0("S60VideoSurface::setSaturation ---"); +} + +/*! + * \return ZERO. \a attribute, \a minimum, \a maximum are not used. +*/ +int S60VideoSurface::getAttribute(const char *attribute, int minimum, int maximum) const +{ + DP0("S60VideoSurface::getAttribute +++"); + + Q_UNUSED(attribute); + Q_UNUSED(minimum); + Q_UNUSED(maximum); + + DP0("S60VideoSurface::getAttribute ---"); + + return 0; +} + +/*! + * Sets the \a attribute, \a minimum, \a maximum. + * But never used. +*/ + +void S60VideoSurface::setAttribute(const char *attribute, int value, int minimum, int maximum) +{ + DP0("S60VideoSurface::setAttribute +++"); + + Q_UNUSED(attribute); + Q_UNUSED(value); + Q_UNUSED(minimum); + Q_UNUSED(maximum); + + DP0("S60VideoSurface::setAttribute ---"); + +} + +/*! + * \return ZERO. + * \a value, \a fromLower, \a fromUpper, \a toLower, \a toUpper are never used. +*/ + +int S60VideoSurface::redistribute( + int value, int fromLower, int fromUpper, int toLower, int toUpper) +{ + DP0("S60VideoSurface::redistribute +++"); + + Q_UNUSED(value); + Q_UNUSED(fromLower); + Q_UNUSED(fromUpper); + Q_UNUSED(toLower); + Q_UNUSED(toUpper); + + DP0("S60VideoSurface::redistribute ---"); + + return 0; +} + +/*! + * \return List of video surface supported Pixel Formats. +*/ + +QList S60VideoSurface::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + DP0("S60VideoSurface::supportedPixelFormats +++"); + + Q_UNUSED(handleType); + QList list; + + DP0("S60VideoSurface::supportedPixelFormats ---"); + + return list; +} + +/*! + * \return always FALSE, as \a format never used. +*/ + +bool S60VideoSurface::start(const QVideoSurfaceFormat &format) +{ + DP0("S60VideoSurface::start"); + + Q_UNUSED(format); + return false; +} + +/*! + * Stops video surface. +*/ +void S60VideoSurface::stop() +{ + DP0("S60VideoSurface::stop +++"); + + DP0("S60VideoSurface::stop ---"); + +} + +/*! + * \return always FALS, as \a format is never used. +*/ +bool S60VideoSurface::present(const QVideoFrame &frame) +{ + DP0("S60VideoSurface::present"); + + Q_UNUSED(frame); + return false; +} + +/*! + * \return always FALSE. +*/ + +bool S60VideoSurface::findPort() +{ + DP0("S60VideoSurface::findPort"); + + return false; +} + +void S60VideoSurface::querySupportedFormats() +{ + DP0("S60VideoSurface::querySupportedFormats +++"); + + DP0("S60VideoSurface::querySupportedFormats ---"); + +} + +/*! + * \return always FLASE, as \a format never used. +*/ + +bool S60VideoSurface::isFormatSupported(const QVideoSurfaceFormat &format) const +{ + DP0("S60VideoSurface::isFormatSupported"); + + Q_UNUSED(format); + return false; +} diff --git a/src/plugins/symbian/mmf/mediaplayer/s60videosurface.h b/src/plugins/symbian/mmf/mediaplayer/s60videosurface.h new file mode 100644 index 000000000..9f13755b7 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60videosurface.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60VIDEOSURFACE_H +#define S60VIDEOSURFACE_H + +#include +#include + +class S60VideoSurface : public QAbstractVideoSurface +{ + Q_OBJECT +public: + S60VideoSurface(QObject *parent = 0); + ~S60VideoSurface(); + + WId winId() const; + void setWinId(WId id); + + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const; + + bool isFormatSupported(const QVideoSurfaceFormat &format) const; + + bool start(const QVideoSurfaceFormat &format); + void stop(); + + bool present(const QVideoFrame &frame); + +private: + WId m_winId; + //XvPortID m_portId; + //GC m_gc; + //XvImage *m_image; + QList m_supportedPixelFormats; + QVector m_formatIds; + QRect m_viewport; + QRect m_displayRect; + QPair m_brightnessRange; + QPair m_contrastRange; + QPair m_hueRange; + QPair m_saturationRange; + + bool findPort(); + void querySupportedFormats(); + + int getAttribute(const char *attribute, int minimum, int maximum) const; + void setAttribute(const char *attribute, int value, int minimum, int maximum); + + static int redistribute(int value, int fromLower, int fromUpper, int toLower, int toUpper); +}; + +#endif diff --git a/src/plugins/symbian/mmf/mmf.pro b/src/plugins/symbian/mmf/mmf.pro new file mode 100644 index 000000000..2bae03e59 --- /dev/null +++ b/src/plugins/symbian/mmf/mmf.pro @@ -0,0 +1,58 @@ +TEMPLATE = lib + +CONFIG += plugin +TARGET = $$qtLibraryTarget(qtmultimediakit_mmfengine) +PLUGIN_TYPE = mediaservice +include (../../../../common.pri) +qtAddLibrary(QtMultimediaKit) + +#includes here so that all defines are added here also +include(mediaplayer/mediaplayer_s60.pri) +include(radio/radio.pri) + +QT += network + +# we include mmf audiorecording only if we are not building openmaxal based backend +!contains(openmaxal_symbian_enabled, yes) { + message("Enabling mmf mediarecording backend") + include(audiosource/audiosource_s60.pri) +} + +DEPENDPATH += . +INCLUDEPATH += . \ + $${SOURCE_DIR}/include \ + $${SOURCE_DIR}/src/multimedia \ + $${SOURCE_DIR}/src/multimedia/audio \ + $${SOURCE_DIR}/src/multimedia/video \ + $${SOURCE_DIR}/plugins/multimedia/symbian/mmf/inc \ + $${SOURCE_DIR} + + +HEADERS += s60mediaserviceplugin.h \ + s60formatsupported.h + +SOURCES += s60mediaserviceplugin.cpp \ + s60formatsupported.cpp + +contains(S60_VERSION, 3.2)|contains(S60_VERSION, 3.1) { + DEFINES += PRE_S60_50_PLATFORM +} +contains(mmf_http_cookies_enabled, yes) { + DEFINES += HTTP_COOKIES_ENABLED +} +load(data_caging_paths) +TARGET.EPOCALLOWDLLDATA = 1 +TARGET.UID3=0x2002AC76 +TARGET.CAPABILITY = ALL -TCB +MMP_RULES += EXPORTUNFROZEN + +#make a sis package from plugin + api + stub (plugin) +pluginDep.sources = $${TARGET}.dll +pluginDep.path = $${QT_PLUGINS_BASE_DIR}/$${PLUGIN_TYPE} +DEPLOYMENT += pluginDep + +#Media API spesific deployment +QtMediaDeployment.sources = QtMultimediaKit.dll +QtMediaDeployment.path = /sys/bin + +DEPLOYMENT += QtMediaDeployment diff --git a/src/plugins/symbian/mmf/radio/radio.pri b/src/plugins/symbian/mmf/radio/radio.pri new file mode 100644 index 000000000..a4703d126 --- /dev/null +++ b/src/plugins/symbian/mmf/radio/radio.pri @@ -0,0 +1,24 @@ +INCLUDEPATH += $$PWD + +contains(tunerlib_s60_enabled, yes) { + + LIBS += -ltunerutility + DEFINES += TUNERLIBUSED + INCLUDEPATH += $${EPOCROOT}epoc32/include/mmf/common + + HEADERS += $$PWD/s60radiotunercontrol_31.h + SOURCES += $$PWD/s60radiotunercontrol_31.cpp +} + +contains(radioutility_s60_enabled, yes) { + LIBS += -lradio_utility + DEFINES += RADIOUTILITYLIBUSED + + HEADERS += $$PWD/s60radiotunercontrol_since32.h + SOURCES += $$PWD/s60radiotunercontrol_since32.cpp +} + +contains(tunerlib_s60_enabled, yes)|contains(radioutility_s60_enabled, yes) { + HEADERS += $$PWD/s60radiotunerservice.h + SOURCES += $$PWD/s60radiotunerservice.cpp +} diff --git a/src/plugins/symbian/mmf/radio/s60radiotunercontrol_31.cpp b/src/plugins/symbian/mmf/radio/s60radiotunercontrol_31.cpp new file mode 100644 index 000000000..b7627e312 --- /dev/null +++ b/src/plugins/symbian/mmf/radio/s60radiotunercontrol_31.cpp @@ -0,0 +1,603 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DebugMacros.h" + +#include "s60radiotunercontrol_31.h" +#include "s60radiotunerservice.h" + +#include +#include + +// from AudioPreference.h +const TInt KAudioPriorityFMRadio = 79; +const TUint KAudioPrefRadioAudioEvent = 0x03000001; + +S60RadioTunerControl::S60RadioTunerControl(QObject *parent) + : QRadioTunerControl(parent) + , m_error(0) + , m_tunerState(0) + , m_apiTunerState(QRadioTuner::StoppedState) + , m_audioInitializationComplete(false) + , m_radioError(QRadioTuner::NoError) + , m_muted(false) + , m_isStereo(true) + , m_stereoMode(QRadioTuner::Auto) + , m_signal(0) + , m_currentBand(QRadioTuner::FM) + , m_currentFreq(87500000) + , m_scanning(false) + , m_vol(50) +{ + DP0("S60RadioTunerControl::S60RadioTunerControl +++"); + + initRadio(); + + DP0("S60RadioTunerControl::S60RadioTunerControl ---"); +} + +S60RadioTunerControl::~S60RadioTunerControl() +{ + DP0("S60RadioTunerControl::~S60RadioTunerControl +++"); + + if (m_tunerUtility) { + m_tunerUtility->Close(); + m_tunerUtility->CancelNotifyChange(); + m_tunerUtility->CancelNotifySignalStrength(); + m_tunerUtility->CancelNotifyStereoChange(); + delete m_tunerUtility; + } + if (m_audioPlayerUtility) { + m_audioPlayerUtility = NULL; + } + + DP0("S60RadioTunerControl::~S60RadioTunerControl ---"); +} + +bool S60RadioTunerControl::initRadio() +{ + DP0("S60RadioTunerControl::initRadio +++"); + + m_available = false; + + TRAPD(tunerError, m_tunerUtility = CMMTunerUtility::NewL(*this, CMMTunerUtility::ETunerBandFm, 1, + CMMTunerUtility::ETunerAccessPriorityNormal)); + if (tunerError != KErrNone) { + m_radioError = QRadioTuner::OpenError; + return m_available; + } + + TRAPD(playerError, m_audioPlayerUtility = m_tunerUtility->TunerPlayerUtilityL(*this)); + if (playerError != KErrNone) { + m_radioError = QRadioTuner::OpenError; + return m_available; + } + + TRAPD(initializeError, m_audioPlayerUtility->InitializeL(KAudioPriorityFMRadio, + TMdaPriorityPreference(KAudioPrefRadioAudioEvent))); + if (initializeError != KErrNone) { + m_radioError = QRadioTuner::OpenError; + return m_available; + } + + m_tunerUtility->NotifyChange(*this); + m_tunerUtility->NotifyStereoChange(*this); + m_tunerUtility->NotifySignalStrength(*this); + + TFrequency freq(m_currentFreq); + m_tunerUtility->Tune(freq); + + m_available = true; + + DP0("S60RadioTunerControl::initRadio ---"); + + return m_available; +} + +void S60RadioTunerControl::start() +{ + DP0("S60RadioTunerControl::start +++"); + + if (!m_audioInitializationComplete) { + TFrequency freq(m_currentFreq); + m_tunerUtility->Tune(freq); + } else { + m_audioPlayerUtility->Play(); + } + + m_apiTunerState = QRadioTuner::ActiveState; + emit stateChanged(m_apiTunerState); + + DP0("S60RadioTunerControl::start ---"); +} + +void S60RadioTunerControl::stop() +{ + DP0("S60RadioTunerControl::stop +++"); + + if (m_audioPlayerUtility) { + m_audioPlayerUtility->Stop(); + m_apiTunerState = QRadioTuner::StoppedState; + emit stateChanged(m_apiTunerState); + } + + DP0("S60RadioTunerControl::stop ---"); +} + +QRadioTuner::State S60RadioTunerControl::state() const +{ + DP0("S60RadioTunerControl::state"); + + return m_apiTunerState; +} + +QRadioTuner::Band S60RadioTunerControl::band() const +{ + DP0("S60RadioTunerControl::band"); + + return m_currentBand; +} + +bool S60RadioTunerControl::isBandSupported(QRadioTuner::Band b) const +{ + DP0("S60RadioTunerControl::isBandSupported"); + + if(b == QRadioTuner::FM) + return true; + else if(b == QRadioTuner::LW) + return false; + else if(b == QRadioTuner::AM) + return true; + else if(b == QRadioTuner::SW) + return false; + else + return false; +} + +void S60RadioTunerControl::setBand(QRadioTuner::Band b) +{ + DP0("S60RadioTunerControl::setBand +++"); + + QRadioTuner::Band tempBand = b; + if (tempBand != m_currentBand) { + m_currentBand = b; + emit bandChanged(m_currentBand); + } + + DP0("S60RadioTunerControl::setBand ---"); +} + +int S60RadioTunerControl::frequency() const +{ + DP0("S60RadioTunerControl::frequency"); + + return m_currentFreq; +} + +void S60RadioTunerControl::setFrequency(int frequency) +{ + DP0("S60RadioTunerControl::setFrequency +++"); + + m_currentFreq = frequency; + TFrequency freq(m_currentFreq); + m_tunerUtility->Tune(freq); + + DP0("S60RadioTunerControl::setFrequency ---"); +} + +int S60RadioTunerControl::frequencyStep(QRadioTuner::Band b) const +{ + DP0("S60RadioTunerControl::frequencyStep +++"); + + int step = 0; + + if(b == QRadioTuner::FM) + step = 100000; // 100kHz steps + else if(b == QRadioTuner::LW) + step = 1000; // 1kHz steps + else if(b == QRadioTuner::AM) + step = 1000; // 1kHz steps + else if(b == QRadioTuner::SW) + step = 500; // 500Hz steps + + DP1("S60RadioTunerControl::frequencyStep, Step:", step); + DP0("S60RadioTunerControl::frequencyStep ---"); + + return step; +} + +QPair S60RadioTunerControl::frequencyRange(QRadioTuner::Band band) const +{ + DP0("S60RadioTunerControl::frequencyRange +++"); + + TFrequency bottomFreq; + TFrequency topFreq; + int bandError = KErrNone; + + if (m_tunerUtility){ + bandError = m_tunerUtility->GetFrequencyBandRange(bottomFreq, topFreq); + if (!bandError) { + return qMakePair(bottomFreq.iFrequency, topFreq.iFrequency); + } + } + + DP0("S60RadioTunerControl::frequencyRange ---"); + + return qMakePair(0,0); +} + +CMMTunerUtility::TTunerBand S60RadioTunerControl::getNativeBand(QRadioTuner::Band b) const +{ + DP0("S60RadioTunerControl::getNativeBand"); + + // api match to native s60 bands + if (b == QRadioTuner::AM) + return CMMTunerUtility::ETunerBandAm; + else if (b == QRadioTuner::FM) + return CMMTunerUtility::ETunerBandFm; + else if (b == QRadioTuner::LW) + return CMMTunerUtility::ETunerBandLw; + else + return CMMTunerUtility::ETunerNoBand; +} + +bool S60RadioTunerControl::isStereo() const +{ + DP0("S60RadioTunerControl::isStereo"); + + return m_isStereo; +} + +QRadioTuner::StereoMode S60RadioTunerControl::stereoMode() const +{ + DP0("S60RadioTunerControl::stereoMode"); + + return m_stereoMode; +} + +void S60RadioTunerControl::setStereoMode(QRadioTuner::StereoMode mode) +{ + DP0("S60RadioTunerControl::setStereoMode +++"); + + m_stereoMode = mode; + if (m_tunerUtility) { + if (QRadioTuner::ForceMono == mode) + m_tunerUtility->ForceMonoReception(true); + else + m_tunerUtility->ForceMonoReception(false); + } + + DP0("S60RadioTunerControl::setStereoMode ---"); +} + +int S60RadioTunerControl::signalStrength() const +{ + DP0("S60RadioTunerControl::signalStrength +++"); + + // return value is a percentage value + if (m_tunerUtility) { + TInt maxSignalStrength; + TInt currentSignalStrength; + m_error = m_tunerUtility->GetMaxSignalStrength(maxSignalStrength); + if (m_error == KErrNone) { + m_error = m_tunerUtility->GetSignalStrength(currentSignalStrength); + if (m_error == KErrNone) { + if (maxSignalStrength == 0 || currentSignalStrength == 0) { + return 0; + } + m_signal = ((TInt64)currentSignalStrength) * 100 / maxSignalStrength; + } + } + } + + DP1("S60RadioTunerControl::signalStrength, m_signal:", m_signal); + DP0("S60RadioTunerControl::signalStrength ---"); + + return m_signal; +} + +int S60RadioTunerControl::volume() const +{ + DP0("S60RadioTunerControl::volume"); + + return m_vol; +} + +void S60RadioTunerControl::setVolume(int volume) +{ + DP0("S60RadioTunerControl::setVolume +++"); + DP1("S60RadioTunerControl::setVolume: ", volume); + + if (m_audioPlayerUtility) { + m_vol = volume; + TInt error = m_audioPlayerUtility->SetVolume(volume/10); + emit volumeChanged(m_vol); + } + + DP0("S60RadioTunerControl::setVolume ---"); +} + +bool S60RadioTunerControl::isMuted() const +{ + DP0("S60RadioTunerControl::isMuted"); + + return m_muted; +} + +void S60RadioTunerControl::setMuted(bool muted) +{ + DP0("S60RadioTunerControl::setMuted +++"); + + DP1("S60RadioTunerControl::setMuted:", muted); + + if (m_audioPlayerUtility && m_audioInitializationComplete) { + m_muted = muted; + m_audioPlayerUtility->Mute(m_muted); + emit mutedChanged(m_muted); + } + + DP0("S60RadioTunerControl::setMuted ---"); +} + +bool S60RadioTunerControl::isSearching() const +{ + DP0("S60RadioTunerControl::isSearching"); + + if (m_tunerUtility) { + TUint32 tempState; + m_tunerUtility->GetState(tempState); + if (tempState == CMMTunerUtility::ETunerStateRetuning || m_scanning) { + return true; + } else + return false; + } + return true; +} + +void S60RadioTunerControl::cancelSearch() +{ + DP0("S60RadioTunerControl::cancelSearch +++"); + + m_tunerUtility->CancelRetune(); + m_scanning = false; + emit searchingChanged(false); + + DP0("S60RadioTunerControl::cancelSearch ---"); +} + +void S60RadioTunerControl::searchForward() +{ + DP0("S60RadioTunerControl::searchForward +++"); + + m_scanning = true; + setVolume(m_vol); + m_tunerUtility->StationSeek(CMMTunerUtility::ESearchDirectionUp); + emit searchingChanged(true); + + DP0("S60RadioTunerControl::searchForward ---"); +} + +void S60RadioTunerControl::searchBackward() +{ + DP0("S60RadioTunerControl::searchBackward +++"); + + m_scanning = true; + setVolume(m_vol); + m_tunerUtility->StationSeek(CMMTunerUtility::ESearchDirectionDown); + emit searchingChanged(true); + + DP0("S60RadioTunerControl::searchBackward ---"); +} + +bool S60RadioTunerControl::isValid() const +{ + DP0("S60RadioTunerControl::isValid"); + + return m_available; +} + +bool S60RadioTunerControl::isAvailable() const +{ + DP0("S60RadioTunerControl::isAvailable"); + + return m_available; +} + +QtMultimediaKit::AvailabilityError S60RadioTunerControl::availabilityError() const +{ + DP0("S60RadioTunerControl::availabilityError"); + + if (m_available) + return QtMultimediaKit::NoError; + else + return QtMultimediaKit::ResourceError; +} + +QRadioTuner::Error S60RadioTunerControl::error() const +{ + DP1("QtMultimediaKit::NoError", m_radioError); + + return m_radioError; +} + +QString S60RadioTunerControl::errorString() const +{ + DP1("S60RadioTunerControl::errorString", m_errorString); + + return m_errorString; +} + +void S60RadioTunerControl::MToTuneComplete(TInt aError) +{ + DP0("S60RadioTunerControl::MToTuneComplete +++"); + DP1("S60RadioTunerControl::MToTuneComplete, aError:",aError); + + if (aError == KErrNone) { + m_scanning = false; + m_audioPlayerUtility->Play(); + if (!m_audioInitializationComplete) { + TRAPD(initializeError, m_audioPlayerUtility->InitializeL(KAudioPriorityFMRadio, + TMdaPriorityPreference(KAudioPrefRadioAudioEvent))); + if (initializeError != KErrNone) { + m_radioError = QRadioTuner::OpenError; + } + } + } + + DP0("S60RadioTunerControl::MToTuneComplete ---"); +} + +void S60RadioTunerControl::MTcoFrequencyChanged(const TFrequency& aOldFrequency, const TFrequency& aNewFrequency) +{ + DP0("S60RadioTunerControl::MTcoFrequencyChanged +++"); + + m_currentFreq = aNewFrequency.iFrequency; + m_scanning = false; + emit frequencyChanged(m_currentFreq); + + DP0("S60RadioTunerControl::MTcoFrequencyChanged ---"); +} + +void S60RadioTunerControl::MTcoStateChanged(const TUint32& aOldState, const TUint32& aNewState) +{ + DP0("S60RadioTunerControl::MTcoStateChanged +++"); + + if (aNewState == CMMTunerUtility::ETunerStateActive) { + m_apiTunerState = QRadioTuner::ActiveState; + } + if (aNewState == CMMTunerUtility::ETunerStatePlaying) { + m_apiTunerState = QRadioTuner::ActiveState; + } + if (aOldState != aNewState){ + emit stateChanged(m_apiTunerState); + } + + DP0("S60RadioTunerControl::MTcoStateChanged ---"); +} + +void S60RadioTunerControl::MTcoAntennaDetached() +{ + DP0("S60RadioTunerControl::MTcoAntennaDetached +++"); + + DP0("S60RadioTunerControl::MTcoAntennaDetached ---"); + + // no actions +} + +void S60RadioTunerControl::MTcoAntennaAttached() +{ + DP0("S60RadioTunerControl::MTcoAntennaAttached +++"); + + DP0("S60RadioTunerControl::MTcoAntennaAttached ---"); + + // no actions +} + +void S60RadioTunerControl::FlightModeChanged(TBool aFlightMode) +{ + DP0("S60RadioTunerControl::FlightModeChanged +++"); + + DP0("S60RadioTunerControl::FlightModeChanged ---"); + + // no actions +} + +void S60RadioTunerControl::MTsoStereoReceptionChanged(TBool aStereo) +{ + DP0("S60RadioTunerControl::MTsoStereoReceptionChanged +++"); + DP1("S60RadioTunerControl::MTsoStereoReceptionChanged, aStereo:", aStereo); + m_isStereo = aStereo; + emit stereoStatusChanged(aStereo); + + DP0("S60RadioTunerControl::MTsoStereoReceptionChanged ---"); +} + +void S60RadioTunerControl::MTsoForcedMonoChanged(TBool aForcedMono) +{ + DP0("S60RadioTunerControl::MTsoForcedMonoChanged +++"); + DP1("S60RadioTunerControl::MTsoForcedMonoChanged, aForcedMono:", aForcedMono); + + if (aForcedMono) { + m_stereoMode = QRadioTuner::ForceMono; + } + + DP0("S60RadioTunerControl::MTsoForcedMonoChanged ---"); +} + +void S60RadioTunerControl::MssoSignalStrengthChanged(TInt aNewSignalStrength) +{ + DP0("S60RadioTunerControl::MssoSignalStrengthChanged +++"); + DP1("S60RadioTunerControl::MssoSignalStrengthChanged, aNewSignalStrength:", aNewSignalStrength); + + m_signal = aNewSignalStrength; + emit signalStrengthChanged(m_signal); + + DP0("S60RadioTunerControl::MssoSignalStrengthChanged ---"); +} + +void S60RadioTunerControl::MTapoInitializeComplete(TInt aError) +{ + DP0("S60RadioTunerControl::MTapoInitializeComplete +++"); + DP1("S60RadioTunerControl::MTapoInitializeComplete, aError:", aError); + if (aError == KErrNone) { + m_audioInitializationComplete = true; + m_available = true; + m_audioPlayerUtility->Play(); + m_apiTunerState = QRadioTuner::ActiveState; + emit stateChanged(m_apiTunerState); + } else if (aError != KErrNone) { + m_radioError = QRadioTuner::OpenError; + } + + DP0("S60RadioTunerControl::MTapoInitializeComplete ---"); +} + +void S60RadioTunerControl::MTapoPlayEvent(TEventType aEvent, TInt aError, TAny* aAdditionalInfo) +{ + DP0("S60RadioTunerControl::MTapoPlayEvent +++"); + + DP0("S60RadioTunerControl::MTapoPlayEvent ---"); + + // no actions +} + + + diff --git a/src/plugins/symbian/mmf/radio/s60radiotunercontrol_31.h b/src/plugins/symbian/mmf/radio/s60radiotunercontrol_31.h new file mode 100644 index 000000000..c8bb8d362 --- /dev/null +++ b/src/plugins/symbian/mmf/radio/s60radiotunercontrol_31.h @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60RADIOTUNERCONTROL_H +#define S60RADIOTUNERCONTROL_H + +#include +#include +#include +#include + +class S60RadioTunerService; + +QT_USE_NAMESPACE + +class S60RadioTunerControl + : public QRadioTunerControl + , public MMMTunerObserver + , public MMMTunerStereoObserver + , public MMMSignalStrengthObserver + , public MMMTunerChangeObserver + , public MMMTunerAudioPlayerObserver +{ + Q_OBJECT +public: + S60RadioTunerControl(QObject *parent = 0); + ~S60RadioTunerControl(); + + QRadioTuner::State state() const; + + QRadioTuner::Band band() const; + void setBand(QRadioTuner::Band b); + bool isBandSupported(QRadioTuner::Band b) const; + + int frequency() const; + int frequencyStep(QRadioTuner::Band b) const; + QPair frequencyRange(QRadioTuner::Band b) const; + void setFrequency(int frequency); + + bool isStereo() const; + QRadioTuner::StereoMode stereoMode() const; + void setStereoMode(QRadioTuner::StereoMode mode); + + int signalStrength() const; + + int volume() const; + void setVolume(int volume); + + bool isMuted() const; + void setMuted(bool muted); + + bool isSearching() const; + void searchForward(); + void searchBackward(); + void cancelSearch(); + + bool isValid() const; + + bool isAvailable() const; + QtMultimediaKit::AvailabilityError availabilityError() const; + + void start(); + void stop(); + + QRadioTuner::Error error() const; + QString errorString() const; + + //MMMTunerObserver + void MToTuneComplete(TInt aError); + + //MMMTunerChangeObserver + void MTcoFrequencyChanged(const TFrequency& aOldFrequency, const TFrequency& aNewFrequency); + void MTcoStateChanged(const TUint32& aOldState, const TUint32& aNewState); + void MTcoAntennaDetached(); + void MTcoAntennaAttached(); + void FlightModeChanged(TBool aFlightMode); + + //MMMTunerStereoObserver + void MTsoStereoReceptionChanged(TBool aStereo); + void MTsoForcedMonoChanged(TBool aForcedMono); + + //MMMSignalStrengthObserver + void MssoSignalStrengthChanged(TInt aNewSignalStrength); + + //MMMTunerAudioPlayerObserver + void MTapoInitializeComplete(TInt aError); + void MTapoPlayEvent(TEventType aEvent, TInt aError, TAny* aAdditionalInfo); + +private slots: + + +private: + bool initRadio(); + CMMTunerUtility::TTunerBand getNativeBand(QRadioTuner::Band b) const; + + mutable int m_error; + CMMTunerUtility *m_tunerUtility; + CMMTunerAudioPlayerUtility *m_audioPlayerUtility; + + bool m_audioInitializationComplete; + bool m_muted; + bool m_isStereo; + bool m_available; + int m_step; + int m_vol; + mutable int m_signal; + bool m_scanning; + bool forward; + QRadioTuner::Band m_currentBand; + qint64 m_currentFreq; + + QRadioTuner::Error m_radioError; + QRadioTuner::StereoMode m_stereoMode; + QString m_errorString; + //caps meaning what the tuner can do. + TTunerCapabilities m_currentTunerCapabilities; + long m_tunerState; + QRadioTuner::State m_apiTunerState; + +}; + +#endif + diff --git a/src/plugins/symbian/mmf/radio/s60radiotunercontrol_since32.cpp b/src/plugins/symbian/mmf/radio/s60radiotunercontrol_since32.cpp new file mode 100644 index 000000000..991c6b8e4 --- /dev/null +++ b/src/plugins/symbian/mmf/radio/s60radiotunercontrol_since32.cpp @@ -0,0 +1,685 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DebugMacros.h" + +#include "s60radiotunercontrol_since32.h" +#include "s60radiotunerservice.h" + +#include +#include + +S60RadioTunerControl::S60RadioTunerControl(QObject *parent) + : QRadioTunerControl(parent) + , m_error(0) + , m_radioUtility(NULL) + , m_fmTunerUtility(NULL) + , m_playerUtility(NULL) + , m_maxVolume(100) + , m_audioInitializationComplete(false) + , m_muted(false) + , m_isStereo(true) + , m_vol(50) + , m_signal(0) + , m_scanning(false) + , m_currentBand(QRadioTuner::FM) + , m_currentFreq(87500000) + , m_radioError(QRadioTuner::NoError) + , m_stereoMode(QRadioTuner::Auto) + , m_apiTunerState(QRadioTuner::StoppedState) + , m_previousSignal(0) + , m_volChangeRequired(false) + , m_signalStrengthTimer(new QTimer(this)) +{ + DP0("S60RadioTunerControl::S60RadioTunerControl +++"); + bool retValue = initRadio(); + if (!retValue) { + m_errorString = QString(tr("Initialize Error.")); + emit error(QRadioTuner::ResourceError); + } else { + connect(m_signalStrengthTimer, SIGNAL(timeout()), this, SLOT(changeSignalStrength())); + } + DP0("S60RadioTunerControl::S60RadioTunerControl ---"); +} + +S60RadioTunerControl::~S60RadioTunerControl() +{ + DP0("S60RadioTunerControl::~S60RadioTunerControl +++"); + + if (m_fmTunerUtility) { + m_fmTunerUtility->Close(); + } + + if (m_playerUtility) { + m_playerUtility->Close(); + } + + delete m_radioUtility; + + DP0("S60RadioTunerControl::~S60RadioTunerControl ---"); +} + +QRadioTuner::State S60RadioTunerControl::state() const +{ + DP0("S60RadioTunerControl::state"); + + return m_apiTunerState; +} + +QRadioTuner::Band S60RadioTunerControl::band() const +{ + DP0("S60RadioTunerControl::band"); + + return m_currentBand; +} + +bool S60RadioTunerControl::isBandSupported(QRadioTuner::Band b) const +{ + DP0("S60RadioTunerControl::isBandSupported"); + if (b == QRadioTuner::FM) + return true; + else if (b == QRadioTuner::LW) + return false; + else if (b == QRadioTuner::AM) + return false; + else if (b == QRadioTuner::SW) + return false; + else if (b == QRadioTuner::FM2) + return false; + else + return false; +} + +void S60RadioTunerControl::changeSignalStrength() + { + + int currentSignal = signalStrength(); + if (currentSignal != m_previousSignal) + { + m_previousSignal = currentSignal; + emit signalStrengthChanged(currentSignal); + } + } +void S60RadioTunerControl::setBand(QRadioTuner::Band b) +{ + DP0("S60RadioTunerControl::setBand +++"); + QRadioTuner::Band tempBand = b; + if (tempBand != m_currentBand ) { + if (isBandSupported(tempBand)){ + m_currentBand = b; + emit bandChanged(m_currentBand); + } + else { + switch(tempBand) + { + case QRadioTuner::FM : + m_errorString = QString(tr("Band FM not Supported")); + break; + case QRadioTuner::AM : + m_errorString = QString(tr("Band AM not Supported")); + break; + case QRadioTuner::SW : + m_errorString = QString(tr("Band SW not Supported")); + break; + case QRadioTuner::LW : + m_errorString = QString(tr("Band LW not Supported")); + break; + case QRadioTuner::FM2 : + m_errorString = QString(tr("Band FM2 not Supported")); + break; + default : + m_errorString = QString("Band %1 not Supported").arg(tempBand); + break; + } + emit error(QRadioTuner::OutOfRangeError); + } + } + + DP0("S60RadioTunerControl::setBand ---"); +} + +int S60RadioTunerControl::frequency() const +{ + DP0("S60RadioTunerControl::frequency"); + + return m_currentFreq; +} + +void S60RadioTunerControl::setFrequency(int frequency) +{ + DP0("S60RadioTunerControl::setFrequency +++"); + DP1("S60RadioTunerControl::setFrequency, frequency:", frequency); + + m_currentFreq = frequency; + m_fmTunerUtility->SetFrequency(m_currentFreq); + + DP0("S60RadioTunerControl::setFrequency ---"); +} +int S60RadioTunerControl::frequencyStep(QRadioTuner::Band b) const +{ + DP0("S60RadioTunerControl::frequencyStep +++"); + + int step = 0; + if (b == QRadioTuner::FM) + step = 100000; // 100kHz steps + else if(b == QRadioTuner::LW) + step = 1000; // 1kHz steps + else if (b == QRadioTuner::AM) + step = 1000; // 1kHz steps + else if(b == QRadioTuner::SW) + step = 500; // 500Hz steps + DP1("S60RadioTunerControl::frequencyStep, Step:", step); + DP0("S60RadioTunerControl::frequencyStep ---"); + + return step; +} + +QPair S60RadioTunerControl::frequencyRange(QRadioTuner::Band band) const +{ + DP0("S60RadioTunerControl::frequencyRange +++"); + + int bottomFreq; + int topFreq; + + int bandError = KErrNone; + TFmRadioFrequencyRange range; + + if (m_fmTunerUtility) { + bandError = m_fmTunerUtility->GetFrequencyRange(range, bottomFreq, topFreq); + } + if (!bandError) { + return qMakePair(bottomFreq, topFreq); + } + + DP0("S60RadioTunerControl::frequencyRange ---"); + + return qMakePair(0,0); +} + +bool S60RadioTunerControl::isStereo() const +{ + DP0("S60RadioTunerControl::isStereo"); + + return m_isStereo; +} + +QRadioTuner::StereoMode S60RadioTunerControl::stereoMode() const +{ + DP0("S60RadioTunerControl::stereoMode"); + + return m_stereoMode; +} + +void S60RadioTunerControl::setStereoMode(QRadioTuner::StereoMode mode) +{ + DP0("S60RadioTunerControl::setStereoMode +++"); + + if (m_fmTunerUtility) { + if (QRadioTuner::ForceMono == mode) { + m_fmTunerUtility->ForceMonoReception(true); + m_stereoMode = QRadioTuner::ForceMono; + m_isStereo = false; + } else { + m_fmTunerUtility->ForceMonoReception(false); + m_isStereo = true; + m_stereoMode = QRadioTuner::ForceStereo; + } + } + + DP0("S60RadioTunerControl::setStereoMode ---"); +} + +int S60RadioTunerControl::signalStrength() const +{ + DP0("S60RadioTunerControl::signalStrength +++"); + + // return value is a percentage value + if (m_fmTunerUtility) { + TInt maxSignalStrength; + TInt currentSignalStrength; + m_error = m_fmTunerUtility->GetMaxSignalStrength(maxSignalStrength); + + if (m_error == KErrNone) { + m_error = m_fmTunerUtility->GetSignalStrength(currentSignalStrength); + if (m_error == KErrNone) { + if (currentSignalStrength == 0 || maxSignalStrength == 0) { + return currentSignalStrength; + } + m_signal = ((TInt64)currentSignalStrength) * 100 / maxSignalStrength; + } + } + } + + DP1("S60RadioTunerControl::signalStrength, m_signal:", m_signal); + DP0("S60RadioTunerControl::signalStrength ---"); + + return m_signal; +} + +int S60RadioTunerControl::volume() const +{ + DP0("S60RadioTunerControl::volume"); + + return m_vol; +} + +void S60RadioTunerControl::setVolume(int volume) +{ + DP0("S60RadioTunerControl::setVolume +++"); + DP1("S60RadioTunerControl::setVolume, Volume:", volume); + + int boundVolume = qBound(0, volume, 100); + + if (m_vol == boundVolume ) + return; + + if (!m_muted && m_playerUtility) { + m_vol = boundVolume; + // Don't set volume until State is in Active State. + if (state() == QRadioTuner::ActiveState ) { + m_playerUtility->SetVolume(m_vol*m_volMultiplier); + + } else { + m_volChangeRequired = TRUE; + emit volumeChanged(boundVolume); + } + } + DP0("S60RadioTunerControl::setVolume ---"); +} + +bool S60RadioTunerControl::isMuted() const +{ + DP0("S60RadioTunerControl::isMuted"); + + return m_muted; +} + +void S60RadioTunerControl::setMuted(bool muted) +{ + DP0("S60RadioTunerControl::setMuted +++"); + DP1("S60RadioTunerControl::setMuted, Muted:", muted); + if (m_playerUtility) { + m_muted = muted; + m_playerUtility->Mute(m_muted); + } + DP0("S60RadioTunerControl::setMuted ---"); +} + +bool S60RadioTunerControl::isSearching() const +{ + DP0("S60RadioTunerControl::isSearching"); + + return m_scanning; +} + +void S60RadioTunerControl::cancelSearch() +{ + DP0("S60RadioTunerControl::cancelSearch +++"); + + m_fmTunerUtility->CancelStationSeek(); + m_scanning = false; + emit searchingChanged(false); + + DP0("S60RadioTunerControl::cancelSearch ---"); +} + +void S60RadioTunerControl::searchForward() +{ + DP0("S60RadioTunerControl::searchForward +++"); + m_fmTunerUtility->StationSeek(true); + m_scanning = true; + emit searchingChanged(m_scanning); + DP0("S60RadioTunerControl::searchForward ---"); +} + +void S60RadioTunerControl::searchBackward() +{ + DP0("S60RadioTunerControl::searchBackward +++"); + m_fmTunerUtility->StationSeek(false); + m_scanning = true; + emit searchingChanged(m_scanning); + DP0("S60RadioTunerControl::searchBackward ---"); +} + +bool S60RadioTunerControl::isValid() const +{ + DP0("S60RadioTunerControl::isValid"); + + return m_available; +} + +bool S60RadioTunerControl::initRadio() +{ + DP0("S60RadioTunerControl::initRadio +++"); + m_available = false; + // create an instance of Radio Utility factory and indicate + // FM Radio is a primary client + TRAPD(utilityError, + m_radioUtility = CRadioUtility::NewL(ETrue); + // Get a tuner utility + m_fmTunerUtility = &m_radioUtility->RadioFmTunerUtilityL(*this); + // we want to listen radio in offline mode too + m_fmTunerUtility->EnableTunerInOfflineMode(ETrue); + // Get a player utility + m_playerUtility = &m_radioUtility->RadioPlayerUtilityL(*this); + ); + if (utilityError != KErrNone) { + m_radioError = QRadioTuner::ResourceError; + return m_available; + } + + m_tunerControl = false; + + m_available = true; + DP1("S60RadioTunerControl::initRadio, m_available:", m_available); + DP0("S60RadioTunerControl::initRadio ---"); + return m_available; +} + +bool S60RadioTunerControl::isAvailable() const +{ + DP0("S60RadioTunerControl::isAvailable"); + + return m_available; +} + +QtMultimediaKit::AvailabilityError S60RadioTunerControl::availabilityError() const +{ + DP0("S60RadioTunerControl::availabilityError"); + if (m_available) + return QtMultimediaKit::NoError; + else + return QtMultimediaKit::ResourceError; +} + +void S60RadioTunerControl::start() +{ + DP0("S60RadioTunerControl::start +++"); + if (!m_tunerControl) { + m_fmTunerUtility->RequestTunerControl(); + } else { + m_playerUtility->Play(); + } + m_signalStrengthTimer->start(3000); + + DP0("S60RadioTunerControl::start ---"); +} + +void S60RadioTunerControl::stop() +{ + DP0("S60RadioTunerControl::stop +++"); + if (m_playerUtility) { + m_playerUtility->Stop(); + } + m_signalStrengthTimer->stop(); + DP0("S60RadioTunerControl::stop ---"); +} + +QRadioTuner::Error S60RadioTunerControl::error() const +{ + DP1("S60RadioTunerControl::error", m_radioError); + + return m_radioError; +} +QString S60RadioTunerControl::errorString() const +{ + DP1("S60RadioTunerControl::errorString", m_errorString); + + return m_errorString; +} + +void S60RadioTunerControl::MrpoStateChange(TPlayerState aState, TInt aError) +{ + DP0("S60RadioTunerControl::MrpoStateChange +++"); + if (aError == KErrNone){ + m_radioError = QRadioTuner::NoError; + if (aState == ERadioPlayerIdle) { + m_apiTunerState = QRadioTuner::StoppedState; + } else if (aState == ERadioPlayerPlaying) { + m_apiTunerState = QRadioTuner::ActiveState; + //Apply pending volume changes. + if(m_volChangeRequired){ + setVolume(m_vol); + } + } + } else { + m_apiTunerState = QRadioTuner::StoppedState; + } + emit stateChanged(m_apiTunerState); + DP0("S60RadioTunerControl::MrpoStateChange ---"); +} + +void S60RadioTunerControl::MrpoVolumeChange(TInt aVolume) +{ + DP0("S60RadioTunerControl::MrpoVolumeChange +++"); + DP1("S60RadioTunerControl::MrpoVolumeChange, aVolume:", aVolume); + m_vol = (aVolume/m_volMultiplier); + if (!m_volChangeRequired) { + emit volumeChanged(m_vol); + + } else { + m_volChangeRequired = false; + } + DP0("S60RadioTunerControl::MrpoVolumeChange ---"); +} + +void S60RadioTunerControl::MrpoMuteChange(TBool aMute) +{ + DP0("S60RadioTunerControl::MrpoMuteChange +++"); + DP1("S60RadioTunerControl::MrpoMuteChange, aMute:", aMute); + m_muted = aMute; + emit mutedChanged(m_muted); + DP0("S60RadioTunerControl::MrpoMuteChange ---"); +} + +void S60RadioTunerControl::MrpoBalanceChange(TInt aLeftPercentage, TInt aRightPercentage) +{ + DP0("S60RadioTunerControl::MrpoBalanceChange +++"); + + DP0("S60RadioTunerControl::MrpoBalanceChange ---"); + + // no actions +} + +void S60RadioTunerControl::MrftoRequestTunerControlComplete(TInt aError) +{ + DP0("S60RadioTunerControl::MrftoRequestTunerControlComplete +++"); + DP1("S60RadioTunerControl::MrftoRequestTunerControlComplete, aError:", aError); + if (aError == KErrNone) { + m_playerUtility->GetMaxVolume(m_maxVolume); + m_volMultiplier = float(m_maxVolume)/float(100); + m_radioError = QRadioTuner::NoError; + m_tunerControl = true; + m_available = true; + m_fmTunerUtility->SetFrequency(m_currentFreq); + m_playerUtility->Play(); + int signal = signalStrength(); + if (m_signal != signal) { + emit signalStrengthChanged(signal); + m_signal = signal; + } + + } else if (aError == KFmRadioErrAntennaNotConnected) { + m_radioError = QRadioTuner::OpenError; + m_errorString = QString(tr("Antenna Not Connected")); + emit error(m_radioError); + } else if (aError == KErrAlreadyExists){ + m_radioError = QRadioTuner::ResourceError; + m_errorString = QString(tr("Resource Error.")); + emit error(m_radioError); + } else if (aError == KFmRadioErrFrequencyOutOfBandRange) { + m_radioError = QRadioTuner::OutOfRangeError; + m_errorString = QString(tr("Frequency out of band range")); + emit error(m_radioError); + }else{ + m_radioError = QRadioTuner::OpenError; + m_errorString = QString(tr("Unknown Error.")); + emit error(m_radioError); + } + + DP0("S60RadioTunerControl::MrftoRequestTunerControlComplete ---"); +} + +void S60RadioTunerControl::MrftoSetFrequencyRangeComplete(TInt aError) +{ + DP0("S60RadioTunerControl::MrftoSetFrequencyRangeComplete +++"); + DP1("S60RadioTunerControl::MrftoSetFrequencyRangeComplete, aError:", aError); + if (aError == KFmRadioErrFrequencyOutOfBandRange || KFmRadioErrFrequencyNotValid) { + m_radioError = QRadioTuner::OutOfRangeError; + m_errorString = QString(tr("Frequency Out of Band Range or Frequency Not Valid")); + emit error(m_radioError); + } else if (aError == KFmRadioErrHardwareFaulty || KFmRadioErrOfflineMode) { + m_radioError = QRadioTuner::OpenError; + m_errorString = QString(tr("Hardware failure or RadioInOfflineMode")); + emit error(m_radioError); + } + DP0("S60RadioTunerControl::MrftoSetFrequencyRangeComplete ---"); +} + +void S60RadioTunerControl::MrftoSetFrequencyComplete(TInt aError) +{ + DP0("S60RadioTunerControl::MrftoSetFrequencyComplete +++"); + DP1("S60RadioTunerControl::MrftoSetFrequencyComplete, aError", aError); + if (aError == KErrNone) { + m_radioError = QRadioTuner::NoError; + } else if (aError == KFmRadioErrFrequencyOutOfBandRange || KFmRadioErrFrequencyNotValid) { + m_radioError = QRadioTuner::OutOfRangeError; + m_errorString = QString(tr("Frequency Out of range or not Valid.")); + emit error(m_radioError); + } else if (aError == KFmRadioErrHardwareFaulty || KFmRadioErrOfflineMode) { + m_radioError = QRadioTuner::OpenError; + m_errorString = QString("Hardware failure or Radio In Offline Mode"); + emit error(m_radioError); + } + DP0("S60RadioTunerControl::MrftoSetFrequencyComplete ---"); +} + +void S60RadioTunerControl::MrftoStationSeekComplete(TInt aError, TInt aFrequency) +{ + DP0("S60RadioTunerControl::MrftoStationSeekComplete +++"); + DP3("S60RadioTunerControl::MrftoStationSeekComplete, aError:", aError, " Frequency:", aFrequency); + m_scanning = false; + if (aError == KErrNone) { + m_radioError = QRadioTuner::NoError; + m_currentFreq = aFrequency; + emit searchingChanged(m_scanning); + } else { + m_radioError = QRadioTuner::OpenError; + emit searchingChanged(m_scanning); + m_errorString = QString("Scanning Error"); + emit error(m_radioError); + } + DP0("S60RadioTunerControl::MrftoStationSeekComplete ---"); +} + +void S60RadioTunerControl::MrftoFmTransmitterStatusChange(TBool aActive) +{ + DP0("S60RadioTunerControl::MrftoFmTransmitterStatusChange +++"); + + DP0("S60RadioTunerControl::MrftoFmTransmitterStatusChange ---"); + + //no actions +} + +void S60RadioTunerControl::MrftoAntennaStatusChange(TBool aAttached) +{ + DP0("S60RadioTunerControl::MrftoAntennaStatusChange +++"); + DP1("S60RadioTunerControl::MrftoAntennaStatusChange, aAttached:", aAttached); + if (aAttached && m_tunerControl) { + m_playerUtility->Play(); + } + DP0("S60RadioTunerControl::MrftoAntennaStatusChange ---"); +} + +void S60RadioTunerControl::MrftoOfflineModeStatusChange(TBool /*aOfflineMode*/) +{ + DP0("S60RadioTunerControl::MrftoOfflineModeStatusChange +++"); + + DP0("S60RadioTunerControl::MrftoOfflineModeStatusChange ---"); + + +} + +void S60RadioTunerControl::MrftoFrequencyRangeChange(TFmRadioFrequencyRange aBand /*, TInt aMinFreq, TInt aMaxFreq*/) +{ + DP0("S60RadioTunerControl::MrftoFrequencyRangeChange +++"); + if (aBand == EFmRangeEuroAmerica) { + setBand(QRadioTuner::FM); + } + DP0("S60RadioTunerControl::MrftoFrequencyRangeChange ---"); +} + +void S60RadioTunerControl::MrftoFrequencyChange(TInt aNewFrequency) +{ + DP0("S60RadioTunerControl::MrftoFrequencyChange +++"); + DP1("S60RadioTunerControl::MrftoFrequencyChange, aNewFrequency:", aNewFrequency); + m_currentFreq = aNewFrequency; + emit frequencyChanged(m_currentFreq); + + int signal = signalStrength(); + if (m_signal != signal) { + emit signalStrengthChanged(signal); + m_signal = signal; + } + DP0("S60RadioTunerControl::MrftoFrequencyChange ---"); +} + +void S60RadioTunerControl::MrftoForcedMonoChange(TBool aForcedMono) +{ + DP0("S60RadioTunerControl::MrftoForcedMonoChange +++"); + DP1("S60RadioTunerControl::MrftoForcedMonoChange, aForcedMono:", aForcedMono); + if (aForcedMono) { + m_stereoMode = QRadioTuner::ForceMono; + } else { + m_stereoMode = QRadioTuner::ForceStereo; + } + emit stereoStatusChanged(!aForcedMono); + DP0("S60RadioTunerControl::MrftoForcedMonoChange ---"); +} + +void S60RadioTunerControl::MrftoSquelchChange(TBool aSquelch) +{ + DP0("S60RadioTunerControl::MrftoSquelchChange"); + + DP1("S60RadioTunerControl::MrftoSquelchChange, aSquelch:", aSquelch); + + // no actions +} diff --git a/src/plugins/symbian/mmf/radio/s60radiotunercontrol_since32.h b/src/plugins/symbian/mmf/radio/s60radiotunercontrol_since32.h new file mode 100644 index 000000000..481d64c67 --- /dev/null +++ b/src/plugins/symbian/mmf/radio/s60radiotunercontrol_since32.h @@ -0,0 +1,296 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60RADIOTUNERCONTROL_H +#define S60RADIOTUNERCONTROL_H + +#include +#include +#include +#include + +#include +#include +#include + +class S60RadioTunerService; +class CFMRadioEngineCallObserver; + +QT_USE_NAMESPACE + +class S60RadioTunerControl + : public QRadioTunerControl + , public MRadioPlayerObserver + , public MRadioFmTunerObserver +{ + Q_OBJECT +public: + S60RadioTunerControl(QObject *parent = 0); + ~S60RadioTunerControl(); + + QRadioTuner::State state() const; + + QRadioTuner::Band band() const; + void setBand(QRadioTuner::Band b); + bool isBandSupported(QRadioTuner::Band b) const; + + int frequency() const; + int frequencyStep(QRadioTuner::Band b) const; + QPair frequencyRange(QRadioTuner::Band b) const; + void setFrequency(int frequency); + + bool isStereo() const; + QRadioTuner::StereoMode stereoMode() const; + void setStereoMode(QRadioTuner::StereoMode mode); + + int signalStrength() const; + + int volume() const; + void setVolume(int volume); + + bool isMuted() const; + void setMuted(bool muted); + + bool isSearching() const; + void searchForward(); + void searchBackward(); + void cancelSearch(); + + bool isValid() const; + + bool isAvailable() const; + QtMultimediaKit::AvailabilityError availabilityError() const; + + void start(); + void stop(); + + QRadioTuner::Error error() const; + QString errorString() const; + + /** + * From MRadioPlayerObserver. + * Called when Radio state changed. + * + * @since S60 3.2 + * @param aState Radio player state + * @param aError A standard system error code, only used when aState is ERadioPlayerIdle + */ + void MrpoStateChange(TPlayerState aState, TInt aError); + + /** + * From MRadioPlayerObserver. + * Called when volume changes. This may be caused by other applications. + * + * @since S60 3.2 + * @param aVolume Current volume. + */ + void MrpoVolumeChange(TInt aVolume); + + /** + * From MRadioPlayerObserver. + * Called when mute setting changes. This may be caused by other applications. + * + * @since S60 3.2 + * @param aMute ETrue indicates audio is muted. + */ + void MrpoMuteChange(TBool aMute); + + /** + * From MRadioPlayerObserver. + * Called when mute setting changes. This may be caused by other applications. + * + * Called when balance setting changes. This may be caused by other applications. + * + * @since S60 3.2 + * Left speaker volume percentage. This can be any value from zero to 100. + * Zero value means left speaker is muted. + * @param aRightPercentage + * Right speaker volume percentage. This can be any value from zero to 100. + * Zero value means right speaker is muted. + */ + void MrpoBalanceChange(TInt aLeftPercentage, TInt aRightPercentage); + + + /** + * From MRadioFmTunerObserver. + * Called when Request for tuner control completes. + * + * @since S60 3.2 + * @param aError A standard system error code or FM tuner error (TFmRadioTunerError). + */ + void MrftoRequestTunerControlComplete(TInt aError); + + /** + * From MRadioFmTunerObserver. + * Set frequency range complete event. This event is asynchronous and is received after + * a call to CRadioFmTunerUtility::SetFrequencyRange. + * + * @since S60 3.2 + * @param aError A standard system error code or FM tuner error (TFmRadioTunerError). + */ + void MrftoSetFrequencyRangeComplete(TInt aError); + + /** + * From MRadioFmTunerObserver. + * Set frequency complete event. This event is asynchronous and is received after a call to + * CRadioFmTunerUtility::SetFrequency. + * + * @since S60 3.2 + * @param aError A standard system error code or FM tuner error (TFmRadioTunerError). + */ + void MrftoSetFrequencyComplete(TInt aError); + + /** + * From MRadioFmTunerObserver. + * Station seek complete event. This event is asynchronous and is received after a call to + * CRadioFmTunerUtility::StationSeek. + * + * @since S60 3.2 + * @param aError A standard system error code or FM tuner error (TFmRadioTunerError). + * @param aFrequency The frequency(Hz) of the radio station that was found. + */ + void MrftoStationSeekComplete(TInt aError, TInt aFrequency); + + /** + * From MRadioFmTunerObserver. + * Called when FM Transmitter status changes (if one is present in the device). Tuner receiver + * is forced to be turned off due to hardware conflicts when FM transmitter is activated. + * + * @since S60 3.2 + * @param aActive ETrue if FM transmitter is active; EFalse otherwise. + */ + void MrftoFmTransmitterStatusChange(TBool aActive); + + /** + * From MRadioFmTunerObserver. + * Called when antenna status changes. + * + * @since S60 3.2 + * @param aAttached ETrue if antenna is attached; EFalse otherwise. + */ + void MrftoAntennaStatusChange(TBool aAttached); + + /** + * From MRadioFmTunerObserver. + * Called when offline mode status changes. + * @since S60 3.2 + * + ** @param aAttached ETrue if offline mode is enabled; EFalse otherwise. + */ + void MrftoOfflineModeStatusChange(TBool aOfflineMode); + + /** + * From MRadioFmTunerObserver. + * Called when the frequency range changes. This may be caused by other applications. + * + * @since S60 3.2 + * @param aNewRange New frequency range. + */ + void MrftoFrequencyRangeChange(TFmRadioFrequencyRange aBand /*, TInt aMinFreq, TInt aMaxFreq*/); + + /** + * From MRadioFmTunerObserver. + * Called when the tuned frequency changes. This may be caused by other + * applications or RDS if AF/TA is enabled. + * + * @since S60 3.2 + * @param aNewFrequency The new tuned frequency(Hz). + */ + void MrftoFrequencyChange(TInt aNewFrequency); + + /** + * From MRadioFmTunerObserver. + * Called when the forced mono status change. This may be caused by other applications. + * + * @since S60 3.2 + * @param aForcedMono ETrue if forced mono mode is enabled; EFalse otherwise. + */ + void MrftoForcedMonoChange(TBool aForcedMono); + + /** + * From MRadioFmTunerObserver. + * Called when the squelch (muting the frequencies without broadcast) status change. + * This may be caused by other applications. + * + * @since S60 3.2 + * @param aSquelch ETrue if squelch is enabled; EFalse otherwise. + */ + void MrftoSquelchChange(TBool aSquelch); + +private: + bool initRadio(); + + mutable int m_error; + + CRadioUtility* m_radioUtility; + CRadioFmTunerUtility* m_fmTunerUtility; + CRadioPlayerUtility* m_playerUtility; + TInt m_maxVolume; + TReal m_volMultiplier; + + bool m_tunerControl; + bool m_audioInitializationComplete; + bool m_muted; + bool m_isStereo; + bool m_available; + int m_vol; + bool m_volChangeRequired; + mutable int m_signal; + int m_previousSignal; + bool m_scanning; + QRadioTuner::Band m_currentBand; + qint64 m_currentFreq; + + QRadioTuner::Error m_radioError; + QRadioTuner::StereoMode m_stereoMode; + QString m_errorString; + QRadioTuner::State m_apiTunerState; + QTimer *m_signalStrengthTimer; + +Q_SIGNALS: + void error(QRadioTuner::Error) const; + +protected slots: + void changeSignalStrength(); +}; + +#endif + diff --git a/src/plugins/symbian/mmf/radio/s60radiotunerservice.cpp b/src/plugins/symbian/mmf/radio/s60radiotunerservice.cpp new file mode 100644 index 000000000..99b0bf0d2 --- /dev/null +++ b/src/plugins/symbian/mmf/radio/s60radiotunerservice.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DebugMacros.h" + +#include "s60radiotunerservice.h" + + +S60RadioTunerService::S60RadioTunerService(QObject *parent) + : QMediaService(parent) +{ + DP0("S60RadioTunerService::S60RadioTunerService +++"); + + m_playerControl = new S60RadioTunerControl(this); + + DP0("S60RadioTunerService::S60RadioTunerService ---"); +} + +S60RadioTunerService::~S60RadioTunerService() +{ + DP0("S60RadioTunerService::~S60RadioTunerService +++"); + + delete m_playerControl; + + DP0("S60RadioTunerService::~S60RadioTunerService ---"); +} + +QMediaControl *S60RadioTunerService::requestControl(const char* name) +{ + DP0("S60RadioTunerService::requestControl"); + + if (qstrcmp(name, QRadioTunerControl_iid) == 0) + return m_playerControl; + + return 0; +} + +void S60RadioTunerService::releaseControl(QMediaControl *control) +{ + DP0("S60RadioTunerService::releaseControl +++"); + + Q_UNUSED(control); + + DP0("S60RadioTunerService::releaseControl ---"); +} diff --git a/src/plugins/symbian/mmf/radio/s60radiotunerservice.h b/src/plugins/symbian/mmf/radio/s60radiotunerservice.h new file mode 100644 index 000000000..92e3eb7f8 --- /dev/null +++ b/src/plugins/symbian/mmf/radio/s60radiotunerservice.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60RADIOTUNERSERVICE_H +#define S60RADIOTUNERSERVICE_H + +#include + +#include + +#ifdef TUNERLIBUSED +#include "s60radiotunercontrol_31.h" +#else +#include "s60radiotunercontrol_since32.h" +#endif + +QT_USE_NAMESPACE + +class S60RadioTunerService : public QMediaService +{ + Q_OBJECT +public: + S60RadioTunerService(QObject *parent = 0); + ~S60RadioTunerService(); + + QMediaControl *requestControl(const char* name); + void releaseControl(QMediaControl *control); + +private: + S60RadioTunerControl *m_playerControl; +}; + +#endif diff --git a/src/plugins/symbian/mmf/s60formatsupported.cpp b/src/plugins/symbian/mmf/s60formatsupported.cpp new file mode 100644 index 000000000..e892008ab --- /dev/null +++ b/src/plugins/symbian/mmf/s60formatsupported.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "s60formatsupported.h" + + + +S60FormatSupported::S60FormatSupported() +{} + +S60FormatSupported::~S60FormatSupported() +{ + if (m_controllerparam) { + delete m_controllerparam; + m_controllerparam = NULL; + } +} + +QStringList S60FormatSupported::supportedPlayMimeTypesL() +{ + + RArray mediaIds; //search for both audio and video + + RMMFControllerImplInfoArray iControllers; + + m_controllerparam = CMMFControllerPluginSelectionParameters::NewL(); + + m_playformatparam = CMMFFormatSelectionParameters::NewL(); + + mediaIds.Append(KUidMediaTypeAudio); + + mediaIds.Append(KUidMediaTypeVideo); + + m_controllerparam->SetMediaIdsL(mediaIds, CMMFPluginSelectionParameters::EAllowOtherMediaIds); + + m_controllerparam->SetRequiredPlayFormatSupportL(*m_playformatparam); + + m_controllerparam->ListImplementationsL(iControllers); + + CDesC8ArrayFlat* controllerArray = new (ELeave) CDesC8ArrayFlat(1); + + for (TInt i = 0; i < iControllers.Count(); i++) { + for (TInt j = 0; j < (iControllers[i]->PlayFormats()).Count(); j++) { + const CDesC8Array& iarr = (iControllers[i]->PlayFormats()[j]->SupportedMimeTypes()); + + TInt count = iarr.Count(); + + for (TInt k = 0; k < count; k++) { + TPtrC8 ptr = iarr.MdcaPoint(k); + + HBufC8* n = HBufC8::NewL(ptr.Length()); + + TPtr8 ptr1 = n->Des(); + + ptr1.Copy((TUint8*) ptr.Ptr(), ptr.Length()); + + controllerArray->AppendL(ptr1); + } + } + } + +// converting CDesC8Array to QStringList + for (TInt x = 0; x < controllerArray->Count(); x++) { + m_supportedplaymime.append(QString::fromUtf8( + (const char*) (controllerArray->MdcaPoint(x).Ptr()), + controllerArray->MdcaPoint(x).Length())); + } + + // populating the list with only audio and controller mime types + QStringList tempaudio = m_supportedplaymime.filter(QString("audio")); + QStringList tempvideo = m_supportedplaymime.filter(QString("video")); + + m_supportedplaymime.clear(); + + m_supportedplaymime = tempaudio + tempvideo; + + mediaIds.Close(); + delete controllerArray; + iControllers.ResetAndDestroy(); + + return m_supportedplaymime; +} diff --git a/src/plugins/symbian/mmf/s60formatsupported.h b/src/plugins/symbian/mmf/s60formatsupported.h new file mode 100644 index 000000000..3b5a3ffe6 --- /dev/null +++ b/src/plugins/symbian/mmf/s60formatsupported.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60FORMATSUPPORTED_H_ +#define S60FORMATSUPPORTED_H_ + +#include +#include +#include +#include +#include + +class S60FormatSupported +{ +public: + S60FormatSupported(); + ~S60FormatSupported(); + + QStringList supportedPlayMimeTypesL(); + +private: + + CMMFFormatSelectionParameters* m_playformatparam; + CMMFControllerPluginSelectionParameters* m_controllerparam; + QStringList m_supportedplaymime; +}; +#endif /* S60FORMATSUPPORTED_H_ */ diff --git a/src/plugins/symbian/mmf/s60mediaserviceplugin.cpp b/src/plugins/symbian/mmf/s60mediaserviceplugin.cpp new file mode 100644 index 000000000..cfb77255f --- /dev/null +++ b/src/plugins/symbian/mmf/s60mediaserviceplugin.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "s60mediaserviceplugin.h" +#if defined(TUNERLIBUSED) || defined(RADIOUTILITYLIBUSED) +#include "s60radiotunerservice.h" +#endif +#ifdef HAS_MEDIA_PLAYER +#include "s60mediaplayerservice.h" +#endif +#ifdef AUDIOSOURCEUSED +#include "s60audiocaptureservice.h" +#endif /* AUDIOSOURCEUSED */ + +QStringList S60MediaServicePlugin::keys() const +{ + QStringList list; +#if defined(TUNERLIBUSED) || defined(RADIOUTILITYLIBUSED) + list << QLatin1String(Q_MEDIASERVICE_RADIO); +#endif + +#ifdef HAS_MEDIA_PLAYER + list << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER); +#endif +#ifdef AUDIOSOURCEUSED + list << QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE); +#endif /* AUDIOSOURCEUSED */ + return list; +} + +QMediaService* S60MediaServicePlugin::create(QString const& key) +{ +#ifdef HAS_MEDIA_PLAYER + if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER)) + return new S60MediaPlayerService; +#endif +#ifdef AUDIOSOURCEUSED + if (key == QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE)) + return new S60AudioCaptureService; +#endif /* AUDIOSOURCEUSED */ +#if defined(TUNERLIBUSED) || defined(RADIOUTILITYLIBUSED) + if (key == QLatin1String(Q_MEDIASERVICE_RADIO)) + return new S60RadioTunerService; +#endif + + return 0; +} + +void S60MediaServicePlugin::release(QMediaService *service) +{ + delete service; +} + +QtMultimediaKit::SupportEstimate S60MediaServicePlugin::hasSupport(const QString &mimeType, const QStringList& codecs) const +{ + Q_UNUSED(mimeType); + Q_UNUSED(codecs); + return QtMultimediaKit::PreferredService; +} + +QStringList S60MediaServicePlugin::supportedMimeTypes() const +{ + if (m_supportedmimetypes.isEmpty()) { + TInt err; + S60FormatSupported* formats = new (ELeave) S60FormatSupported(); + if (formats) { + TRAP(err, m_supportedmimetypes = formats->supportedPlayMimeTypesL()); + delete formats; + } + } + return m_supportedmimetypes; +} + +Q_EXPORT_PLUGIN2(qtmultimediakit_mmfengine, S60MediaServicePlugin); diff --git a/src/plugins/symbian/mmf/s60mediaserviceplugin.h b/src/plugins/symbian/mmf/s60mediaserviceplugin.h new file mode 100644 index 000000000..b2140dd6f --- /dev/null +++ b/src/plugins/symbian/mmf/s60mediaserviceplugin.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef S60SERVICEPLUGIN_H +#define S60SERVICEPLUGIN_H + +#include +#include +#include +#include "s60formatsupported.h" + +QT_USE_NAMESPACE + +class S60MediaServicePlugin : public QMediaServiceProviderPlugin,public QMediaServiceSupportedFormatsInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceSupportedFormatsInterface) +public: + + QStringList keys() const; + QMediaService* create(QString const& key); + void release(QMediaService *service); + + QtMultimediaKit::SupportEstimate hasSupport(const QString &mimeType, const QStringList& codecs) const; + QStringList supportedMimeTypes() const; +private: + mutable QStringList m_supportedmimetypes; +}; + +#endif // S60SERVICEPLUGIN_H diff --git a/src/plugins/symbian/openmaxal/mediaplayer/mediaplayer.pri b/src/plugins/symbian/openmaxal/mediaplayer/mediaplayer.pri new file mode 100644 index 000000000..7c6843e19 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/mediaplayer.pri @@ -0,0 +1,36 @@ +INCLUDEPATH += $$PWD + +LIBS += \ + -lws32 \ + -lcone + +#DEFINES += USE_VIDEOPLAYERUTILITY + +HEADERS += \ + $$PWD/qxametadatacontrol.h \ + $$PWD/qxamediastreamscontrol.h \ + $$PWD/qxamediaplayercontrol.h \ + $$PWD/qxaplaymediaservice.h \ + $$PWD/qxaplaysession.h \ + $$PWD/xaplaysessioncommon.h \ + $$PWD/qxavideowidgetcontrol.h \ + $$PWD/qxavideowindowcontrol.h \ + $$PWD/qxawidget.h \ + $$PWD/xaplaysessionimpl.h + +SOURCES += \ + $$PWD/qxamediaplayercontrol.cpp \ + $$PWD/qxametadatacontrol.cpp \ + $$PWD/qxamediastreamscontrol.cpp \ + $$PWD/qxaplaymediaservice.cpp \ + $$PWD/qxaplaysession.cpp \ + $$PWD/qxavideowidgetcontrol.cpp \ + $$PWD/qxavideowindowcontrol.cpp \ + $$PWD/qxawidget.cpp \ + $$PWD/xaplaysessionimpl.cpp + +# check for USE_VIDEOPLAYERUTILITY +contains(DEFINES, USE_VIDEOPLAYERUTILITY) { + message("Using VideoPlayerUtility instead of OpenMAX AL.") + LIBS += -lmediaclientvideo +} diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxamediaplayercontrol.cpp b/src/plugins/symbian/openmaxal/mediaplayer/qxamediaplayercontrol.cpp new file mode 100644 index 000000000..ee192105b --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxamediaplayercontrol.cpp @@ -0,0 +1,288 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include "qxamediaplayercontrol.h" +#include "qxaplaysession.h" +#include "qxacommon.h" + +QXAMediaPlayerControl::QXAMediaPlayerControl(QXAPlaySession *session, QObject *parent) + :QMediaPlayerControl(parent), mSession(session) +{ + QT_TRACE_FUNCTION_ENTRY; + connect(mSession, SIGNAL(mediaChanged(const QMediaContent &)), + this, SIGNAL(mediaChanged(const QMediaContent& ))); + connect(mSession, SIGNAL(durationChanged(qint64)), + this, SIGNAL(durationChanged(qint64))); + connect(mSession, SIGNAL(positionChanged(qint64)), + this, SIGNAL(positionChanged(qint64))); + connect(mSession, SIGNAL(stateChanged(QMediaPlayer::State)), + this, SIGNAL(stateChanged(QMediaPlayer::State))); + connect(mSession, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + this, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(mSession, SIGNAL(volumeChanged(int)), + this, SIGNAL(volumeChanged(int))); + connect(mSession, SIGNAL(mutedChanged(bool)), + this, SIGNAL(mutedChanged(bool))); + connect(mSession, SIGNAL(audioAvailableChanged(bool)), + this, SIGNAL(audioAvailableChanged(bool))); + connect(mSession, SIGNAL(videoAvailableChanged(bool)), + this, SIGNAL(videoAvailableChanged(bool))); + connect(mSession,SIGNAL(bufferStatusChanged(int)), + this, SIGNAL(bufferStatusChanged(int))); + connect(mSession, SIGNAL(seekableChanged(bool)), + this, SIGNAL(seekableChanged(bool))); + connect(mSession, SIGNAL(availablePlaybackRangesChanged(const QMediaTimeRange&)), + this, SIGNAL(availablePlaybackRangesChanged(const QMediaTimeRange&))); + connect(mSession, SIGNAL(playbackRateChanged(qreal)), + this, SIGNAL(playbackRateChanged(qreal))); + connect(mSession, SIGNAL(error(int, const QString &)), + this, SIGNAL(error(int, const QString &))); + QT_TRACE_FUNCTION_EXIT; +} + +QXAMediaPlayerControl::~QXAMediaPlayerControl() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +QMediaPlayer::State QXAMediaPlayerControl::state() const +{ + QT_TRACE_FUNCTION_ENTRY; + QMediaPlayer::State retVal = QMediaPlayer::StoppedState; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->state(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +QMediaPlayer::MediaStatus QXAMediaPlayerControl::mediaStatus() const +{ + QT_TRACE_FUNCTION_ENTRY; + QMediaPlayer::MediaStatus retVal = QMediaPlayer::NoMedia; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->mediaStatus(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +qint64 QXAMediaPlayerControl::duration() const +{ + QT_TRACE_FUNCTION_ENTRY; + qint64 retVal = 0; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->duration(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +qint64 QXAMediaPlayerControl::position() const +{ + QT_TRACE_FUNCTION_ENTRY; + qint64 retVal = 0; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->position(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +void QXAMediaPlayerControl::setPosition(qint64 pos) +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->setPosition(pos); + QT_TRACE_FUNCTION_EXIT; +} + +int QXAMediaPlayerControl::volume() const +{ + QT_TRACE_FUNCTION_ENTRY; + int retVal = 0; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->volume(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +void QXAMediaPlayerControl::setVolume(int volume) +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->setVolume(volume); + QT_TRACE_FUNCTION_EXIT; +} + +bool QXAMediaPlayerControl::isMuted() const +{ + QT_TRACE_FUNCTION_ENTRY; + bool retVal = false; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->isMuted(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +void QXAMediaPlayerControl::setMuted(bool muted) +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->setMuted(muted); + QT_TRACE_FUNCTION_EXIT; +} + +int QXAMediaPlayerControl::bufferStatus() const +{ + QT_TRACE_FUNCTION_ENTRY; + int retVal = 0; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->bufferStatus(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +bool QXAMediaPlayerControl::isAudioAvailable() const +{ + QT_TRACE_FUNCTION_ENTRY; + bool retVal = false; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->isAudioAvailable(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +bool QXAMediaPlayerControl::isVideoAvailable() const +{ + QT_TRACE_FUNCTION_ENTRY; + bool retVal = false; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->isVideoAvailable(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +bool QXAMediaPlayerControl::isSeekable() const +{ + QT_TRACE_FUNCTION_ENTRY; + bool retVal = false; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->isSeekable(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +QMediaTimeRange QXAMediaPlayerControl::availablePlaybackRanges() const +{ + QT_TRACE_FUNCTION_ENTRY; + QMediaTimeRange retVal; + RET_s_IF_p_IS_NULL(mSession, retVal); + if (mSession->isSeekable()) + retVal.addInterval(0, mSession->duration()); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +float QXAMediaPlayerControl::playbackRate() const +{ + QT_TRACE_FUNCTION_ENTRY; + float retVal = 0; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->playbackRate(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +void QXAMediaPlayerControl::setPlaybackRate(float rate) +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->setPlaybackRate(rate); + QT_TRACE_FUNCTION_EXIT; +} + +QMediaContent QXAMediaPlayerControl::media() const +{ + QT_TRACE_FUNCTION_ENTRY; + QMediaContent retVal; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->media(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +const QIODevice *QXAMediaPlayerControl::mediaStream() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return mStream; +} + +void QXAMediaPlayerControl::setMedia(const QMediaContent &content, QIODevice *stream) +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->setMedia(content); + mStream = stream; + QT_TRACE_FUNCTION_EXIT; +} + +void QXAMediaPlayerControl::play() +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->play(); + QT_TRACE_FUNCTION_EXIT; +} + +void QXAMediaPlayerControl::pause() +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->pause(); + QT_TRACE_FUNCTION_EXIT; +} + +void QXAMediaPlayerControl::stop() +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->stop(); + QT_TRACE_FUNCTION_EXIT; +} diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxamediaplayercontrol.h b/src/plugins/symbian/openmaxal/mediaplayer/qxamediaplayercontrol.h new file mode 100644 index 000000000..b9d7802bd --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxamediaplayercontrol.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXAMEDIAPLAYERCONTROL_H +#define QXAMEDIAPLAYERCONTROL_H + +#include "qmediaplayercontrol.h" +#include "qmediaplayer.h" + +QT_USE_NAMESPACE + +class QXAPlaySession; + +class QXAMediaPlayerControl : public QMediaPlayerControl +{ + Q_OBJECT +public: + QXAMediaPlayerControl(QXAPlaySession *session, QObject *parent = 0); + ~QXAMediaPlayerControl(); + + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + + qint64 duration() const; + + qint64 position() const; + void setPosition(qint64 position); + + int volume() const; + void setVolume(int volume); + + bool isMuted() const; + void setMuted(bool muted); + + int bufferStatus() const; + + bool isAudioAvailable() const; + bool isVideoAvailable() const; + + bool isSeekable() const; + + QMediaTimeRange availablePlaybackRanges() const; + + float playbackRate() const; + void setPlaybackRate(float rate); + + QMediaContent media() const; + const QIODevice *mediaStream() const; + void setMedia(const QMediaContent&, QIODevice *); + + void play(); + void pause(); + void stop(); + + +private: + QXAPlaySession *mSession; + QIODevice *mStream; +}; + +#endif /* QXAMEDIAPLAYERCONTROL_H */ diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxamediastreamscontrol.cpp b/src/plugins/symbian/openmaxal/mediaplayer/qxamediastreamscontrol.cpp new file mode 100644 index 000000000..528fb1837 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxamediastreamscontrol.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include + +#include "qxamediastreamscontrol.h" +#include "qxaplaysession.h" +#include "qxacommon.h" + +QXAMediaStreamsControl::QXAMediaStreamsControl(QXAPlaySession *session, QObject *parent) + :QMediaStreamsControl(parent), mSession(session) +{ + QT_TRACE_FUNCTION_ENTRY; + connect(mSession, SIGNAL(activeStreamsChanged()), + this, SIGNAL(activeStreamsChanged())); + connect(mSession, SIGNAL(streamsChanged()), + this, SIGNAL(streamsChanged())); + QT_TRACE_FUNCTION_EXIT; +} + +QXAMediaStreamsControl::~QXAMediaStreamsControl() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +bool QXAMediaStreamsControl::isActive (int stream) +{ + RET_s_IF_p_IS_NULL(mSession, false); + return mSession->isStreamActive(stream); +} + +QVariant QXAMediaStreamsControl::metaData (int stream, QtMultimediaKit::MetaData key) +{ + QVariant var; + RET_s_IF_p_IS_NULL(mSession, var); + QT_TRACE_FUNCTION_ENTRY; + var = mSession->metaData(stream, key); + QT_TRACE_FUNCTION_EXIT; + return var; +} + +void QXAMediaStreamsControl::setActive (int stream, bool state) +{ + Q_UNUSED(stream); + Q_UNUSED(state); +} + +int QXAMediaStreamsControl::streamCount() +{ + RET_s_IF_p_IS_NULL(mSession, 0); + return mSession->streamCount(); +} + +QMediaStreamsControl::StreamType QXAMediaStreamsControl::streamType (int stream) +{ + RET_s_IF_p_IS_NULL(mSession, QMediaStreamsControl::UnknownStream); + return mSession->streamType(stream); +} + diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxamediastreamscontrol.h b/src/plugins/symbian/openmaxal/mediaplayer/qxamediastreamscontrol.h new file mode 100644 index 000000000..d77b89ca5 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxamediastreamscontrol.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QXAMEDIASTREAMSCONTROL_H +#define QXAMEDIASTREAMSCONTROL_H + + + +#include +#include +#include +#include + +#include + +#include + +QT_USE_NAMESPACE + +class QXAPlaySession; + +class QXAMediaStreamsControl : public QMediaStreamsControl +{ + Q_OBJECT +public: + QXAMediaStreamsControl(QXAPlaySession *session, QObject *parent = 0); + ~QXAMediaStreamsControl(); + + bool isActive (int stream); + QVariant metaData (int stream, QtMultimediaKit::MetaData key); + void setActive (int stream, bool state); + int streamCount(); + QMediaStreamsControl::StreamType streamType (int stream); +private: + QXAPlaySession *mSession; +}; + +#endif //QXAMEDIASTREAMSCONTROL_H diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxametadatacontrol.cpp b/src/plugins/symbian/openmaxal/mediaplayer/qxametadatacontrol.cpp new file mode 100644 index 000000000..9c6b906cf --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxametadatacontrol.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "qxametadatacontrol.h" +#include "qxaplaysession.h" +#include "qxacommon.h" + +QXAMetaDataControl::QXAMetaDataControl(QXAPlaySession *session, QObject *parent) + :QMetaDataReaderControl(parent), mSession(session) +{ + QT_TRACE_FUNCTION_ENTRY; + connect(mSession, SIGNAL(metaDataAvailableChanged(bool)), + this, SIGNAL(metaDataAvailableChanged(bool))); + connect(mSession, SIGNAL(metaDataChanged()), + this, SIGNAL(metaDataChanged())); + QT_TRACE_FUNCTION_EXIT; +} + +QXAMetaDataControl::~QXAMetaDataControl() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +QStringList QXAMetaDataControl::availableExtendedMetaData ()const +{ + QStringList list; + RET_s_IF_p_IS_NULL(mSession, list); + QT_TRACE_FUNCTION_ENTRY; + list = mSession->availableExtendedMetaData(); + QT_TRACE_FUNCTION_EXIT; + return list; +} + +QList QXAMetaDataControl::availableMetaData () const +{ + QList list; + RET_s_IF_p_IS_NULL(mSession, list); + QT_TRACE_FUNCTION_ENTRY; + list = mSession->availableMetaData(); + QT_TRACE_FUNCTION_EXIT; + return list; +} + +QVariant QXAMetaDataControl::extendedMetaData(const QString & key ) const +{ + QVariant var; + RET_s_IF_p_IS_NULL(mSession, var); + QT_TRACE_FUNCTION_ENTRY; + var = mSession->extendedMetaData(key); + QT_TRACE_FUNCTION_EXIT; + return var; +} + +bool QXAMetaDataControl::isMetaDataAvailable() const +{ + RET_s_IF_p_IS_NULL(mSession, false); + QT_TRACE_FUNCTION_ENTRY_EXIT; + return mSession->isMetaDataAvailable(); +} + +bool QXAMetaDataControl::isWritable() const +{ + RET_s_IF_p_IS_NULL(mSession, false); + QT_TRACE_FUNCTION_ENTRY_EXIT; + return mSession->isWritable(); +} + +QVariant QXAMetaDataControl::metaData( QtMultimediaKit::MetaData key ) const +{ + QVariant var; + RET_s_IF_p_IS_NULL(mSession, var); + QT_TRACE_FUNCTION_ENTRY; + var = mSession->metaData(key); + QT_TRACE_FUNCTION_ENTRY_EXIT; + return var; +} + +void QXAMetaDataControl::setExtendedMetaData( const QString & key, const QVariant & value ) +{ + RET_IF_p_IS_NULL(mSession); + QT_TRACE_FUNCTION_ENTRY_EXIT; + return mSession->setExtendedMetaData(key,value); +} + +void QXAMetaDataControl::setMetaData( QtMultimediaKit::MetaData key, const QVariant & value ) +{ + RET_IF_p_IS_NULL(mSession); + QT_TRACE_FUNCTION_ENTRY_EXIT; + return mSession->setMetaData(key,value); +} + diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxametadatacontrol.h b/src/plugins/symbian/openmaxal/mediaplayer/qxametadatacontrol.h new file mode 100644 index 000000000..8904a5ff4 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxametadatacontrol.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXAMETADATACONTROL_H +#define QXAMETADATACONTROL_H + + + +#include +#include +#include +#include + +#include +#include +QT_USE_NAMESPACE + +class QXAPlaySession; + +class QXAMetaDataControl : public QMetaDataReaderControl +{ + Q_OBJECT +public: + QXAMetaDataControl(QXAPlaySession *session, QObject *parent = 0); + ~QXAMetaDataControl(); + + QStringList availableExtendedMetaData () const; + QList availableMetaData () const; + QVariant extendedMetaData(const QString & key ) const; + bool isMetaDataAvailable() const; + bool isWritable() const; + QVariant metaData( QtMultimediaKit::MetaData key ) const; + void setExtendedMetaData( const QString & key, const QVariant & value ); + void setMetaData( QtMultimediaKit::MetaData key, const QVariant & value ); + +private: + QXAPlaySession *mSession; +}; + +#endif //QXAMETADATACONTROL_H diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxaplaymediaservice.cpp b/src/plugins/symbian/openmaxal/mediaplayer/qxaplaymediaservice.cpp new file mode 100644 index 000000000..f2d3c4b15 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxaplaymediaservice.cpp @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include "qxaplaymediaservice.h" +#include "qxaplaysession.h" +#include "qxamediaplayercontrol.h" +#include "qxacommon.h" +#include "qxavideowidgetcontrol.h" +#include "qxavideowindowcontrol.h" +#include "qxametadatacontrol.h" +#include "qxamediastreamscontrol.h" + +QXAPlayMediaService::QXAPlayMediaService(QObject *parent) : QMediaService(parent) +{ + mSession = NULL; + mMediaPlayerControl = NULL; + mVideowidgetControl = NULL; + mVideoWindowControl = NULL; + mMetaDataControl = NULL; + mMediaStreamsControl = NULL; + + mSession = new QXAPlaySession(this); + mMediaPlayerControl = new QXAMediaPlayerControl(mSession, this); + mMetaDataControl = new QXAMetaDataControl(mSession, this); + mMediaStreamsControl = new QXAMediaStreamsControl(mSession, this); +} + +QXAPlayMediaService::~QXAPlayMediaService() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +QMediaControl *QXAPlayMediaService::requestControl(const char *name) +{ + if (qstrcmp(name, QMediaPlayerControl_iid) == 0) { + return mMediaPlayerControl; + } + else if (qstrcmp(name, QVideoWidgetControl_iid) == 0) { + if (!mVideowidgetControl) { + mVideowidgetControl = new QXAVideoWidgetControl(mSession, this); + if (mSession && mVideowidgetControl) + mSession->setVideoWidgetControl(mVideowidgetControl); + } + return mVideowidgetControl; + } + else if (qstrcmp(name, QVideoWindowControl_iid) == 0) { + if (!mVideoWindowControl) { + mVideoWindowControl = new QXAVideoWindowControl(mSession, this); + if (mSession && mVideoWindowControl) + mSession->setVideoWindowControl(mVideoWindowControl); + } + return mVideoWindowControl; + } + else if (qstrcmp(name,QMetaDataReaderControl_iid) == 0) { + return mMetaDataControl; + } + else if (qstrcmp(name,QMediaStreamsControl_iid) == 0) { + return mMediaStreamsControl; + } + + return 0; +} + +void QXAPlayMediaService::releaseControl(QMediaControl *control) +{ + if (control == mVideowidgetControl) { + if (mSession) + mSession->unsetVideoWidgetControl(qobject_cast(control)); + mVideowidgetControl = NULL; + } + else if (control == mVideoWindowControl) { + if (mSession) + mSession->unsetVideoWindowControl(qobject_cast(control)); + mVideoWindowControl = NULL; + } +} + diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxaplaymediaservice.h b/src/plugins/symbian/openmaxal/mediaplayer/qxaplaymediaservice.h new file mode 100644 index 000000000..4a344b087 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxaplaymediaservice.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXAPLAYMEDIASERVICE_H +#define QXAPLAYMEDIASERVICE_H + +#include +#include + +QT_USE_NAMESPACE + +class QXAPlaySession; +class QXAMediaPlayerControl; +class QXAVideoWidgetControl; +class QXAVideoWindowControl; +class QXAMetaDataControl; +class QXAMediaStreamsControl; + +class QXAPlayMediaService : public QMediaService +{ + Q_OBJECT +public: + QXAPlayMediaService(QObject *parent = 0); + ~QXAPlayMediaService(); + QMediaControl *requestControl(const char *name); + void releaseControl( QMediaControl *control); +private: + QXAPlaySession *mSession; + QXAMediaPlayerControl *mMediaPlayerControl; + QXAVideoWidgetControl *mVideowidgetControl; + QXAVideoWindowControl *mVideoWindowControl; + QXAMetaDataControl *mMetaDataControl; + QXAMediaStreamsControl *mMediaStreamsControl; +}; + +#endif /* QXAPLAYMEDIASERVICE_H */ diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxaplaysession.cpp b/src/plugins/symbian/openmaxal/mediaplayer/qxaplaysession.cpp new file mode 100644 index 000000000..2254a9363 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxaplaysession.cpp @@ -0,0 +1,610 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "qxaplaysession.h" +#include "xaplaysessionimpl.h" +#include "qxacommon.h" +#include + +QXAPlaySession::QXAPlaySession(QObject *parent):QObject(parent), +m_state(QMediaPlayer::StoppedState), +m_mediaStatus(QMediaPlayer::NoMedia), +mSeekable(-1), +mNumStreams(0), +mbAudioAvailable(EFalse), +mbVideoAvailable(EFalse), +mImpl(NULL), +mVideowidgetControl(NULL), +mWidgetCtrlWindow(NULL), +mWidgetCtrlWindowId(NULL), +mVideoWindowControl(NULL), +mWindowCtrlWindow(NULL), +mWindowCtrlWindowId(NULL), +mWsSession(&(CCoeEnv::Static()->WsSession())) +{ + QT_TRACE_FUNCTION_ENTRY; + mImpl = new XAPlaySessionImpl(*this); + + if (mImpl && (mImpl->postConstruct() != KErrNone)) { + delete mImpl; + mImpl = NULL; + QT_TRACE1("Error initializing implementation"); + } + + if (!mImpl) + emit error(QMediaPlayer::ResourceError, tr("Service has not been started")); + + QT_TRACE_FUNCTION_EXIT; +} + +QXAPlaySession::~QXAPlaySession() +{ + QT_TRACE_FUNCTION_ENTRY; + delete mImpl; + QT_TRACE_FUNCTION_EXIT; +} + +void QXAPlaySession::setVideoWidgetControl( QXAVideoWidgetControl * videoWidgetControl ) +{ + QT_TRACE_FUNCTION_ENTRY; + if (mVideowidgetControl) { + disconnect(mVideowidgetControl, SIGNAL(widgetUpdated()), + this, SLOT(videoWidgetControlWidgetUpdated())); + RWindow* window = static_cast(mVideowidgetControl->videoWidgetWId()->DrawableWindow()); + mImpl->removeNativeDisplay(window, mWsSession); + } + mVideowidgetControl = videoWidgetControl; + if (mVideowidgetControl) + connect(mVideowidgetControl, SIGNAL(widgetUpdated()), + this, SLOT(videoWidgetControlWidgetUpdated())); + QT_TRACE_FUNCTION_EXIT; +} + +void QXAPlaySession::unsetVideoWidgetControl( QXAVideoWidgetControl * videoWidgetControl ) +{ + QT_TRACE_FUNCTION_ENTRY; + if ((mVideowidgetControl == videoWidgetControl) && (mImpl)) { + disconnect(mVideowidgetControl, SIGNAL(widgetUpdated()), + this, SLOT(videoWidgetControlWidgetUpdated())); + RWindow* window = static_cast(mVideowidgetControl->videoWidgetWId()->DrawableWindow()); + mImpl->removeNativeDisplay(window, mWsSession); + } + mVideowidgetControl = NULL; + mWidgetCtrlWindow = NULL; + mWidgetCtrlWindowId = NULL; + QT_TRACE_FUNCTION_EXIT; +} + +void QXAPlaySession::setVideoWindowControl( QXAVideoWindowControl * videoWindowControl ) +{ + QT_TRACE_FUNCTION_ENTRY; + if (mVideoWindowControl) { + disconnect(mVideoWindowControl, SIGNAL(windowUpdated()), + this, SLOT(videoWindowControlWindowUpdated())); + RWindow* window = static_cast(mVideoWindowControl->winId()->DrawableWindow()); + mImpl->removeNativeDisplay(window, mWsSession); + } + mVideoWindowControl = videoWindowControl; + if (mVideoWindowControl) { + connect(mVideoWindowControl, SIGNAL(windowUpdated()), + this, SLOT(videoWindowControlWindowUpdated())); + videoWindowControlWindowUpdated(); + } + QT_TRACE_FUNCTION_EXIT; +} + +void QXAPlaySession::unsetVideoWindowControl( QXAVideoWindowControl * videoWindowControl ) +{ + QT_TRACE_FUNCTION_ENTRY; + if ((mVideoWindowControl == videoWindowControl) && (mImpl)) { + disconnect(mVideoWindowControl, SIGNAL(windowUpdated()), + this, SLOT(videoWindowControlWindowUpdated())); + RWindow* window = static_cast(mVideoWindowControl->winId()->DrawableWindow()); + mImpl->removeNativeDisplay(window, mWsSession); + } + mVideoWindowControl = NULL; + mWindowCtrlWindow = NULL; + mWindowCtrlWindowId = NULL; + QT_TRACE_FUNCTION_EXIT; +} + +qint64 QXAPlaySession::duration() +{ + TInt64 dur(0); + if (mImpl) + mImpl->duration(dur); + + return (qint64)dur; +} + +qint64 QXAPlaySession::position() +{ + TInt64 pos(0); + if (mImpl) + mImpl->position(pos); + + return (qint64)pos; +} + +void QXAPlaySession::setPosition(qint64 ms) +{ + if (mImpl) { + qint64 currPos = position(); + mImpl->seek(ms); + + if(currPos != position()) { + emit positionChanged(position()); + + if(position()>=duration()) { + setMediaStatus(QMediaPlayer::EndOfMedia); + stop(); + } + } + } +} + +int QXAPlaySession::volume() +{ + if(mImpl) { + TInt v(0); + + TInt err = mImpl->volume(v); + if(KErrNone == err) + return v; + } + + return 50; +} + +void QXAPlaySession::setVolume(int v) +{ + if(mImpl) { + if(v != volume()) { + TInt err = mImpl->setVolume(v); + if(KErrNone == err) + emit volumeChanged(volume()); + } + } +} + + +bool QXAPlaySession::isMuted() +{ + if(mImpl) { + TBool bCurrMute = EFalse; + TInt err = mImpl->getMute(bCurrMute); + if(err == KErrNone) + return bCurrMute; + } + + return EFalse; +} + +void QXAPlaySession::setMuted(bool muted) +{ + if(muted != isMuted()) + { + if(mImpl) + { + TInt err = mImpl->setMute(muted); + + if(KErrNone == err) + { + emit mutedChanged(muted); + } + } + } +} + +int QXAPlaySession::bufferStatus() +{ + if(mImpl) { + TInt fillLevel = 0; + TInt err = mImpl->bufferStatus(fillLevel); + if(err == KErrNone) + return fillLevel; + } + + return 100;//default +} + +bool QXAPlaySession::isAudioAvailable() +{ + return mbAudioAvailable; +} + +bool QXAPlaySession::isVideoAvailable() +{ + return mbVideoAvailable; +} + +bool QXAPlaySession::isSeekable() +{ + return ((mSeekable==1) || (mSeekable==-1));//default seekable +} + +float QXAPlaySession::playbackRate() +{ + if(mImpl) { + TReal32 currPBRate = 0.0; + TInt ret = mImpl->getPlaybackRate(currPBRate); + if(ret == KErrNone) + return currPBRate; + } + + return 1.0; +} + +void QXAPlaySession::setPlaybackRate(float rate) +{ + if(mImpl) { + TReal32 currPBRate = 0.0; + TInt ret = mImpl->getPlaybackRate(currPBRate); + if( (ret == KErrNone) && + (rate!=currPBRate)) { + ret = mImpl->setPlaybackRate(rate); + if(ret == KErrNone) + emit playbackRateChanged(rate); + } + } +} + +QMediaContent QXAPlaySession::media() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return mMediaContent; +} + +void QXAPlaySession::setMedia(const QMediaContent& media) +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL_EMIT_PLAYER_RESOURCE_ERROR(mImpl); + + if (media.isNull() || + mMediaContent == media) { + return; + } + + setMediaStatus(QMediaPlayer::NoMedia); + + QString urlStr = media.canonicalUrl().toString(); + TPtrC16 urlPtr(reinterpret_cast(urlStr.utf16())); + + setMediaStatus(QMediaPlayer::LoadingMedia); + if (mImpl->load(urlPtr) == 0) { + setMediaStatus(QMediaPlayer::LoadedMedia); + emit error(QMediaPlayer::NoError, ""); + mMediaContent = media; + setPlayerState(QMediaPlayer::StoppedState); + emit mediaChanged(mMediaContent); + + if(mImpl->isMetaDataAvailable()) { + emit metaDataAvailableChanged(true); + emit metaDataChanged(); + } + else { + emit metaDataAvailableChanged(false); + } + } + else { + setMediaStatus(QMediaPlayer::NoMedia); + emit error(QMediaPlayer::ResourceError, tr("Unable to load media")); + } + QT_TRACE_FUNCTION_EXIT; +} + +void QXAPlaySession::play() +{ + if (mImpl) { + setMediaStatus(QMediaPlayer::BufferingMedia); + + TInt err = mImpl->play(); + if (err != KErrNone) { + setMediaStatus(QMediaPlayer::NoMedia); + RET_IF_ERROR(err); + } + setPlayerState(QMediaPlayer::PlayingState); + + TInt fillLevel = 0; + err = mImpl->bufferStatus(fillLevel); + RET_IF_ERROR(err); + if (fillLevel == 100) { + setMediaStatus(QMediaPlayer::BufferedMedia); + } + } +} + +void QXAPlaySession::pause() +{ + if (mImpl) { + TInt err = mImpl->pause(); + RET_IF_ERROR(err); + setPlayerState(QMediaPlayer::PausedState); + } +} + +void QXAPlaySession::stop() +{ + if (mImpl) { + TInt err = mImpl->stop(); + RET_IF_ERROR(err); + setPlayerState(QMediaPlayer::StoppedState); + } +} + +void QXAPlaySession::cbDurationChanged(TInt64 new_dur) +{ + emit durationChanged((qint64)new_dur); +} + +void QXAPlaySession::cbPositionChanged(TInt64 new_pos) +{ + emit positionChanged((qint64)new_pos); +} + +void QXAPlaySession::cbSeekableChanged(TBool seekable) +{ + if( (mSeekable==-1) || + (seekable != (TBool)mSeekable)) { + mSeekable = seekable?1:0; + emit seekableChanged((bool)seekable); + } +} + +void QXAPlaySession::cbPlaybackStopped(TInt err) +{ + if (err) { + emit error(QMediaPlayer::ResourceError, tr("Resources Unavailable")); + SIGNAL_EMIT_TRACE1("emit error(QMediaPlayer::ResourceError, tr(\"Resources Unavailable\"))"); + emit positionChanged(position()); + setPlayerState(QMediaPlayer::StoppedState); + setMediaStatus(QMediaPlayer::NoMedia); + } + else { + setMediaStatus(QMediaPlayer::EndOfMedia); + /* Set player state to Stopped */ + stop(); + } +} + +void QXAPlaySession::cbPrefetchStatusChanged() +{ + if(mImpl) { + TInt fillLevel = 0; + TInt err = mImpl->bufferStatus(fillLevel); + if(err == KErrNone) { + emit bufferStatusChanged(fillLevel); + + if(fillLevel == 100) + setMediaStatus(QMediaPlayer::BufferedMedia); + else if(fillLevel ==0) + setMediaStatus(QMediaPlayer::StalledMedia); + } + } +} + +void QXAPlaySession::cbStreamInformation(TBool bFirstTime) +{ + updateStreamInfo(bFirstTime); +} + + + +void QXAPlaySession::videoWidgetControlWidgetUpdated() +{ + QT_TRACE_FUNCTION_ENTRY; + if (mVideowidgetControl) { + WId newId = mVideowidgetControl->videoWidgetWId(); + if ((newId != NULL) && (newId != mWidgetCtrlWindowId)) { + mWidgetCtrlWindow = static_cast(newId->DrawableWindow()); + if (mWidgetCtrlWindowId == NULL) + mImpl->addNativeDisplay(mWidgetCtrlWindow, mWsSession); + else + mImpl->updateNativeDisplay(mWidgetCtrlWindow, mWsSession); + mWidgetCtrlWindowId = newId; + } + } + QT_TRACE_FUNCTION_EXIT; +} + +void QXAPlaySession::videoWindowControlWindowUpdated() +{ + QT_TRACE_FUNCTION_ENTRY; + if (mVideoWindowControl) { + WId newId = mVideoWindowControl->winId(); + if ((newId != NULL) && (newId != mWindowCtrlWindowId)) { + mWidgetCtrlWindow = static_cast(newId->DrawableWindow()); + if (mWindowCtrlWindowId == NULL) + mImpl->addNativeDisplay(mWidgetCtrlWindow, mWsSession); + else + mImpl->updateNativeDisplay(mWidgetCtrlWindow, mWsSession); + mWindowCtrlWindowId = newId; + } + } + QT_TRACE_FUNCTION_EXIT; +} + +void QXAPlaySession::setMediaStatus(QMediaPlayer::MediaStatus status) +{ + if (m_mediaStatus != status) { + m_mediaStatus = status; + emit mediaStatusChanged(status); + } +} + +void QXAPlaySession::setPlayerState(QMediaPlayer::State state) +{ + if (m_state != state) { + m_state = state; + emit stateChanged(m_state); + } +} + +QStringList QXAPlaySession::availableExtendedMetaData () const +{ + QStringList list; + RET_s_IF_p_IS_NULL(mImpl, list); + list = mImpl->availableExtendedMetaData(); + return list; +} + +QList QXAPlaySession::availableMetaData () const +{ + QList list; + RET_s_IF_p_IS_NULL(mImpl, list); + return mImpl->availableMetaData(); +} + +QVariant QXAPlaySession::extendedMetaData(const QString & key ) const +{ + QVariant var; + RET_s_IF_p_IS_NULL(mImpl, var); + return mImpl->extendedMetaData(key); +} + +bool QXAPlaySession::isMetaDataAvailable() const +{ + RET_s_IF_p_IS_NULL(mImpl, false); + return mImpl->isMetaDataAvailable(); +} + +bool QXAPlaySession::isWritable() const +{ + RET_s_IF_p_IS_NULL(mImpl, false); + return mImpl->isWritable(); +} + +QVariant QXAPlaySession::metaData( QtMultimediaKit::MetaData key ) const +{ + QVariant var; + RET_s_IF_p_IS_NULL(mImpl, var); + return mImpl->metaData(key); +} + +void QXAPlaySession::setExtendedMetaData( const QString & key, const QVariant & value ) +{ + RET_IF_p_IS_NULL(mImpl); + mImpl->setExtendedMetaData(key, value); +} + +void QXAPlaySession::setMetaData( QtMultimediaKit::MetaData key, const QVariant & value ) +{ + RET_IF_p_IS_NULL(mImpl); + mImpl->setMetaData(key, value); +} + +void QXAPlaySession::updateStreamInfo(TBool emitSignal) +{ + if(mImpl) { + mNumStreams = 0; + TInt ret = mImpl->numMediaStreams(mNumStreams); + if(ret == KErrNone) { + TBool bAudioAvailable = EFalse;//lcoal variable + TBool bVideoAvailable = EFalse;//lcvoal variable + + for(TUint i = 0; i < mNumStreams; i++) { + QMediaStreamsControl::StreamType strType; + mImpl->streamType(i, strType); + if(strType == QMediaStreamsControl::AudioStream) + bAudioAvailable = ETrue; + else if(strType == QMediaStreamsControl::VideoStream) + bVideoAvailable = ETrue; + } + + if(emitSignal || (bAudioAvailable != mbAudioAvailable)) { + emit audioAvailableChanged(bAudioAvailable); + mbAudioAvailable = bAudioAvailable; + } + + if(emitSignal || (bVideoAvailable != mbVideoAvailable)) { + emit videoAvailableChanged(bVideoAvailable); + mbVideoAvailable = bVideoAvailable; + } + + emit streamsChanged(); + } + } +} + +bool QXAPlaySession::isStreamActive ( int stream ) +{ + RET_s_IF_p_IS_NULL(mImpl, false); + TBool isActive = EFalse; + mImpl->isStreamActive(stream,isActive); + return isActive; +} + +QVariant QXAPlaySession::metaData ( int /*stream*/, QtMultimediaKit::MetaData key ) +{ + return this->metaData(key); +} + +int QXAPlaySession::streamCount() +{ + return mNumStreams; +} + +QMediaStreamsControl::StreamType QXAPlaySession::streamType ( int stream ) +{ + QMediaStreamsControl::StreamType strType = QMediaStreamsControl::UnknownStream; + RET_s_IF_p_IS_NULL(mImpl, strType); + if(mImpl->streamType(stream, strType) == KErrNone) { + return strType; + } + + return QMediaStreamsControl::UnknownStream; +} + +////AspectRatioMode +void QXAPlaySession::setAspectRatioMode(Qt::AspectRatioMode aspectRatioMode) +{ + RET_IF_p_IS_NULL(mImpl); + mImpl->setAspectRatioMode(aspectRatioMode); +} + +Qt::AspectRatioMode QXAPlaySession::getAspectRatioMode() +{ + RET_s_IF_p_IS_NULL(mImpl, Qt::KeepAspectRatio); + return mImpl->getAspectRatioMode(); +} + + diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxaplaysession.h b/src/plugins/symbian/openmaxal/mediaplayer/qxaplaysession.h new file mode 100644 index 000000000..0d366518f --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxaplaysession.h @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXAPLAYSESSION_H +#define QXAPLAYSESSION_H + +#include +#include +#include + +#include "qxamediaplayercontrol.h" +#include "qxametadatacontrol.h" +#include "qmediaplayer.h" +#include "xaplaysessioncommon.h" +#include "qxavideowidgetcontrol.h" +#include "qxavideowindowcontrol.h" +#include "qmediastreamscontrol.h" + + +QT_USE_NAMESPACE + +class XAPlaySessionImpl; +class RWindow; +class RWsSession; +class QXAVideoWidgetControl; + +class QXAPlaySession : public QObject, + public XAPlayObserver +{ + Q_OBJECT +public: + QXAPlaySession(QObject *parent); + virtual ~QXAPlaySession(); + + void setVideoWidgetControl( QXAVideoWidgetControl * videoWidgetControl ); + void unsetVideoWidgetControl( QXAVideoWidgetControl * videoWidgetControl ); + void setVideoWindowControl( QXAVideoWindowControl * videoWindowControl ); + void unsetVideoWindowControl( QXAVideoWindowControl * videoWindowControl ); + + //QXAMediaPlayerControl + QMediaPlayer::State state() const { return m_state; } + QMediaPlayer::MediaStatus mediaStatus() const { return m_mediaStatus; } + qint64 duration(); + qint64 position(); + void setPosition(qint64 position); + int volume(); + void setVolume(int volume); + bool isMuted(); + void setMuted(bool muted); + int bufferStatus(); + bool isAudioAvailable(); + bool isVideoAvailable(); + bool isSeekable(); + float playbackRate(); + void setPlaybackRate(float rate); + QMediaContent media(); + void setMedia(const QMediaContent& media); + void play(); + void pause(); + void stop(); + + // Callback from XAPlaySessionImpl + void cbDurationChanged(TInt64 new_dur); + void cbPositionChanged(TInt64 new_pos); + void cbSeekableChanged(TBool seekable); + void cbPlaybackStopped(TInt error); + void cbPrefetchStatusChanged(); + void cbStreamInformation(TBool); + + //MetadataControl methods + QStringList availableExtendedMetaData () const; + QList availableMetaData () const; + QVariant extendedMetaData(const QString & key ) const; + bool isMetaDataAvailable() const; + bool isWritable() const; + QVariant metaData( QtMultimediaKit::MetaData key ) const; + void setExtendedMetaData( const QString & key, const QVariant & value ); + void setMetaData( QtMultimediaKit::MetaData key, const QVariant & value ); + + //QMediaStreamsControl + bool isStreamActive ( int stream ) ; + QVariant metaData ( int stream, QtMultimediaKit::MetaData key ); + int streamCount(); + QMediaStreamsControl::StreamType streamType ( int stream ); + + //QVideoWidgetControl + void setAspectRatioMode(Qt::AspectRatioMode); + Qt::AspectRatioMode getAspectRatioMode(); + +public Q_SLOTS: + void videoWidgetControlWidgetUpdated(); + void videoWindowControlWindowUpdated(); + +Q_SIGNALS: + void mediaChanged(const QMediaContent& content); + void durationChanged(qint64 duration); + void positionChanged(qint64 position); + void stateChanged(QMediaPlayer::State newState); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void audioAvailableChanged(bool audioAvailable); + void videoAvailableChanged(bool videoAvailable); + void bufferStatusChanged(int percentFilled); + void seekableChanged(bool); + void availablePlaybackRangesChanged(const QMediaTimeRange&); + void error(int errorCode, const QString &errorString); + void playbackRateChanged(qreal rate); + + //metadata + void metaDataAvailableChanged(bool); + void metaDataChanged(); + void writableChanged(bool); + + //QMediaStreamsControl + void streamsChanged(); + void activeStreamsChanged(); + +private: + void setMediaStatus(QMediaPlayer::MediaStatus); + void setPlayerState(QMediaPlayer::State state); + void updateStreamInfo(TBool emitSignal = EFalse); + +private: + QMediaPlayer::State m_state; + QMediaPlayer::MediaStatus m_mediaStatus; + + QMap m_tags; + QList< QMap > m_streamProperties; + + //seekable + int mSeekable; //-1 =unintialized, 0=nonseekable, 1=seekable + + //StreamInfo + TUint mNumStreams; + TBool mbAudioAvailable; + TBool mbVideoAvailable; + + //Own + XAPlaySessionImpl* mImpl; + + // Does not own + QXAVideoWidgetControl *mVideowidgetControl; + RWindow *mWidgetCtrlWindow; + WId mWidgetCtrlWindowId; + QXAVideoWindowControl *mVideoWindowControl; + RWindow *mWindowCtrlWindow; + WId mWindowCtrlWindowId; + RWsSession *mWsSession; + + QMediaContent mMediaContent; +}; + +#endif /* QXAPLAYSESSION_H */ diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxavideowidgetcontrol.cpp b/src/plugins/symbian/openmaxal/mediaplayer/qxavideowidgetcontrol.cpp new file mode 100644 index 000000000..6e9c833fd --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxavideowidgetcontrol.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxavideowidgetcontrol.h" +#include "qxacommon.h" +#include "qxawidget.h" +#include + +QXAVideoWidgetControl::QXAVideoWidgetControl(QXAPlaySession *session, QObject *parent) + : QVideoWidgetControl(parent), mSession(session) +{ + QT_TRACE_FUNCTION_ENTRY; + mWidget = new QXAWidget; + if (mWidget) + mWidget->installEventFilter(this); + QT_TRACE_FUNCTION_EXIT; +} + +QXAVideoWidgetControl::~QXAVideoWidgetControl() +{ + QT_TRACE_FUNCTION_ENTRY; + delete mWidget; + QT_TRACE_FUNCTION_EXIT; +} + +QWidget* QXAVideoWidgetControl::videoWidget() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return mWidget; +} + +Qt::AspectRatioMode QXAVideoWidgetControl::aspectRatioMode() const +{ + QT_TRACE_FUNCTION_ENTRY; + RET_s_IF_p_IS_NULL(mSession, Qt::IgnoreAspectRatio); + QT_TRACE_FUNCTION_EXIT; + return mSession->getAspectRatioMode(); +} + +void QXAVideoWidgetControl::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->setAspectRatioMode(mode); + QT_TRACE_FUNCTION_EXIT; +} + +bool QXAVideoWidgetControl::isFullScreen() const +{ + QT_TRACE_FUNCTION_ENTRY; + bool retVal = false; + RET_s_IF_p_IS_NULL(mWidget, retVal); + retVal = mWidget->isFullScreen(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +void QXAVideoWidgetControl::setFullScreen(bool fullScreen) +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mWidget); + if (fullScreen == mWidget->isFullScreen()) + return; + else if (fullScreen) + mWidget->showFullScreen(); + else + mWidget->showNormal(); + + emit fullScreenChanged(fullScreen); + + QT_TRACE_FUNCTION_EXIT; +} + +int QXAVideoWidgetControl::brightness() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return 0; +} + +void QXAVideoWidgetControl::setBrightness(int brightness) +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + Q_UNUSED(brightness); +} + +int QXAVideoWidgetControl::contrast() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return 0; +} + +void QXAVideoWidgetControl::setContrast(int contrast) +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + Q_UNUSED(contrast); +} + +int QXAVideoWidgetControl::hue() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return 0; +} + +void QXAVideoWidgetControl::setHue(int hue) +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + Q_UNUSED(hue); +} + +int QXAVideoWidgetControl::saturation() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return 0; +} + +void QXAVideoWidgetControl::setSaturation(int saturation) +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + Q_UNUSED(saturation); +} + +bool QXAVideoWidgetControl::eventFilter(QObject *object, QEvent *event) +{ + if (object == mWidget) { + if ( event->type() == QEvent::Resize + || event->type() == QEvent::Move + || event->type() == QEvent::WinIdChange + || event->type() == QEvent::ParentChange + || event->type() == QEvent::Show) { + emit widgetUpdated(); + } + } + return false; +} + +WId QXAVideoWidgetControl::videoWidgetWId() +{ + if (mWidget->internalWinId()) + return mWidget->internalWinId(); + else if (mWidget->effectiveWinId()) + return mWidget->effectiveWinId(); + + return NULL; +} diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxavideowidgetcontrol.h b/src/plugins/symbian/openmaxal/mediaplayer/qxavideowidgetcontrol.h new file mode 100644 index 000000000..7a0eda765 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxavideowidgetcontrol.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXAVIDEOWIDGETCONTROL_H +#define QXAVIDEOWIDGETCONTROL_H + +#include +#include +#include "qxaplaysession.h" + +QT_USE_NAMESPACE + +class QXAWidget; + +class QXAVideoWidgetControl : public QVideoWidgetControl +{ + Q_OBJECT +public: + QXAVideoWidgetControl(QXAPlaySession *session, QObject *parent = 0); + ~QXAVideoWidgetControl(); + + QWidget *videoWidget(); + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + bool eventFilter(QObject *object, QEvent *event); + + WId videoWidgetWId(); + +Q_SIGNALS: + void widgetUpdated(); + +private: + QXAPlaySession *mSession; + QXAWidget *mWidget; + +}; + +#endif // QXAVIDEOWIDGETCONTROL_H diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxavideowindowcontrol.cpp b/src/plugins/symbian/openmaxal/mediaplayer/qxavideowindowcontrol.cpp new file mode 100644 index 000000000..c19b949ac --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxavideowindowcontrol.cpp @@ -0,0 +1,222 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxavideowindowcontrol.h" +#include "qxacommon.h" +#include +#include "qxaplaysession.h" + +QXAVideoWindowControl::QXAVideoWindowControl(QXAPlaySession* session, QObject *parent) + :QVideoWindowControl(parent), + mWid(NULL), + mWidget(NULL), + mAspectRatioMode(Qt::IgnoreAspectRatio), + mSession(session) +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +QXAVideoWindowControl::~QXAVideoWindowControl() +{ + QT_TRACE_FUNCTION_ENTRY; + if (mWidget) + mWidget->removeEventFilter(this); + QT_TRACE_FUNCTION_EXIT; +} + +WId QXAVideoWindowControl::winId() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return mWid; +} + +void QXAVideoWindowControl::setWinId(WId id) +{ + QT_TRACE_FUNCTION_ENTRY; + if (mWid != id) { + if (mWidget) + mWidget->removeEventFilter(this); + mWid = id; + mWidget = QWidget::find(mWid); + if (mWidget) + mWidget->installEventFilter(this); + emit windowUpdated(); + } + QT_TRACE_FUNCTION_EXIT; +} + +QRect QXAVideoWindowControl::displayRect() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return mDisplayRect; +} + +void QXAVideoWindowControl::setDisplayRect(const QRect &rect) +{ + QT_TRACE_FUNCTION_ENTRY; + mDisplayRect = rect; + QT_TRACE_FUNCTION_EXIT; +} + +bool QXAVideoWindowControl::isFullScreen() const +{ + QT_TRACE_FUNCTION_ENTRY; + bool retVal(false); + if (mWidget) + retVal = mWidget->isFullScreen(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +void QXAVideoWindowControl::setFullScreen(bool fullScreen) +{ + QT_TRACE_FUNCTION_ENTRY; + if (mWidget && (fullScreen != mWidget->isFullScreen())) { + if (fullScreen) + mWidget->showFullScreen(); + else + mWidget->showNormal(); + emit fullScreenChanged(fullScreen); + } + QT_TRACE_FUNCTION_EXIT; +} + +void QXAVideoWindowControl::repaint() +{ +} + +QSize QXAVideoWindowControl::nativeSize() const +{ + QT_TRACE_FUNCTION_ENTRY; + QSize size(0, 0); + RET_s_IF_p_IS_NULL(mSession, size); + QVariant sizeBundle = mSession->metaData(QtMultimediaKit::Resolution); + QString metadata = sizeBundle.toString(); + if (!metadata.isNull() && !metadata.isEmpty()) { + int xIndex = metadata.indexOf('x'); + if (xIndex > 0) { + size.setWidth(metadata.left(xIndex).toInt()); + xIndex = metadata.length() - (xIndex + 1); + if (xIndex > 0) + size.setHeight(metadata.right(xIndex).toInt()); + } + } + QT_TRACE_FUNCTION_EXIT; + return size; +} + +Qt::AspectRatioMode QXAVideoWindowControl::aspectRatioMode() const +{ + QT_TRACE_FUNCTION_ENTRY; + RET_s_IF_p_IS_NULL(mSession, Qt::IgnoreAspectRatio); + QT_TRACE_FUNCTION_EXIT; + return mSession->getAspectRatioMode(); +} + +void QXAVideoWindowControl::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->setAspectRatioMode(mode); + QT_TRACE_FUNCTION_EXIT; +} + +int QXAVideoWindowControl::brightness() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return 0; +} + +void QXAVideoWindowControl::setBrightness(int brightness) +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + Q_UNUSED(brightness); +} + +int QXAVideoWindowControl::contrast() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return 0; +} + +void QXAVideoWindowControl::setContrast(int contrast) +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + Q_UNUSED(contrast); +} + +int QXAVideoWindowControl::hue() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return 0; +} + +void QXAVideoWindowControl::setHue(int hue) +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + Q_UNUSED(hue); +} + +int QXAVideoWindowControl::saturation() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return 0; +} + +void QXAVideoWindowControl::setSaturation(int saturation) +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + Q_UNUSED(saturation); +} + +bool QXAVideoWindowControl::eventFilter(QObject *object, QEvent *event) +{ + if (object == mWidget) { + if (event->type() == QEvent::Resize + || event->type() == QEvent::Move + || event->type() == QEvent::WinIdChange + || event->type() == QEvent::ParentChange + || event->type() == QEvent::Show) { + emit windowUpdated(); + } + } + return false; +} diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxavideowindowcontrol.h b/src/plugins/symbian/openmaxal/mediaplayer/qxavideowindowcontrol.h new file mode 100644 index 000000000..879349822 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxavideowindowcontrol.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXAVIDEOWINDOWCONTROL_H +#define QXAVIDEOWINDOWCONTROL_H + +#include +#include + +QT_USE_NAMESPACE + +class QXAPlaySession; + +class QXAVideoWindowControl : public QVideoWindowControl +{ + Q_OBJECT + +public: + QXAVideoWindowControl(QXAPlaySession* session, QObject *parent = 0); + ~QXAVideoWindowControl(); + + // QVideoWindowControl virtual functions + WId winId() const; + void setWinId(WId id); + + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + void repaint(); + + QSize nativeSize() const; + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + //Callback function to receive event from Qt framework + //for object represented by mWid + bool eventFilter(QObject *object, QEvent *event); + +Q_SIGNALS: + void windowUpdated(); + +private: + WId mWid; + QWidget* mWidget; /* QWidget represented by mWid */ + QRect mDisplayRect; + Qt::AspectRatioMode mAspectRatioMode; + + QXAPlaySession* mSession; +}; + +#endif /* QXAVIDEOWINDOWCONTROL_H */ diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxawidget.cpp b/src/plugins/symbian/openmaxal/mediaplayer/qxawidget.cpp new file mode 100644 index 000000000..4685226fd --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxawidget.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxawidget.h" +#include + +QXAWidget::QXAWidget(QWidget *parent) + : QWidget(parent) +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + setAttribute(Qt::WA_OpaquePaintEvent, true); + setAttribute(Qt::WA_NoSystemBackground, true); + setAutoFillBackground(false); + setPalette(QPalette(Qt::black)); + /* Initialize the native window*/ + winId(); +} + +QXAWidget::~QXAWidget() +{ +} + +void QXAWidget::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event); +} diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxawidget.h b/src/plugins/symbian/openmaxal/mediaplayer/qxawidget.h new file mode 100644 index 000000000..d36be1fa4 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxawidget.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXAWIDGET_H +#define QXAWIDGET_H + +#include +#include + +QT_USE_NAMESPACE + +class QXAWidget : public QWidget +{ + Q_OBJECT + +public: + QXAWidget(QWidget *parent = 0); + virtual ~QXAWidget(); + +protected: + void paintEvent(QPaintEvent *event); +}; + + +#endif /* QXAWIDGET_H */ diff --git a/src/plugins/symbian/openmaxal/mediaplayer/xaplaysessioncommon.h b/src/plugins/symbian/openmaxal/mediaplayer/xaplaysessioncommon.h new file mode 100644 index 000000000..a9497e475 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/xaplaysessioncommon.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef XAPLAYSESSIONCOMMON_H +#define XAPLAYSESSIONCOMMON_H + +#include + +class XAPlayObserver + { +public: + virtual void cbDurationChanged(TInt64 new_dur) = 0; + virtual void cbPositionChanged(TInt64 new_pos) = 0; + virtual void cbSeekableChanged(TBool seekable) = 0; + virtual void cbPlaybackStopped(TInt error) = 0; + virtual void cbPrefetchStatusChanged() = 0; + virtual void cbStreamInformation(TBool bFirstTime) = 0; + }; + +#endif /*XAPLAYSESSIONCOMMON_H*/ diff --git a/src/plugins/symbian/openmaxal/mediaplayer/xaplaysessionimpl.cpp b/src/plugins/symbian/openmaxal/mediaplayer/xaplaysessionimpl.cpp new file mode 100644 index 000000000..88a06807f --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/xaplaysessionimpl.cpp @@ -0,0 +1,1259 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "xaplaysessionimpl.h" +#include "xaplaysessioncommon.h" +#include "xacommon.h" + +#ifdef USE_VIDEOPLAYERUTILITY +#include +#endif + +_LIT8(K8WAVMIMETYPE, "audio/wav"); + +#define RET_ERR_IF_ERR(e) \ + if (e != 0) {\ + return e; \ + } \ + +#define MAX_NUMBER_INTERFACES 20 +const TUint KPlayPosUpdatePeriod = 1000; + +/* Local functions for callback registation */ +void MediaPlayerCallback( XAObjectItf caller, + const void *pContext, + XAuint32 event, + XAresult result, + XAuint32 param, + void *pInterface); + +void PlayItfCallback( XAPlayItf caller, + void *pContext, + XAuint32 event); + +void PrefetchItfCallback( XAPrefetchStatusItf caller, + void * pContext, + XAuint32 event); + +void StreamInformationItfCallback( XAStreamInformationItf caller, + XAuint32 eventId, + XAuint32 streamIndex, + void * pEventData, + void * pContext); + +XAPlaySessionImpl::XAPlaySessionImpl(XAPlayObserver& parent) +:mParent(parent), +mEOEngine(NULL), +mMOPlayer(NULL), +mPlayItf(NULL), +mSeekItf(NULL), +mURIName(NULL), +mWAVMime(NULL), +mbMetadataAvailable(EFalse), +mbVolEnabled(EFalse), +mbMuteEnabled(EFalse), +mbPrefetchStatusChange(EFalse), +mbStreamInfoAvailable(EFalse), +mbPlaybackRateItfAvailable(EFalse), +mbScalable(EFalse), +mCurrAspectRatioMode(Qt::KeepAspectRatio) +#ifdef USE_VIDEOPLAYERUTILITY +, mVideoPlayUtil(NULL) +, mActiveSchedulerWait(NULL) +#endif +{ +} + +XAPlaySessionImpl::~XAPlaySessionImpl() +{ + if (mMOPlayer) + (*mMOPlayer)->Destroy(mMOPlayer); + + if (mEOEngine) + (*mEOEngine)->Destroy(mEOEngine); + + delete mURIName; + delete mWAVMime; + + //clear metadata datastructures + alKeyMap.clear(); + keyMap.clear(); + extendedKeyMap.clear(); + +#ifdef USE_VIDEOPLAYERUTILITY + delete mVideoPlayUtil; + if (mActiveSchedulerWait && \ + mActiveSchedulerWait->IsStarted()) { + mActiveSchedulerWait->AsyncStop(); + } + + delete mActiveSchedulerWait; +#endif + +} + +TInt XAPlaySessionImpl::postConstruct() +{ + TInt retVal; + XAresult xaRes; + XAEngineOption engineOption[] = { (XAuint32) XA_ENGINEOPTION_THREADSAFE, + (XAuint32) XA_BOOLEAN_TRUE + }; + XAEngineItf engineItf; + + mNativeDisplay.locatorType = XA_DATALOCATOR_NATIVEDISPLAY; + mNativeDisplay.hWindow = NULL; + mNativeDisplay.hDisplay = NULL; + mVideoSink.pLocator = (void*)&mNativeDisplay; + mVideoSink.pFormat = NULL; + + // Create and realize Engine object + xaRes = xaCreateEngine (&mEOEngine, 1, engineOption, 0, NULL, NULL); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + xaRes = (*mEOEngine)->Realize(mEOEngine, XA_BOOLEAN_FALSE); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + // Create and realize Output Mix object to be used by player + xaRes = (*mEOEngine)->GetInterface(mEOEngine, XA_IID_ENGINE, (void**) &engineItf); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + TRAP(retVal, mWAVMime = HBufC8::NewL(K8WAVMIMETYPE().Length() + 1)); + RET_ERR_IF_ERR(retVal); + TPtr8 ptr = mWAVMime->Des(); + ptr = K8WAVMIMETYPE(); // copy uri name into local variable + ptr.PtrZ(); // append zero terminator to end of URI + +#ifdef USE_VIDEOPLAYERUTILITY + TRAP(retVal, mVideoPlayUtil = + CVideoPlayerUtility2::NewL( *this, + EMdaPriorityNormal, + EMdaPriorityPreferenceTimeAndQuality) + ); + mActiveSchedulerWait = new CActiveSchedulerWait; +#endif + + return retVal; +} + +TInt XAPlaySessionImpl::addNativeDisplay(RWindow* window, RWsSession* wssession) + { + TInt retVal(KErrNotReady); + + if (!mMOPlayer && !mPlayItf) { + // window can only be set before player creation + mNativeDisplay.locatorType = XA_DATALOCATOR_NATIVEDISPLAY; + mNativeDisplay.hWindow = (void*)window; + mNativeDisplay.hDisplay = (void*)wssession; + retVal = KErrNone; + } + return retVal; +} + +TInt XAPlaySessionImpl::updateNativeDisplay(RWindow* /*window*/, RWsSession* /*wssession*/) +{ + return KErrNone; +} + +TInt XAPlaySessionImpl::removeNativeDisplay(RWindow* /*window*/, RWsSession* /*wssession*/) +{ + return KErrNone; +} + +TInt XAPlaySessionImpl::load(const TDesC& aURI) +{ + TInt retVal; + XAresult xaRes; + XAEngineItf engineItf; + XADynamicSourceItf dynamicSourceItf; + XAboolean required[MAX_NUMBER_INTERFACES]; + XAInterfaceID iidArray[MAX_NUMBER_INTERFACES]; + XAuint32 noOfInterfaces = 0; + TInt i; + + XAmillisecond dur(0); + TPtr8 uriPtr(0,0,0); + TPtr8 mimeTypePtr(0,0,0); + +#ifdef USE_VIDEOPLAYERUTILITY + TRAP(m_VPError, mVideoPlayUtil->OpenFileL(_L("C:\\data\\test.3gp"))); + if (m_VPError) + return 0; + + if(!mActiveSchedulerWait->IsStarted()) + mActiveSchedulerWait->Start(); + + if (m_VPError) + return 0; + + mVideoPlayUtil->Prepare(); + + if(!mActiveSchedulerWait->IsStarted()) + mActiveSchedulerWait->Start(); + + return 0; +#endif + + delete mURIName; + mURIName = NULL; + TRAP(retVal, mURIName = HBufC8::NewL(aURI.Length()+1)); + RET_ERR_IF_ERR(retVal); + uriPtr.Set(mURIName->Des()); + + // This has to be done here since we can not destroy the Player + // in the Resource Lost callback. + if (mbMediaPlayerUnrealized) { + if (mMOPlayer) { + (*mMOPlayer)->Destroy(mMOPlayer); + mMOPlayer = NULL; + } + } + + //py uri name into local variable + //TODO fix copy issue from 16 bit to 8 bit + uriPtr.Copy(aURI); + + //If media player object already exists, just switch source + //using dynamic source interface + if (mMOPlayer && mPlayItf) { + dynamicSourceItf = NULL; + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_DYNAMICSOURCE, &dynamicSourceItf); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + //Setup the data source + //TODO Hard coded locator type + mUri.locatorType = XA_DATALOCATOR_URI; + + //append zero terminator to end of URI + mUri.URI = (XAchar*) uriPtr.PtrZ(); + + //TODO Hard coded locator type + mMime.containerType = XA_CONTAINERTYPE_WAV; + + //TODO Hard coded locator type + mMime.formatType = XA_DATAFORMAT_MIME; + mimeTypePtr.Set(mWAVMime->Des()); + mMime.mimeType = (XAchar*)mimeTypePtr.Ptr(); + mDataSource.pFormat = (void*)&mMime; + mDataSource.pLocator = (void*)&mUri; + + xaRes = (*dynamicSourceItf)->SetSource(dynamicSourceItf, &mDataSource); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + } + else { // Create media player object + + // Setup the data source + // TODO Hard coded locator type + mUri.locatorType = XA_DATALOCATOR_URI; + + //append zero terminator to end of URI + mUri.URI = (XAchar*) uriPtr.PtrZ(); + + //TODO Hard coded locator type + mMime.containerType = XA_CONTAINERTYPE_WAV; + + //TODO Hard coded locator type + mMime.formatType = XA_DATAFORMAT_MIME; + mimeTypePtr.Set(mWAVMime->Des()); + mMime.mimeType = (XAchar*)mimeTypePtr.Ptr(); + mDataSource.pFormat = (void*)&mMime; + mDataSource.pLocator = (void*)&mUri; + + //Setup the audio data sink + mLocatorOutputDevice.locatorType = XA_DATALOCATOR_IODEVICE; + mLocatorOutputDevice.deviceType = 6; + mAudioSink.pLocator = (void*) &mLocatorOutputDevice; + mAudioSink.pFormat = NULL; + + //Init arrays required[] and iidArray[] + for (i = 0; i < MAX_NUMBER_INTERFACES; i++) { + required[i] = XA_BOOLEAN_FALSE; + iidArray[i] = XA_IID_NULL; + } + + noOfInterfaces = 0; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_SEEK; + noOfInterfaces++; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_DYNAMICSOURCE; + noOfInterfaces++; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_METADATAEXTRACTION; + noOfInterfaces++; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_NOKIALINEARVOLUME; + noOfInterfaces++; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_NOKIAVOLUMEEXT; + noOfInterfaces++; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_PREFETCHSTATUS; + noOfInterfaces++; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_STREAMINFORMATION; + noOfInterfaces++; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_PLAYBACKRATE; + noOfInterfaces++; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_VIDEOPOSTPROCESSING; + noOfInterfaces++; + + xaRes = (*mEOEngine)->GetInterface(mEOEngine, XA_IID_ENGINE, (void**) &engineItf); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + xaRes = (*engineItf)->CreateMediaPlayer(engineItf, + &mMOPlayer, + &mDataSource, + NULL, + &mAudioSink, + &mVideoSink, + NULL, + NULL, + noOfInterfaces, + iidArray, + required); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + xaRes = (*mMOPlayer)->Realize(mMOPlayer, XA_BOOLEAN_FALSE); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + mbMediaPlayerUnrealized = FALSE; + + xaRes = (*mMOPlayer)->RegisterCallback(mMOPlayer, MediaPlayerCallback, (void*)this); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_PLAY, &mPlayItf); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + xaRes = (*mPlayItf)->RegisterCallback(mPlayItf, PlayItfCallback, (void*)this); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + xaRes = (*mPlayItf)->SetPositionUpdatePeriod(mPlayItf, (XAmillisecond)KPlayPosUpdatePeriod); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + xaRes = (*mPlayItf)->SetCallbackEventsMask( mPlayItf, + ( XA_PLAYEVENT_HEADATEND | + XA_PLAYEVENT_HEADATNEWPOS | + XA_PLAYEVENT_HEADMOVING ) + ); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_SEEK, &mSeekItf); + retVal = mapError(xaRes, ETrue); + + //Metadata + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_METADATAEXTRACTION, &mMetadataExtItf); + if(mapError(xaRes, ETrue)==KErrNone) { + mbMetadataAvailable = ETrue; + setupALKeyMap(); //done only once at creation of meadia player + } + + //volume + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_NOKIALINEARVOLUME, &mNokiaLinearVolumeItf); + if(mapError(xaRes, ETrue)==KErrNone) + mbVolEnabled = ETrue; + + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_NOKIAVOLUMEEXT, &mNokiaVolumeExtItf); + if(mapError(xaRes, ETrue)==KErrNone) + mbMuteEnabled = ETrue; + + //buffer status + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_PREFETCHSTATUS, &mPrefetchStatusItf); + if(mapError(xaRes, ETrue)==KErrNone) { + mbPrefetchStatusChange = ETrue; + (*mPrefetchStatusItf)->RegisterCallback(mPrefetchStatusItf, PrefetchItfCallback, (void*)this); + (*mPrefetchStatusItf)->SetCallbackEventsMask(mPrefetchStatusItf, XA_PREFETCHEVENT_FILLLEVELCHANGE); + } + + //stream information + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_STREAMINFORMATION, &mStreamInformationItf); + if(mapError(xaRes, ETrue)==KErrNone) { + mbStreamInfoAvailable = ETrue; + mParent.cbStreamInformation(ETrue); //indicate first time + (*mStreamInformationItf)->RegisterStreamChangeCallback(mStreamInformationItf, StreamInformationItfCallback, (void*)this); + } + + //playback rate + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_PLAYBACKRATE, &mPlaybackRateItf); + if(mapError(xaRes, ETrue)==KErrNone) + mbPlaybackRateItfAvailable = ETrue; + + + //videopostprocessing + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_VIDEOPOSTPROCESSING, &mVideoPostProcessingItf); + if(mapError(xaRes, ETrue)==KErrNone) + mbScalable = ETrue; + + } + + if(mbMetadataAvailable) { + keyMap.clear(); + extendedKeyMap.clear(); + setupMetaData(); //done every time source is changed + } + else { //send signal for seekable + mParent.cbSeekableChanged(ETrue); + } + + mCurPosition = 0; + mParent.cbPositionChanged(mCurPosition); + + xaRes = (*mPlayItf)->GetDuration(mPlayItf, &dur); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + mDuration = dur; + mParent.cbDurationChanged(mDuration); + + return retVal; +} + +void XAPlaySessionImpl::unload() +{ + mPlayItf = NULL; + mSeekItf = NULL; + + //Metadata + mbMetadataAvailable = FALSE; + mMetadataExtItf = NULL; + alKeyMap.clear(); + keyMap.clear(); + extendedKeyMap.clear(); + //Volume + mNokiaLinearVolumeItf = NULL; + mbVolEnabled = FALSE; + mNokiaVolumeExtItf = NULL; + mbMuteEnabled = NULL; + + //buffer status + mPrefetchStatusItf = NULL; + mbPrefetchStatusChange = FALSE; + + //stream information + mStreamInformationItf = NULL; + mbStreamInfoAvailable = FALSE; + mbAudioStream = FALSE; + mbVideoStream = FALSE; + mNumStreams = 0; + + //Playbackrate + mPlaybackRateItf = NULL; + mbPlaybackRateItfAvailable = FALSE; + + mVideoPostProcessingItf = NULL; + mbScalable = FALSE; + mCurrAspectRatioMode = Qt::KeepAspectRatio; + + //internal + mCurPosition = 0; // in milliseconds + mDuration = 0; // in milliseconds + + + mbMediaPlayerUnrealized = TRUE; + + delete mURIName; + mURIName = NULL; + +} + +TInt XAPlaySessionImpl::play() +{ + TInt retVal(KErrGeneral); + XAresult xaRes; + XAuint32 state; + +#ifdef USE_VIDEOPLAYERUTILITY + mVideoPlayUtil->Play(); + return 0; +#endif + + if (!mMOPlayer || !mPlayItf) + return retVal; + + xaRes = (*mPlayItf)->GetPlayState(mPlayItf, &state); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + if ((state == XA_PLAYSTATE_STOPPED) || + (state == XA_PLAYSTATE_PAUSED)) { + xaRes = (*mPlayItf)->SetPlayState(mPlayItf, XA_PLAYSTATE_PLAYING); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + } + return retVal; +} + +TInt XAPlaySessionImpl::pause() +{ + TInt retVal(KErrGeneral); + XAresult xaRes; + XAuint32 state; + +#ifdef USE_VIDEOPLAYERUTILITY + TRAPD(err, mVideoPlayUtil->PauseL()); + return 0; +#endif + + if (!mMOPlayer || !mPlayItf) + return retVal; + + xaRes = (*mPlayItf)->GetPlayState(mPlayItf, &state); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + if ((state == XA_PLAYSTATE_STOPPED) || + (state == XA_PLAYSTATE_PLAYING)) { + xaRes = (*mPlayItf)->SetPlayState(mPlayItf, XA_PLAYSTATE_PAUSED); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + } + + return retVal; +} + +TInt XAPlaySessionImpl::stop() +{ + TInt retVal(KErrGeneral); + XAresult xaRes; + XAuint32 state; + +#ifdef USE_VIDEOPLAYERUTILITY + mVideoPlayUtil->Stop(); + return 0; +#endif + + if (!mMOPlayer || !mPlayItf) + return retVal; + + xaRes = (*mPlayItf)->GetPlayState(mPlayItf, &state); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + if ((state == XA_PLAYSTATE_PAUSED) || + (state == XA_PLAYSTATE_PLAYING)) { + xaRes = (*mPlayItf)->SetPlayState(mPlayItf, XA_PLAYSTATE_STOPPED); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + mCurPosition += KPlayPosUpdatePeriod; + mParent.cbPositionChanged(mCurPosition); + } + + return retVal; +} + +TInt XAPlaySessionImpl::duration(TInt64& aDur) +{ + TInt retVal(KErrGeneral); + +#ifdef USE_VIDEOPLAYERUTILITY + TTimeIntervalMicroSeconds dur(0); + TRAPD(err, mVideoPlayUtil->DurationL()); + if (!err) + aDur = dur.Int64() / 1000; + return 0; +#endif + if (!mMOPlayer || !mPlayItf) + return retVal; + aDur = mDuration; + return retVal; +} + +TInt XAPlaySessionImpl::position(TInt64& aPos) +{ + TInt retVal(KErrGeneral); +#ifdef USE_VIDEOPLAYERUTILITY + TTimeIntervalMicroSeconds dur(0); + TRAPD(err, mVideoPlayUtil->PositionL()); + if (!err) + aPos = dur.Int64() / 1000; + return 0; +#endif + +/* XAresult xaRes; + XAmillisecond pos(0);*/ + + if (!mMOPlayer || !mPlayItf) + return retVal; + + aPos = mCurPosition; + return retVal; +} + +TInt XAPlaySessionImpl::getSeekable(TBool& seekable) +{ + TInt retVal(KErrGeneral); + + if (!mMOPlayer || !mSeekItf) + return retVal; + + retVal = ETrue; + seekable = ETrue; + + return retVal; +} + +TInt XAPlaySessionImpl::seek(TInt64 pos) +{ + TInt retVal(KErrGeneral); + XAresult xaRes; + + if (!mMOPlayer || !mSeekItf) + return retVal; + + xaRes = (*mSeekItf)->SetPosition(mSeekItf, (XAmillisecond)pos, XA_SEEKMODE_FAST); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + mCurPosition = pos; + + return retVal; +} + +void XAPlaySessionImpl::cbMediaPlayer(XAObjectItf /*caller*/, + const void */*pContext*/, + XAuint32 event, + XAresult result, + XAuint32 /*param*/, + void */*pInterface*/) + +{ + switch (event) { + case XA_OBJECT_EVENT_RESOURCES_LOST: + unload(); + mParent.cbPlaybackStopped(result); + break; + case XA_OBJECT_EVENT_RUNTIME_ERROR: + { + switch (result) { + case XA_RESULT_RESOURCE_LOST: + unload(); + mParent.cbPlaybackStopped(result); + break; + default: + break; + }; /* of switch (result) */ + } + default: + break; + } /* of switch (event) */ +} + +void XAPlaySessionImpl::cbPlayItf(XAPlayItf /*caller*/, + void */*pContext*/, + XAuint32 event) +{ + switch(event) { + case XA_PLAYEVENT_HEADATEND: + mParent.cbPlaybackStopped(KErrNone); + break; + case XA_PLAYEVENT_HEADATMARKER: + break; + case XA_PLAYEVENT_HEADATNEWPOS: + mCurPosition += KPlayPosUpdatePeriod; + mParent.cbPositionChanged(mCurPosition); + break; + case XA_PLAYEVENT_HEADMOVING: + break; + case XA_PLAYEVENT_HEADSTALLED: + break; + default: + break; + } +} + +void XAPlaySessionImpl::cbPrefetchItf(XAuint32 event) +{ + if(event == XA_PREFETCHEVENT_FILLLEVELCHANGE) + mParent.cbPrefetchStatusChanged(); +} + +void XAPlaySessionImpl::cbStreamInformationItf( XAuint32 /*eventId*/, + XAuint32 /*streamIndex*/, + void * /*pEventData*/) +{ + mParent.cbStreamInformation(EFalse); +} + +void XAPlaySessionImpl::setAspectRatioMode(Qt::AspectRatioMode aspectRatioMode) +{ + if( !mbScalable || + (mCurrAspectRatioMode == aspectRatioMode)) { + return; + } + + XAuint32 scaleOptions;; + XAuint32 backgrndColor = 1; + XAuint32 renderingHints = 1; + + switch(aspectRatioMode) { + case Qt::IgnoreAspectRatio: + scaleOptions = XA_VIDEOSCALE_STRETCH; + break; + case Qt::KeepAspectRatio: + scaleOptions = XA_VIDEOSCALE_FIT; + break; + case Qt::KeepAspectRatioByExpanding: + scaleOptions = XA_VIDEOSCALE_CROP; + break; + default: + return; + } + + XAresult xaRes = (*mVideoPostProcessingItf)->SetScaleOptions(mVideoPostProcessingItf, \ + scaleOptions, backgrndColor, renderingHints); + if(mapError(xaRes, ETrue) == KErrNone) + xaRes = (*mVideoPostProcessingItf)->Commit(mVideoPostProcessingItf); + + if(mapError(xaRes, ETrue) == KErrNone) + mCurrAspectRatioMode = aspectRatioMode; +} + +Qt::AspectRatioMode XAPlaySessionImpl::getAspectRatioMode() +{ + return mCurrAspectRatioMode; +} + + +#ifdef USE_VIDEOPLAYERUTILITY +void XAPlaySessionImpl::MvpuoOpenComplete(TInt aError) +{ + TRACE_FUNCTION_ENTRY; + m_VPError = aError; + if (mActiveSchedulerWait->IsStarted()) + mActiveSchedulerWait->AsyncStop(); + TRACE_FUNCTION_EXIT; +} + +void XAPlaySessionImpl::MvpuoPrepareComplete(TInt aError) +{ + TRACE_FUNCTION_ENTRY; + m_VPError = aError; + if (mActiveSchedulerWait->IsStarted()) + mActiveSchedulerWait->AsyncStop(); + + RWindow* window = (RWindow*)mNativeDisplay.hWindow; + RWsSession* wssession = (RWsSession*)mNativeDisplay.hDisplay; + + if (window) { + TRect videoExtent = TRect(window->Size()); + TRect clipRect = TRect(window->Size()); + TRAP_IGNORE(mVideoPlayUtil->AddDisplayWindowL(*wssession, *(CCoeEnv::Static()->ScreenDevice()), *window, videoExtent, clipRect)); + TRAP_IGNORE(mVideoPlayUtil->SetAutoScaleL(*window, EAutoScaleBestFit)); + } + TRACE_FUNCTION_EXIT; +} + +void XAPlaySessionImpl::MvpuoFrameReady(CFbsBitmap& /*aFrame*/,TInt /*aError*/) +{ + TRACE_FUNCTION_ENTRY_EXIT; +} + +void XAPlaySessionImpl::MvpuoPlayComplete(TInt /*aError*/) +{ + TRACE_FUNCTION_ENTRY; + mParent.cbPlaybackStopped_EOS(); + TRACE_FUNCTION_EXIT; +} + +void XAPlaySessionImpl::MvpuoEvent(const TMMFEvent& /*aEvent*/) +{ + TRACE_FUNCTION_ENTRY_EXIT; +} + +#endif + +TInt XAPlaySessionImpl::mapError(XAresult xa_err, TBool /*debPrn*/) +{ + TInt retVal(KErrGeneral); + + switch(xa_err) { + case XA_RESULT_SUCCESS: + retVal = KErrNone; + break; + case XA_RESULT_PRECONDITIONS_VIOLATED: + break; + case XA_RESULT_PARAMETER_INVALID: + break; + case XA_RESULT_MEMORY_FAILURE: + break; + case XA_RESULT_RESOURCE_ERROR: + break; + case XA_RESULT_RESOURCE_LOST: + break; + case XA_RESULT_IO_ERROR: + break; + case XA_RESULT_BUFFER_INSUFFICIENT: + break; + case XA_RESULT_CONTENT_CORRUPTED: + break; + case XA_RESULT_CONTENT_UNSUPPORTED: + break; + case XA_RESULT_CONTENT_NOT_FOUND: + break; + case XA_RESULT_PERMISSION_DENIED: + break; + case XA_RESULT_FEATURE_UNSUPPORTED: + break; + case XA_RESULT_INTERNAL_ERROR: + break; + case XA_RESULT_UNKNOWN_ERROR: + break; + case XA_RESULT_OPERATION_ABORTED: + break; + case XA_RESULT_CONTROL_LOST: + break; + default: + break; + } + + return retVal; +} + + +QStringList XAPlaySessionImpl::availableExtendedMetaData () const +{ + QStringList retList; + + //create a qlist with all keys in keyMap hash + QHashIterator it(extendedKeyMap); + while(it.hasNext()) { + it.next(); + retList << it.key(); + } + + return retList; +} + +QList XAPlaySessionImpl::availableMetaData () const +{ + QList retList; + + //create a qlist with all keys in keyMap hash + QHashIterator it(keyMap); + while( it.hasNext() ) { + it.next(); + retList << it.key(); + } + + return retList; +} + +QVariant XAPlaySessionImpl::getMetaData( int alIndex ) const +{ + QVariant ret; //invalid variant + + //find index for the given key + if(mMetadataExtItf) { + XAuint32 valueSize = 0; + XAresult res = (*mMetadataExtItf)->GetValueSize(mMetadataExtItf, alIndex, &valueSize); + if(res == XA_RESULT_SUCCESS) { + XAMetadataInfo * value = (XAMetadataInfo*)calloc(valueSize, 1); + if(value) { + res = (*mMetadataExtItf)->GetValue(mMetadataExtItf, alIndex, valueSize, value); + if(res == XA_RESULT_SUCCESS) { + if(value->encoding == XA_CHARACTERENCODING_ASCII) + ret = QVariant ((const char*)value->data); + else if(value->encoding == XA_CHARACTERENCODING_UTF16LE) + ret = QVariant(QString::fromUtf16((ushort*)value->data, (value->size/2)-1)); //dont include null terminating character + else if(value->encoding == XA_CHARACTERENCODING_BINARY) + ret = QVariant(QImage::fromData(value->data, value->size)); + } + + free(value); + } + } + } + + return ret; +} + +QVariant XAPlaySessionImpl::metaData( QtMultimediaKit::MetaData key ) const +{ + QVariant ret; + if(keyMap.contains(key)) + ret = getMetaData(keyMap[key]); + return ret; +} + +QVariant XAPlaySessionImpl::extendedMetaData(const QString & key ) const +{ + QVariant ret; + if(extendedKeyMap.contains(key)) + ret = getMetaData(extendedKeyMap[key]); + + return ret; +} + +bool XAPlaySessionImpl::isMetaDataAvailable() const +{ + return ((keyMap.size()>0) || (extendedKeyMap.size()>0)); +} + +bool XAPlaySessionImpl::isWritable() const +{ + return false; +} + +void XAPlaySessionImpl::setExtendedMetaData( const QString&, const QVariant&) +{ + //Do Nothing +} + +void XAPlaySessionImpl::setMetaData( QtMultimediaKit::MetaData, const QVariant& ) +{ + //Do Nothing +} + +void XAPlaySessionImpl::setupALKeyMap() +{ + alKeyMap["KhronosTitle"] = QtMultimediaKit::Title; + alKeyMap["KhronosComment"] = QtMultimediaKit::Comment; + alKeyMap["KhronosTrackNumber"] = QtMultimediaKit::TrackNumber; + alKeyMap["KhronosAlbumArtJPEG"] = QtMultimediaKit::CoverArtImage; + alKeyMap["KhronosAlbumArtPNG"] = QtMultimediaKit::CoverArtImage; + alKeyMap["KhronosAlbum"] = QtMultimediaKit::AlbumTitle; + alKeyMap["KhronosArtist"] = QtMultimediaKit::AlbumArtist; + alKeyMap["KhronosGenre"] = QtMultimediaKit::Genre; + alKeyMap["KhronosYear"] = QtMultimediaKit::Year; + alKeyMap["KhronosYear"] = QtMultimediaKit::Date; + alKeyMap["KhronosRating"] = QtMultimediaKit::UserRating; + alKeyMap["KhronosCopyright"] = QtMultimediaKit::Copyright; + alKeyMap["Author"] = QtMultimediaKit::Author; + alKeyMap["Duration"] = QtMultimediaKit::Duration; + alKeyMap["Stream Count"] = QtMultimediaKit::ChannelCount; + alKeyMap["Composer"] = QtMultimediaKit::Composer; + alKeyMap["Resolution"] = QtMultimediaKit::Resolution; + alKeyMap["FrameRate"] = QtMultimediaKit::VideoFrameRate; + alKeyMap["ClipBitRate"] = QtMultimediaKit::VideoBitRate; + alKeyMap["Codec"] = QtMultimediaKit::VideoCodec; + alKeyMap["attachedpicture"] = QtMultimediaKit::CoverArtImage; + + /*Keys not available + QtMedia::SubTitle + QtMedia::Description + QtMedia::Category + QtMedia::Keywords + QtMedia::Language + QtMedia::Publisher + QtMedia::ParentalRating + QtMedia::RatingOrganisation + QtMedia::Size + QtMedia::MediaType + QtMedia::AudioBitrate + QtMedia::AudioCodec + QtMedia::AverageLevel + QtMedia::PeakValue + QtMedia::Frequency + QtMedia::ContributingArtist + QtMedia::Conductor + QtMedia::Lyrics + QtMedia::Mood + QtMedia::TrackCount + QtMedia::PixelAspectRatio + QtMedia::PosterUri + QtMedia::ChapterNumber + QtMedia::Director + QtMedia::LeadPerformer + QtMedia::Writer */ +} + +TInt XAPlaySessionImpl::mapMetaDataKey(const char* asckey, QtMultimediaKit::MetaData& key) +{ + if(alKeyMap.contains(asckey)) { + key = alKeyMap[asckey]; + return KErrNone; + } + + return KErrNotFound; +} + +TInt XAPlaySessionImpl::setupMetaData() +{ + XAresult res; + if(mMetadataExtItf) { + XAuint32 numItems = 0; + res = (*mMetadataExtItf)->GetItemCount(mMetadataExtItf, &numItems); + RET_ERR_IF_ERR(mapError(res, ETrue)); + + for(int i=0; iGetKeySize(mMetadataExtItf, i, &keySize); + RET_ERR_IF_ERR(mapError(res, ETrue)); + + XAMetadataInfo *key = (XAMetadataInfo *)calloc(keySize,1); + if(key) { + res = (*mMetadataExtItf)->GetKey(mMetadataExtItf, i, keySize, key); + RET_ERR_IF_ERR(mapError(res, ETrue)); + + if(key->encoding == XA_CHARACTERENCODING_ASCII) { //only handle ASCII keys ignore others + QtMultimediaKit::MetaData qtKey; + if(mapMetaDataKey((const char*)key->data, qtKey) == KErrNone)//qt metadata + keyMap[qtKey] = i; + else //extended metadata + extendedKeyMap[(const char*)key->data] = i; + } + + free(key); + } + } + + //check for seek property to generate seekable signal + QVariant var = extendedMetaData("Seekable"); + if(!var.isValid() || (var.toString() == "1")) + mParent.cbSeekableChanged(ETrue); + else + mParent.cbSeekableChanged(EFalse); + + } + + return KErrGeneral; +} + +//Volume +TInt XAPlaySessionImpl::volume(TInt& v) +{ + if(mbVolEnabled) { + XAresult res = (*mNokiaLinearVolumeItf)->GetVolumeLevel(mNokiaLinearVolumeItf, (XAuint32 *)&v); + return mapError(res, ETrue); + } + + return KErrNotFound; +} + +TInt XAPlaySessionImpl::setVolume(TInt v) +{ + if(mbVolEnabled) { + XAresult res = (*mNokiaLinearVolumeItf)->SetVolumeLevel(mNokiaLinearVolumeItf, (XAuint32*)&v); + return mapError(res, ETrue); + } + + return KErrNotFound; +} + +TInt XAPlaySessionImpl::setMute(TBool bMute) +{ + if(mbMuteEnabled) { + XAresult res = (*mNokiaVolumeExtItf)->SetMute(mNokiaVolumeExtItf, (XAboolean)bMute); + return mapError(res, ETrue); + } + + return KErrNotFound; + +} + +TInt XAPlaySessionImpl::getMute(TBool& bIsMute) +{ + if(mbMuteEnabled) { + XAboolean xaMute; + XAresult res = (*mNokiaVolumeExtItf)->GetMute(mNokiaVolumeExtItf, &xaMute); + bIsMute = xaMute; + return mapError(res, ETrue); + } + + return KErrNotFound; +} + + +TInt XAPlaySessionImpl::bufferStatus(TInt &bs) +{ + TInt ret = KErrNotFound; + + if(mbPrefetchStatusChange) { + XApermille satusPerThousand; + XAresult res = (*mPrefetchStatusItf)->GetFillLevel(mPrefetchStatusItf, &satusPerThousand); + ret = mapError(res, ETrue); + if(ret == KErrNone) + bs = satusPerThousand/10.0; //convert to parts per hundred + } + return ret; +} + +QMediaStreamsControl::StreamType XAPlaySessionImpl::mapStreamType(XAuint32& alStreamType) +{ + switch(alStreamType) { + case XA_DOMAINTYPE_AUDIO: + return QMediaStreamsControl::AudioStream; + case XA_DOMAINTYPE_VIDEO: + return QMediaStreamsControl::VideoStream; + case XA_DOMAINTYPE_IMAGE: + return QMediaStreamsControl::DataStream; + } + return QMediaStreamsControl::UnknownStream; +} + + +TInt XAPlaySessionImpl::numMediaStreams(TUint& numStreams) +{ + TInt ret = KErrNotFound; + numStreams = 0; + if(mbStreamInfoAvailable) { + XAMediaContainerInformation mediaContainerInfo; + XAresult res = (*mStreamInformationItf)->QueryMediaContainerInformation(mStreamInformationItf, &mediaContainerInfo); + ret = mapError(res, ETrue); + if(ret == KErrNone) + numStreams = mediaContainerInfo.numStreams; + } + return ret; +} + +TInt XAPlaySessionImpl::streamType(TUint index, QMediaStreamsControl::StreamType& type) +{ + TInt ret = KErrNotFound; + type = QMediaStreamsControl::UnknownStream; + if(mbStreamInfoAvailable) { + XAuint32 strType; + XAresult res = (*mStreamInformationItf)->QueryStreamType(mStreamInformationItf, (XAuint32)(index+1), &strType); + ret = mapError(res, ETrue); + if(ret == KErrNone) + type = mapStreamType(strType); + } + return ret; +} + +TInt XAPlaySessionImpl::isStreamActive(TUint index, TBool& isActive) +{ + TUint numStreams; + TInt ret = numMediaStreams(numStreams); + if((ret == KErrNone) && (index < numStreams)) { + isActive = EFalse; + if(numStreams > 0) { + //create array of bools + XAboolean *activeStreams = new XAboolean[numStreams+1]; + XAresult res = (*mStreamInformationItf)->QueryActiveStreams(mStreamInformationItf, (XAuint32*)&numStreams, activeStreams); + ret = mapError(res, ETrue); + if(ret == KErrNone) + isActive = activeStreams[index+1]; + delete[] activeStreams; + } + } + return ret; +} + +TInt XAPlaySessionImpl::getPlaybackRate(TReal32 &rate) +{ + TInt ret = KErrNotFound; + + if(mbPlaybackRateItfAvailable) { + XApermille perMilleRate = 0; + ret = (*mPlaybackRateItf)->GetRate(mPlaybackRateItf, &perMilleRate); + rate = perMilleRate / 1000.0; + } + return ret; +} + +TInt XAPlaySessionImpl::setPlaybackRate(TReal32 rate) +{ + TInt ret = KErrNotFound; + if(mbPlaybackRateItfAvailable) + ret = (*mPlaybackRateItf)->SetRate(mPlaybackRateItf, (XApermille)(rate * 1000.0)); + return ret; +} + + +/* Local function implementation */ +void MediaPlayerCallback( XAObjectItf caller, + const void *pContext, + XAuint32 event, + XAresult result, + XAuint32 param, + void *pInterface) +{ + if (pContext) + ((XAPlaySessionImpl*)pContext)->cbMediaPlayer( caller, + pContext, + event, + result, + param, + pInterface); +} + +void PlayItfCallback( XAPlayItf caller, + void *pContext, + XAuint32 event) +{ + if (pContext) + ((XAPlaySessionImpl*)pContext)->cbPlayItf(caller, + pContext, + event); +} + +void PrefetchItfCallback( XAPrefetchStatusItf /*caller*/, + void *pContext, + XAuint32 event) +{ + if (pContext) + ((XAPlaySessionImpl*)pContext)->cbPrefetchItf(event); +} + +void StreamInformationItfCallback( XAStreamInformationItf /*caller*/, + XAuint32 eventId, + XAuint32 streamIndex, + void * pEventData, + void * pContext) +{ + if (pContext) + ((XAPlaySessionImpl*)pContext)->cbStreamInformationItf( eventId, + streamIndex, + pEventData); +} + + + +// End of file diff --git a/src/plugins/symbian/openmaxal/mediaplayer/xaplaysessionimpl.h b/src/plugins/symbian/openmaxal/mediaplayer/xaplaysessionimpl.h new file mode 100644 index 000000000..30144712a --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/xaplaysessionimpl.h @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef XAPLAYSESSIONIMPL_H +#define XAPLAYSESSIONIMPL_H + +#include +#include +#include +#ifdef USE_VIDEOPLAYERUTILITY +#include +#endif + +#include "qtmedianamespace.h" +#include "qmediastreamscontrol.h" + +class XAPlayObserver; +class RWindow; +class RWsSession; + +class XAPlaySessionImpl +#ifdef USE_VIDEOPLAYERUTILITY + : public MVideoPlayerUtilityObserver +#endif +{ +public: + XAPlaySessionImpl(XAPlayObserver& parent); + ~XAPlaySessionImpl(); + TInt postConstruct(); + TInt addNativeDisplay(RWindow* window, RWsSession* wssession); + TInt updateNativeDisplay(RWindow* window, RWsSession* wssession); + TInt removeNativeDisplay(RWindow* window, RWsSession* wssession); + TInt load(const TDesC& aURI); + void unload(); + TInt play(); + TInt pause(); + TInt stop(); + TInt duration(TInt64& aDur); + TInt position(TInt64& aPos); + TInt getSeekable(TBool& seekable); + TInt seek(TInt64 pos); + + //Metadata + QStringList availableExtendedMetaData () const; + QList availableMetaData () const; + QVariant extendedMetaData(const QString & key ) const; + bool isMetaDataAvailable() const; + bool isWritable() const; + QVariant metaData( QtMultimediaKit::MetaData key ) const; + void setExtendedMetaData( const QString & key, const QVariant & value ); + void setMetaData( QtMultimediaKit::MetaData key, const QVariant & value ); + + TInt volume(TInt&); + TInt setVolume(TInt); + TInt setMute(TBool); + TInt getMute(TBool&); + + TInt bufferStatus(TInt &); + + + TInt numMediaStreams(TUint& numStreams); + TInt streamType(TUint index, QMediaStreamsControl::StreamType& type); + TInt isStreamActive(TUint index, TBool& isActive); + + TInt getPlaybackRate(TReal32 &rate); + TInt setPlaybackRate(TReal32 rate); + + //AspectRatioMode + void setAspectRatioMode(Qt::AspectRatioMode); + Qt::AspectRatioMode getAspectRatioMode(); + +public: + void cbMediaPlayer( XAObjectItf caller, + const void *pContext, + XAuint32 event, + XAresult result, + XAuint32 param, + void *pInterface); + + void cbPlayItf(XAPlayItf caller, + void *pContext, + XAuint32 event); + + + void cbPrefetchItf(XAuint32); + + void cbStreamInformationItf(XAuint32, XAuint32, void*); + +#ifdef USE_VIDEOPLAYERUTILITY + //MVideoPlayerUtilityObserver + void MvpuoOpenComplete(TInt aError); + void MvpuoPrepareComplete(TInt aError); + void MvpuoFrameReady(CFbsBitmap& aFrame,TInt aError); + void MvpuoPlayComplete(TInt aError); + void MvpuoEvent(const TMMFEvent& aEvent); +#endif + +private: + TInt mapError(XAresult xa_err, + TBool debPrn); + void setupALKeyMap(); + TInt setupMetaData(); + TInt mapMetaDataKey(const char* asckey, QtMultimediaKit::MetaData& key); + QVariant getMetaData( int alIndex ) const; + + QMediaStreamsControl::StreamType mapStreamType(XAuint32& alStreamType); + + +private: + XAPlayObserver& mParent; + XAObjectItf mEOEngine; + XAObjectItf mMOPlayer; + XAPlayItf mPlayItf; + XASeekItf mSeekItf; + HBufC8* mURIName; + HBufC8* mWAVMime; + // Audio Source + XADataSource mDataSource; + XADataFormat_MIME mMime; + XADataLocator_URI mUri; + //Audio Sink + XADataSink mAudioSink; + XADataLocator_IODevice mLocatorOutputDevice; + //Video Sink + XADataSink mVideoSink; + XADataLocator_NativeDisplay mNativeDisplay; + + //Metadata + TBool mbMetadataAvailable; + XAMetadataExtractionItf mMetadataExtItf; + QHash alKeyMap; + QHash keyMap; + QHash extendedKeyMap; + + //Volume + XANokiaLinearVolumeItf mNokiaLinearVolumeItf; + TBool mbVolEnabled; + XANokiaVolumeExtItf mNokiaVolumeExtItf; + TBool mbMuteEnabled; + + //buffer status + XAPrefetchStatusItf mPrefetchStatusItf; + TBool mbPrefetchStatusChange; + + //stream information + XAStreamInformationItf mStreamInformationItf; + TBool mbStreamInfoAvailable; + TBool mbAudioStream; + TBool mbVideoStream; + TInt mNumStreams; + + //Playbackrate + XAPlaybackRateItf mPlaybackRateItf; + TBool mbPlaybackRateItfAvailable; + + XAVideoPostProcessingItf mVideoPostProcessingItf; + TBool mbScalable; + Qt::AspectRatioMode mCurrAspectRatioMode; + + //internal + TInt64 mCurPosition; // in milliseconds + TInt64 mDuration; // in milliseconds + + TBool mbMediaPlayerUnrealized; +#ifdef USE_VIDEOPLAYERUTILITY + CVideoPlayerUtility2* mVideoPlayUtil; + CActiveSchedulerWait* mActiveSchedulerWait; + TInt m_VPError; +#endif +}; + +#endif /* XAPLAYSESSIONIMPL_H */ diff --git a/src/plugins/symbian/openmaxal/mediarecorder/mediarecorder.pri b/src/plugins/symbian/openmaxal/mediarecorder/mediarecorder.pri new file mode 100644 index 000000000..ee78e8348 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/mediarecorder.pri @@ -0,0 +1,24 @@ +INCLUDEPATH += $$PWD + +# Input +HEADERS += \ + $$PWD/qxarecordmediaservice.h \ + $$PWD/qxarecordsession.h \ + $$PWD/qxaaudioendpointselector.h \ + $$PWD/qxaaudioencodercontrol.h \ + $$PWD/qxamediacontainercontrol.h \ + $$PWD/qxamediarecordercontrol.h \ + $$PWD/xarecordsessionimpl.h \ + $$PWD/xarecordsessioncommon.h + +SOURCES += \ + $$PWD/qxarecordmediaservice.cpp \ + $$PWD/qxarecordsession.cpp \ + $$PWD/qxaaudioendpointselector.cpp \ + $$PWD/qxaaudioencodercontrol.cpp \ + $$PWD/qxamediacontainercontrol.cpp \ + $$PWD/qxamediarecordercontrol.cpp \ + $$PWD/xarecordsessionimpl.cpp + +LIBS += \ + -lbafl diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioencodercontrol.cpp b/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioencodercontrol.cpp new file mode 100644 index 000000000..2826f79a2 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioencodercontrol.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxaaudioencodercontrol.h" +#include "qxarecordsession.h" +#include "qxacommon.h" + +QXAAudioEncoderControl::QXAAudioEncoderControl(QXARecordSession *session, QObject *parent) +:QAudioEncoderControl(parent), m_session(session) +{ +} + +QXAAudioEncoderControl::~QXAAudioEncoderControl() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +QStringList QXAAudioEncoderControl::supportedAudioCodecs() const +{ + if (m_session) + return m_session->supportedAudioCodecs(); + return QStringList(); +} + +QString QXAAudioEncoderControl::codecDescription(const QString &codecName) const +{ + if (m_session) + return m_session->codecDescription(codecName); + return QString(); +} + +QList QXAAudioEncoderControl::supportedSampleRates( + const QAudioEncoderSettings &settings, + bool *continuous) const +{ + if (m_session) + return m_session->supportedSampleRates(settings, continuous); + return QList(); +} + +QAudioEncoderSettings QXAAudioEncoderControl::audioSettings() const +{ + if (m_session) + return m_session->audioSettings(); + return QAudioEncoderSettings(); +} + +void QXAAudioEncoderControl::setAudioSettings(const QAudioEncoderSettings &settings) +{ + if (m_session) + m_session->setAudioSettings(settings); +} + +QStringList QXAAudioEncoderControl::supportedEncodingOptions(const QString &codec) const +{ + if (m_session) + return m_session->supportedEncodingOptions(codec); + return QStringList(); +} + +QVariant QXAAudioEncoderControl::encodingOption(const QString &codec, const QString &name) const +{ + if (m_session) + return m_session->encodingOption(codec, name); + return QVariant(); +} + +void QXAAudioEncoderControl::setEncodingOption( + const QString &codec, const QString &name, const QVariant &value) +{ + if (m_session) + m_session->setEncodingOption(codec, name, value); +} diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioencodercontrol.h b/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioencodercontrol.h new file mode 100644 index 000000000..117d36fdc --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioencodercontrol.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXAAUDIOENCODERCONTROL_H +#define QXAAUDIOENCODERCONTROL_H + +#include + +QT_USE_NAMESPACE + +/* + * This class implements QAudioEncoderControl interface. + */ +class QXARecordSession; + +class QXAAudioEncoderControl : public QAudioEncoderControl +{ + Q_OBJECT + +public: + QXAAudioEncoderControl(QXARecordSession *session, QObject *parent = 0); + virtual ~QXAAudioEncoderControl(); + + QStringList supportedAudioCodecs() const; + QString codecDescription(const QString &codecName) const; + + QList supportedSampleRates(const QAudioEncoderSettings &settings, + bool *continuous = 0) const; + + QAudioEncoderSettings audioSettings() const; + void setAudioSettings(const QAudioEncoderSettings &settings); + + QStringList supportedEncodingOptions(const QString &codec) const; + QVariant encodingOption(const QString &codec, const QString &name) const; + void setEncodingOption(const QString &codec, const QString &name, const QVariant &value); + +private: + QXARecordSession *m_session; +}; + +#endif /* QXAAUDIOENCODERCONTROL_H */ diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioendpointselector.cpp b/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioendpointselector.cpp new file mode 100644 index 000000000..7e546595c --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioendpointselector.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxaaudioendpointselector.h" +#include "qxarecordsession.h" +#include "qxacommon.h" + +QXAAudioEndpointSelector::QXAAudioEndpointSelector(QXARecordSession *session, QObject *parent) +:QAudioEndpointSelector(parent), m_session(session) +{ + connect(m_session, SIGNAL(availableAudioInputsChanged()), + this, SLOT(availableAudioInputsChanged())); + connect(m_session, SIGNAL(activeEndpointChanged(QString)), + this, SIGNAL(activeEndpointChanged(QString))); +} + +QXAAudioEndpointSelector::~QXAAudioEndpointSelector() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +QList QXAAudioEndpointSelector::availableEndpoints() const +{ + if (m_session) + return m_session->availableEndpoints(); + return QList(); +} + +QString QXAAudioEndpointSelector::endpointDescription(const QString &name) const +{ + if (m_session) + return m_session->endpointDescription(name); + return QString(); +} + +QString QXAAudioEndpointSelector::defaultEndpoint() const +{ + if (m_session) + return m_session->defaultEndpoint(); + return QString(); +} + +QString QXAAudioEndpointSelector::activeEndpoint() const +{ + if (m_session) + return m_session->activeEndpoint(); + return QString(); +} + +void QXAAudioEndpointSelector::setActiveEndpoint(const QString &name) +{ + if (m_session) + m_session->setActiveEndpoint(name); +} + +void QXAAudioEndpointSelector::availableAudioInputsChanged() + { + emit availableEndpointsChanged(); + } + diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioendpointselector.h b/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioendpointselector.h new file mode 100644 index 000000000..5fbadbc64 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioendpointselector.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXAAUDIOENDPOINTSELECTOR_H +#define QXAAUDIOENDPOINTSELECTOR_H + +#include + +QT_USE_NAMESPACE + +/* + * This class implements QAudioEncoderControl interface. + */ +class QXARecordSession; + +class QXAAudioEndpointSelector : public QAudioEndpointSelector +{ + Q_OBJECT + +public: + QXAAudioEndpointSelector(QXARecordSession *session, QObject *parent); + ~QXAAudioEndpointSelector(); + + QList availableEndpoints() const; + QString endpointDescription(const QString &name) const; + QString defaultEndpoint() const; + QString activeEndpoint() const; + +public Q_SLOTS: + void setActiveEndpoint(const QString &name); + +private Q_SLOTS: + void availableAudioInputsChanged(); + +private: + QXARecordSession *m_session; +}; + +#endif /* QXAAUDIOENDPOINTSELECTOR_H */ diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxamediacontainercontrol.cpp b/src/plugins/symbian/openmaxal/mediarecorder/qxamediacontainercontrol.cpp new file mode 100644 index 000000000..0d97fd5e5 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxamediacontainercontrol.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxamediacontainercontrol.h" +#include "qxarecordsession.h" +#include "qxacommon.h" + +QXAMediaContainerControl::QXAMediaContainerControl(QXARecordSession *session, QObject *parent) +:QMediaContainerControl(parent), m_session(session) +{ +} + +QXAMediaContainerControl::~QXAMediaContainerControl() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +QStringList QXAMediaContainerControl::supportedContainers() const +{ + if (m_session) + return m_session->supportedContainers(); + return QStringList(); +} + +QString QXAMediaContainerControl::containerMimeType() const +{ + if (m_session) + return m_session->containerMimeType(); + return QString(); +} + +void QXAMediaContainerControl::setContainerMimeType(const QString &formatMimeType) +{ + if (m_session) + m_session->setContainerMimeType(formatMimeType); +} + +QString QXAMediaContainerControl::containerDescription(const QString &formatMimeType) const +{ + if (m_session) + return m_session->containerDescription(formatMimeType); + return QString(); +} diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxamediacontainercontrol.h b/src/plugins/symbian/openmaxal/mediarecorder/qxamediacontainercontrol.h new file mode 100644 index 000000000..4b05fc190 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxamediacontainercontrol.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXAMEDIACONTAINERCONTROL_H +#define QXAMEDIACONTAINERCONTROL_H + +#include + +QT_USE_NAMESPACE + +/* + * This class implements QMediaContainerControl interface. + */ +class QXARecordSession; + +class QXAMediaContainerControl : public QMediaContainerControl +{ + Q_OBJECT + +public: + QXAMediaContainerControl(QXARecordSession *session, QObject *parent = 0); + virtual ~QXAMediaContainerControl(); + + QStringList supportedContainers() const; + QString containerMimeType() const; + void setContainerMimeType(const QString &formatMimeType); + QString containerDescription(const QString &formatMimeType) const; + +private: + QXARecordSession *m_session; +}; + +#endif /* QXAMEDIACONTAINERCONTROL_H */ diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxamediarecordercontrol.cpp b/src/plugins/symbian/openmaxal/mediarecorder/qxamediarecordercontrol.cpp new file mode 100644 index 000000000..330edf008 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxamediarecordercontrol.cpp @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxamediarecordercontrol.h" +#include "qxarecordsession.h" +#include "qxacommon.h" + +QXAMediaRecoderControl::QXAMediaRecoderControl(QXARecordSession *session, QObject *parent) +:QMediaRecorderControl(parent), m_session(session) +{ + connect(m_session, SIGNAL(stateChanged(QMediaRecorder::State)), + this, SIGNAL(stateChanged(QMediaRecorder::State))); + connect(m_session, SIGNAL(error(int,QString)), + this,SIGNAL(error(int,QString))); + connect(m_session, SIGNAL(durationChanged(qint64)), + this, SIGNAL(durationChanged(qint64))); +} + +QXAMediaRecoderControl::~QXAMediaRecoderControl() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +QUrl QXAMediaRecoderControl::outputLocation() const +{ + if (m_session) + return m_session->outputLocation(); + return QUrl(); +} + +bool QXAMediaRecoderControl::setOutputLocation(const QUrl &location) +{ + if (m_session) + return m_session->setOutputLocation(location); + return false; +} + +QMediaRecorder::State QXAMediaRecoderControl::state() const +{ + if (m_session) + return m_session->state(); + return QMediaRecorder::StoppedState; +} + +qint64 QXAMediaRecoderControl::duration() const +{ + if (m_session) + return m_session->duration(); + return 0; +} + +void QXAMediaRecoderControl::record() +{ + if (m_session) + m_session->record(); +} + +void QXAMediaRecoderControl::pause() +{ + if (m_session) + m_session->pause(); +} + +void QXAMediaRecoderControl::stop() +{ + if (m_session) + m_session->stop(); +} + +void QXAMediaRecoderControl::applySettings() +{ + if (m_session) + m_session->applySettings(); +} + +bool QXAMediaRecoderControl::isMuted() const +{ + return false; +} + +void QXAMediaRecoderControl::setMuted(bool) +{ + +} diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxamediarecordercontrol.h b/src/plugins/symbian/openmaxal/mediarecorder/qxamediarecordercontrol.h new file mode 100644 index 000000000..c6495f2e4 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxamediarecordercontrol.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXAMEDIARECORDERCONTROL_H +#define QXAMEDIARECORDERCONTROL_H + +#include +#include + +QT_USE_NAMESPACE + +/* + * This class implements QMediaRecorderControl interface. + */ + +class QXARecordSession; + +class QXAMediaRecoderControl : public QMediaRecorderControl +{ + Q_OBJECT + +public: + QXAMediaRecoderControl(QXARecordSession *session, QObject *parent = 0); + virtual ~QXAMediaRecoderControl(); + + QUrl outputLocation() const; + bool setOutputLocation(const QUrl &location); + + QMediaRecorder::State state() const; + + qint64 duration() const; + bool isMuted() const; + void applySettings(); + +public Q_SLOTS: + void record(); + void pause(); + void stop(); + void setMuted(bool); + +private: + QXARecordSession *m_session; +}; + +#endif /* QXAMEDIARECORDERCONTROL_H */ diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxarecordmediaservice.cpp b/src/plugins/symbian/openmaxal/mediarecorder/qxarecordmediaservice.cpp new file mode 100644 index 000000000..05c57feb7 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxarecordmediaservice.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "qxarecordmediaservice.h" +#include "qxarecordsession.h" +#include "qxamediarecordercontrol.h" +#include "qxaaudioendpointselector.h" +#include "qxaaudioencodercontrol.h" +#include "qxamediacontainercontrol.h" +#include "qxacommon.h" + +QXARecodMediaService::QXARecodMediaService(QObject *parent) +:QMediaService(parent) +{ + QT_TRACE_FUNCTION_ENTRY; + m_session = new QXARecordSession(this); + m_control = new QXAMediaRecoderControl(m_session, this); + m_endpoint = new QXAAudioEndpointSelector(m_session, this); + m_encoder = new QXAAudioEncoderControl(m_session, this); + m_container = new QXAMediaContainerControl(m_session, this); +} + +QXARecodMediaService::~QXARecodMediaService() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +QMediaControl* QXARecodMediaService::requestControl(const char *name) +{ + QT_TRACE_FUNCTION_ENTRY; + if (qstrcmp(name, QMediaRecorderControl_iid) == 0) + return m_control; + else if (qstrcmp(name, QAudioEndpointSelector_iid) == 0) + return m_endpoint; + else if (qstrcmp(name, QAudioEncoderControl_iid) == 0) + return m_encoder; + else if (qstrcmp(name, QMediaContainerControl_iid) == 0) + return m_container; + QT_TRACE_FUNCTION_EXIT; + return 0; +} + +void QXARecodMediaService::releaseControl(QMediaControl *control) +{ + Q_UNUSED(control) +} diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxarecordmediaservice.h b/src/plugins/symbian/openmaxal/mediarecorder/qxarecordmediaservice.h new file mode 100644 index 000000000..98f5136e8 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxarecordmediaservice.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXARECORDMEDIASERVICE_H +#define QXARECORDMEDIASERVICE_H + +#include +#include + +QT_USE_NAMESPACE + +/* + * This class implements QMediaService interface. + */ + +class QXARecordSession; +class QXAMediaRecoderControl; +class QXAAudioEndpointSelector; +class QXAAudioEncoderControl; +class QXAMediaContainerControl; + +class QXARecodMediaService : public QMediaService +{ + + Q_OBJECT + +public: + QXARecodMediaService(QObject *parent = 0); + ~QXARecodMediaService(); + QMediaControl *requestControl(const char *name); + void releaseControl( QMediaControl *control); +private: + QXARecordSession *m_session; + QXAMediaRecoderControl *m_control; + QXAAudioEndpointSelector *m_endpoint; + QXAAudioEncoderControl *m_encoder; + QXAMediaContainerControl *m_container; +}; + +#endif /* QXARECORDMEDIASERVICE_H */ diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxarecordsession.cpp b/src/plugins/symbian/openmaxal/mediarecorder/qxarecordsession.cpp new file mode 100644 index 000000000..76cdfc3da --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxarecordsession.cpp @@ -0,0 +1,766 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include "qxarecordsession.h" +#include "xarecordsessionimpl.h" +#include "qxacommon.h" + +/* The following declaration is required to allow QList to be added to + * QVariant + */ +Q_DECLARE_METATYPE(QList) + +/* This macro checks for m_impl null pointer. If it is, emits an error signal + * error(QMediaRecorder::ResourceError, tr("Service has not been started")); + * and returns from function immediately with value 's'. + */ + +#define RETURN_s_IF_m_impl_IS_NULL(s) \ + if (!m_impl) { \ + emit error(QMediaRecorder::ResourceError, QXARecordSession::tr("Service has not been started")); \ + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Service has not been started\"))"); \ + return s; \ + } + +/* This macro checks for m_impl null pointer. If it is, emits an error signal + * error(QMediaRecorder::ResourceError, tr("Service has not been started")); + * and returns from function immediately. + */ +#define RETURN_IF_m_impl_IS_NULL \ + if (!m_impl) { \ + emit error(QMediaRecorder::ResourceError, QXARecordSession::tr("Service has not been started")); \ + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Service has not been started\"))"); \ + return; \ + } + +QXARecordSession::QXARecordSession(QObject *parent) +:QObject(parent), +m_state(QMediaRecorder::StoppedState), +m_previousState(QMediaRecorder::StoppedState) +{ + QT_TRACE_FUNCTION_ENTRY; + m_impl = NULL; + m_impl = new XARecordSessionImpl(*this); + if (m_impl) { + if (m_impl->postConstruct() == KErrNone) { + initCodecsList(); + initContainersList(); + m_containerMimeType = QString("audio/wav"); + m_audioencodersettings.setCodec("pcm"); + m_audioencodersettings.setBitRate(0); + m_audioencodersettings.setChannelCount(-1); + m_audioencodersettings.setEncodingMode(QtMultimediaKit::ConstantQualityEncoding); + m_audioencodersettings.setQuality(QtMultimediaKit::NormalQuality); + m_audioencodersettings.setSampleRate(-1); + setEncoderSettingsToImpl(); + m_URItoImplSet = false; + QT_TRACE1("Initialized implementation"); + } + else { + delete m_impl; + m_impl = NULL; + QT_TRACE1("Error initializing implementation"); + } + } + else { + emit error(QMediaRecorder::ResourceError, tr("Unable to start Service")); + } + QT_TRACE_FUNCTION_EXIT; +} + +QXARecordSession::~QXARecordSession() +{ + QT_TRACE_FUNCTION_ENTRY; + delete m_impl; + QT_TRACE_FUNCTION_EXIT; +} + +QUrl QXARecordSession::outputLocation() +{ + return m_outputLocation; +} + +bool QXARecordSession::setOutputLocation(const QUrl &location) +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_s_IF_m_impl_IS_NULL(false); + + // Location can be set only when recorder is in stopped state. + if (state() != QMediaRecorder::StoppedState) + return false; + + // Validate URL + if (!location.isValid()) + return false; + + // If old and new locations are same, do nothing. + QString newUrlStr = (QUrl::fromUserInput(location.toString())).toString(); + QString curUrlStr = (QUrl::fromUserInput(m_outputLocation.toString())).toString(); + if (curUrlStr.compare(newUrlStr) == KErrNone) + return true; + + QT_TRACE2("Location:", newUrlStr); + m_outputLocation = location; + /* New file, so user can set new settings */ + m_previousState = QMediaRecorder::StoppedState; + m_URItoImplSet = false; + + QT_TRACE_FUNCTION_EXIT; + return true; +} + +QMediaRecorder::State QXARecordSession::state() +{ + return m_state; +} + +qint64 QXARecordSession::duration() +{ + TInt64 dur(0); + + QT_TRACE_FUNCTION_ENTRY; + + RETURN_s_IF_m_impl_IS_NULL(dur); + + m_impl->duration(dur); + + QT_TRACE_FUNCTION_EXIT; + return (qint64)dur; +} + +void QXARecordSession::applySettings() +{ + /* Settings can only be applied when the recorder is in the stopped + * state after creation. */ + if ((state() == QMediaRecorder::StoppedState) && (m_state == m_previousState)) { + if (m_appliedaudioencodersettings != m_audioencodersettings) + setEncoderSettingsToImpl(); + } + else { + emit error(QMediaRecorder::FormatError, tr("Settings cannot be changed once recording started")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Settings cannot be changed once recording started\"))"); + } +} + +void QXARecordSession::record() +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_IF_m_impl_IS_NULL; + + /* No op if object is already in recording state */ + if (state() == QMediaRecorder::RecordingState) + return; + + /* 1. Set encoder settings here */ + if (m_appliedaudioencodersettings != m_audioencodersettings) + RET_IF_FALSE(setEncoderSettingsToImpl()); + + /* 2. Set URI to impl */ + RET_IF_FALSE(setURIToImpl()); + + /* 3. Start recording... + * If successful, setRecorderState(QMediaRecorder::RecordingState); + * will be called from the callback cbRecordingStarted() + */ + if (m_impl->record() != KErrNone) { + emit error(QMediaRecorder::ResourceError, tr("Generic error")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Generic error\"))"); + } + + QT_TRACE_FUNCTION_EXIT; +} + +void QXARecordSession::pause() +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_IF_m_impl_IS_NULL; + + /* No op if object is already in paused/stopped state */ + if ((state() == QMediaRecorder::PausedState) || (state() == QMediaRecorder::StoppedState)) { + return; + } + + if (m_impl->pause() == KErrNone) { + setRecorderState(QMediaRecorder::PausedState); + } + else { + emit error(QMediaRecorder::ResourceError, tr("Unable to pause")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Unable to pause\"))"); + } + + QT_TRACE_FUNCTION_EXIT; +} + +void QXARecordSession::stop() +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_IF_m_impl_IS_NULL; + + /* No op if object is already in paused state */ + if (state() == QMediaRecorder::StoppedState) + return; + + if ((m_impl->stop() == KErrNone)) { + setRecorderState(QMediaRecorder::StoppedState); + } + else { + emit error(QMediaRecorder::ResourceError, tr("Unable to stop")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Unable to stop\"))"); + } + + QT_TRACE_FUNCTION_EXIT; +} + +void QXARecordSession::cbDurationChanged(TInt64 new_pos) +{ + QT_TRACE_FUNCTION_ENTRY; + + emit durationChanged((qint64)new_pos); + SIGNAL_EMIT_TRACE1("emit durationChanged((qint64)new_pos);"); + + QT_TRACE_FUNCTION_EXIT; +} + +void QXARecordSession::cbAvailableAudioInputsChanged() +{ + QT_TRACE_FUNCTION_ENTRY; + + emit availableAudioInputsChanged(); + SIGNAL_EMIT_TRACE1("emit availableAudioInputsChanged();"); + + QT_TRACE_FUNCTION_EXIT; +} + +void QXARecordSession::cbRecordingStarted() +{ + QT_TRACE_FUNCTION_ENTRY; + + setRecorderState(QMediaRecorder::RecordingState); + + QT_TRACE_FUNCTION_EXIT; +} + +void QXARecordSession::cbRecordingStopped() +{ + QT_TRACE_FUNCTION_ENTRY; + + emit error(QMediaRecorder::ResourceError, tr("Resources Unavailable")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Resources Unavailable\"))"); + setRecorderState(QMediaRecorder::StoppedState); + /* Set record state to Stopped */ + if (m_impl) + m_impl->stop(); + + QT_TRACE_FUNCTION_EXIT; +} + +/* For QAudioEndpointSelector begin */ +QList QXARecordSession::availableEndpoints() +{ + QT_TRACE_FUNCTION_ENTRY; + + QList strList; + + RETURN_s_IF_m_impl_IS_NULL(strList); + + QString str; + RArray names; + m_impl->getAudioInputDeviceNames(names); + for (TInt index = 0; index < names.Count(); index++) { + str = QString((QChar*)names[index].Ptr(), names[index].Length()); + strList.append(str); + } + + QT_TRACE_FUNCTION_EXIT; + return strList; +} + +QString QXARecordSession::endpointDescription(const QString &name) +{ + /* From AL we get only device name */ + return name; +} + +QString QXARecordSession::defaultEndpoint() +{ + QT_TRACE_FUNCTION_ENTRY; + + QString str; + + RETURN_s_IF_m_impl_IS_NULL(str); + + TPtrC name; + if(m_impl->defaultAudioInputDevice(name) == KErrNone) + str = QString((QChar*)name.Ptr(), name.Length()); + + QT_TRACE_FUNCTION_EXIT; + return str; +} + +QString QXARecordSession::activeEndpoint() +{ + QT_TRACE_FUNCTION_ENTRY; + + QString str; + + RETURN_s_IF_m_impl_IS_NULL(str); + + TPtrC name; + if(m_impl->activeAudioInputDevice(name) == KErrNone) + str = QString((QChar*)name.Ptr(), name.Length()); + + QT_TRACE_FUNCTION_EXIT; + return str; +} + +void QXARecordSession::setActiveEndpoint(const QString &name) +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_IF_m_impl_IS_NULL; + + if (name.isNull() || name.isEmpty()) + return; + + TPtrC16 tempPtr(reinterpret_cast(name.utf16())); + if (m_impl->setAudioInputDevice(tempPtr) == true) { + emit activeEndpointChanged(name); + SIGNAL_EMIT_TRACE1("emit activeEndpointChanged(name)"); + } + else { + emit error(QMediaRecorder::ResourceError, tr("Invalid endpoint")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Invalid endpoint\"))"); + } + + QT_TRACE_FUNCTION_EXIT; +} +/* For QAudioEndpointSelector end */ + +/* For QAudioEncoderControl begin */ +QStringList QXARecordSession::supportedAudioCodecs() +{ + return m_codecs; +} + +QString QXARecordSession::codecDescription(const QString &codecName) +{ + if (m_codecs.contains(codecName)) + return QString(codecName); + return QString(); +} + +QList QXARecordSession::supportedSampleRates( + const QAudioEncoderSettings &settings, + bool *continuous) +{ + QT_TRACE_FUNCTION_ENTRY; + + QList srList; + + RETURN_s_IF_m_impl_IS_NULL(srList); + + QString selectedCodec = settings.codec(); + if (selectedCodec.isNull() || selectedCodec.isEmpty()) + selectedCodec = QString("pcm"); + + if (m_codecs.indexOf(selectedCodec) >= 0) { + RArray sampleRates; + TBool isContinuous; + TPtrC16 tempPtr(reinterpret_cast(selectedCodec.utf16())); + if (m_impl->getSampleRates(tempPtr, sampleRates, isContinuous) == KErrNone) { + for (TInt index = 0; index < sampleRates.Count(); index++) + srList.append(sampleRates[index]); + sampleRates.Close(); + if (continuous) + { + *continuous = false; + if (isContinuous == true) + *continuous = true; + } + } + } + + QT_TRACE_FUNCTION_EXIT; + return srList; +} + +QAudioEncoderSettings QXARecordSession::audioSettings() +{ + return m_appliedaudioencodersettings; +} + +void QXARecordSession::setAudioSettings(const QAudioEncoderSettings &settings) +{ + /* Settings can only be set when the recorder is in the stopped + * state after creation. */ + if ((state() == QMediaRecorder::StoppedState) && (m_state == m_previousState)) { + /* Validate and ignore rest of the settings */ + m_audioencodersettings = settings; + } + else { + emit error(QMediaRecorder::FormatError, tr("Settings cannot be changed once recording started")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Settings cannot be changed once recording started\"))"); + } +} + +QStringList QXARecordSession::supportedEncodingOptions(const QString &codec) +{ + QT_TRACE_FUNCTION_ENTRY; + Q_UNUSED(codec); + QStringList options; + if ((codec.compare("aac") == 0) || + (codec.compare("amr") == 0)) + { + options << "bitrate" << "quality"; + } + + + QT_TRACE_FUNCTION_EXIT; + return options; +} + +QVariant QXARecordSession::encodingOption(const QString &codec, const QString &name) +{ + QT_TRACE_FUNCTION_ENTRY; + + QVariant encodingOption; + QMap map; + RETURN_s_IF_m_impl_IS_NULL(encodingOption); + + if (name.compare("bitrate") == 0) { + TPtrC16 tempPtr(reinterpret_cast(codec.utf16())); + QList bitrateList; + RArray bitrates; + TBool continuous; + if (m_impl->getBitrates(tempPtr, bitrates, continuous) == KErrNone) { + for (TInt index = 0; index < bitrates.Count(); index++) + bitrateList.append(bitrates[index]); + bitrates.Close(); + } + encodingOption.setValue(bitrateList); + map.insert("continuous", QVariant(continuous)); + map.insert("bitrates", encodingOption); + } + + QT_TRACE_FUNCTION_EXIT; + return map; +} + +void QXARecordSession::setEncodingOption( + const QString &codec, + const QString &name, + const QVariant &value) +{ + /* + * Currently nothing can be set via this function. + * Bitrate is set via QAudioEncoderSettings::setBitrate(). + */ + Q_UNUSED(codec); + Q_UNUSED(name); + Q_UNUSED(value); +} +/* For QAudioEncoderControl end */ + +QStringList QXARecordSession::supportedContainers() +{ + return m_containers; +} + +QString QXARecordSession::containerMimeType() +{ + return m_containerMimeType; +} + +void QXARecordSession::setContainerMimeType(const QString &formatMimeType) +{ + if (formatMimeType.isNull() || formatMimeType.isEmpty()) + return; + else if (m_containers.indexOf(formatMimeType) >= 0 ) + m_containerMimeType = formatMimeType; + else { + emit error(QMediaRecorder::FormatError, tr("Invalid container")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid container\"))"); + } +} + +QString QXARecordSession::containerDescription(const QString &formatMimeType) +{ + int index = m_containers.indexOf(formatMimeType); + if (index >= 0) { + return m_containersDesc.at(index); + } + else { + emit error(QMediaRecorder::FormatError, tr("Invalid container")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid container\"))"); + } + return QString(); +} + +void QXARecordSession::setRecorderState(QMediaRecorder::State state) +{ + if (state != m_state) { + m_previousState = m_state; + m_state = state; + emit stateChanged(m_state); + SIGNAL_EMIT_TRACE1("emit stateChanged(m_state);"); + } +} + +void QXARecordSession::initCodecsList() +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_IF_m_impl_IS_NULL; + + m_codecs.clear(); + + const RArray& names = m_impl->getAudioEncoderNames(); + QString str; + + for (TInt index = 0; index < names.Count(); index++) { + str = QString((QChar*)names[index].Ptr(), names[index].Length()); + m_codecs.append(str); + } + QT_TRACE_FUNCTION_EXIT; +} + +void QXARecordSession::initContainersList() +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_IF_m_impl_IS_NULL; + + m_containers.clear(); + m_containersDesc.clear(); + + const RArray& names = m_impl->getContainerNames(); + const RArray& descs = m_impl->getContainerDescs(); + QString str; + + for (TInt32 index = 0; index < names.Count(); index++) { + str = QString((QChar*)names[index].Ptr(), names[index].Length()); + m_containers.append(str); + str = QString((QChar*)descs[index].Ptr(), descs[index].Length()); + m_containersDesc.append(str); + } + QT_TRACE_FUNCTION_EXIT; +} + +bool QXARecordSession::setEncoderSettingsToImpl() +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_s_IF_m_impl_IS_NULL(false); + + m_impl->resetEncoderAttributes(); + + /* m_containerMimeType is alredy validated in ::setContainerMimeType() */ + QString tempStr = m_containerMimeType; + TPtrC16 tempPtr(reinterpret_cast(tempStr.utf16())); + m_impl->setContainerType(tempPtr); + + /* vaidate and assign codec */ + if (m_audioencodersettings.codec().isNull() || m_audioencodersettings.codec().isEmpty()) { + m_audioencodersettings.setCodec(m_appliedaudioencodersettings.codec()); + } + tempStr = m_audioencodersettings.codec(); + if (m_codecs.indexOf(tempStr) >= 0) { + tempPtr.Set(reinterpret_cast(tempStr.utf16())); + /* We already did validation above, so function always returns true */ + m_impl->setCodec(tempPtr); + } + else { + QT_TRACE2("Codec selected is :", m_audioencodersettings.codec()); + emit error(QMediaRecorder::FormatError, tr("Invalid codec")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid codec\"));"); + return false; + } + + /* Validate and set bitrate only if encoding mode is other than quality encoding and container type is not wav*/ + if ((m_audioencodersettings.encodingMode() != QtMultimediaKit::ConstantQualityEncoding) && + (m_containerMimeType.compare("audio/wav") != 0)) { + m_impl->setBitRate(m_audioencodersettings.bitRate()); + m_audioencodersettings.setBitRate(m_impl->getBitRate()); + } + + if (m_audioencodersettings.channelCount() == -1) { + m_impl->setOptimalChannelCount(); + } + else { + m_impl->setChannels(m_audioencodersettings.channelCount()); + m_audioencodersettings.setChannelCount(m_impl->getChannels()); + } + + switch (m_audioencodersettings.encodingMode()) { + case QtMultimediaKit::ConstantQualityEncoding: { + switch (m_audioencodersettings.quality()) { + case QtMultimediaKit::VeryLowQuality: + m_impl->setVeryLowQuality(); + m_audioencodersettings.setBitRate(m_impl->getBitRate()); + break; + case QtMultimediaKit::LowQuality: + m_impl->setLowQuality(); + m_audioencodersettings.setBitRate(m_impl->getBitRate()); + break; + case QtMultimediaKit::NormalQuality: + m_impl->setNormalQuality(); + m_audioencodersettings.setBitRate(m_impl->getBitRate()); + break; + case QtMultimediaKit::HighQuality: + m_impl->setHighQuality(); + m_audioencodersettings.setBitRate(m_impl->getBitRate()); + break; + case QtMultimediaKit::VeryHighQuality: + m_impl->setVeryHighQuality(); + m_audioencodersettings.setBitRate(m_impl->getBitRate()); + break; + default: + break; + }; /* end of switch (m_audioencodersettings.quality())*/ + } + break; + case QtMultimediaKit::ConstantBitRateEncoding: { + TInt32 status = m_impl->setCBRMode(); + if (status == KErrNotSupported) { + emit error(QMediaRecorder::FormatError, tr("Invalid encoding mode setting")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid encoding mode setting\"));"); + return false; + } + else if (status != KErrNone) { + emit error(QMediaRecorder::ResourceError, tr("Internal error")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Internal error\"));"); + return false; + } + } + break; + case QtMultimediaKit::AverageBitRateEncoding: { + TInt32 status = m_impl->setVBRMode(); + if (status == KErrNotSupported) { + emit error(QMediaRecorder::FormatError, tr("Invalid encoding mode setting")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid encoding mode setting\"));"); + return false; + } + else if (status != KErrNone) { + emit error(QMediaRecorder::ResourceError, tr("Internal error")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Internal error\"));"); + return false; + } + } + break; + case QtMultimediaKit::TwoPassEncoding: + // fall through + default: { + emit error(QMediaRecorder::FormatError, tr("Invalid encoding mode setting")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid encoding mode setting\"));"); + return false; + } + }; /* switch (m_audioencodersettings.encodingMode()) */ + + if (m_audioencodersettings.sampleRate() == -1) { + m_impl->setOptimalSampleRate(); + } + else { + m_impl->setSampleRate(m_audioencodersettings.sampleRate()); + m_audioencodersettings.setSampleRate(m_impl->getSampleRate()); + } + m_appliedaudioencodersettings = m_audioencodersettings; + + QT_TRACE_FUNCTION_EXIT; + return true; +} + +bool QXARecordSession::setURIToImpl() +{ + QT_TRACE_FUNCTION_ENTRY; + if (m_URItoImplSet) + return true; + + /* If m_outputLocation is null, set a default location */ + if (m_outputLocation.isEmpty()) { + QDir outputDir(QDir::rootPath()); + + int lastImage = 0; + int fileCount = 0; + foreach(QString fileName, outputDir.entryList(QStringList() << "recordclip_*")) { + int imgNumber = fileName.mid(5, fileName.size() - 9).toInt(); + lastImage = qMax(lastImage, imgNumber); + if (outputDir.exists(fileName)) + fileCount += 1; + } + lastImage += fileCount; + m_outputLocation = QUrl(QDir::toNativeSeparators(outputDir.canonicalPath() + QString("/recordclip_%1").arg(lastImage + 1, 4, 10, QLatin1Char('0')))); + } + + QString newUrlStr = (QUrl::fromUserInput(m_outputLocation.toString())).toString(); + // append file prefix if required + if (newUrlStr.lastIndexOf('.') == -1) { + QString fileExtension; + if ((m_containerMimeType.compare("audio/wav")) == KErrNone) { + fileExtension = QString(".wav"); + } + else if ((m_containerMimeType.compare("audio/amr")) == KErrNone) { + fileExtension = QString(".amr"); + } + else if ((m_containerMimeType.compare("audio/mpeg")) == KErrNone) { + fileExtension = QString(".mp4"); + } + newUrlStr.append(fileExtension); + } + + QT_TRACE2("Filename selected is :", newUrlStr); + TPtrC16 tempPtr(reinterpret_cast(newUrlStr.utf16())); + if (m_impl->setURI(tempPtr) != 0) { + emit error(QMediaRecorder::ResourceError, tr("Generic error")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Generic error\"))"); + return false; + } + m_URItoImplSet = true; + m_outputLocation = QUrl(newUrlStr); + QT_TRACE_FUNCTION_EXIT; + return true; +} diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxarecordsession.h b/src/plugins/symbian/openmaxal/mediarecorder/qxarecordsession.h new file mode 100644 index 000000000..cabe58fc9 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxarecordsession.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXARECORDSESSION_H +#define QXARECORDSESSION_H + +#include +#include +#include "qmediarecorder.h" +#include "xarecordsessioncommon.h" + +QT_USE_NAMESPACE + +class XARecordSessionImpl; + +/* + * This is a backend class for all QXXXControl objects. + * This class contains actual implementation of recording functionality + * from the control object's perspective. + */ + + +class QXARecordSession : public QObject, + public XARecordObserver +{ +Q_OBJECT + +public: + QXARecordSession(QObject *parent); + virtual ~QXARecordSession(); + + /* For QMediaRecorderControl begin */ + QUrl outputLocation(); + bool setOutputLocation(const QUrl &location); + QMediaRecorder::State state(); + qint64 duration(); + void applySettings(); + + void record(); + void pause(); + void stop(); + + void cbDurationChanged(TInt64 new_pos); + void cbAvailableAudioInputsChanged(); + void cbRecordingStarted(); + void cbRecordingStopped(); + /* For QMediaRecorderControl end */ + + /* For QAudioEndpointSelector begin */ + QList availableEndpoints(); + QString endpointDescription(const QString &name); + QString defaultEndpoint(); + QString activeEndpoint(); + void setActiveEndpoint(const QString &name); + /* For QAudioEndpointSelector end */ + + /* For QAudioEncoderControl begin */ + QStringList supportedAudioCodecs(); + QString codecDescription(const QString &codecName); + QList supportedSampleRates( + const QAudioEncoderSettings &settings, + bool *continuous); + QAudioEncoderSettings audioSettings(); + void setAudioSettings(const QAudioEncoderSettings &settings); + QStringList supportedEncodingOptions(const QString &codec); + QVariant encodingOption(const QString &codec, const QString &name); + void setEncodingOption(const QString &codec, const QString &name, const QVariant &value); + /* For QAudioEncoderControl end */ + + /* For QMediaContainerControl begin */ + QStringList supportedContainers(); + QString containerMimeType(); + void setContainerMimeType(const QString &formatMimeType); + QString containerDescription(const QString &formatMimeType); + /* For QMediaContainerControl end */ + +Q_SIGNALS: + void stateChanged(QMediaRecorder::State state); + void durationChanged(qint64 duration); + void error(int error, const QString &errorString); + void activeEndpointChanged(const QString& name); + void availableAudioInputsChanged(); + +private: + void setRecorderState(QMediaRecorder::State state); + void initCodecsList(); + void initContainersList(); + bool setEncoderSettingsToImpl(); + bool setURIToImpl(); + +private: + /* Own */ + XARecordSessionImpl *m_impl; + QUrl m_outputLocation; + bool m_URItoImplSet; + QMediaRecorder::State m_state; + QMediaRecorder::State m_previousState; + QStringList m_codecs; + QAudioEncoderSettings m_audioencodersettings; + QAudioEncoderSettings m_appliedaudioencodersettings; + QStringList m_containers; + QStringList m_containersDesc; + QString m_containerMimeType; +}; + +#endif /* QXARECORDSESSION_H */ diff --git a/src/plugins/symbian/openmaxal/mediarecorder/xarecordsessioncommon.h b/src/plugins/symbian/openmaxal/mediarecorder/xarecordsessioncommon.h new file mode 100644 index 000000000..cdf8c1886 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/xarecordsessioncommon.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef XARECORDSESSIONCOMMON_H +#define XARECORDSESSIONCOMMON_H + +#include +#include "xacommon.h" + +#define MAX_NUMBER_INTERFACES 20 +#define MAX_NUMBER_INPUT_DEVICES 10 +#define MAX_NUMBER_ENCODERS 10 + +//const TInt32 KExtErr = (TInt32)(-2147483648); +const TInt32 KExtErr = -32768; +const TInt32 KExtErrUnspecifiedCodecForContainer = (KExtErr+1); +const TInt32 KExtErrUnsupportedCodecForContainer = (KExtErr+2); +const TInt32 KExtErrUnsupportedURISuffixForContainer = (KExtErr+3); + +class XARecordObserver +{ +public: + virtual void cbDurationChanged(TInt64 new_pos) = 0; + virtual void cbAvailableAudioInputsChanged() = 0; + virtual void cbRecordingStarted() = 0; + virtual void cbRecordingStopped() = 0; +}; + +#endif /* XARECORDSESSIONCOMMON_H */ diff --git a/src/plugins/symbian/openmaxal/mediarecorder/xarecordsessionimpl.cpp b/src/plugins/symbian/openmaxal/mediarecorder/xarecordsessionimpl.cpp new file mode 100644 index 000000000..d18c781d4 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/xarecordsessionimpl.cpp @@ -0,0 +1,1378 @@ +/**************************************************************************** + ** + ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + ** All rights reserved. + ** Contact: Nokia Corporation (qt-info@nokia.com) + ** + ** This file is part of the Qt Mobility Components. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** No Commercial Usage + ** This file contains pre-release code and may not be distributed. + ** You may use this file in accordance with the terms and conditions + ** contained in the Technology Preview License Agreement accompanying + ** this package. + ** + ** 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 as published by the Free Software + ** Foundation and appearing in the file LICENSE.LGPL included in the + ** packaging of this file. Please review the following information to + ** ensure the GNU Lesser General Public License version 2.1 requirements + ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + ** + ** In addition, as a special exception, Nokia gives you certain additional + ** rights. These rights are described in the Nokia Qt LGPL Exception + ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + ** + ** If you have questions regarding the use of this file, please contact + ** Nokia at qt-info@nokia.com. + ** + ** + ** + ** + ** + ** + ** + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ +#include "xarecordsessionimpl.h" +#include "xarecordsessioncommon.h" +_LIT8(K8WAVMIMETYPE, "audio/x-wav"); +/* + * These codec names are not part of AL. Hence we need to define names here. + * */ +_LIT(KAUDIOCODECPCM, "pcm"); +_LIT(KAUDIOCODECAMR, "amr"); +_LIT(KAUDIOCODECAAC, "aac"); +_LIT(KCONTAINERWAV, "audio/wav"); +_LIT(KCONTAINERWAVDESC, "wav container"); +_LIT(KCONTAINERAMR, "audio/amr"); +_LIT(KCONTAINERAMRDESC, "amr File format"); +_LIT(KCONTAINERMP4, "audio/mpeg"); +_LIT(KCONTAINERMP4DESC, "mpeg container"); + +const TUint KRecordPosUpdatePeriod = 1000; +const TUint KMilliToHz = 1000; +const TUint KMaxNameLength = 256; + +/* Local functions for callback registation */ +void cbXAObjectItf( + XAObjectItf caller, + const void *pContext, + XAuint32 event, + XAresult result, + XAuint32 param, + void *pInterface); + +void cbXARecordItf( + XARecordItf caller, + void *pContext, + XAuint32 event); + +void cbXAAvailableAudioInputsChanged( + XAAudioIODeviceCapabilitiesItf caller, + void *pContext, + XAuint32 deviceID, + XAint32 numInputs, + XAboolean isNew); + +XARecordSessionImpl::XARecordSessionImpl(XARecordObserver &parent) : + m_Parent(parent), + m_EOEngine(NULL), + m_MORecorder(NULL), + m_RecordItf(NULL), + m_AudioEncItf(NULL), + m_WAVMime(NULL), + m_URIName(NULL), + m_InputDeviceId(0), + m_ContainerType(0), + m_BitRate(0), + m_RateControl(0), + m_ChannelsOut(1), + m_SampleRate(0), + m_AudioIODevCapsItf(NULL), + m_AudioInputDeviceNames(NULL), + m_DefaultAudioInputDeviceNames(NULL), + m_AudioEncCapsItf(NULL) +{ + TRACE_FUNCTION_ENTRY_EXIT; +} + +XARecordSessionImpl::~XARecordSessionImpl() +{ + TRACE_FUNCTION_ENTRY; + + if (m_MORecorder) + (*m_MORecorder)->Destroy(m_MORecorder); + + if (m_EOEngine) + (*m_EOEngine)->Destroy(m_EOEngine); + + delete m_WAVMime; + delete m_URIName; + + m_InputDeviceIDs.Close(); + if (m_AudioInputDeviceNames) + m_AudioInputDeviceNames->Reset(); + delete m_AudioInputDeviceNames; + m_DefaultInputDeviceIDs.Close(); + if (m_DefaultAudioInputDeviceNames) + m_DefaultAudioInputDeviceNames->Reset(); + delete m_DefaultAudioInputDeviceNames; + m_EncoderIds.Close(); + m_EncoderNames.Close(); + m_ContainerNames.Close(); + m_ContainerDescs.Close(); + + TRACE_FUNCTION_EXIT; +} + +TInt32 XARecordSessionImpl::postConstruct() +{ + TRACE_FUNCTION_ENTRY; + + XAEngineOption engineOption[] = { (XAuint32) XA_ENGINEOPTION_THREADSAFE, (XAuint32) XA_BOOLEAN_TRUE}; + + /* Create and realize Engine object */ + TRACE_LOG(_L("XARecordSessionImpl: Creating Engine...")); + XAresult xa_result = xaCreateEngine(&m_EOEngine, 1, engineOption, 0, NULL, NULL); + TInt returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + TRACE_LOG(_L("XARecordSessionImpl: Realizing engine...")); + xa_result = (*m_EOEngine)->Realize(m_EOEngine, XA_BOOLEAN_FALSE); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + TRACE_LOG(_L("XARecordSessionImpl: OMX AL Engine realized successfully")); + + XAEngineItf engineItf; + xa_result = (*m_EOEngine)->GetInterface(m_EOEngine, XA_IID_ENGINE, (void**) &engineItf); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + xa_result = (*m_EOEngine)->GetInterface(m_EOEngine, + XA_IID_AUDIOIODEVICECAPABILITIES, + (void**) &m_AudioIODevCapsItf); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + xa_result = (*m_AudioIODevCapsItf)->RegisterAvailableAudioInputsChangedCallback( + m_AudioIODevCapsItf, + cbXAAvailableAudioInputsChanged, + (void*)this); + + xa_result = (*m_EOEngine)->GetInterface( + m_EOEngine, + XA_IID_AUDIOENCODERCAPABILITIES, + (void**) &m_AudioEncCapsItf); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + TRAP(returnValue, m_WAVMime = HBufC8::NewL(K8WAVMIMETYPE().Length() + 1)); + RET_ERR_IF_ERR(returnValue); + TPtr8 ptr = m_WAVMime->Des(); + ptr = K8WAVMIMETYPE(); // copy uri name into local variable + ptr.PtrZ(); // append zero terminator to end of URI + + m_AudioInputDeviceNames = new CDesC16ArrayFlat(2); + if (m_AudioInputDeviceNames == NULL) + returnValue = KErrNoMemory; + RET_ERR_IF_ERR(returnValue); + + m_DefaultAudioInputDeviceNames = new CDesC16ArrayFlat(2); + if (m_DefaultAudioInputDeviceNames == NULL) + returnValue = KErrNoMemory; + RET_ERR_IF_ERR(returnValue); + + returnValue = initContainersList(); + RET_ERR_IF_ERR(returnValue); + returnValue = initAudioEncodersList(); + RET_ERR_IF_ERR(returnValue); + returnValue = initAudioInputDevicesList(); + RET_ERR_IF_ERR(returnValue); + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::setURI(const TDesC &aURI) +{ + TRACE_FUNCTION_ENTRY; + + /* This function will only get called when aURI is different than m_URIName + * and only when recorder is in stopped state. + * If the recorder object was created for a different URI (than aURI), we + * need to tear it down here. + */ + if (m_MORecorder) { + (*m_MORecorder)->Destroy(m_MORecorder); + m_MORecorder = NULL; + m_RecordItf = NULL; + } + + delete m_URIName; + m_URIName = NULL; + TRAPD(returnValue, m_URIName = HBufC8::NewL(aURI.Length()+1)); + RET_ERR_IF_ERR(returnValue); + + TPtr8 uriPtr = m_URIName->Des(); + /* copy uri name into local variable */ + uriPtr.Copy(aURI); + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::record() +{ + TRACE_FUNCTION_ENTRY; + + TInt32 returnValue(KErrGeneral); + if (!m_MORecorder || !m_RecordItf) { + TRACE_LOG(_L("XARecordSessionImpl::Record: MORecorder/RecordItf is not created")); + returnValue = createMediaRecorderObject(); + RET_ERR_IF_ERR(returnValue); + + returnValue = setEncoderSettingsToMediaRecorder(); + RET_ERR_IF_ERR(returnValue); + } + + XAuint32 state; + XAresult xa_result = (*m_RecordItf)->GetRecordState(m_RecordItf, &state); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + if ((state == XA_RECORDSTATE_STOPPED) + || (state == XA_RECORDSTATE_PAUSED)) { + TRACE_LOG(_L("XARecordSessionImpl::Record: Setting State to Recording...")); + xa_result = (*m_RecordItf)->SetRecordState(m_RecordItf, XA_RECORDSTATE_RECORDING); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + TRACE_LOG(_L("XARecordSessionImpl::Record: SetState to Recording")); + } + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::pause() +{ + TRACE_FUNCTION_ENTRY; + + TInt32 returnValue(KErrGeneral); + if (!m_MORecorder || !m_RecordItf) { + TRACE_LOG(_L("XARecordSessionImpl::Record: MORecorder/RecordItf is not created")); + return returnValue; + } + + XAuint32 state; + XAresult xa_result = (*m_RecordItf)->GetRecordState(m_RecordItf, &state); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + if ((state == XA_RECORDSTATE_STOPPED) + || (state == XA_RECORDSTATE_RECORDING)) { + TRACE_LOG(_L("XARecordSessionImpl::Record: Setting State to Paused...")); + xa_result = (*m_RecordItf)->SetRecordState(m_RecordItf, XA_RECORDSTATE_PAUSED); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + TRACE_LOG(_L("XARecordSessionImpl::Record: SetState to Paused")); + } + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::stop() +{ + TRACE_FUNCTION_ENTRY; + + TInt32 returnValue(KErrGeneral); + if (!m_MORecorder || !m_RecordItf) { + TRACE_LOG(_L("XARecordSessionImpl::Record: MORecorder/RecordItf is not created")); + return returnValue; + } + + XAuint32 state; + XAresult xa_result = (*m_RecordItf)->GetRecordState(m_RecordItf, &state); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + if ((state == XA_RECORDSTATE_PAUSED) + || (state == XA_RECORDSTATE_RECORDING)) { + TRACE_LOG(_L("XARecordSessionImpl::Record: Setting State to Stopped...")); + xa_result = (*m_RecordItf)->SetRecordState(m_RecordItf, XA_RECORDSTATE_STOPPED); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + TRACE_LOG(_L("XARecordSessionImpl::Record: SetState to Stopped")); + } + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::duration(TInt64 &aDur) +{ + TRACE_FUNCTION_ENTRY; + + TInt32 returnValue(KErrGeneral); + + if (!m_MORecorder || !m_RecordItf) { + TRACE_LOG(_L("XARecordSessionImpl::Duration: MORecoder/RecordItf is not created")); + return returnValue; + } + + XAmillisecond milliSec; + XAresult xa_result = (*m_RecordItf)->GetPosition(m_RecordItf, &milliSec); + returnValue = mapError(xa_result, ETrue); + if (returnValue == KErrNone) + aDur = (TInt64)milliSec; + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +void XARecordSessionImpl::cbMediaRecorder( + XAObjectItf /*caller*/, + const void */*pContext*/, + XAuint32 event, + XAresult result, + XAuint32 /*param*/, + void */*pInterface*/) +{ + TRACE_FUNCTION_ENTRY; + + switch (event) { + case XA_OBJECT_EVENT_RESOURCES_LOST: + m_Parent.cbRecordingStopped(); + break; + case XA_OBJECT_EVENT_RUNTIME_ERROR: { + switch (result) { + case XA_RESULT_RESOURCE_LOST: + m_Parent.cbRecordingStopped(); + break; + default: + break; + }; /* of switch (result) */ + } + default: + break; + } /* of switch (event) */ + + TRACE_FUNCTION_EXIT; +} + +void XARecordSessionImpl::cbRecordItf( + XARecordItf /*caller*/, + void */*pContext*/, + XAuint32 event) +{ + TRACE_FUNCTION_ENTRY; + + switch(event) { + case XA_RECORDEVENT_HEADATLIMIT: + TRACE_LOG(_L("XA_RECORDEVENT_HEADATLIMIT")); + break; + case XA_RECORDEVENT_HEADATMARKER: + TRACE_LOG(_L("XA_RECORDEVENT_HEADATMARKER")); + break; + case XA_RECORDEVENT_HEADATNEWPOS: { + TInt32 returnValue; + XAresult xa_result; + XAmillisecond milliSec; + xa_result = (*m_RecordItf)->GetPosition(m_RecordItf, &milliSec); + returnValue = mapError(xa_result, ETrue); + if (returnValue == KErrNone) + m_Parent.cbDurationChanged((TInt64) milliSec); + } + break; + case XA_RECORDEVENT_HEADMOVING: + TRACE_LOG(_L("XA_RECORDEVENT_HEADMOVING")); + m_Parent.cbRecordingStarted(); + break; + case XA_RECORDEVENT_HEADSTALLED: + TRACE_LOG(_L("XA_RECORDEVENT_HEADSTALLED")); + break; + case XA_RECORDEVENT_BUFFER_FULL: + TRACE_LOG(_L("XA_RECORDEVENT_BUFFER_FULL")); + break; + default: + TRACE_LOG(_L("UNKNOWN RECORDEVENT EVENT")); + break; + } /* of switch(event) */ + + TRACE_FUNCTION_EXIT; +} + +/* For QAudioEndpointSelector begin */ +void XARecordSessionImpl::getAudioInputDeviceNames(RArray &aArray) +{ + TRACE_FUNCTION_ENTRY; + + for (TInt index = 0; index < m_AudioInputDeviceNames->MdcaCount(); index++) + aArray.Append(m_AudioInputDeviceNames->MdcaPoint(index)); + TRACE_FUNCTION_EXIT; +} + +TInt32 XARecordSessionImpl::defaultAudioInputDevice(TPtrC &endPoint) +{ + TRACE_FUNCTION_ENTRY; + + TInt32 err(KErrGeneral); + if (m_DefaultAudioInputDeviceNames->MdcaCount() >= 0) { + endPoint.Set(m_DefaultAudioInputDeviceNames->MdcaPoint(0)); + err = KErrNone; + } + + TRACE_FUNCTION_EXIT; + return err; +} + +TInt32 XARecordSessionImpl::activeAudioInputDevice(TPtrC &endPoint) +{ + TRACE_FUNCTION_ENTRY; + + TInt32 returnValue(KErrGeneral); + TBool found(EFalse); + TInt index = 0; + for (; index < m_InputDeviceIDs.Count(); index++) { + if (m_InputDeviceIDs[index] == m_InputDeviceId) { + found = ETrue; + break; + } + } + + /* Comparing found with ETrue produces linker error */ + if (found == true) { + endPoint.Set(m_AudioInputDeviceNames->MdcaPoint(index)); + returnValue = KErrNone; + } + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TBool XARecordSessionImpl::setAudioInputDevice(const TDesC &aDevice) +{ + TRACE_FUNCTION_ENTRY; + + /* validate if we can set input device id */ + TBool found(EFalse); + m_InputDeviceId = 0; + TInt index = 0; + for (; index < m_AudioInputDeviceNames->MdcaCount(); index++) { + if (m_AudioInputDeviceNames->MdcaPoint(index).Compare(aDevice) == 0) { + found = ETrue; + break; + } + } + if (found == true) { + m_InputDeviceId = m_InputDeviceIDs[index]; + } + + TRACE_FUNCTION_EXIT; + return found; +} + +void XARecordSessionImpl::cbAvailableAudioInputsChanged( + XAAudioIODeviceCapabilitiesItf /*caller*/, + void */*pContext*/, + XAuint32 deviceID, + XAint32 /*numInputs*/, + XAboolean isNew) +{ + TRACE_FUNCTION_ENTRY; + + /* If a new device is added into the system, append it to available input list */ + if (isNew == XA_BOOLEAN_TRUE) { + XAAudioInputDescriptor audioInputDescriptor; + m_InputDeviceIDs.Append(deviceID); + + XAresult xa_result = (*m_AudioIODevCapsItf)->QueryAudioInputCapabilities( + m_AudioIODevCapsItf, + deviceID, + &audioInputDescriptor); + + if ((mapError(xa_result, ETrue)) == KErrNone) { + TUint8* inDevNamePtr = audioInputDescriptor.deviceName; + TUint8* tempPtr = audioInputDescriptor.deviceName; + TInt32 inDevNameLength = 0; + while (*tempPtr++) + inDevNameLength++; + TPtrC8 ptr(inDevNamePtr, inDevNameLength); + /* Convert 8 bit to 16 bit */ + TBuf16 name; + name.Copy(ptr); + /* Using TRAP with returnValue results in compiler error */ + TRAP_IGNORE(m_AudioInputDeviceNames->AppendL(name)); + } + } + else { + /* an available device has been removed from the the system, remove it from + * available input list and also default list */ + TBool found(EFalse); + TInt index = 0; + for (; index < m_InputDeviceIDs.Count(); index++) { + if (deviceID == m_InputDeviceIDs[index]) { + found = ETrue; + break; + } + } + if (found == true) { + m_InputDeviceIDs.Remove(index); + m_AudioInputDeviceNames->Delete(index); + } + if (deviceID == m_InputDeviceId) + m_InputDeviceId = 0; + + found = EFalse; + for (index = 0; index < m_DefaultInputDeviceIDs.Count(); index++) { + if (deviceID == m_DefaultInputDeviceIDs[index]) { + found = ETrue; + break; + } + } + if (found == true) { + m_DefaultInputDeviceIDs.Remove(index); + m_DefaultAudioInputDeviceNames->Delete(index); + } + } + m_Parent.cbAvailableAudioInputsChanged(); + + TRACE_FUNCTION_EXIT; +} +/* For QAudioEndpointSelector end */ + +/* For QAudioEncoderControl begin */ +const RArray& XARecordSessionImpl::getAudioEncoderNames() +{ + TRACE_FUNCTION_ENTRY_EXIT; + return m_EncoderNames; +} + +TInt32 XARecordSessionImpl::getSampleRates( + const TDesC& aEncoder, + RArray &aSampleRates, + TBool &aIsContinuous) +{ + TRACE_FUNCTION_ENTRY; + + aSampleRates.Reset(); + aIsContinuous = EFalse; + + XAuint32 encoderId = 0; + TBool found(EFalse); + for (TInt index = 0; index < m_EncoderIds.Count(); index++) { + if (m_EncoderNames[index].Compare(aEncoder) == 0) { + found = ETrue; + encoderId = m_EncoderIds[index]; + break; + } + } + + TInt32 returnValue(KErrGeneral); + if (found == false) + return returnValue; + + returnValue = getSampleRatesByAudioCodecID(encoderId, aSampleRates); + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::getBitrates( + const TDesC& aEncoder, + RArray &aBitrates, + TBool& aContinuous) +{ + TRACE_FUNCTION_ENTRY; + + aBitrates.Reset(); + + XAuint32 encoderId = 0; + TBool found(EFalse); + for (TInt index = 0; index < m_EncoderIds.Count(); index++) { + if (m_EncoderNames[index].Compare(aEncoder) == 0) { + found = ETrue; + encoderId = m_EncoderIds[index]; + break; + } + } + + TInt32 returnValue(KErrNotSupported); + XAboolean cont; + if (found == false) + return returnValue; + + returnValue = getBitratesByAudioCodecID(encoderId, aBitrates, cont); + aContinuous = cont; + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +/* For QAudioEncoderControl end */ + +/* For QMediaContainerControl begin */ +const RArray& XARecordSessionImpl::getContainerNames() +{ + TRACE_FUNCTION_ENTRY_EXIT; + return m_ContainerNames; +} + +const RArray& XARecordSessionImpl::getContainerDescs() +{ + TRACE_FUNCTION_ENTRY_EXIT; + return m_ContainerDescs; +} + +/* For QMediaContainerControl end */ + +void XARecordSessionImpl::resetEncoderAttributes() +{ + m_ContainerType = 0; + m_AudioEncoderId = 0; + m_ProfileSetting = 0; + m_BitRate = 0; + m_ChannelsOut = 1; + m_SampleRate = 0; + m_RateControl = 0; +} + +void XARecordSessionImpl::setContainerType(const TDesC &aURI) +{ + TRACE_FUNCTION_ENTRY; + + if (aURI.Compare(KCONTAINERWAV()) == 0) + m_ContainerType = XA_CONTAINERTYPE_WAV; + else if (aURI.Compare(KCONTAINERAMR()) == 0) + m_ContainerType = XA_CONTAINERTYPE_AMR; + else if (aURI.Compare(KCONTAINERMP4()) == 0) + m_ContainerType = XA_CONTAINERTYPE_MP4; + + TRACE_FUNCTION_EXIT; +} + +TBool XARecordSessionImpl::setCodec(const TDesC &aCodec) +{ + TRACE_FUNCTION_ENTRY; + + TBool returnValue(EFalse); + if (aCodec.Compare(KAUDIOCODECPCM()) == 0) { + m_AudioEncoderId = XA_AUDIOCODEC_PCM; + m_ProfileSetting = XA_AUDIOPROFILE_PCM; + returnValue = ETrue; + } + else if (aCodec.Compare(KAUDIOCODECAAC()) == 0) { + m_AudioEncoderId = XA_AUDIOCODEC_AAC; + m_ProfileSetting = XA_AUDIOPROFILE_AAC_AAC; + returnValue = ETrue; + } + else if (aCodec.Compare(KAUDIOCODECAMR()) == 0) { + m_AudioEncoderId = XA_AUDIOCODEC_AMR; + m_ProfileSetting = XA_AUDIOPROFILE_AMR; + returnValue = ETrue; + } + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TUint32 XARecordSessionImpl::getBitRate() +{ + return m_BitRate; +} + +void XARecordSessionImpl::setBitRate(TUint32 aBitRate) +{ + TRACE_FUNCTION_ENTRY; + RArray bitrates; + XAboolean isContinuous; + m_BitRate = 0; + if (getBitratesByAudioCodecID(m_AudioEncoderId, bitrates, isContinuous) == KErrNone) { + bitrates.SortUnsigned(); + TInt loopIndex(0); + while (loopIndex < bitrates.Count() + && aBitRate <= bitrates[loopIndex]) { + m_BitRate = bitrates[loopIndex]; + loopIndex++; + } + bitrates.Close(); + } + TRACE_LOG((_L("BitRate[%d]"), m_BitRate)); + TRACE_FUNCTION_EXIT; +} + +TUint32 XARecordSessionImpl::getChannels() +{ + return m_ChannelsOut; +} + +void XARecordSessionImpl::setChannels(TUint32 aChannels) +{ + TRACE_FUNCTION_ENTRY; + switch (m_AudioEncoderId) { + case XA_AUDIOCODEC_PCM: + case XA_AUDIOCODEC_AAC: + m_ChannelsOut = 1; + if ((aChannels >= 1) && (aChannels <= 2)) + m_ChannelsOut = aChannels; + break; + case XA_AUDIOCODEC_AMR: + m_ChannelsOut = 1; + break; + default: + break; + } + TRACE_LOG((_L("ChannelCount[%d]"), m_ChannelsOut)); + TRACE_FUNCTION_EXIT; +} + +void XARecordSessionImpl::setOptimalChannelCount() +{ + TRACE_FUNCTION_ENTRY; + m_ChannelsOut = 1; + TRACE_FUNCTION_EXIT; +} + +TUint32 XARecordSessionImpl::getSampleRate() +{ + return m_SampleRate; +} + +void XARecordSessionImpl::setSampleRate(TUint32 aSampleRate) +{ + TRACE_FUNCTION_ENTRY; + + m_SampleRate = 0; + + RArray samplerates; + if (getSampleRatesByAudioCodecID(m_AudioEncoderId, samplerates) == KErrNone) { + samplerates.SortUnsigned(); + TInt loopIndex(0); + while (loopIndex < samplerates.Count()) { + m_SampleRate = samplerates[loopIndex]; + if (samplerates[loopIndex] > aSampleRate) + break; + loopIndex++; + } + samplerates.Close(); + } + + /* convert Hz to MilliHz */ + m_SampleRate *= KMilliToHz; + TRACE_LOG((_L("SampleRate[%d]"), m_SampleRate)); + TRACE_FUNCTION_EXIT; +} + +void XARecordSessionImpl::setOptimalSampleRate() +{ + TRACE_FUNCTION_ENTRY; + m_SampleRate = 0; + + if (m_AudioEncoderId == XA_AUDIOCODEC_AAC) { + m_SampleRate = 32000 * KMilliToHz; + } + else if (m_AudioEncoderId == XA_AUDIOCODEC_AMR) { + m_SampleRate = 8000 * KMilliToHz; + } + else { + RArray sampleRates; + TInt res = getSampleRatesByAudioCodecID(m_AudioEncoderId, sampleRates); + if ((res == KErrNone) && (sampleRates.Count() > 0)) { + /* Sort the array and pick the middle range sample rate */ + sampleRates.SortUnsigned(); + m_SampleRate = sampleRates[sampleRates.Count() / 2] * KMilliToHz; + } + sampleRates.Close(); + } + + TRACE_FUNCTION_EXIT; +} + +TInt32 XARecordSessionImpl::setCBRMode() +{ + TRACE_FUNCTION_ENTRY; + + m_RateControl = XA_RATECONTROLMODE_CONSTANTBITRATE; + + TRACE_FUNCTION_EXIT; + return KErrNone; +} + +TInt32 XARecordSessionImpl::setVBRMode() +{ + TRACE_FUNCTION_ENTRY; + + m_RateControl = XA_RATECONTROLMODE_VARIABLEBITRATE; + + TRACE_FUNCTION_EXIT; + return KErrNone; +} + +void XARecordSessionImpl::setVeryLowQuality() +{ + /* Set to very low quality encoder preset */ + RArray bitrates; + XAboolean continuous; + TInt res = getBitratesByAudioCodecID(m_AudioEncoderId, bitrates, continuous); + if ((res == KErrNone) && (bitrates.Count() > 0)) { + /* Sort the array and pick the lowest bit rate */ + bitrates.SortUnsigned(); + m_BitRate = bitrates[0]; + } + bitrates.Close(); +} + +void XARecordSessionImpl::setLowQuality() +{ + /* Set to low quality encoder preset */ + RArray bitrates; + XAboolean continuous; + TInt res = getBitratesByAudioCodecID(m_AudioEncoderId, bitrates, continuous); + if ((res == KErrNone) && (bitrates.Count() > 0)) { + /* Sort the array and pick the low quality bit rate */ + bitrates.SortUnsigned(); + if (continuous == XA_BOOLEAN_FALSE) + m_BitRate = bitrates[bitrates.Count() / 4]; + else + m_BitRate = (bitrates[1] - bitrates[0]) / 4; + } + bitrates.Close(); +} + +void XARecordSessionImpl::setNormalQuality() +{ + /* Set to normal quality encoder preset */ + RArray bitrates; + XAboolean continuous; + TInt res = getBitratesByAudioCodecID(m_AudioEncoderId, bitrates, continuous); + if ((res == KErrNone) && (bitrates.Count() > 0)) { + /* Sort the array and pick the middle range bit rate */ + bitrates.SortUnsigned(); + if (continuous == XA_BOOLEAN_FALSE) + m_BitRate = bitrates[bitrates.Count() / 2]; + else + m_BitRate = (bitrates[1] - bitrates[0]) / 2; + } + bitrates.Close(); +} + +void XARecordSessionImpl::setHighQuality() +{ + /* Set to high quality encoder preset */ + RArray bitrates; + XAboolean continuous; + TInt res = getBitratesByAudioCodecID(m_AudioEncoderId, bitrates, continuous); + if ((res == KErrNone) && (bitrates.Count() > 0)) { + /* Sort the array and pick the high quality bit rate */ + bitrates.SortUnsigned(); + if (continuous == XA_BOOLEAN_FALSE) + m_BitRate = bitrates[bitrates.Count() * 3 / 4]; + else + m_BitRate = (bitrates[1] - bitrates[0]) * 3 / 4; + } + bitrates.Close(); +} + +void XARecordSessionImpl::setVeryHighQuality() +{ + /* Set to very high quality encoder preset */ + RArray bitrates; + XAboolean continuous; + TInt res = getBitratesByAudioCodecID(m_AudioEncoderId, bitrates, continuous); + if ((res == KErrNone) && (bitrates.Count() > 0)) { + /* Sort the array and pick the highest bit rate */ + bitrates.SortUnsigned(); + m_BitRate = bitrates[bitrates.Count() - 1]; + } + bitrates.Close(); +} + +/* Internal function */ +TInt32 XARecordSessionImpl::createMediaRecorderObject() +{ + TRACE_FUNCTION_ENTRY; + + if (!m_EOEngine) + return KErrGeneral; + + TInt32 returnValue(KErrNone); + + TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject")); + if (!m_MORecorder && !m_RecordItf) { + + /* Setup the data source */ + m_LocatorMic.locatorType = XA_DATALOCATOR_IODEVICE; + m_LocatorMic.deviceType = XA_IODEVICE_AUDIOINPUT; + m_LocatorMic.deviceID = m_InputDeviceId; + m_LocatorMic.device = NULL; + m_DataSource.pLocator = (void*) &m_LocatorMic; + m_DataSource.pFormat = NULL; + + /* Setup the data sink structure */ + m_Uri.locatorType = XA_DATALOCATOR_URI; + /* append zero terminator to end of URI */ + TPtr8 uriPtr = m_URIName->Des(); + m_Uri.URI = (XAchar*) uriPtr.PtrZ(); + m_Mime.formatType = XA_DATAFORMAT_MIME; + m_Mime.containerType = m_ContainerType; + TPtr8 mimeTypePtr(m_WAVMime->Des()); + m_Mime.mimeType = (XAchar*) mimeTypePtr.Ptr(); + m_DataSink.pLocator = (void*) &m_Uri; + m_DataSink.pFormat = (void*) &m_Mime; + + /* Init arrays required[] and iidArray[] */ + XAboolean required[MAX_NUMBER_INTERFACES]; + XAInterfaceID iidArray[MAX_NUMBER_INTERFACES]; + for (TInt32 i = 0; i < MAX_NUMBER_INTERFACES; i++) { + required[i] = XA_BOOLEAN_FALSE; + iidArray[i] = XA_IID_NULL; + } + XAuint32 noOfInterfaces = 0; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_RECORD; + noOfInterfaces++; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_AUDIOENCODER; + noOfInterfaces++; + + XAEngineItf engineItf; + XAresult xa_result = (*m_EOEngine)->GetInterface(m_EOEngine, XA_IID_ENGINE, (void**) &engineItf); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: Create Media Recorder...")); + + /* Create recorder with NULL for a the image/video source, since this is for audio-only recording */ + xa_result = (*engineItf)->CreateMediaRecorder( + engineItf, + &m_MORecorder, + &m_DataSource, + NULL, + &m_DataSink, + noOfInterfaces, + iidArray, + required); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: Realize Media Recorder...")); + xa_result = (*m_MORecorder)->Realize(m_MORecorder, XA_BOOLEAN_FALSE); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: Register Callback on recorder...")); + xa_result = (*m_MORecorder)->RegisterCallback(m_MORecorder, cbXAObjectItf, (void*) this); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: Getting Record Interface...")); + xa_result = (*m_MORecorder)->GetInterface(m_MORecorder, XA_IID_RECORD, &m_RecordItf); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: Registering Callback on record Interface...")); + xa_result = (*m_RecordItf)->RegisterCallback(m_RecordItf, cbXARecordItf, (void*) this); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: SetPositionUpdatePeriod on record Interface...")); + xa_result = (*m_RecordItf)->SetPositionUpdatePeriod(m_RecordItf, (XAmillisecond)KRecordPosUpdatePeriod); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: SetCallbackEventsMask on record Interface...")); + xa_result = (*m_RecordItf)->SetCallbackEventsMask(m_RecordItf, XA_RECORDEVENT_HEADATNEWPOS | + XA_RECORDEVENT_HEADMOVING | + XA_RECORDEVENT_HEADSTALLED); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: Getting Audio Encoder Interface...")); + xa_result = (*m_MORecorder)->GetInterface(m_MORecorder, XA_IID_AUDIOENCODER, &m_AudioEncItf); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + } + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::mapError(XAresult xa_err, TBool debPrn) +{ + TInt32 returnValue(KErrGeneral); + switch (xa_err) { + case XA_RESULT_SUCCESS: + returnValue = KErrNone; + break; + case XA_RESULT_PRECONDITIONS_VIOLATED: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_PRECONDITIONS_VIOLATED")); + break; + case XA_RESULT_PARAMETER_INVALID: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_PARAMETER_INVALID")); + break; + case XA_RESULT_MEMORY_FAILURE: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_MEMORY_FAILURE")); + break; + case XA_RESULT_RESOURCE_ERROR: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_RESOURCE_ERROR")); + break; + case XA_RESULT_RESOURCE_LOST: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_RESOURCE_LOST")); + break; + case XA_RESULT_IO_ERROR: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_IO_ERROR")); + break; + case XA_RESULT_BUFFER_INSUFFICIENT: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_BUFFER_INSUFFICIENT")); + break; + case XA_RESULT_CONTENT_CORRUPTED: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_CONTENT_CORRUPTED")); + break; + case XA_RESULT_CONTENT_UNSUPPORTED: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_CONTENT_UNSUPPORTED")); + break; + case XA_RESULT_CONTENT_NOT_FOUND: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_CONTENT_NOT_FOUND")); + break; + case XA_RESULT_PERMISSION_DENIED: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_PERMISSION_DENIED")); + break; + case XA_RESULT_FEATURE_UNSUPPORTED: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_FEATURE_UNSUPPORTED")); + break; + case XA_RESULT_INTERNAL_ERROR: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_INTERNAL_ERROR")); + break; + case XA_RESULT_UNKNOWN_ERROR: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_UNKNOWN_ERROR")); + break; + case XA_RESULT_OPERATION_ABORTED: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_OPERATION_ABORTED")); + break; + case XA_RESULT_CONTROL_LOST: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_CONTROL_LOST")); + break; + default: + if (debPrn) + TRACE_LOG(_L("Unknown Error!!!")); + break; + } + return returnValue; +} + +TInt32 XARecordSessionImpl::initContainersList() +{ + TRACE_FUNCTION_ENTRY; + + m_ContainerNames.Reset(); + m_ContainerDescs.Reset(); + + m_ContainerNames.Append(KCONTAINERWAV()); + m_ContainerNames.Append(KCONTAINERAMR()); + m_ContainerNames.Append(KCONTAINERMP4()); + + m_ContainerDescs.Append(KCONTAINERWAVDESC()); + m_ContainerDescs.Append(KCONTAINERAMRDESC()); + m_ContainerDescs.Append(KCONTAINERMP4DESC()); + + TRACE_FUNCTION_EXIT; + return KErrNone; +} + +TInt32 XARecordSessionImpl::initAudioEncodersList() +{ + TRACE_FUNCTION_ENTRY; + + m_EncoderIds.Reset(); + m_EncoderNames.Reset(); + + XAuint32 encoderIds[MAX_NUMBER_ENCODERS]; + + for (TInt index = 0; index < MAX_NUMBER_ENCODERS; index++) + encoderIds[index] = 0; + + XAuint32 numEncoders = MAX_NUMBER_ENCODERS; + XAresult xa_result = (*m_AudioEncCapsItf)->GetAudioEncoders( + m_AudioEncCapsItf, + &numEncoders, + encoderIds); + TInt32 returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + for (TInt index = 0; index < numEncoders; index++) { + m_EncoderIds.Append(encoderIds[index]); + switch (encoderIds[index]) { + case XA_AUDIOCODEC_PCM: + m_EncoderNames.Append(KAUDIOCODECPCM()); + break; + case XA_AUDIOCODEC_AMR: + m_EncoderNames.Append(KAUDIOCODECAMR()); + break; + case XA_AUDIOCODEC_AAC: + m_EncoderNames.Append(KAUDIOCODECAAC()); + break; + default: + break; + }; + } + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::initAudioInputDevicesList() +{ + TRACE_FUNCTION_ENTRY; + + m_InputDeviceIDs.Reset(); + + XAuint32 deviceIds[MAX_NUMBER_INPUT_DEVICES]; + for (TInt index = 0; index < MAX_NUMBER_INPUT_DEVICES; index++) + deviceIds[index] = 0; + + XAint32 numInputs = MAX_NUMBER_INPUT_DEVICES; + XAresult xa_result = (*m_AudioIODevCapsItf)->GetAvailableAudioInputs( + m_AudioIODevCapsItf, + &numInputs, + deviceIds); + TInt32 returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + XAAudioInputDescriptor audioInputDescriptor; + for (TInt index = 0; index < numInputs; index++) { + xa_result = (*m_AudioIODevCapsItf)->QueryAudioInputCapabilities( + m_AudioIODevCapsItf, + deviceIds[index], + &audioInputDescriptor); + returnValue = mapError(xa_result, ETrue); + if (returnValue != KErrNone) + continue; + + TUint8 * inDevNamePtr = audioInputDescriptor.deviceName; + TUint8 * tempPtr = audioInputDescriptor.deviceName; + TInt32 inDevNameLength = 0; + while (*tempPtr++) + inDevNameLength++; + TPtrC8 ptr(inDevNamePtr, inDevNameLength); + /* Convert 8 bit to 16 bit */ + TBuf16 name; + name.Copy(ptr); + /* Using TRAP with returnValue results in compiler error */ + TRAPD(err2, m_AudioInputDeviceNames->AppendL(name)); + returnValue = err2; + if (returnValue != KErrNone) + continue; + m_InputDeviceIDs.Append(deviceIds[index]); + } + + numInputs = MAX_NUMBER_INPUT_DEVICES; + for (TInt index = 0; index < MAX_NUMBER_INPUT_DEVICES; index++) + deviceIds[index] = 0; + xa_result = (*m_AudioIODevCapsItf)->GetDefaultAudioDevices( + m_AudioIODevCapsItf, + XA_DEFAULTDEVICEID_AUDIOINPUT, + &numInputs, + deviceIds); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + for (TInt index = 0; index < numInputs; index++) { + xa_result = (*m_AudioIODevCapsItf)->QueryAudioInputCapabilities( + m_AudioIODevCapsItf, + deviceIds[index], + &audioInputDescriptor); + returnValue = mapError(xa_result, ETrue); + if (returnValue != KErrNone) + continue; + TUint8* inDevNamePtr = audioInputDescriptor.deviceName; + TUint8* tempPtr = audioInputDescriptor.deviceName; + TInt32 inDevNameLength = 0; + while (*tempPtr++) + inDevNameLength++; + TPtrC8 ptr(inDevNamePtr, inDevNameLength); + /* Convert 8 bit to 16 bit */ + TBuf16 name; + name.Copy(ptr); + /* Using TRAP with returnValue results in compiler error */ + TRAPD(err2, m_DefaultAudioInputDeviceNames->AppendL(name)); + returnValue = err2; + if (returnValue != KErrNone) + continue; + m_DefaultInputDeviceIDs.Append(deviceIds[index]); + m_InputDeviceId = deviceIds[index]; + } + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::setEncoderSettingsToMediaRecorder() +{ + TRACE_FUNCTION_EXIT; + + /* Get current settings */ + XAAudioEncoderSettings settings; + XAresult xa_result = (*m_AudioEncItf)->GetEncoderSettings( + m_AudioEncItf, + &settings); + TInt32 returnValue = mapError(xa_result, ETrue); + + settings.encoderId = m_AudioEncoderId; + settings.channelsOut = m_ChannelsOut; + if ((m_SampleRate != 0) && (m_SampleRate != 0xffffffff)) + settings.sampleRate = m_SampleRate; + if ((m_BitRate != 0) && (m_BitRate != 0xffffffff)) + settings.bitRate = m_BitRate; + if (m_RateControl != 0) + settings.rateControl = m_RateControl; + settings.profileSetting = m_ProfileSetting; + xa_result = (*m_AudioEncItf)->SetEncoderSettings( + m_AudioEncItf, + &settings); + returnValue = mapError(xa_result, ETrue); + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::getBitratesByAudioCodecID( + XAuint32 encoderId, + RArray &aBitrates, + XAboolean& aContinuous) +{ + TRACE_FUNCTION_ENTRY; + + if (!m_AudioEncCapsItf) + return KErrGeneral; + + XAuint32 numCaps = 0; + XAAudioCodecDescriptor codecDesc; + XAresult xa_result = (*m_AudioEncCapsItf)->GetAudioEncoderCapabilities( + m_AudioEncCapsItf, + encoderId, + &numCaps, + &codecDesc); + TInt32 returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + aContinuous = codecDesc.isBitrateRangeContinuous; + /* TODO What do we do if we have more than one caps?? */ + if (codecDesc.isBitrateRangeContinuous == XA_BOOLEAN_TRUE) { + aBitrates.Append(codecDesc.minBitRate); + aBitrates.Append(codecDesc.maxBitRate); + } + else { + XAuint32 numBrSupported = codecDesc.numBitratesSupported; + XAuint32 * pBitratesSupported(NULL); + pBitratesSupported = codecDesc.pBitratesSupported; + TInt32 index = 0; + for (index = 0; index < numBrSupported; index++) + aBitrates.Append(*(pBitratesSupported + index)); + } + + TRACE_FUNCTION_ENTRY; + return returnValue; +} + +TInt32 XARecordSessionImpl::getSampleRatesByAudioCodecID(XAuint32 encoderId, + RArray &aSampleRates) +{ + TRACE_FUNCTION_ENTRY; + + if (!m_AudioEncCapsItf) + return KErrGeneral; + + XAuint32 numCaps = 0; + XAAudioCodecDescriptor codecDesc; + XAresult xa_result = (*m_AudioEncCapsItf)->GetAudioEncoderCapabilities( + m_AudioEncCapsItf, + encoderId, + &numCaps, + &codecDesc); + TInt returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + /* TODO What do we do if we have more than one caps?? */ + if (codecDesc.isFreqRangeContinuous == XA_BOOLEAN_TRUE) { + aSampleRates.Append(codecDesc.minSampleRate / KMilliToHz); + aSampleRates.Append(codecDesc.maxSampleRate / KMilliToHz); + } + else { + XAuint32 numSRSupported = codecDesc.numSampleRatesSupported; + XAmilliHertz *pSampleRatesSupported(NULL); + pSampleRatesSupported = codecDesc.pSampleRatesSupported; + for (TInt index = 0; index < numSRSupported; index++) + aSampleRates.Append((*(pSampleRatesSupported + index)) / KMilliToHz); + } + + TRACE_FUNCTION_ENTRY; + return returnValue; +} + +/* Local function implementation */ +void cbXAObjectItf( + XAObjectItf caller, + const void *pContext, + XAuint32 event, + XAresult result, + XAuint32 param, + void *pInterface) +{ + if (pContext) { + ((XARecordSessionImpl*)pContext)->cbMediaRecorder( + caller, + pContext, + event, + result, + param, + pInterface); + } +} + +void cbXARecordItf( + XARecordItf caller, + void *pContext, + XAuint32 event) +{ + if (pContext) { + ((XARecordSessionImpl*)pContext)->cbRecordItf( + caller, + pContext, + event); + } +} + +void cbXAAvailableAudioInputsChanged( + XAAudioIODeviceCapabilitiesItf caller, + void * pContext, + XAuint32 deviceID, + XAint32 numInputs, + XAboolean isNew) +{ + if (pContext) { + ((XARecordSessionImpl*)pContext)->cbAvailableAudioInputsChanged( + caller, + pContext, + deviceID, + numInputs, + isNew); + } +} diff --git a/src/plugins/symbian/openmaxal/mediarecorder/xarecordsessionimpl.h b/src/plugins/symbian/openmaxal/mediarecorder/xarecordsessionimpl.h new file mode 100644 index 000000000..81e4ac763 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/xarecordsessionimpl.h @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef XARECORDSESSIONIMPL_H +#define XARECORDSESSIONIMPL_H + +#include +#include + + +class XARecordObserver; +class XARecordSessionImpl +{ +public: + XARecordSessionImpl(XARecordObserver &parent); + ~XARecordSessionImpl(); + TInt32 postConstruct(); + + /* For QMediaRecorderControl begin */ + TInt32 setURI(const TDesC &aURI); + TInt32 record(); + TInt32 pause(); + TInt32 stop(); + TInt32 duration(TInt64 &aDur); + /* For QMediaRecorderControl end */ + + void cbMediaRecorder(XAObjectItf caller, + const void *pContext, + XAuint32 event, + XAresult result, + XAuint32 param, + void *pInterface); + void cbRecordItf(XARecordItf caller, + void *pContext, + XAuint32 event); + + /* For QAudioEndpointSelector begin */ + void getAudioInputDeviceNames(RArray &aArray); + TInt32 defaultAudioInputDevice(TPtrC &endPoint); + TInt32 activeAudioInputDevice(TPtrC &endPoint); + TBool setAudioInputDevice(const TDesC &aDevice); + void cbAvailableAudioInputsChanged(XAAudioIODeviceCapabilitiesItf caller, + void *pContext, + XAuint32 deviceID, + XAint32 numInputs, + XAboolean isNew); + /* For QAudioEndpointSelector end */ + + /* For QAudioEncoderControl begin */ + const RArray& getAudioEncoderNames(); + TInt32 getSampleRates(const TDesC &aEncoder, + RArray &aSampleRates, + TBool &aIsContinuous); + TInt32 getBitrates(const TDesC &aEncoder, + RArray &aBitrates, + TBool& aContinuous); + /* For QAudioEncoderControl end */ + + /* For QMediaContainerControl begin */ + const RArray& getContainerNames(); + const RArray& getContainerDescs(); + /* For QMediaContainerControl end */ + + void resetEncoderAttributes(); + void setContainerType(const TDesC &aURI); + TBool setCodec(const TDesC &aURI); + TUint32 getBitRate(); + void setBitRate(TUint32 aBitRate); + TUint32 getChannels(); + void setChannels(TUint32 aChannels); + void setOptimalChannelCount(); + TUint32 getSampleRate(); + void setSampleRate(TUint32 aSampleRate); + void setOptimalSampleRate(); + TInt32 setCBRMode(); + TInt32 setVBRMode(); + void setVeryLowQuality(); + void setLowQuality(); + void setNormalQuality(); + void setHighQuality(); + void setVeryHighQuality(); + +private: + TInt32 createMediaRecorderObject(); + TInt32 mapError(XAresult xa_err, + TBool debPrn); + TInt32 initContainersList(); + TInt32 initAudioEncodersList(); + TInt32 initAudioInputDevicesList(); + TInt32 setEncoderSettingsToMediaRecorder(); + TInt32 getBitratesByAudioCodecID(XAuint32 encoderId, + RArray &aBitrates, + XAboolean& aContinuous); + TInt32 getSampleRatesByAudioCodecID(XAuint32 encoderId, + RArray &aSampleRates); + + +private: + XARecordObserver &m_Parent; + XAObjectItf m_EOEngine; + XAObjectItf m_MORecorder; + XARecordItf m_RecordItf; + XAAudioEncoderItf m_AudioEncItf; + /* Audio Source */ + XADataSource m_DataSource; + XADataLocator_IODevice m_LocatorMic; + XADataFormat_MIME m_Mime; + XADataLocator_URI m_Uri; + /*Audio Sink*/ + XADataSink m_DataSink; + HBufC8 *m_WAVMime; + + /* Set by client*/ + HBufC8 *m_URIName; + XAuint32 m_AudioEncoderId; + XAuint32 m_InputDeviceId; + XAuint32 m_ContainerType; + XAuint32 m_BitRate; + XAuint32 m_RateControl; + XAuint32 m_ProfileSetting; + XAuint32 m_ChannelsOut; + XAuint32 m_SampleRate; + + /* For QAudioEndpointSelector begin */ + XAAudioIODeviceCapabilitiesItf m_AudioIODevCapsItf; + RArray m_InputDeviceIDs; + CDesC16ArrayFlat *m_AudioInputDeviceNames; + RArray m_DefaultInputDeviceIDs; + CDesC16ArrayFlat *m_DefaultAudioInputDeviceNames; + /* For QAudioEndpointSelector end */ + + /* For QAudioEncoderControl begin */ + XAAudioEncoderCapabilitiesItf m_AudioEncCapsItf; + RArray m_EncoderIds; + RArray m_EncoderNames; + RArray m_ContainerNames; + RArray m_ContainerDescs; + /* For QAudioEncoderControl begin */ +}; + +#endif /* XARECORDSESSIONIMPL_H */ diff --git a/src/plugins/symbian/openmaxal/openmaxal.pro b/src/plugins/symbian/openmaxal/openmaxal.pro new file mode 100644 index 000000000..0565536a4 --- /dev/null +++ b/src/plugins/symbian/openmaxal/openmaxal.pro @@ -0,0 +1,58 @@ +TEMPLATE = lib + +CONFIG += plugin +TARGET = $$qtLibraryTarget(qtmultimediakit_openmaxalengine) +PLUGIN_TYPE = mediaservice +include (../../../../common.pri) +qtAddLibrary(QtMultimediaKit) + +#includes here so that all defines are added here also +include(mediaplayer/mediaplayer.pri) +include(mediarecorder/mediarecorder.pri) +include(radiotuner/radiotuner.pri) + +DEPENDPATH += . + +HEADERS += qxamediaserviceproviderplugin.h \ + qxacommon.h \ + xacommon.h + +SOURCES += qxamediaserviceproviderplugin.cpp + +# Input parameters for the generated bld.inf file +# ----------------------------------------------- +SYMBIAN_PLATFORMS = DEFAULT + +# Input parameters for the generated mmp file +# ------------------------------------------- +load(data_caging_paths) +TARGET.UID3 = 0x10207CA1 +TARGET.CAPABILITY = ALL -TCB +TARGET.EPOCALLOWDLLDATA = 1 +MMP_RULES += EXPORTUNFROZEN + +# Macros controlling debug traces +#DEFINES += PROFILE_TIME +#DEFINES += PROFILE_RAM_USAGE +#DEFINES += PROFILE_HEAP_USAGE +#DEFINES += PLUGIN_QT_TRACE_ENABLED +#DEFINES += PLUGIN_QT_SIGNAL_EMIT_TRACE_ENABLED +#DEFINES += PLUGIN_SYMBIAN_TRACE_ENABLED + +INCLUDEPATH += $$MW_LAYER_SYSTEMINCLUDE +INCLUDEPATH += /epoc32/include/platform/mw/khronos + + +# Input parameters for qmake to make the dll a qt plugin +pluginDep.sources = $${TARGET}.dll +pluginDep.path = $${QT_PLUGINS_BASE_DIR}/$${PLUGIN_TYPE} +DEPLOYMENT += pluginDep + +LIBS += \ + -lQtMultimediaKit \ + -lopenmaxal + +# check for PROFILE_RAM_USAGE +contains(DEFINES, PROFILE_RAM_USAGE) { + LIBS += -lhal +} diff --git a/src/plugins/symbian/openmaxal/qxacommon.h b/src/plugins/symbian/openmaxal/qxacommon.h new file mode 100644 index 000000000..f19a75d1c --- /dev/null +++ b/src/plugins/symbian/openmaxal/qxacommon.h @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXACOMMON_H +#define QXACOMMON_H + +#if defined(PLUGIN_QT_TRACE_ENABLED) \ + || defined(PLUGIN_QT_SIGNAL_EMIT_TRACE_ENABLED) \ + || defined(PROFILE_TIME) \ + || defined(PROFILE_RAM_USAGE) \ + || defined(PROFILE_HEAP_USAGE) +# include +#endif /* PLUGIN_QT_TRACE_ENABLED */ + +#ifdef PROFILE_RAM_USAGE +# include +#endif + + +#ifdef PLUGIN_QT_TRACE_ENABLED +# define QT_TRACE_FUNCTION_ENTRY qDebug() << __PRETTY_FUNCTION__ << ">" +# define QT_TRACE_FUNCTION_EXIT qDebug() << __PRETTY_FUNCTION__ << "<" +# define QT_TRACE_FUNCTION_ENTRY_EXIT qDebug() << __PRETTY_FUNCTION__ << "><" +# define QT_TRACE1(v1) qDebug() << v1 +# define QT_TRACE2(v1, v2) qDebug() << v1 << v2 +#else +# define QT_TRACE_FUNCTION_ENTRY +# define QT_TRACE_FUNCTION_EXIT +# define QT_TRACE_FUNCTION_ENTRY_EXIT +# define QT_TRACE1(v1) +# define QT_TRACE2(v1, v2) +#endif /*PLUGIN_QT_TRACE_ENABLED*/ + +#ifdef PLUGIN_QT_SIGNAL_EMIT_TRACE_ENABLED +# define SIGNAL_EMIT_TRACE1(v1) qDebug() << __PRETTY_FUNCTION__ << v1 +#else +# define SIGNAL_EMIT_TRACE1(v1) +#endif /*PLUGIN_QT_SIGNAL_EMIT_TRACE_ENABLED*/ + +#ifdef PROFILE_TIME_ELAPSED +# define TAG_TIME_PROFILING_BEGIN \ + TTime beginProfilingTime; \ + beginProfilingTime.HomeTime() + +# define TAG_TIME_PROFILING_END \ + TTime endProfilingTime; \ + endProfilingTime.HomeTime(); \ + TTimeIntervalMicroSeconds diffInMicroSecs = endProfilingTime.MicroSecondsFrom(beginProfilingTime) + +# define QT_PRINT_TO_CONSOLE_TIME_DIFF \ + qDebug() << "VPROFILEDAT: " << __PRETTY_FUNCTION__ << ": Time taken " << diffInMicroSecs.Int64() << " microseconds" +#else /* Empty macros */ +# define TAG_TIME_PROFILING_BEGIN +# define TAG_TIME_PROFILING_END +# define QT_PRINT_TO_CONSOLE_TIME_DIFF +#endif /*PROFILE_TIME_ELAPSED*/ + +#ifdef PROFILE_RAM_USAGE +# define TAG_RAM_PROFILING_BEGIN \ + TInt beginProfilingRAM; \ + TInt err1 = HAL::Get(HALData::EMemoryRAMFree, beginProfilingRAM) + +# define TAG_RAM_PROFILING_END \ + TInt endProfilingRAM; \ + TInt err2 = HAL::Get(HALData::EMemoryRAMFree, endProfilingRAM) + +# define QT_PRINT_TO_CONSOLE_RAM_DIFF \ + if ((err1 == KErrNone) && (err2 == KErrNone)) \ + { \ + TInt diffRAM = (beginProfilingRAM - endProfilingRAM); \ + if ( diffRAM > 0 ) \ + { \ + qDebug() << "VPROFILEDAT: " << __PRETTY_FUNCTION__ << ": " << diffRAM << " bytes of RAM used"; \ + } \ + else \ + { \ + qDebug() << "VPROFILEDAT: " << __PRETTY_FUNCTION__ << ": " << -(diffRAM) << " bytes of RAM freed"; \ + } \ + } \ + else \ + { \ + qDebug() << "VPROFILEDAT: " << __PRETTY_FUNCTION__ << "Error1[" << err1 << "] Error2[" << err2; \ + } + +#else /* Empty macros */ +# define TAG_RAM_PROFILING_BEGIN +# define TAG_RAM_PROFILING_END +# define QT_PRINT_TO_CONSOLE_RAM_DIFF +#endif /*PROFILE_RAM_USAGE*/ + +#ifdef PROFILE_HEAP_USAGE +# define TAG_DEFAULT_HEAP_PROFILING_BEGIN \ + TInt beginProfilingHEAPBiggestBlock; \ + TInt beginProfilingHEAP = User::Available(beginProfilingHEAPBiggestBlock) \ + +# define TAG_DEFAULT_HEAP_PROFILING_END \ + TInt endProfilingHEAPBiggestBlock; \ + TInt endProfilingHEAP = User::Available(endProfilingHEAPBiggestBlock) \ + +# define QT_PRINT_TO_CONSOLE_HEAP_DIFF \ + TInt diffHEAP = beginProfilingHEAP - endProfilingHEAP; \ + if ( diffHEAP > 0 ) \ + { \ + qDebug() << "VPROFILEDAT: " << __PRETTY_FUNCTION__ << ": " << diffHEAP << " bytes in default HEAP used"; \ + } \ + else \ + { \ + qDebug() << "VPROFILEDAT: " << __PRETTY_FUNCTION__ << ": " << -(diffHEAP) << " bytes in default HEAP freed"; \ + } +#else /* Empty macros */ +# define TAG_DEFAULT_HEAP_PROFILING_BEGIN +# define TAG_DEFAULT_HEAP_PROFILING_END +# define QT_PRINT_TO_CONSOLE_HEAP_DIFF +#endif /*PROFILE_HEAP_USAGE*/ + +/* This macro checks p pointer for null. If it is, returns value 's' from + * function immediately. + */ +#define RET_s_IF_p_IS_NULL(p, s) \ + if (p == NULL) { \ + return s; \ + } + +/* This macro checks p pointer for null. If it is, returns from function + * immediately. + */ +#define RET_IF_p_IS_NULL(p) \ + if (p == NULL) { \ + return; \ + } + +/* This macro checks p pointer for null. If it is, emits an error signal + * error(QMediaPlayer::ResourceError, tr("Resource Error")); + * and returns value 's' from function immediately. + */ +#define RET_s_IF_p_IS_NULL_EMIT_PLAYER_RESOURCE_ERROR(p, s) \ + if (p == NULL) { \ + emit error(QMediaPlayer::ResourceError, tr("Resource Error")); \ + SIGNAL_EMIT_TRACE1("emit error(QMediaPlayer::ResourceError, tr(\"Resource Error\"))"); \ + return s; \ + } + +/* This macro checks p pointer for null. If it is, emits an error signal + * error(QMediaPlayer::ResourceError, tr("Resource Error")); + * and returns from function immediately. + */ +#define RET_IF_p_IS_NULL_EMIT_PLAYER_RESOURCE_ERROR(p) \ + if (p == NULL) { \ + emit error(QMediaPlayer::ResourceError, tr("Resource Error")); \ + SIGNAL_EMIT_TRACE1("emit error(QMediaPlayer::ResourceError, tr(\"Resource Error\"))"); \ + return; \ + } + +/* This macro checks p pointer for null. If it is, emits an error signal + * error(QMediaPlayer::ResourceError, tr("Resource Error")); + * and returns from function immediately. + */ +#define RET_IF_ERROR(p) \ + if (p != KErrNone) { \ + emit error(QMediaPlayer::ResourceError, tr("Resource Error")); \ + SIGNAL_EMIT_TRACE1("emit error(QMediaPlayer::ResourceError, tr(\"Resource Error\"))"); \ + return; \ + } + +#endif /* QXACOMMON_H */ diff --git a/src/plugins/symbian/openmaxal/qxamediaserviceproviderplugin.cpp b/src/plugins/symbian/openmaxal/qxamediaserviceproviderplugin.cpp new file mode 100644 index 000000000..bfbb4333a --- /dev/null +++ b/src/plugins/symbian/openmaxal/qxamediaserviceproviderplugin.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "qxamediaserviceproviderplugin.h" +#include "qxaplaymediaservice.h" +#include "qxarecordmediaservice.h" +#include "qxaradiomediaservice.h" +#include "qxacommon.h" + +QStringList QXAMediaServiceProviderPlugin::keys() const +{ + return QStringList() + << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER) + << QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE) + << QLatin1String(Q_MEDIASERVICE_RADIO); +} + +QMediaService* QXAMediaServiceProviderPlugin::create(QString const& key) +{ + QT_TRACE_FUNCTION_ENTRY; + QMediaService* service = NULL; + if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER) ) { + service = new QXAPlayMediaService; + QT_TRACE1("Created QXAPlayMediaService"); + } + else if (key == QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE)) { + service = new QXARecodMediaService; + QT_TRACE1("Created QXARecodMediaService"); + } + else if (key == QLatin1String(Q_MEDIASERVICE_RADIO) ) { + service = new QXARadioMediaService; + QT_TRACE1("Created QXARadioMediaService"); + } + else { + QT_TRACE2("unsupported key:", key); + } + QT_TRACE_FUNCTION_EXIT; + return service; +} + +void QXAMediaServiceProviderPlugin::release(QMediaService *service) +{ + QT_TRACE_FUNCTION_ENTRY; + delete service; + QT_TRACE_FUNCTION_EXIT; +} + +Q_EXPORT_PLUGIN2(qtmultimediakit_openmaxalengine, QXAMediaServiceProviderPlugin); diff --git a/src/plugins/symbian/openmaxal/qxamediaserviceproviderplugin.h b/src/plugins/symbian/openmaxal/qxamediaserviceproviderplugin.h new file mode 100644 index 000000000..6d3530349 --- /dev/null +++ b/src/plugins/symbian/openmaxal/qxamediaserviceproviderplugin.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXAMEDIASERVICEPROVIDERPLUGIN_H +#define QXAMEDIASERVICEPROVIDERPLUGIN_H + +#include +#include +#include + +QT_USE_NAMESPACE + +class QXAMediaServiceProviderPlugin : public QMediaServiceProviderPlugin +{ + Q_OBJECT +public: + QStringList keys() const; + QMediaService* create(QString const& key); + void release(QMediaService *service); +}; + +#endif /* QXAMEDIASERVICEPROVIDERPLUGIN_H */ diff --git a/src/plugins/symbian/openmaxal/radiotuner/qxaradiocontrol.cpp b/src/plugins/symbian/openmaxal/radiotuner/qxaradiocontrol.cpp new file mode 100644 index 000000000..9666b0410 --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/qxaradiocontrol.cpp @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxaradiocontrol.h" +#include "qxaradiosession.h" +#include "xaradiosessionimpl.h" + +QXARadioControl::QXARadioControl(QXARadioSession *session, QObject *parent) +:QRadioTunerControl(parent), m_session(session) +{ + + connect(m_session, SIGNAL(stateChanged(QRadioTuner::State)), this, SIGNAL(stateChanged(QRadioTuner::State))); + + connect(m_session, SIGNAL(bandChanged(QRadioTuner::Band)), this, SIGNAL(bandChanged(QRadioTuner::Band))); + + connect(m_session, SIGNAL(frequencyChanged(int)), this, SIGNAL(frequencyChanged(int))); + + connect(m_session, SIGNAL(stereoStatusChanged(bool)), this, SIGNAL(stereoStatusChanged(bool))); + + connect(m_session, SIGNAL(searchingChanged(bool)), this, SIGNAL(searchingChanged(bool))); + + connect(m_session, SIGNAL(signalStrengthChanged(int)), this, SIGNAL(signalStrengthChanged(int))); + + connect(m_session, SIGNAL(volumeChanged(int)), this, SIGNAL(volumeChanged(int))); + + connect(m_session, SIGNAL(mutedChanged(bool)), this, SIGNAL(mutedChanged(bool))); + +// connect(m_session, SIGNAL(error(int,QString)), this,SIGNAL(error(int,QString))); +} + +QXARadioControl::~QXARadioControl() +{ + +} + +QtMultimediaKit::AvailabilityError QXARadioControl::availabilityError() const +{ + return m_session->availabilityError(); +} + +bool QXARadioControl::isAvailable() const +{ + return m_session->isAvailable(); +} + +QRadioTuner::State QXARadioControl::state() const +{ + return m_session->state(); +} + +QRadioTuner::Band QXARadioControl::band() const +{ + return m_session->band(); +} + +void QXARadioControl::setBand(QRadioTuner::Band band) +{ + m_session->setBand(band); +} + +bool QXARadioControl::isBandSupported(QRadioTuner::Band band) const +{ + return m_session->isBandSupported(band); +} + +int QXARadioControl::frequency() const +{ + return m_session->frequency(); +} + +int QXARadioControl::frequencyStep(QRadioTuner::Band band) const +{ + return m_session->frequencyStep(band); +} + +QPair QXARadioControl::frequencyRange(QRadioTuner::Band band) const +{ + return m_session->frequencyRange(band); +} + +void QXARadioControl::setFrequency(int freq) +{ + m_session->setFrequency(freq); +} + +bool QXARadioControl::isStereo() const +{ + return m_session->isStereo(); +} + +QRadioTuner::StereoMode QXARadioControl::stereoMode() const +{ + return m_session->stereoMode(); +} + +void QXARadioControl::setStereoMode(QRadioTuner::StereoMode stereoMode) +{ + m_session->setStereoMode(stereoMode); +} + +int QXARadioControl::signalStrength() const +{ + return m_session->signalStrength(); +} + +int QXARadioControl::volume() const +{ + return m_session->volume(); +} + +void QXARadioControl::setVolume(int volume) +{ + m_session->setVolume(volume); +} + +bool QXARadioControl::isMuted() const +{ + return m_session->isMuted(); +} + +void QXARadioControl::setMuted(bool muted) +{ + m_session->setMuted(muted); +} + +bool QXARadioControl::isSearching() const +{ + return m_session->isSearching(); +} + +void QXARadioControl::searchForward() +{ + m_session->searchForward(); +} + +void QXARadioControl::searchBackward() +{ + m_session->searchBackward(); +} + +void QXARadioControl::cancelSearch() +{ + m_session->cancelSearch(); +} + +void QXARadioControl::start() +{ + m_session->start(); +} + +void QXARadioControl::stop() +{ + m_session->stop(); +} + +QRadioTuner::Error QXARadioControl::error() const +{ + return m_session->error(); +} + +QString QXARadioControl::errorString() const +{ + return m_session->errorString(); +} diff --git a/src/plugins/symbian/openmaxal/radiotuner/qxaradiocontrol.h b/src/plugins/symbian/openmaxal/radiotuner/qxaradiocontrol.h new file mode 100644 index 000000000..47d4f827d --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/qxaradiocontrol.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXARADIOCONTROL_H +#define QXARADIOCONTROL_H + +#include +#include + +QT_USE_NAMESPACE + +class QXARadioSession; + +class QXARadioControl : public QRadioTunerControl +{ + Q_OBJECT + +public: + QXARadioControl(QXARadioSession *session, QObject *parent = 0); + virtual ~QXARadioControl(); + QRadioTuner::State state() const; + + QRadioTuner::Band band() const; + void setBand(QRadioTuner::Band band); + bool isBandSupported(QRadioTuner::Band band) const; + int frequency() const; + int frequencyStep(QRadioTuner::Band band) const; + QPair frequencyRange(QRadioTuner::Band band) const; + void setFrequency(int freq); + bool isStereo() const; + QRadioTuner::StereoMode stereoMode() const; + void setStereoMode(QRadioTuner::StereoMode stereoMode); + int signalStrength() const; + int volume() const; + void setVolume(int volume); + bool isMuted() const; + void setMuted(bool muted); + bool isSearching() const; + void searchForward(); + void searchBackward(); + void cancelSearch(); + bool isValid() const; + bool isAvailable() const; + QtMultimediaKit::AvailabilityError availabilityError() const; + void start(); + void stop(); + QRadioTuner::Error error() const; + QString errorString() const; + +private: + QXARadioSession *m_session; + +protected: + QXARadioControl(QObject* parent = 0); +}; + +#endif /* QXARADIOCONTROL_H */ diff --git a/src/plugins/symbian/openmaxal/radiotuner/qxaradiomediaservice.cpp b/src/plugins/symbian/openmaxal/radiotuner/qxaradiomediaservice.cpp new file mode 100644 index 000000000..f399ef8c5 --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/qxaradiomediaservice.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "qxaradiomediaservice.h" +#include "qxaradiosession.h" +#include "qxaradiocontrol.h" +#include + +QXARadioMediaService::QXARadioMediaService(QObject *parent) + : QMediaService(parent) +{ + m_session = new QXARadioSession(this); + m_control = new QXARadioControl(m_session, this); +} + +QXARadioMediaService::~QXARadioMediaService() +{ +} + +QMediaControl* QXARadioMediaService::requestControl(const char *name) +{ + + if (qstrcmp(name, QRadioTunerControl_iid) == 0) { + return m_control; + } + return 0; +} + +void QXARadioMediaService::releaseControl(QMediaControl *control) +{ + Q_UNUSED(control) +} diff --git a/src/plugins/symbian/openmaxal/radiotuner/qxaradiomediaservice.h b/src/plugins/symbian/openmaxal/radiotuner/qxaradiomediaservice.h new file mode 100644 index 000000000..7ac014f8f --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/qxaradiomediaservice.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXARADIOMEDIASERVICE_H +#define QXARADIOMEDIASERVICE_H + +#include +#include + +QT_USE_NAMESPACE + +class QXARadioSession; +class QXARadioControl; + +class QXARadioMediaService : public QMediaService +{ + Q_OBJECT +public: + QXARadioMediaService(QObject *parent = 0); + ~QXARadioMediaService(); + QMediaControl *requestControl(const char *name); + void releaseControl( QMediaControl *control); +private: + QXARadioSession *m_session; + QXARadioControl *m_control; +}; + +#endif /*QXARADIOMEDIASERVICE_H*/ diff --git a/src/plugins/symbian/openmaxal/radiotuner/qxaradiosession.cpp b/src/plugins/symbian/openmaxal/radiotuner/qxaradiosession.cpp new file mode 100644 index 000000000..6822813c4 --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/qxaradiosession.cpp @@ -0,0 +1,323 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "qxaradiosession.h" +#include "xaradiosessionimpl.h" +#include "qxacommon.h" + +QXARadioSession::QXARadioSession(QObject *parent) +:QObject(parent) +{ + QT_TRACE_FUNCTION_ENTRY; + m_impl = new XARadioSessionImpl(*this); + if (!m_impl) { + QT_TRACE1("RadioSession::RadioSession(): ERROR creating RadioSessionImpl..."); + return; + } + if (m_impl->PostConstruct() != QRadioTuner::NoError) { + QT_TRACE1("RadioSession::RadioSession(): ERROR from RadioSessionImpl::PostContstruct..."); + delete m_impl; + m_impl = NULL; + } + QT_TRACE_FUNCTION_EXIT; +} + +QXARadioSession::~QXARadioSession() +{ + delete m_impl; +} + +QRadioTuner::State QXARadioSession::state() const +{ + QRadioTuner::State state = QRadioTuner::StoppedState; + if (m_impl) + state = m_impl->State(); + return state; + } +QtMultimediaKit::AvailabilityError QXARadioSession::availabilityError() const +{ + QtMultimediaKit::AvailabilityError error = QtMultimediaKit::NoError; + if (m_impl) + error = m_impl->AvailabilityError(); + return error; +} + +QRadioTuner::Band QXARadioSession::band() const +{ + QRadioTuner::Band band = QRadioTuner::FM; + if (m_impl) + band = m_impl->Band(); + return band; +} + +void QXARadioSession::setBand(QRadioTuner::Band band) +{ + if (m_impl) + m_impl->SetBand(band); +} + +bool QXARadioSession::isBandSupported(QRadioTuner::Band band) const +{ + if (m_impl) + return m_impl->IsBandSupported(band); + return false; +} + +bool QXARadioSession::isAvailable() const +{ + if (m_impl) + return m_impl->IsAvailable(); + return false; +} + +int QXARadioSession::frequency() const +{ + TInt frequency = 0; + if (m_impl) + frequency = m_impl->GetFrequency(); + return (int)frequency; +} + +int QXARadioSession::frequencyStep(QRadioTuner::Band band) const +{ + TInt freqStep = 0; + if (m_impl) + freqStep = m_impl->FrequencyStep(band); + return (int)freqStep; +} + +QPair QXARadioSession::frequencyRange(QRadioTuner::Band /*band*/) const +{ + QPair freqRange; + freqRange.first = 0; + freqRange.second =0; + + if (m_impl) { + TInt freqRangeType = m_impl->GetFrequencyRange(); + m_impl->GetFrequencyRangeProperties(freqRangeType, freqRange.first, freqRange.second); + } + + return freqRange; +} + +void QXARadioSession::setFrequency(int frequency) +{ + if (m_impl) + m_impl->SetFrequency(frequency); +} + +bool QXARadioSession::isStereo() const +{ + bool isStereo = false; + if (m_impl) + isStereo = m_impl->IsStereo(); + return isStereo; +} + +QRadioTuner::StereoMode QXARadioSession::stereoMode() const +{ + QRadioTuner::StereoMode mode(QRadioTuner::Auto); + if (m_impl) + mode = m_impl->StereoMode(); + return mode; +} + +void QXARadioSession::setStereoMode(QRadioTuner::StereoMode mode) +{ + if (m_impl) + m_impl->SetStereoMode(mode); +} + +int QXARadioSession::signalStrength() const +{ + TInt signalStrength = 0; + if (m_impl) + signalStrength = m_impl->GetSignalStrength(); + return (int)signalStrength; +} + +int QXARadioSession::volume() const +{ + TInt volume = 0; + if (m_impl) + volume = m_impl->GetVolume(); + return volume; +} + +int QXARadioSession::setVolume(int volume) +{ + TInt newVolume = 0; + if (m_impl) { + m_impl->SetVolume(volume); + newVolume = m_impl->GetVolume(); + } + return newVolume; +} + +bool QXARadioSession::isMuted() const +{ + bool isMuted = false; + if (m_impl) + isMuted = m_impl->IsMuted(); + return isMuted; +} + +void QXARadioSession::setMuted(bool muted) +{ + if (m_impl) + m_impl->SetMuted(muted); +} + +bool QXARadioSession::isSearching() const +{ + bool isSearching = false; + if (m_impl) + isSearching = m_impl->IsSearching(); + return isSearching; +} + +void QXARadioSession::searchForward() +{ + if (m_impl) + m_impl->Seek(true); +} + +void QXARadioSession::searchBackward() +{ + if (m_impl) + m_impl->Seek(false); +} + +void QXARadioSession::cancelSearch() +{ + if (m_impl) + m_impl->StopSeeking(); +} + +void QXARadioSession::start() +{ + if (m_impl) + m_impl->Start(); +} + +void QXARadioSession::stop() +{ + if (m_impl) + m_impl->Stop(); +} + +QRadioTuner::Error QXARadioSession::error() const +{ + QRadioTuner::Error err(QRadioTuner::NoError); + if (m_impl) + err = m_impl->Error(); + return err; +} + +QString QXARadioSession::errorString() const +{ + QString str = NULL; + switch (iError) { + case QRadioTuner::ResourceError: + str = "Resource Error"; + break; + case QRadioTuner::OpenError: + str = "Open Error"; + break; + case QRadioTuner::OutOfRangeError: + str = "Out of Range Error"; + break; + default: + break; + } + + return str; +} + +// Callbacks, which will emit signals to client: +void QXARadioSession::CBStateChanged(QRadioTuner::State state) +{ + emit stateChanged(state); +} + +void QXARadioSession::CBBandChanged(QRadioTuner::Band band) +{ + emit bandChanged(band); +} + +void QXARadioSession::CBFrequencyChanged(TInt newFrequency) +{ + emit frequencyChanged(newFrequency); +} + +void QXARadioSession::CBStereoStatusChanged(bool isStereo) +{ + emit stereoStatusChanged(isStereo); +} + +void QXARadioSession::CBSignalStrengthChanged(int signalStrength) +{ + emit signalStrengthChanged(signalStrength); +} + +void QXARadioSession::CBVolumeChanged(int volume) +{ + emit volumeChanged(volume); +} + +void QXARadioSession::CBMutedChanged(bool isMuted) +{ + emit mutedChanged(isMuted); +} + +void QXARadioSession::CBSearchingChanged(bool isSearching) +{ + emit searchingChanged(isSearching); +} + +void QXARadioSession::CBError(QRadioTuner::Error err) +{ + iError = err; + emit error((int)err, errorString()); +} + + diff --git a/src/plugins/symbian/openmaxal/radiotuner/qxaradiosession.h b/src/plugins/symbian/openmaxal/radiotuner/qxaradiosession.h new file mode 100644 index 000000000..72f6a7a01 --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/qxaradiosession.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXARADIOSESSION_H +#define QXARADIOSESSION_H + +#include +#include +#include +#include "xaradiosessionimplobserver.h" + +QT_USE_NAMESPACE + +class XARadioSessionImpl; + +class QXARadioSession : public QObject, public XARadioSessionImplObserver +{ +Q_OBJECT + +public: + QXARadioSession(QObject *parent); + virtual ~QXARadioSession(); + + QRadioTuner::State state() const; + QRadioTuner::Band band() const; + void setBand(QRadioTuner::Band band); + bool isBandSupported(QRadioTuner::Band band) const; + int frequency() const; + int frequencyStep(QRadioTuner::Band b) const; + QPair frequencyRange(QRadioTuner::Band b) const; + void setFrequency(int frequency); + bool isStereo() const; + QRadioTuner::StereoMode stereoMode() const; + void setStereoMode(QRadioTuner::StereoMode mode); + int signalStrength() const; + int volume() const; + int setVolume(int volume); + bool isMuted() const; + void setMuted(bool muted); + bool isSearching() const; + void searchForward(); + void searchBackward(); + void cancelSearch(); + void start(); + void stop(); + bool isAvailable() const; + QtMultimediaKit::AvailabilityError availabilityError() const; + QRadioTuner::Error error() const; + QString errorString() const; + + /* Callbacks from XARadioSessionImplObserver begin */ + void CBBandChanged(QRadioTuner::Band band); + void CBStateChanged(QRadioTuner::State state); + void CBFrequencyChanged(TInt newFrequency); + void CBStereoStatusChanged(bool isStereo); + void CBSignalStrengthChanged(int signalStrength); + void CBVolumeChanged(int volume); + void CBMutedChanged(bool isMuted); + void CBSearchingChanged(bool isSearching); + void CBError(QRadioTuner::Error err); + /* Callbacks from XARadioSessionImplObserver end */ + +signals: + void stateChanged(QRadioTuner::State state); + void bandChanged(QRadioTuner::Band band); + void frequencyChanged(int frequency); + void stereoStatusChanged(bool stereo); + void searchingChanged(bool stereo); + void signalStrengthChanged(int signalStrength); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void error(int err, QString str); + +private: + /* Own */ + QRadioTuner::Error iError; + XARadioSessionImpl* m_impl; +}; + +#endif /*QXARADIOSESSION_H*/ diff --git a/src/plugins/symbian/openmaxal/radiotuner/radiotuner.pri b/src/plugins/symbian/openmaxal/radiotuner/radiotuner.pri new file mode 100644 index 000000000..bf83d05fc --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/radiotuner.pri @@ -0,0 +1,18 @@ +INCLUDEPATH += $$PWD + +# Input +HEADERS += \ + $$PWD/qxaradiomediaservice.h \ + $$PWD/qxaradiosession.h \ + $$PWD/qxaradiocontrol.h \ + $$PWD/xaradiosessionimpl.h \ + $$PWD/xaradiosessionimplobserver.h + +SOURCES += \ + $$PWD/qxaradiomediaservice.cpp \ + $$PWD/qxaradiosession.cpp \ + $$PWD/qxaradiocontrol.cpp \ + $$PWD/xaradiosessionimpl.cpp + +LIBS += \ + -lbafl diff --git a/src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimpl.cpp b/src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimpl.cpp new file mode 100644 index 000000000..94bebc373 --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimpl.cpp @@ -0,0 +1,715 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "xaradiosessionimpl.h" +#include "xaradiosessionimplobserver.h" +#include +#include "xacommon.h" + +#define MAX_NUMBER_INTERFACES 20 +#define FM_STEP 100000; // Hz (.1 MHz) + +/* + * function declarations. + * */ +void EngineObjectCallback(XAObjectItf caller, const void */*pContext*/, + XAuint32 event, XAresult result, XAuint32 /*param*/, + void */*pInterface*/); + +void RadioCallback(XARadioItf caller, void* pContext, XAuint32 event, XAuint32 eventIntData, XAboolean eventBooleanData); +void NokiaVolumeExtItfCallback(XANokiaVolumeExtItf caller, void* pContext, XAuint32 event, XAboolean eventBooleanData); +void NokiaLinearVolumeItfCallback(XANokiaLinearVolumeItf caller, void* pContext, XAuint32 event, XAboolean eventBooleanData); +void PlayItfCallbackForRadio(XAPlayItf caller, void* pContext, XAuint32 event); + +XARadioSessionImpl::XARadioSessionImpl(XARadioSessionImplObserver& parent) +:iParent(parent), +iRadio(NULL), +iEngine(NULL), +iPlayer(NULL), +iSearching(EFalse), +iRadioAvailable(EFalse), +iState(QRadioTuner::StoppedState) +{ + iAvailabilityError = QtMultimediaKit::NoError; +} + +XARadioSessionImpl::~XARadioSessionImpl() +{ + if (iRadio) { + TRACE_LOG((_L("XARadioSessionImpl::~XARadioSessionImpl(): Deleting Radio Device..."))); + (*iRadio)->Destroy(iRadio); + iRadio = NULL; + TRACE_LOG((_L("XARadioSessionImpl::~XARadioSessionImpl(): Deleted Radio Device"))); + } + if (iPlayer) { + TRACE_LOG((_L("XARadioSessionImpl::~XARadioSessionImpl(): Deleting player..."))); + (*iPlayer)->Destroy(iPlayer); + iPlayer = NULL; + TRACE_LOG((_L("XARadioSessionImpl::~XARadioSessionImpl(): Deleted iPlayer"))); + } + if ( iEngine ) { + TRACE_LOG((_L("XARadioSessionImpl::~XARadioSessionImpl(): Deleting engine..."))); + (*iEngine)->Destroy(iEngine); + iEngine = NULL; + TRACE_LOG((_L("XARadioSessionImpl::~XARadioSessionImpl(): Deleted engine"))); + } +} + +QRadioTuner::Error XARadioSessionImpl::PostConstruct() +{ + XAresult res = CreateEngine(); + if (res != KErrNone) + return QRadioTuner::ResourceError; + else + return QRadioTuner::NoError; +} + +TInt XARadioSessionImpl::CreateEngine() +{ + TRACE_FUNCTION_ENTRY; + XAboolean required[MAX_NUMBER_INTERFACES]; + XAInterfaceID iidArray[MAX_NUMBER_INTERFACES]; + XAuint32 noOfInterfaces = 0; + int i; + XAresult res; + + XAEngineOption EngineOption[] = + { + { + (XAuint32) XA_ENGINEOPTION_THREADSAFE, + (XAuint32) XA_BOOLEAN_TRUE + } + }; + + /* Create XA engine */ + if (!iEngine) { + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Creating Engine..."))); + res = xaCreateEngine(&iEngine, 1, EngineOption, 0, NULL, NULL); + RET_ERR_IF_ERR(CheckErr(res)); + res = (*iEngine)->RegisterCallback(iEngine, EngineObjectCallback, NULL); + RET_ERR_IF_ERR(CheckErr(res)); + + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Realizing..."))); + res = (*iEngine)->Realize(iEngine, XA_BOOLEAN_FALSE); + RET_ERR_IF_ERR(CheckErr(res)); + + // Create Engine Interface: + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Creating Engine Interface"))); + RET_ERR_IF_ERR(CheckErr((*iEngine)->GetInterface(iEngine, XA_IID_ENGINE, (void*)&iEngineItf))); + + // Create Radio Device and interface(s): + if (!iRadio) { + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Creating Radio Device"))); + res = (*iEngineItf)->CreateRadioDevice(iEngineItf,&iRadio, 0, NULL, NULL); + RET_ERR_IF_ERR(CheckErr(res)); + + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Realize Radio Device"))); + res = (*iRadio)->Realize(iRadio, XA_BOOLEAN_FALSE); + RET_ERR_IF_ERR(CheckErr(res)); + + // Get Radio interface: + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Get Radio Interface"))); + res = (*iRadio)->GetInterface(iRadio, XA_IID_RADIO, (void*)&iRadioItf); + RET_ERR_IF_ERR(CheckErr(res)); + iRadioAvailable = ETrue; + // Register Radio Callback: + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Create Radio Callback:"))); + res = (*iRadioItf)->RegisterRadioCallback(iRadioItf, RadioCallback, (void*)this); + RET_ERR_IF_ERR(CheckErr(res)); + } + XADataSource audioSource; + XADataLocator_IODevice locatorIODevice; + XADataSink audioSink; + XADataLocator_OutputMix locator_outputmix; + + /* Init arrays required[] and iidArray[] */ + for (i = 0; i < MAX_NUMBER_INTERFACES; i++) { + required[i] = XA_BOOLEAN_FALSE; + iidArray[i] = XA_IID_NULL; + } + + iidArray[0] = XA_IID_NOKIAVOLUMEEXT; + iidArray[1] = XA_IID_NOKIALINEARVOLUME; + noOfInterfaces = 2; + + locatorIODevice.locatorType = XA_DATALOCATOR_IODEVICE; + locatorIODevice.deviceType = XA_IODEVICE_RADIO; + locatorIODevice.deviceID = 0; /* ignored */ + locatorIODevice.device = iRadio; + audioSource.pLocator = (void*) &locatorIODevice; + audioSource.pFormat = NULL; + + /* Setup the data sink structure */ + locator_outputmix.locatorType = XA_DEFAULTDEVICEID_AUDIOOUTPUT; + locator_outputmix.outputMix = NULL; + audioSink.pLocator = (void*) &locator_outputmix; + audioSink.pFormat = NULL; + + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Create Media Player:"))); + res = (*iEngineItf)->CreateMediaPlayer(iEngineItf, &iPlayer, &audioSource, NULL, &audioSink, NULL, NULL, NULL, noOfInterfaces, iidArray, required); + RET_ERR_IF_ERR(CheckErr(res)); + + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Realize Media Player:"))); + res = (*iPlayer)->Realize(iPlayer, XA_BOOLEAN_FALSE); + RET_ERR_IF_ERR(CheckErr(res)); + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Get Play Interface from player:"))); + res = (*iPlayer)->GetInterface(iPlayer, XA_IID_PLAY, (void*) &iPlayItf); + RET_ERR_IF_ERR(CheckErr(res)); + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Create PlayItf Callback:"))); + res = (*iPlayItf)->RegisterCallback(iPlayItf, PlayItfCallbackForRadio, (void*)this); + RET_ERR_IF_ERR(CheckErr(res)); + + // Get Volume Interfaces specific for Nokia impl: + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Get NokiaVolumeExt Interface"))); + res = (*iPlayer)->GetInterface(iPlayer, XA_IID_NOKIAVOLUMEEXT, (void*)&iNokiaVolumeExtItf); + RET_ERR_IF_ERR(CheckErr(res)); + + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Get NokiaLinearVolume Interface"))); + res = (*iPlayer)->GetInterface(iPlayer, XA_IID_NOKIALINEARVOLUME, (void*)&iNokiaLinearVolumeItf); + RET_ERR_IF_ERR(CheckErr(res)); + + // Register Volume Callbacks: + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Create NokiaVolumeExtItf Callback:"))); + res = (*iNokiaVolumeExtItf)->RegisterVolumeCallback(iNokiaVolumeExtItf, NokiaVolumeExtItfCallback, (void*)this); + RET_ERR_IF_ERR(CheckErr(res)); + res = (*iNokiaVolumeExtItf)->SetCallbackEventsMask(iNokiaVolumeExtItf,(XA_NOKIAVOLUMEEXT_EVENT_MUTE_CHANGED)); + RET_ERR_IF_ERR(CheckErr(res)); + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Create NokiaLinearVolumeItf Callback:"))); + res = (*iNokiaLinearVolumeItf)->RegisterVolumeCallback(iNokiaLinearVolumeItf, NokiaLinearVolumeItfCallback, (void*)this); + RET_ERR_IF_ERR(CheckErr(res)); + res = (*iNokiaLinearVolumeItf)->SetCallbackEventsMask(iNokiaLinearVolumeItf,(XA_NOKIALINEARVOLUME_EVENT_VOLUME_CHANGED)); + RET_ERR_IF_ERR(CheckErr(res)); + } + + TRACE_FUNCTION_EXIT; + return EFalse; +} + +QRadioTuner::State XARadioSessionImpl::State() const +{ + TRACE_FUNCTION_ENTRY_EXIT; + return iState; +} + +QtMultimediaKit::AvailabilityError XARadioSessionImpl::AvailabilityError() const +{ + TRACE_FUNCTION_ENTRY_EXIT; + return iAvailabilityError; +} + + bool XARadioSessionImpl::IsAvailable() const +{ + TRACE_FUNCTION_ENTRY_EXIT; + return iRadioAvailable; +} + +QRadioTuner::Band XARadioSessionImpl::Band() const +{ + TRACE_FUNCTION_ENTRY_EXIT; + return iBand; +} + +void XARadioSessionImpl::SetBand(QRadioTuner::Band band) +{ + if (band != QRadioTuner::FM) + iParent.CBError(QRadioTuner::OpenError); + else + iBand = band; +} + +bool XARadioSessionImpl::IsBandSupported(QRadioTuner::Band band) const +{ + if (band == QRadioTuner::FM) + return ETrue; + else + return EFalse; +} + +// Returns the number of Hertz to increment the frequency by when stepping through frequencies within a given band. +TInt XARadioSessionImpl::FrequencyStep(QRadioTuner::Band /*band*/) const +{ + TInt freqStep = FM_STEP; + return (int)freqStep; +} + +bool XARadioSessionImpl::IsStereo() //const +{ + bool isStereo = EFalse; + QRadioTuner::StereoMode mode = StereoMode(); + if (mode == QRadioTuner::ForceStereo || mode == QRadioTuner::Auto) + isStereo = ETrue; + return isStereo; +} + +bool XARadioSessionImpl::IsMuted() const +{ + TRACE_FUNCTION_ENTRY; + XAboolean isMuted = EFalse; + (*iNokiaVolumeExtItf)->GetMute(iNokiaVolumeExtItf, &isMuted ); + TRACE_LOG((_L("XARadioSessionImpl::IsMuted: isMuted = %d"), isMuted)); + + TRACE_FUNCTION_EXIT; + return isMuted; +} + +bool XARadioSessionImpl::IsSearching() const +{ + //iSearching is set when seek (QT:searchForward-backward) + // iSearching is cleared when SearchingStatusChanged is called or StopSeeking is called + return iSearching; +} + +TInt XARadioSessionImpl::GetFrequency() +{ + TRACE_FUNCTION_ENTRY; + + XAuint32 freq = 0; + XAresult res = (*iRadioItf)->GetFrequency(iRadioItf, &freq ); + RET_ERR_IF_ERR(CheckErr(res)); + TRACE_LOG((_L("XARadioSessionImpl::GetFrequency: Frequency = %d"), freq)); + + TRACE_FUNCTION_EXIT; + return (int)freq; +} + +TInt XARadioSessionImpl::GetFrequencyRange() +{ + TRACE_FUNCTION_ENTRY; + XAuint8 range = 0; + + XAresult res = (*iRadioItf)->GetFreqRange(iRadioItf, &range); + RET_ERR_IF_ERR(CheckErr(res)); + TRACE_LOG((_L("XARadioSessionImpl::GetFrequencyRange: Frequency Range = %d"), range)); + + TRACE_FUNCTION_EXIT; + return (int)range; +} + +TInt XARadioSessionImpl::GetFrequencyRangeProperties(TInt range, TInt &minFreq, TInt &maxFreq) +{ + TRACE_FUNCTION_ENTRY; + XAuint32 freqInterval = 0; + XAresult res = (*iRadioItf)->GetFreqRangeProperties(iRadioItf, (XAuint8)range, (XAuint32*)&minFreq,(XAuint32*)&maxFreq, (XAuint32*)&freqInterval); + RET_ERR_IF_ERR(CheckErr(res)); + TRACE_LOG((_L("XARadioSessionImpl::GetFrequencyRangeProperties: minFreq = %d, maxFreq = %d"), minFreq, maxFreq)); + + TRACE_FUNCTION_EXIT; + return res; +} + +TInt XARadioSessionImpl::SetFrequency(TInt aFreq) +{ + TRACE_FUNCTION_ENTRY; + + TRACE_LOG((_L("XARadioSessionImpl::SetFrequency: Setting Frequency to: %d"), aFreq)); + XAresult res = (*iRadioItf)->SetFrequency(iRadioItf, aFreq ); + RET_ERR_IF_ERR(CheckErr(res)); + + TRACE_FUNCTION_EXIT; + return res; +} + +QRadioTuner::StereoMode XARadioSessionImpl::StereoMode() +{ + TRACE_FUNCTION_ENTRY; + QRadioTuner::StereoMode qtStereoMode; + XAuint32 symStereoMode; + (*iRadioItf)->GetStereoMode(iRadioItf, &symStereoMode); + + if (symStereoMode == XA_STEREOMODE_MONO) + qtStereoMode = QRadioTuner::ForceMono; + else if (symStereoMode == XA_STEREOMODE_STEREO) + qtStereoMode = QRadioTuner::ForceStereo; + else + qtStereoMode = QRadioTuner::Auto; + + TRACE_FUNCTION_EXIT; + return qtStereoMode; +} + +TInt XARadioSessionImpl::SetStereoMode(QRadioTuner::StereoMode qtStereoMode) +{ + TRACE_FUNCTION_ENTRY; + XAuint32 symStereoMode; + + if (qtStereoMode == QRadioTuner::ForceMono) + symStereoMode = XA_STEREOMODE_MONO; + else if (qtStereoMode == QRadioTuner::ForceStereo) + symStereoMode = XA_STEREOMODE_STEREO; + else + symStereoMode = XA_STEREOMODE_AUTO; + + XAresult res = (*iRadioItf)->SetStereoMode(iRadioItf, (symStereoMode)); + TRACE_FUNCTION_EXIT; + return res; +} + +TInt XARadioSessionImpl::GetSignalStrength() +{ + TRACE_FUNCTION_ENTRY; + XAuint32 signalStrength = 0; + + (*iRadioItf)->GetSignalStrength(iRadioItf, &signalStrength ); + TRACE_LOG((_L("XARadioSessionImpl::GetSignalStrength: Signal Strength = %d"), signalStrength)); + TRACE_FUNCTION_EXIT; + return (int)signalStrength; +} + +TInt XARadioSessionImpl::GetVolume() +{ + TRACE_FUNCTION_ENTRY; + XAuint32 vol; + if (iPlayer && iNokiaLinearVolumeItf) { + (*iNokiaLinearVolumeItf)->GetVolumeLevel(iNokiaLinearVolumeItf, &vol ); + TRACE_LOG((_L("XARadioSessionImpl::GetVolume: Volume = %d"), vol)); + } + TRACE_FUNCTION_EXIT; + return (TInt)vol; +} + +TInt XARadioSessionImpl::SetVolume(TInt aVolume) +{ + TRACE_FUNCTION_ENTRY; + XAuint32 newVolume = 0; + TRACE_LOG((_L("XARadioSessionImpl::SetVolume: Setting volume to: %d"), aVolume)); + if (iPlayer && iNokiaLinearVolumeItf) { + newVolume = aVolume; + XAresult res = (*iNokiaLinearVolumeItf)->SetVolumeLevel(iNokiaLinearVolumeItf, &newVolume); + } + TRACE_FUNCTION_EXIT; + return (TInt)newVolume; +} + +TInt XARadioSessionImpl::SetMuted(TBool aMuted) +{ + TRACE_FUNCTION_ENTRY; + XAresult res = (*iNokiaVolumeExtItf)->SetMute(iNokiaVolumeExtItf, aMuted); + TRACE_FUNCTION_EXIT; + return res; +} + +TInt XARadioSessionImpl::Seek(TBool aDirection) +{ + TRACE_FUNCTION_ENTRY; + iSearching = true; + XAresult res = (*iRadioItf)->Seek(iRadioItf, aDirection ); + TRACE_FUNCTION_EXIT; + return res; +} + +TInt XARadioSessionImpl::StopSeeking() +{ + TRACE_FUNCTION_ENTRY; + XAresult res = (*iRadioItf)->StopSeeking(iRadioItf); + iSearching = EFalse; + TRACE_FUNCTION_EXIT; + return res; +} + +void XARadioSessionImpl::Start() +{ + TRACE_FUNCTION_ENTRY; + if (iPlayItf) { + XAresult res = (*iPlayItf)->SetPlayState(iPlayItf, XA_PLAYSTATE_PLAYING); + // add error handling if res != 0 (call errorCB) + } + TRACE_FUNCTION_EXIT; +} + +void XARadioSessionImpl::Stop() +{ + TRACE_FUNCTION_ENTRY; + if (iPlayItf) { + XAresult res = (*iPlayItf)->SetPlayState(iPlayItf, XA_PLAYSTATE_STOPPED); + // add error handling if res != 0 (call errorCB) + } + TRACE_FUNCTION_EXIT; +} + +QRadioTuner::Error XARadioSessionImpl::Error() +{ + TRACE_FUNCTION_ENTRY_EXIT; + return QRadioTuner::NoError; +} + +//TInt XARadioSessionImpl::ErrorString(); +// { +// TRACE_FUNCTION_ENTRY; + +// TRACE_FUNCTION_EXIT; +// } + +void XARadioSessionImpl::StateChanged(QRadioTuner::State state) +{ + TRACE_FUNCTION_ENTRY; + iState = state; + iParent.CBStateChanged(state); + TRACE_FUNCTION_EXIT; +} + +void XARadioSessionImpl::FrequencyChanged(XAuint32 freq) +{ + TRACE_FUNCTION_ENTRY; + iParent.CBFrequencyChanged(freq); + TRACE_FUNCTION_EXIT; +} + +void XARadioSessionImpl::SearchingChanged(TBool isSearching) +{ + TRACE_FUNCTION_ENTRY; + iSearching = EFalse; + iParent.CBSearchingChanged(isSearching); + TRACE_FUNCTION_EXIT; +} + +void XARadioSessionImpl::StereoStatusChanged(TBool stereoStatus) +{ + TRACE_FUNCTION_ENTRY; + iParent.CBStereoStatusChanged(stereoStatus); + TRACE_FUNCTION_EXIT; +} + +void XARadioSessionImpl::SignalStrengthChanged(TBool stereoStatus) +{ + TRACE_FUNCTION_ENTRY; + iParent.CBSignalStrengthChanged(stereoStatus); + TRACE_FUNCTION_EXIT; +} + +void XARadioSessionImpl::VolumeChanged() +{ + TRACE_FUNCTION_ENTRY; + int vol = 0; + iParent.CBVolumeChanged(vol); + TRACE_FUNCTION_EXIT; +} + +void XARadioSessionImpl::MutedChanged(TBool mute) +{ + TRACE_FUNCTION_ENTRY; + iParent.CBMutedChanged(mute); + TRACE_FUNCTION_EXIT; +} + +void EngineObjectCallback(XAObjectItf /*caller*/, + const void */*pContext*/, +#ifdef PLUGIN_SYMBIAN_TRACE_ENABLED + XAuint32 event, +#else + XAuint32 /*event*/, +#endif /*PLUGIN_SYMBIAN_TRACE_ENABLED*/ + XAresult /*result*/, + XAuint32 /*param*/, + void */*pInterface*/) +{ +#ifdef PLUGIN_SYMBIAN_TRACE_ENABLED + TRACE_LOG((_L("Engine object event: 0x%x\n"), (int)event)); +#endif /*PLUGIN_SYMBIAN_TRACE_ENABLED*/ +} + +void RadioCallback(XARadioItf /*caller*/, + void* pContext, + XAuint32 event, + XAuint32 eventIntData, + XAboolean eventBooleanData) +{ + XAuint32 freq; + XAboolean stereoStatus(XA_BOOLEAN_FALSE); + + switch (event) { + case XA_RADIO_EVENT_ANTENNA_STATUS_CHANGED: + TRACE_LOG((_L("RadioCallback: XA_RADIO_EVENT_ANTENNA_STATUS_CHANGED"))); + // Qt API has no callback defined for this event. + break; + case XA_RADIO_EVENT_FREQUENCY_CHANGED: + freq = eventIntData; + TRACE_LOG((_L("RadioCallback: XA_RADIO_EVENT_FREQUENCY_CHANGED to: %d"), freq)); + if (pContext) + ((XARadioSessionImpl*)pContext)->FrequencyChanged(freq); + break; + case XA_RADIO_EVENT_FREQUENCY_RANGE_CHANGED: + TRACE_LOG((_L("RadioCallback: XA_RADIO_EVENT_FREQUENCY_RANGE_CHANGED"))); + // Qt API has no callback defined for this event. + break; + case XA_RADIO_EVENT_PRESET_CHANGED: + TRACE_LOG((_L("RadioCallback: XA_RADIO_EVENT_PRESET_CHANGED"))); + // Qt API has no callback defined for this event. + break; + case XA_RADIO_EVENT_SEEK_COMPLETED: + TRACE_LOG((_L("RadioCallback: XA_RADIO_EVENT_SEEK_COMPLETED"))); + if (pContext) + ((XARadioSessionImpl*)pContext)->SearchingChanged(false); + break; + case XA_RADIO_EVENT_STEREO_STATUS_CHANGED: + stereoStatus = eventBooleanData; + TRACE_LOG((_L("RadioCallback: XA_RADIO_EVENT_STEREO_STATUS_CHANGED: %d"), stereoStatus)); + if (pContext) + ((XARadioSessionImpl*)pContext)->StereoStatusChanged(stereoStatus); + break; + case XA_RADIO_EVENT_SIGNAL_STRENGTH_CHANGED: + TRACE_LOG((_L("RadioCallback: XA_RADIO_EVENT_SIGNAL_STRENGTH_CHANGED"))); + if (pContext) + ((XARadioSessionImpl*)pContext)->SignalStrengthChanged(stereoStatus); + break; + default: + TRACE_LOG((_L("RadioCallback: default"))); + break; + } +} + +void NokiaVolumeExtItfCallback(XANokiaVolumeExtItf /*caller*/, + void* pContext, + XAuint32 event, + XAboolean eventBooleanData) +{ + XAboolean mute; + switch (event) { + case XA_NOKIAVOLUMEEXT_EVENT_MUTE_CHANGED: + mute = eventBooleanData; + TRACE_LOG((_L("NokiaVolumeExtItfCallback: XA_NOKIAVOLUMEEXT_EVENT_MUTE_CHANGED to: %d"), mute)); + if (pContext) + ((XARadioSessionImpl*)pContext)->MutedChanged(mute); + break; + default: + TRACE_LOG((_L("NokiaVolumeExtItfCallback: default"))); + break; + } +} + +void NokiaLinearVolumeItfCallback(XANokiaLinearVolumeItf /*caller*/, + void* pContext, + XAuint32 event, + XAboolean /*eventBooleanData*/) +{ + switch (event) { + case XA_NOKIALINEARVOLUME_EVENT_VOLUME_CHANGED: + if (pContext) + ((XARadioSessionImpl*)pContext)->VolumeChanged(); + break; + default: + TRACE_LOG((_L("NokiaLinearVolumeItfCallback: default"))); + break; + } +} + +void PlayItfCallbackForRadio(XAPlayItf /*caller*/, + void* pContext, + XAuint32 event) +{ + switch (event) { + case XA_PLAYEVENT_HEADMOVING: + if (pContext) + ((XARadioSessionImpl*)pContext)->StateChanged(QRadioTuner::ActiveState); + break; + case XA_PLAYEVENT_HEADSTALLED: + if (pContext) + ((XARadioSessionImpl*)pContext)->StateChanged(QRadioTuner::StoppedState); + break; + default: + TRACE_LOG((_L("NokiaLinearVolumeItfCallback: default"))); + break; + } +} + +TInt XARadioSessionImpl::CheckErr(XAresult res) +{ + TInt status(KErrGeneral); + switch(res) { + case XA_RESULT_SUCCESS: + //TRACE_LOG((_L("XA_RESULT_SUCCESS"))); + status = KErrNone; + break; + case XA_RESULT_PRECONDITIONS_VIOLATED: + TRACE_LOG((_L("XA_RESULT_PRECONDITIONS_VIOLATED"))); + break; + case XA_RESULT_PARAMETER_INVALID: + TRACE_LOG((_L("XA_RESULT_PARAMETER_INVALID"))); + break; + case XA_RESULT_MEMORY_FAILURE: + TRACE_LOG((_L("XA_RESULT_MEMORY_FAILURE"))); + iAvailabilityError = QtMultimediaKit::ResourceError; + break; + case XA_RESULT_RESOURCE_ERROR: + TRACE_LOG((_L("XA_RESULT_RESOURCE_ERROR"))); + iAvailabilityError = QtMultimediaKit::ResourceError; + break; + case XA_RESULT_RESOURCE_LOST: + TRACE_LOG((_L("XA_RESULT_RESOURCE_LOST"))); + iAvailabilityError = QtMultimediaKit::ResourceError; + break; + case XA_RESULT_IO_ERROR: + TRACE_LOG((_L("XA_RESULT_IO_ERROR"))); + break; + case XA_RESULT_BUFFER_INSUFFICIENT: + TRACE_LOG((_L("XA_RESULT_BUFFER_INSUFFICIENT"))); + break; + case XA_RESULT_CONTENT_CORRUPTED: + TRACE_LOG((_L("XA_RESULT_CONTENT_CORRUPTED"))); + break; + case XA_RESULT_CONTENT_UNSUPPORTED: + TRACE_LOG((_L("XA_RESULT_CONTENT_UNSUPPORTED"))); + break; + case XA_RESULT_CONTENT_NOT_FOUND: + TRACE_LOG((_L("XA_RESULT_CONTENT_NOT_FOUND"))); + break; + case XA_RESULT_PERMISSION_DENIED: + TRACE_LOG((_L("XA_RESULT_PERMISSION_DENIED"))); + break; + case XA_RESULT_FEATURE_UNSUPPORTED: + TRACE_LOG((_L("XA_RESULT_FEATURE_UNSUPPORTED"))); + break; + case XA_RESULT_INTERNAL_ERROR: + TRACE_LOG((_L("XA_RESULT_INTERNAL_ERROR"))); + break; + case XA_RESULT_UNKNOWN_ERROR: + TRACE_LOG((_L("XA_RESULT_UNKNOWN_ERROR"))); + break; + case XA_RESULT_OPERATION_ABORTED: + TRACE_LOG((_L("XA_RESULT_OPERATION_ABORTED"))); + break; + case XA_RESULT_CONTROL_LOST: + TRACE_LOG((_L("XA_RESULT_CONTROL_LOST"))); + break; + default: + TRACE_LOG((_L("Unknown Error!!!"))); + } + return status; +} diff --git a/src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimpl.h b/src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimpl.h new file mode 100644 index 000000000..ee5f53a2f --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimpl.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef XARADIOSESSIONIMPL_H +#define XARADIOSESSIONIMPL_H + +#include +#include +#include +#include +#include + +QT_USE_NAMESPACE + +class XARadioSessionImplObserver; + +class XARadioSessionImpl +{ +public: + XARadioSessionImpl(XARadioSessionImplObserver& parent); + ~XARadioSessionImpl(); + QRadioTuner::Error PostConstruct(); + QRadioTuner::Band Band() const; + QRadioTuner::State State() const; + QtMultimediaKit::AvailabilityError AvailabilityError() const; + bool IsAvailable() const; + void SetBand(QRadioTuner::Band band); + bool IsBandSupported(QRadioTuner::Band band) const; + TInt FrequencyStep(QRadioTuner::Band band) const; + bool IsStereo(); //const; + bool IsMuted() const; + bool IsSearching() const; + TInt GetFrequency(); + TInt GetFrequencyRange(); + TInt GetFrequencyRangeProperties(TInt range, TInt &minFreq, TInt &maxFreq); + TInt SetFrequency(TInt aFreq); + QRadioTuner::StereoMode StereoMode(); + TInt SetStereoMode(QRadioTuner::StereoMode stereoMode); + TInt GetSignalStrength(); + TInt GetVolume(); + TInt SetVolume(TInt aVolume); + TInt SetMuted(TBool aMuted); + TInt Seek(TBool aDirection); + TInt StopSeeking(); + void Start(); + void Stop(); + QRadioTuner::Error Error(); +//TInt ErrorString(); + void StateChanged(QRadioTuner::State state); + void FrequencyChanged(XAuint32 freq); + void SearchingChanged(TBool isSearching); + void StereoStatusChanged(TBool stereoStatus); + void SignalStrengthChanged(TBool stereoStatus); + void VolumeChanged(); + void MutedChanged(TBool mute); + +private: + TInt CreateEngine(); + TInt CheckErr(XAresult res); + + +private: + XARadioSessionImplObserver& iParent; + XAObjectItf iRadio; + XAObjectItf iEngine; + XAObjectItf iPlayer; + XAEngineItf iEngineItf; + XARecordItf iRecordItf; + XAPlayItf iPlayItf; + XARadioItf iRadioItf; + XARDSItf iRdsItf; + XANokiaVolumeExtItf iNokiaVolumeExtItf; // used for mute functionality + XANokiaLinearVolumeItf iNokiaLinearVolumeItf; // used for volume functionality + + /* Audio Source */ + XADataSource iDataSource; + + /*Audio Sink*/ + XADataSink iAudioSink; + XADataLocator_OutputMix iLocator_outputmix; + + TBool iAutoFlag; + TBool iSearching; + TBool iRadioAvailable; + QtMultimediaKit::AvailabilityError iAvailabilityError; + QRadioTuner::Band iBand; + QRadioTuner::State iState; +}; + +#endif /* XARADIOSESSIONIMPL_H */ diff --git a/src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimplobserver.h b/src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimplobserver.h new file mode 100644 index 000000000..73c734fd3 --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimplobserver.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef XARADIOSESSIONIMPLOBSERVER_H +#define XARADIOSESSIONIMPLOBSERVER_H + +#include +#include + +QT_USE_NAMESPACE + +class XARadioSessionImplObserver +{ +public: + virtual void CBStateChanged(QRadioTuner::State state) = 0; + virtual void CBBandChanged(QRadioTuner::Band band) = 0; + virtual void CBFrequencyChanged(TInt newFrequency) = 0; + virtual void CBStereoStatusChanged(bool isStereo) = 0; + virtual void CBSignalStrengthChanged(int signalStrength) = 0; + virtual void CBVolumeChanged(int volume) = 0; + virtual void CBMutedChanged(bool isMuted) = 0; + virtual void CBSearchingChanged(bool isSearching) = 0; + virtual void CBError(QRadioTuner::Error err) = 0; +}; + +#endif /*XARADIOSESSIONIMPLOBSERVER_H*/ diff --git a/src/plugins/symbian/openmaxal/xacommon.h b/src/plugins/symbian/openmaxal/xacommon.h new file mode 100644 index 000000000..9aecbc8f5 --- /dev/null +++ b/src/plugins/symbian/openmaxal/xacommon.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef XACOMMON_H +#define XACOMMON_H + +#ifdef PLUGIN_SYMBIAN_TRACE_ENABLED +# include +#endif /* PLUGIN_SYMBIAN_TRACE_ENABLED */ + +#ifdef PLUGIN_SYMBIAN_TRACE_ENABLED +# define TRACE_FUNCTION_ENTRY RDebug::Printf( "%s >", __PRETTY_FUNCTION__) +# define TRACE_FUNCTION_EXIT RDebug::Printf( "%s <", __PRETTY_FUNCTION__) +# define TRACE_FUNCTION_ENTRY_EXIT RDebug::Printf( "%s ><", __PRETTY_FUNCTION__) +# define TRACE_LOG(s) RDebug::Print s +#else +# define TRACE_FUNCTION_ENTRY +# define TRACE_FUNCTION_EXIT +# define TRACE_FUNCTION_ENTRY_EXIT +# define TRACE_LOG +#endif /* PLUGIN_SYMBIAN_TRACE_ENABLED */ + +#define RET_IF_FALSE(e) \ + if (e == false) \ + { \ + return; \ + } + +#define RET_BOOL_IF_FALSE(e) \ + if (e == false) \ + { \ + return e; \ + } + +#define RET_ERR_IF_ERR(e) \ + if (e != 0) \ + { \ + return e; \ + } + +#endif /* XACOMMON_H */ diff --git a/src/plugins/symbian/symbian.pro b/src/plugins/symbian/symbian.pro new file mode 100644 index 000000000..7fc2c8690 --- /dev/null +++ b/src/plugins/symbian/symbian.pro @@ -0,0 +1,23 @@ +###################################################################### +# +# Mobility API project - Symbian backends +# +###################################################################### + +TEMPLATE = subdirs + +include (../../../config.pri) + +# The openmax-al backend is currently not supported +# we include mmf only if we are not building openmaxal based backend +#contains(openmaxal_symbian_enabled, no) { +# message("Enabling mmf mediarecording, playback and radio backend") +# symbian:SUBDIRS += mmf +# +#else { +# message("Enabling OpenMAX AL audio record, playback and radio backend") +# symbian:SUBDIRS += openmaxal +# + +symbian:SUBDIRS += ecam mmf + diff --git a/src/plugins/symbian/videooutput/s60videodisplay.cpp b/src/plugins/symbian/videooutput/s60videodisplay.cpp new file mode 100644 index 000000000..35e234e98 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videodisplay.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "s60videodisplay.h" +#include +#include +#include +#include + +S60VideoDisplay::S60VideoDisplay(QObject *parent) +: QObject(parent) +, m_fullScreen(false) +, m_visible(true) +, m_aspectRatioMode(Qt::KeepAspectRatio) +, m_paintingEnabled(false) +, m_rotation(0.0f) +{ + connect(this, SIGNAL(displayRectChanged(QRect, QRect)), + this, SLOT(updateContentRect())); + connect(this, SIGNAL(nativeSizeChanged(QSize)), + this, SLOT(updateContentRect())); +} + +S60VideoDisplay::~S60VideoDisplay() +{ + +} + +RWindow *S60VideoDisplay::windowHandle() const +{ + return winId() ? static_cast(winId()->DrawableWindow()) : 0; +} + +QRect S60VideoDisplay::clipRect() const +{ + QRect displayableRect; +#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES + if (RWindow *window = windowHandle()) + displayableRect = QRect(0, 0, window->Size().iWidth, window->Size().iHeight); +#else + displayableRect = QApplication::desktop()->screenGeometry(); +#endif + return extentRect().intersected(displayableRect); +} + +QRect S60VideoDisplay::contentRect() const +{ + return m_contentRect; +} + +void S60VideoDisplay::setFullScreen(bool enabled) +{ + if (m_fullScreen != enabled) { + m_fullScreen = enabled; + emit fullScreenChanged(m_fullScreen); + } +} + +bool S60VideoDisplay::isFullScreen() const +{ + return m_fullScreen; +} + +void S60VideoDisplay::setVisible(bool enabled) +{ + if (m_visible != enabled) { + m_visible = enabled; + emit visibilityChanged(m_visible); + } +} + +bool S60VideoDisplay::isVisible() const +{ + return m_visible; +} + +void S60VideoDisplay::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + if (m_aspectRatioMode != mode) { + m_aspectRatioMode = mode; + emit aspectRatioModeChanged(m_aspectRatioMode); + } +} + +Qt::AspectRatioMode S60VideoDisplay::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void S60VideoDisplay::setNativeSize(const QSize &size) +{ + if (m_nativeSize != size) { + m_nativeSize = size; + emit nativeSizeChanged(m_nativeSize); + } +} + +const QSize& S60VideoDisplay::nativeSize() const +{ + return m_nativeSize; +} + +void S60VideoDisplay::setPaintingEnabled(bool enabled) +{ + if (m_paintingEnabled != enabled) { + m_paintingEnabled = enabled; + emit paintingEnabledChanged(m_paintingEnabled); + } +} + +bool S60VideoDisplay::isPaintingEnabled() const +{ + return m_paintingEnabled; +} + +void S60VideoDisplay::setRotation(qreal value) +{ + if (value != m_rotation) { + m_rotation = value; + emit rotationChanged(m_rotation); + } +} + +qreal S60VideoDisplay::rotation() const +{ + return m_rotation; +} + +void S60VideoDisplay::updateContentRect() +{ + if (isPaintingEnabled()) { + const int dx = qMax(0, extentRect().width() - nativeSize().width()); + const int dy = qMax(0, extentRect().height() - nativeSize().height()); + QRect contentRect(QPoint(dx/2, dy/2), nativeSize()); + if (m_contentRect != contentRect) { + m_contentRect = contentRect; + emit contentRectChanged(m_contentRect); + } + } +} + diff --git a/src/plugins/symbian/videooutput/s60videodisplay.h b/src/plugins/symbian/videooutput/s60videodisplay.h new file mode 100644 index 000000000..e16e7bb71 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videodisplay.h @@ -0,0 +1,188 @@ +/** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60VIDEODISPLAY_H +#define S60VIDEODISPLAY_H + +#include +#include +#include +#include +#include + +class CFbsBitmap; +class RWindow; + +QT_USE_NAMESPACE + +/* + * This class defines a common API used by Symbian camera and mediaplayer + * backends to render to on-screen video outputs, i.e. implementations of + * QVideoWidgetControl and QVideoWindowControl. + */ +class S60VideoDisplay : public QObject +{ + Q_OBJECT +public: + S60VideoDisplay(QObject *parent); + virtual ~S60VideoDisplay(); + + /* + * Returns native Symbian handle of the window to be used for rendering + */ + RWindow *windowHandle() const; + + /* + * Returns Qt WId (CCoeControl* on Symbian) + */ + virtual WId winId() const = 0; + + /* + * Returns video display rectangle + * + * This is the rectangle which includes both the video content itself, plus + * any border bars which added around the video. The aspect ratio of this + * rectangle therefore may differ from that of the nativeSize(). + * + * If running on a platform supporting video rendering to graphics + * surfaces (i.e. if VIDEOOUTPUT_GRAPHICS_SURFACES is defined), the return + * value is the relative to the origin of the video window. Otherwise, the + * return value is an absolute screen rectangle. + * + * Note that this rectangle can extend beyond the bounds of the screen or of + * the video window. + * + * When using QVideoWindowControl, the size of the extentRect matches the + * displayRect; if running on a platform which supports only DSA rendering, + * the origin differs as described above. + * + * See also clipRect, contentRect + */ + virtual QRect extentRect() const = 0; + + /* + * Returns video clipping rectangle + * + * This rectangle is the intersection of displayRect() with either the window + * rectangle (on platforms supporting video rendering to graphics surfaces), + * or the screen rectangle (on platforms supporting only DSA video rendering). + * + * If running on a platform supporting video rendering to graphics + * surfaces (i.e. if VIDEOOUTPUT_GRAPHICS_SURFACES is defined), the return + * value is the relative to the origin of the video window. Otherwise, the + * return value is an absolute screen rectangle. + * + * See also extentRect, contentRect + */ + QRect clipRect() const; + + /* + * Returns video content rectangle + * + * This is the rectangle in which the video content is rendered, i.e. its + * size is that of extentRect() minus border bars. The aspect ratio of this + * rectangle is therefore equal to that of the nativeSize(). + * + * This rectangle is always relative to the window in which video is rendered. + * + * See also extentRect, clipRect + */ + QRect contentRect() const; + + void setFullScreen(bool enabled); + bool isFullScreen() const; + + void setVisible(bool visible); + bool isVisible() const; + + void setAspectRatioMode(Qt::AspectRatioMode mode); + Qt::AspectRatioMode aspectRatioMode() const; + + const QSize& nativeSize() const; + + void setPaintingEnabled(bool enabled); + bool isPaintingEnabled() const; + + void setRotation(qreal value); + qreal rotation() const; + +public slots: + void setNativeSize(const QSize &size); + + /* + * Provide new video frame + * + * If setPaintingEnabled(true) has been called, the frame is rendered to + * the display. + * + * If a QWidget is available to the control (i.e. the control is a + * QVideoWidgetControl), the frame is rendered via QPainter. Otherwise, the + * frame is blitted to the window using native Symbian drawing APIs. + */ + virtual void setFrame(const CFbsBitmap &bitmap) = 0; + +signals: + void windowHandleChanged(RWindow *); + void displayRectChanged(QRect extentRect, QRect clipRect); + void fullScreenChanged(bool); + void visibilityChanged(bool); + void aspectRatioModeChanged(Qt::AspectRatioMode); + void nativeSizeChanged(QSize); + void contentRectChanged(QRect); + void paintingEnabledChanged(bool); + void rotationChanged(qreal); + void beginVideoWindowNativePaint(); + void endVideoWindowNativePaint(); + +private slots: + void updateContentRect(); + +private: + QRect m_contentRect; + bool m_fullScreen; + bool m_visible; + Qt::AspectRatioMode m_aspectRatioMode; + QSize m_nativeSize; + bool m_paintingEnabled; + qreal m_rotation; +}; + +#endif // S60VIDEODISPLAY_H + diff --git a/src/plugins/symbian/videooutput/s60videooutpututils.cpp b/src/plugins/symbian/videooutput/s60videooutpututils.cpp new file mode 100644 index 000000000..feac346d1 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videooutpututils.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "s60videooutpututils.h" + +#ifdef PRIVATE_QTGUI_HEADERS_AVAILABLE +#if QT_VERSION >= 0x040601 && !defined(__WINSCW__) +#include +#include +#define USE_PRIVATE_QTGUI_APIS +#endif // QT_VERSION >= 0x040601 && !defined(__WINSCW__) +#endif // PRIVATE_QTGUI_HEADERS_AVAILABLE + +namespace S60VideoOutputUtils +{ + +void setIgnoreFocusChanged(QWidget *widget) +{ +#ifdef USE_PRIVATE_QTGUI_APIS + // Warning: if this flag is not set, the application may crash due to + // CGraphicsContext being called from within the context of + // QGraphicsVideoItem::paint(), when the video widget is shown. + static_cast(widget->winId())->setIgnoreFocusChanged(true); +#else + Q_UNUSED(widget) +#endif +} + +void setNativePaintMode(QWidget *widget, NativePaintMode mode) +{ +#ifdef USE_PRIVATE_QTGUI_APIS + QWidgetPrivate *widgetPrivate = qt_widget_private(widget->window()); + widgetPrivate->createExtra(); + QWExtra::NativePaintMode widgetMode = QWExtra::Default; + switch (mode) { + case Default: + break; + case ZeroFill: + widgetMode = QWExtra::ZeroFill; + break; + case BlitWriteAlpha: +#if QT_VERSION >= 0x040704 + widgetMode = QWExtra::BlitWriteAlpha; +#endif + break; + case Disable: + widgetMode = QWExtra::Disable; + break; + } + widgetPrivate->extraData()->nativePaintMode = widgetMode; +#else + Q_UNUSED(widget) + Q_UNUSED(mode) +#endif +} + +void setNativePaintMode(WId wid, NativePaintMode mode) +{ +#ifdef USE_PRIVATE_QTGUI_APIS + QWidget *window = static_cast(wid)->widget()->window(); + setNativePaintMode(window, mode); +#else + Q_UNUSED(wid) + Q_UNUSED(mode) +#endif +} + +void setReceiveNativePaintEvents(QWidget *widget, bool enabled) +{ +#ifdef USE_PRIVATE_QTGUI_APIS + QWidgetPrivate *widgetPrivate = qt_widget_private(widget); + widgetPrivate->createExtra(); + widgetPrivate->extraData()->receiveNativePaintEvents = enabled; +#else + Q_UNUSED(widget) + Q_UNUSED(enabled) +#endif +} + +} // namespace S60VideoOutputUtils + diff --git a/src/plugins/symbian/videooutput/s60videooutpututils.h b/src/plugins/symbian/videooutput/s60videooutpututils.h new file mode 100644 index 000000000..6d83062c3 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videooutpututils.h @@ -0,0 +1,71 @@ +/** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60VIDEOOUTPUTUTILS_H +#define S60VIDEOOUTPUTUTILS_H + +#include +#include + +QT_FORWARD_DECLARE_CLASS(QWidget) + +/* + * Helper functions used by video output. + */ +namespace S60VideoOutputUtils +{ + +enum NativePaintMode +{ + Default, + ZeroFill, + BlitWriteAlpha, + Disable +}; + +void setIgnoreFocusChanged(QWidget *widget); +void setNativePaintMode(QWidget *widget, NativePaintMode mode); +void setNativePaintMode(WId wid, NativePaintMode mode); +void setReceiveNativePaintEvents(QWidget *widget, bool enabled); + +} // namespace S60VideoOutputUtils + +#endif // S60VIDEOOUTPUTUTILS_H + diff --git a/src/plugins/symbian/videooutput/s60videowidget.cpp b/src/plugins/symbian/videooutput/s60videowidget.cpp new file mode 100644 index 000000000..44c0919ba --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowidget.cpp @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "s60videowidget.h" +#include "s60videooutpututils.h" + +#include +#include +#include +#include + +#include // CCoeEnv +#include // CCoeControl +#include + +using namespace S60VideoOutputUtils; + +const int NullOrdinalPosition = -1; + +S60VideoWidget::S60VideoWidget(QWidget *parent) +: QWidget(parent) +, m_pixmap(NULL) +, m_paintingEnabled(false) +, m_topWinId(0) +, m_ordinalPosition(NullOrdinalPosition) +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + setPalette(QPalette(Qt::black)); + setAutoFillBackground(false); + if (!parent) + setProperty("_q_DummyWindowSurface", true); + S60VideoOutputUtils::setIgnoreFocusChanged(this); +} + +S60VideoWidget::~S60VideoWidget() +{ + +} + +bool S60VideoWidget::event(QEvent *event) +{ + if (event->type() == QEvent::WinIdChange) + updateOrdinalPosition(); + return QWidget::event(event); +} + +void S60VideoWidget::paintEvent(QPaintEvent *event) +{ + if (m_paintingEnabled && m_pixmap) { + QPainter painter(this); + if (m_pixmap->size() != m_contentRect.size()) + qWarning("pixmap size does not match expected value"); + painter.drawPixmap(m_contentRect.topLeft(), *m_pixmap); + } +} + +void S60VideoWidget::setVisible(bool visible) +{ + queueReactivateWindow(); + QWidget::setVisible(visible); +} + + +WId S60VideoWidget::videoWinId() const +{ + WId wid = 0; + if (internalWinId()) + wid = internalWinId(); + else if (parentWidget() && effectiveWinId()) + wid = effectiveWinId(); + return wid; +} + +void S60VideoWidget::setPixmap(const QPixmap *pixmap) +{ + m_pixmap = pixmap; + update(); +} + +void S60VideoWidget::setContentRect(const QRect &rect) +{ + if (m_contentRect != rect) { + m_contentRect = rect; + update(); + } +} + +void S60VideoWidget::setWindowBackgroundColor() +{ + if (WId wid = internalWinId()) + static_cast(wid->DrawableWindow())->SetBackgroundColor(TRgb(0, 0, 0, 255)); +} + +WId S60VideoWidget::topWinId() const +{ + return m_topWinId; +} + +void S60VideoWidget::setTopWinId(WId id) +{ + m_topWinId = id; + updateOrdinalPosition(); +#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES + // This function may be called from a paint event, so defer any window + // manipulation until painting is complete. + QMetaObject::invokeMethod(this, "setWindowsNonFading", Qt::QueuedConnection); +#endif +} + +void S60VideoWidget::setOrdinalPosition(int ordinalPosition) +{ + m_ordinalPosition = ordinalPosition; + updateOrdinalPosition(); +} + +int S60VideoWidget::ordinalPosition() const +{ + return m_ordinalPosition; +} + +void S60VideoWidget::updateOrdinalPosition() +{ + if ((m_ordinalPosition != NullOrdinalPosition) && m_topWinId) { + if (WId wid = videoWinId()) { + int topOrdinalPosition = m_topWinId->DrawableWindow()->OrdinalPosition(); + queueReactivateWindow(); + wid->DrawableWindow()->SetOrdinalPosition(m_ordinalPosition + topOrdinalPosition); + } + } +} + +void S60VideoWidget::queueReactivateWindow() +{ + if (!parent()) { + if (QWidget *activeWindow = QApplication::activeWindow()) + QMetaObject::invokeMethod(this, "reactivateWindow", Qt::QueuedConnection, + Q_ARG(QWidget *, activeWindow)); + } +} + +void S60VideoWidget::reactivateWindow(QWidget *widget) +{ + widget->activateWindow(); +} + +void S60VideoWidget::setWindowsNonFading() +{ + winId()->DrawableWindow()->SetNonFading(ETrue); + if (m_topWinId) + m_topWinId->DrawableWindow()->SetNonFading(ETrue); +} + +void S60VideoWidget::beginNativePaintEvent(const QRect &rect) +{ + Q_UNUSED(rect) + emit beginVideoWidgetNativePaint(); +} + +void S60VideoWidget::endNativePaintEvent(const QRect &rect) +{ + Q_UNUSED(rect) + CCoeEnv::Static()->WsSession().Flush(); + emit endVideoWidgetNativePaint(); +} + +void S60VideoWidget::setPaintingEnabled(bool enabled) +{ + if (enabled) { +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + setAttribute(Qt::WA_OpaquePaintEvent, false); + setAttribute(Qt::WA_NoSystemBackground, false); + S60VideoOutputUtils::setReceiveNativePaintEvents(this, false); + S60VideoOutputUtils::setNativePaintMode(this, Default); +#else + S60VideoOutputUtils::setNativePaintMode(this, Default); +#endif // !VIDEOOUTPUT_GRAPHICS_SURFACES + } else { +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + setAttribute(Qt::WA_OpaquePaintEvent, true); + setAttribute(Qt::WA_NoSystemBackground, true); + S60VideoOutputUtils::setReceiveNativePaintEvents(this, true); + S60VideoOutputUtils::setNativePaintMode(this, ZeroFill); +#else + S60VideoOutputUtils::setNativePaintMode(this, Disable); +#endif // !VIDEOOUTPUT_GRAPHICS_SURFACES + winId(); // Create native window handle + } + m_paintingEnabled = enabled; + setWindowBackgroundColor(); +} + +void S60VideoWidget::setFullScreen(bool enabled) +{ + if (enabled) + showFullScreen(); + else + showMaximized(); +} + diff --git a/src/plugins/symbian/videooutput/s60videowidget.h b/src/plugins/symbian/videooutput/s60videowidget.h new file mode 100644 index 000000000..30e7a3bd0 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowidget.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60VIDEOWIDGET_H +#define S60VIDEOWIDGET_H + +#include + +QT_USE_NAMESPACE + +class S60VideoWidget : public QWidget +{ + Q_OBJECT +public: + S60VideoWidget(QWidget *parent = 0); + ~S60VideoWidget(); + + // QWidget + bool event(QEvent *event); + void paintEvent(QPaintEvent *event); + void setVisible(bool visible); + + WId videoWinId() const; + void setPixmap(const QPixmap *pixmap); + void setWindowBackgroundColor(); + void setTopWinId(WId id); + WId topWinId() const; + void setOrdinalPosition(int ordinalPosition); + int ordinalPosition() const; + +public slots: + void beginNativePaintEvent(const QRect &rect); + void endNativePaintEvent(const QRect &rect); + void setPaintingEnabled(bool enabled); + void setFullScreen(bool enabled); + void setContentRect(const QRect &rect); + +signals: + void beginVideoWidgetNativePaint(); + void endVideoWidgetNativePaint(); + +private: + void updateOrdinalPosition(); + void queueReactivateWindow(); + +private slots: + void reactivateWindow(QWidget *window); + void setWindowsNonFading(); + +private: + const QPixmap *m_pixmap; + QRect m_contentRect; + bool m_paintingEnabled; + WId m_topWinId; + int m_ordinalPosition; +}; + +#endif // S60VIDEOWIDGET_H + diff --git a/src/plugins/symbian/videooutput/s60videowidgetcontrol.cpp b/src/plugins/symbian/videooutput/s60videowidgetcontrol.cpp new file mode 100644 index 000000000..46cb2963e --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowidgetcontrol.cpp @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "s60videowidgetcontrol.h" +#include "s60videowidgetdisplay.h" + +S60VideoWidgetControl::S60VideoWidgetControl(QObject *parent) +: QVideoWidgetControl(parent) +, m_display(new S60VideoWidgetDisplay(this)) +{ + connect(m_display, SIGNAL(nativeSizeChanged(QSize)), + this, SIGNAL(nativeSizeChanged())); +} + +S60VideoWidgetControl::~S60VideoWidgetControl() +{ + +} + +QWidget *S60VideoWidgetControl::videoWidget() +{ + return m_display->widget(); +} + +Qt::AspectRatioMode S60VideoWidgetControl::aspectRatioMode() const +{ + return m_display->aspectRatioMode(); +} + +void S60VideoWidgetControl::setAspectRatioMode(Qt::AspectRatioMode ratio) +{ + m_display->setAspectRatioMode(ratio); +} + +bool S60VideoWidgetControl::isFullScreen() const +{ + return m_display->isFullScreen(); +} + +void S60VideoWidgetControl::setFullScreen(bool fullScreen) +{ + m_display->setFullScreen(fullScreen); +} + +int S60VideoWidgetControl::brightness() const +{ + return 0; +} + +void S60VideoWidgetControl::setBrightness(int brightness) +{ + Q_UNUSED(brightness); +} + +int S60VideoWidgetControl::contrast() const +{ + return 0; +} + +void S60VideoWidgetControl::setContrast(int contrast) +{ + Q_UNUSED(contrast); +} + +int S60VideoWidgetControl::hue() const +{ + return 0; +} + +void S60VideoWidgetControl::setHue(int hue) +{ + Q_UNUSED(hue); +} + +int S60VideoWidgetControl::saturation() const +{ + return 0; +} + +void S60VideoWidgetControl::setSaturation(int saturation) +{ + Q_UNUSED(saturation); +} + +S60VideoWidgetDisplay *S60VideoWidgetControl::display() const +{ + return m_display; +} + +void S60VideoWidgetControl::setTopWinId(WId id) +{ + m_display->setTopWinId(id); +} + +WId S60VideoWidgetControl::topWinId() const +{ + return m_display->topWinId(); +} + +int S60VideoWidgetControl::ordinalPosition() const +{ + return m_display->ordinalPosition(); +} + +void S60VideoWidgetControl::setOrdinalPosition(int ordinalPosition) +{ + m_display->setOrdinalPosition(ordinalPosition); +} + +const QRect &S60VideoWidgetControl::extentRect() const +{ + return m_display->explicitExtentRect(); +} + +void S60VideoWidgetControl::setExtentRect(const QRect &rect) +{ + m_display->setExplicitExtentRect(rect); +} + +QSize S60VideoWidgetControl::nativeSize() const +{ + return m_display->nativeSize(); +} + +qreal S60VideoWidgetControl::rotation() const +{ + return m_display->rotation(); +} + +void S60VideoWidgetControl::setRotation(qreal value) +{ + m_display->setRotation(value); +} diff --git a/src/plugins/symbian/videooutput/s60videowidgetcontrol.h b/src/plugins/symbian/videooutput/s60videowidgetcontrol.h new file mode 100644 index 000000000..eb103b6b8 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowidgetcontrol.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60VIDEOWIDGETCONTROL_H +#define S60VIDEOWIDGETCONTROL_H + +#include + +QT_USE_NAMESPACE + +class S60VideoWidgetDisplay; + +class S60VideoWidgetControl : public QVideoWidgetControl +{ + Q_OBJECT + + /** + * WId of the topmost window in the application, used to calculate the + * absolute ordinal position of the video widget. + * This is used by the "window" implementation of QGraphicsVideoItem. + */ + Q_PROPERTY(WId topWinId READ topWinId WRITE setTopWinId) + + /** + * Ordinal position of the video widget, relative to the topmost window + * in the application. If both the topWinId property and the ordinalPosition + * property are set, the absolute ordinal position of the video widget is + * the sum of the topWinId ordinal position and the value of the + * ordinalPosition property. + * This is used by the "window" implementation of QGraphicsVideoItem. + */ + Q_PROPERTY(int ordinalPosition READ ordinalPosition WRITE setOrdinalPosition) + + /** + * Extent of the video, relative to this video widget. + * This is used by the "window" implementation of QGraphicsVideoItem. + */ + Q_PROPERTY(QRect extentRect READ extentRect WRITE setExtentRect) + + /** + * Native size of video. + * This is used by the "window" implementation of QGraphicsVideoItem. + */ + Q_PROPERTY(QSize nativeSize READ nativeSize) + + /** + * Rotation to be applied to video. + * Angle is measured in degrees, with positive values counter-clockwise. + * Zero is at 12 o'clock. + */ + Q_PROPERTY(qreal rotation READ rotation WRITE setRotation) + +public: + S60VideoWidgetControl(QObject *parent); + ~S60VideoWidgetControl(); + +public: + // QVideoWidgetControl + QWidget *videoWidget(); + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode ratio); + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + int brightness() const; + void setBrightness(int brightness); + int contrast() const; + void setContrast(int contrast); + int hue() const; + void setHue(int hue); + int saturation() const; + void setSaturation(int saturation); + + S60VideoWidgetDisplay *display() const; + + WId topWinId() const; + void setTopWinId(WId id); + int ordinalPosition() const; + void setOrdinalPosition(int ordinalPosition); + const QRect &extentRect() const; + void setExtentRect(const QRect &rect); + QSize nativeSize() const; + qreal rotation() const; + void setRotation(qreal value); + +signals: + void nativeSizeChanged(); + +private: + S60VideoWidgetDisplay *m_display; +}; + +#endif // S60VIDEOWIDGETCONTROL_H + diff --git a/src/plugins/symbian/videooutput/s60videowidgetdisplay.cpp b/src/plugins/symbian/videooutput/s60videowidgetdisplay.cpp new file mode 100644 index 000000000..de7440dbf --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowidgetdisplay.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "s60videowidget.h" +#include "s60videowidgetdisplay.h" +#include +#include +#include +#include + +S60VideoWidgetDisplay::S60VideoWidgetDisplay(QObject *parent) +: S60VideoDisplay(parent) +, m_widget(new S60VideoWidget) +{ + connect(this, SIGNAL(paintingEnabledChanged(bool)), m_widget, SLOT(setPaintingEnabled(bool))); + connect(this, SIGNAL(fullScreenChanged(bool)), m_widget, SLOT(setFullScreen(bool))); + connect(this, SIGNAL(contentRectChanged(const QRect&)), m_widget, SLOT(setContentRect(const QRect &))); +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + connect(m_widget, SIGNAL(beginVideoWidgetNativePaint()), this, SIGNAL(beginVideoWindowNativePaint())); + connect(m_widget, SIGNAL(endVideoWidgetNativePaint()), this, SIGNAL(endVideoWindowNativePaint())); +#endif + m_widget->installEventFilter(this); + m_widget->setPaintingEnabled(false); +} + +S60VideoWidgetDisplay::~S60VideoWidgetDisplay() +{ + // Notify observers that window is about to be destroyed + QScopedPointer widget(m_widget); + m_widget = 0; + emit windowHandleChanged(windowHandle()); + // Widget will be deleted by QScopedPointer +} + +bool S60VideoWidgetDisplay::eventFilter(QObject *object, QEvent *e) +{ + if (object == m_widget) { + switch (e->type()) { + case QEvent::ParentChange: + if (QWidget *parent = m_widget->parentWidget()) + parent->setProperty("_q_DummyWindowSurface", true); + break; + case QEvent::WinIdChange: + m_widget->setWindowBackgroundColor(); + emit windowHandleChanged(windowHandle()); + break; + case QEvent::Resize: + emit displayRectChanged(extentRect(), clipRect()); + break; +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + case QEvent::Move: + // TODO: this is insufficient - we also need to respond to changes in + // the position of ancestor widgets + emit displayRectChanged(extentRect(), clipRect()); + break; +#endif + case QEvent::Show: + emit windowHandleChanged(windowHandle()); + emit visibilityChanged(true); + break; + case QEvent::Hide: + emit visibilityChanged(false); + break; + default: + // Do nothing + break; + } + } + return false; +} + +WId S60VideoWidgetDisplay::winId() const +{ + return m_widget ? m_widget->videoWinId() : 0; +} + +QRect S60VideoWidgetDisplay::extentRect() const +{ + QRect rect; + if (const RWindow *window = windowHandle()) { + const TSize size = window ? window->Size() : TSize(); + if (m_explicitExtentRect.isValid()) + rect = m_explicitExtentRect; + else + rect = QRect(0, 0, size.iWidth, size.iHeight); +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + const TPoint pos = window ? window->AbsPosition() : TPoint(); + rect.moveTopLeft(QPoint(pos.iX, pos.iY)); +#endif + } + return rect; +} + +void S60VideoWidgetDisplay::setFrame(const CFbsBitmap &bitmap) +{ + m_pixmap = QPixmap::fromSymbianCFbsBitmap(const_cast(&bitmap)); + m_widget->setPixmap(&m_pixmap); +} + +QWidget *S60VideoWidgetDisplay::widget() const +{ + return m_widget; +} + +void S60VideoWidgetDisplay::setTopWinId(WId id) +{ + m_widget->setTopWinId(id); +} + +WId S60VideoWidgetDisplay::topWinId() const +{ + return m_widget->topWinId(); +} + +void S60VideoWidgetDisplay::setOrdinalPosition(int ordinalPosition) +{ + m_widget->setOrdinalPosition(ordinalPosition); +} + +int S60VideoWidgetDisplay::ordinalPosition() const +{ + return m_widget->ordinalPosition(); +} + +const QRect &S60VideoWidgetDisplay::explicitExtentRect() const +{ + return m_explicitExtentRect; +} + +void S60VideoWidgetDisplay::setExplicitExtentRect(const QRect &rect) +{ + if (rect != m_explicitExtentRect) { + m_explicitExtentRect = rect; + emit displayRectChanged(extentRect(), clipRect()); + } +} diff --git a/src/plugins/symbian/videooutput/s60videowidgetdisplay.h b/src/plugins/symbian/videooutput/s60videowidgetdisplay.h new file mode 100644 index 000000000..d3d92d953 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowidgetdisplay.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60VIDEOWIDGETDISPLAY_H +#define S60VIDEOWIDGETDISPLAY_H + +#include "s60videodisplay.h" +#include +#include + +class CFbsBitmap; +class S60VideoWidget; +class QWidget; + +QT_USE_NAMESPACE + +class S60VideoWidgetDisplay : public S60VideoDisplay +{ + Q_OBJECT +public: + S60VideoWidgetDisplay(QObject *parent); + ~S60VideoWidgetDisplay(); + + // QObject + bool eventFilter(QObject *object, QEvent *e); + + // S60VideoDisplay + WId winId() const; + QRect extentRect() const; + void setFrame(const CFbsBitmap &bitmap); + + QWidget *widget() const; + WId topWinId() const; + void setTopWinId(WId id); + void setOrdinalPosition(int ordinalPosition); + int ordinalPosition() const; + const QRect &explicitExtentRect() const; + void setExplicitExtentRect(const QRect &rect); + +private: + S60VideoWidget *m_widget; + QPixmap m_pixmap; + QRect m_explicitExtentRect; +}; + +#endif // S60VIDEOWIDGETDISPLAY_H + diff --git a/src/plugins/symbian/videooutput/s60videowindowcontrol.cpp b/src/plugins/symbian/videooutput/s60videowindowcontrol.cpp new file mode 100644 index 000000000..db33a5f32 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowindowcontrol.cpp @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "s60videowindowcontrol.h" +#include "s60videowindowdisplay.h" + +S60VideoWindowControl::S60VideoWindowControl(QObject *parent) +: QVideoWindowControl(parent) +, m_display(new S60VideoWindowDisplay(this)) +{ + connect(m_display, SIGNAL(nativeSizeChanged(QSize)), + this, SIGNAL(nativeSizeChanged())); + connect(m_display, SIGNAL(fullScreenChanged(bool)), + this, SIGNAL(fullScreenChanged(bool))); +} + +S60VideoWindowControl::~S60VideoWindowControl() +{ + +} + +WId S60VideoWindowControl::winId() const +{ + return m_display->winId(); +} + +void S60VideoWindowControl::setWinId(WId id) +{ + m_display->setWinId(id); +} + +QRect S60VideoWindowControl::displayRect() const +{ + return m_display->displayRect(); +} + +void S60VideoWindowControl::setDisplayRect(const QRect &rect) +{ + m_display->setDisplayRect(rect); +} + +Qt::AspectRatioMode S60VideoWindowControl::aspectRatioMode() const +{ + return m_display->aspectRatioMode(); +} + +void S60VideoWindowControl::setAspectRatioMode(Qt::AspectRatioMode ratio) +{ + m_display->setAspectRatioMode(ratio); +} + +QSize S60VideoWindowControl::customAspectRatio() const +{ + return QSize(); +} + +void S60VideoWindowControl::setCustomAspectRatio(const QSize &customRatio) +{ + Q_UNUSED(customRatio); +} + +void S60VideoWindowControl::repaint() +{ + m_display->repaint(); +} + +int S60VideoWindowControl::brightness() const +{ + return 0; +} + +void S60VideoWindowControl::setBrightness(int brightness) +{ + Q_UNUSED(brightness) +} + +int S60VideoWindowControl::contrast() const +{ + return 0; +} + +void S60VideoWindowControl::setContrast(int contrast) +{ + Q_UNUSED(contrast) +} + +int S60VideoWindowControl::hue() const +{ + return 0; +} + +void S60VideoWindowControl::setHue(int hue) +{ + Q_UNUSED(hue) +} + +int S60VideoWindowControl::saturation() const +{ + return 0; +} + +void S60VideoWindowControl::setSaturation(int saturation) +{ + Q_UNUSED(saturation) +} + +bool S60VideoWindowControl::isFullScreen() const +{ + return m_display->isFullScreen(); +} + +void S60VideoWindowControl::setFullScreen(bool fullScreen) +{ + m_display->setFullScreen(fullScreen); +} + +QSize S60VideoWindowControl::nativeSize() const +{ + return m_display->nativeSize(); +} + +void S60VideoWindowControl::refreshDisplay() +{ + m_display->refreshDisplay(); +} + +S60VideoWindowDisplay *S60VideoWindowControl::display() const +{ + return m_display; +} + +qreal S60VideoWindowControl::rotation() const +{ + return m_display->rotation(); +} + +void S60VideoWindowControl::setRotation(qreal value) +{ + m_display->setRotation(value); +} diff --git a/src/plugins/symbian/videooutput/s60videowindowcontrol.h b/src/plugins/symbian/videooutput/s60videowindowcontrol.h new file mode 100644 index 000000000..a62d29a13 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowindowcontrol.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60VIDEOWINDOWCONTROL_H +#define S60VIDEOWINDOWCONTROL_H + +#include + +class S60VideoWindowDisplay; + +QT_USE_NAMESPACE + +class S60VideoWindowControl : public QVideoWindowControl +{ + Q_OBJECT + + /** + * Rotation to be applied to video. + * Angle is measured in degrees, with positive values counter-clockwise. + * Zero is at 12 o'clock. + */ + Q_PROPERTY(qreal rotation READ rotation WRITE setRotation) + +public: + S60VideoWindowControl(QObject *parent); + ~S60VideoWindowControl(); + +public: + // QVideoWindowControl + WId winId() const; + void setWinId(WId id); + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + void repaint(); + QSize nativeSize() const; + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + QSize customAspectRatio() const; + void setCustomAspectRatio(const QSize &customRatio); + int brightness() const; + void setBrightness(int brightness); + int contrast() const; + void setContrast(int contrast); + int hue() const; + void setHue(int hue); + int saturation() const; + void setSaturation(int saturation); + + S60VideoWindowDisplay *display() const; + + qreal rotation() const; + void setRotation(qreal value); + +public slots: + void refreshDisplay(); + +private: + S60VideoWindowDisplay *m_display; +}; + +#endif // S60VIDEOWINDOWCONTROL_H + diff --git a/src/plugins/symbian/videooutput/s60videowindowdisplay.cpp b/src/plugins/symbian/videooutput/s60videowindowdisplay.cpp new file mode 100644 index 000000000..a8bdb8b4a --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowindowdisplay.cpp @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "s60videowindowdisplay.h" +#include "s60videooutpututils.h" +#include +#include +#include + +using namespace S60VideoOutputUtils; + +S60VideoWindowDisplay::S60VideoWindowDisplay(QObject *parent) +: S60VideoDisplay(parent) +, m_winId(0) +, m_bitmap(0) +{ + parent->setProperty("colorKey", Qt::transparent); +} + +S60VideoWindowDisplay::~S60VideoWindowDisplay() +{ + +} + +WId S60VideoWindowDisplay::winId() const +{ + return m_winId; +} + +QRect S60VideoWindowDisplay::extentRect() const +{ + QRect rect = displayRect(); +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + if (RWindow *window = windowHandle()) { + const TPoint windowPos = window->AbsPosition(); + rect.translate(windowPos.iX, windowPos.iY); + } +#endif // VIDEOOUTPUT_GRAPHICS_SURFACES + return rect; +} + +void S60VideoWindowDisplay::setFrame(const CFbsBitmap &bitmap) +{ + m_bitmap = const_cast(&bitmap); + if (m_winId) { + // Blit the bitmap into the native window owned by m_winId + CWindowGc &gc = m_winId->SystemGc(); + RWindow *window = windowHandle(); + gc.Activate(*window); + const QPoint offsetQ = displayRect().topLeft() + contentRect().topLeft(); + const TPoint offsetT(offsetQ.x(), offsetQ.y()); + const TRect winRect(offsetT, m_bitmap->SizeInPixels()); + window->BeginRedraw(winRect); + gc.BitBlt(offsetT, m_bitmap); + window->EndRedraw(); + gc.Deactivate(); + } +} + +void S60VideoWindowDisplay::setWinId(WId id) +{ + if (m_winId != id) { + m_winId = id; + if (m_winId) { + static_cast(m_winId->DrawableWindow())->SetBackgroundColor(TRgb(0, 0, 0, 0)); +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + if (QSysInfo::s60Version() >= QSysInfo::SV_S60_5_0) + S60VideoOutputUtils::setNativePaintMode(m_winId, BlitWriteAlpha); +#endif // !VIDEOOUTPUT_GRAPHICS_SURFACES + } + emit windowHandleChanged(windowHandle()); + } +} + +void S60VideoWindowDisplay::setDisplayRect(const QRect &rect) +{ + if (m_displayRect != rect) { + // If QGraphicsVideoItem moves out of screen, display rect is invalidated + if (rect == QRect(QPoint(-1,-1), QSize(1,1))) + emit visibilityChanged(false); + else + emit visibilityChanged(true); + m_displayRect = rect; + emit displayRectChanged(extentRect(), clipRect()); + } +} + +QRect S60VideoWindowDisplay::displayRect() const +{ + return m_displayRect; +} + +void S60VideoWindowDisplay::repaint() +{ + // TODO +} + +void S60VideoWindowDisplay::refreshDisplay() +{ + emit displayRectChanged(extentRect(), clipRect()); +} + diff --git a/src/plugins/symbian/videooutput/s60videowindowdisplay.h b/src/plugins/symbian/videooutput/s60videowindowdisplay.h new file mode 100644 index 000000000..8e749dcf3 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowindowdisplay.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef S60VIDEOWINDOWDISPLAY_H +#define S60VIDEOWINDOWDISPLAY_H + +#include "s60videodisplay.h" + +QT_USE_NAMESPACE + +class S60VideoWindowDisplay : public S60VideoDisplay +{ +public: + S60VideoWindowDisplay(QObject *parent); + ~S60VideoWindowDisplay(); + + // S60VideoDisplay + WId winId() const; + QRect extentRect() const; + void setFrame(const CFbsBitmap &bitmap); + + void setWinId(WId id); + void setDisplayRect(const QRect &rect); + QRect displayRect() const; + void repaint(); + void refreshDisplay(); + +private: + WId m_winId; + QRect m_displayRect; + CFbsBitmap *m_bitmap; +}; + +#endif // S60VIDEOWINDOWDISPLAY_H + diff --git a/src/plugins/symbian/videooutput/videooutput.pri b/src/plugins/symbian/videooutput/videooutput.pri new file mode 100644 index 000000000..13aa7a0fc --- /dev/null +++ b/src/plugins/symbian/videooutput/videooutput.pri @@ -0,0 +1,37 @@ +INCLUDEPATH += $$PWD + +message("VideoOutput: using common implementation") + +contains(surfaces_s60_enabled, yes) { + message("VideoOutput: graphics surface rendering supported") + DEFINES += VIDEOOUTPUT_GRAPHICS_SURFACES +} else { + message("VideoOutput: no graphics surface rendering support - DSA only") +} + +exists($$[QT_INSTALL_HEADERS]/QtGui/private/qwidget_p.h) { + DEFINES += PRIVATE_QTGUI_HEADERS_AVAILABLE + message("VideoOutput: private QtGui headers are available") +} else { + message("VideoOutput: private QtGui headers not available - video and viewfinder may not be rendered correctly") +} + +HEADERS += $$PWD/s60videodisplay.h \ + $$PWD/s60videooutpututils.h \ + $$PWD/s60videowidget.h \ + $$PWD/s60videowidgetcontrol.h \ + $$PWD/s60videowidgetdisplay.h \ + $$PWD/s60videowindowcontrol.h \ + $$PWD/s60videowindowdisplay.h + +SOURCES += $$PWD/s60videodisplay.cpp \ + $$PWD/s60videooutpututils.cpp \ + $$PWD/s60videowidget.cpp \ + $$PWD/s60videowidgetcontrol.cpp \ + $$PWD/s60videowidgetdisplay.cpp \ + $$PWD/s60videowindowcontrol.cpp \ + $$PWD/s60videowindowdisplay.cpp + +LIBS *= -lcone +LIBS *= -lws32 + diff --git a/src/plugins/v4l/radio/radio.pri b/src/plugins/v4l/radio/radio.pri new file mode 100644 index 000000000..04c6720c5 --- /dev/null +++ b/src/plugins/v4l/radio/radio.pri @@ -0,0 +1,29 @@ +INCLUDEPATH += $$PWD + +maemo5 { + QT += dbus + + CONFIG += link_pkgconfig + + PKGCONFIG += gstreamer-0.10 + + LIBS += -lasound + + HEADERS += \ + $$PWD/v4lradiocontrol_maemo5.h \ + $$PWD/v4lradioservice.h + + SOURCES += \ + $$PWD/v4lradiocontrol_maemo5.cpp \ + $$PWD/v4lradioservice.cpp + +} else { + +HEADERS += \ + $$PWD/v4lradiocontrol.h \ + $$PWD/v4lradioservice.h + +SOURCES += \ + $$PWD/v4lradiocontrol.cpp \ + $$PWD/v4lradioservice.cpp +} diff --git a/src/plugins/v4l/radio/v4lradiocontrol.cpp b/src/plugins/v4l/radio/v4lradiocontrol.cpp new file mode 100644 index 000000000..1b698279a --- /dev/null +++ b/src/plugins/v4l/radio/v4lradiocontrol.cpp @@ -0,0 +1,538 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "v4lradiocontrol.h" +#include "v4lradioservice.h" + +#include + +#include + +#include +#include "linux/videodev2.h" + +#include +#include +#include +#include +#include +#include + +V4LRadioControl::V4LRadioControl(QObject *parent) + :QRadioTunerControl(parent) +{ + fd = -1; + initRadio(); + muted = false; + stereo = false; + m_error = false; + sig = 0; + currentBand = QRadioTuner::FM; + step = 100000; + scanning = false; + playTime.restart(); + timer = new QTimer(this); + timer->setInterval(200); + connect(timer,SIGNAL(timeout()),this,SLOT(search())); + timer->start(); +} + +V4LRadioControl::~V4LRadioControl() +{ + timer->stop(); + + if(fd > 0) + ::close(fd); +} + +bool V4LRadioControl::isAvailable() const +{ + return available; +} + +QtMultimediaKit::AvailabilityError V4LRadioControl::availabilityError() const +{ + if (fd > 0) + return QtMultimediaKit::NoError; + else + return QtMultimediaKit::ResourceError; +} + +QRadioTuner::State V4LRadioControl::state() const +{ + return fd > 0 ? QRadioTuner::ActiveState : QRadioTuner::StoppedState; +} + +QRadioTuner::Band V4LRadioControl::band() const +{ + return currentBand; +} + +bool V4LRadioControl::isBandSupported(QRadioTuner::Band b) const +{ + QRadioTuner::Band bnd = (QRadioTuner::Band)b; + switch(bnd) { + case QRadioTuner::FM: + if(freqMin <= 87500000 && freqMax >= 108000000) + return true; + break; + case QRadioTuner::LW: + if(freqMin <= 148500 && freqMax >= 283500) + return true; + case QRadioTuner::AM: + if(freqMin <= 520000 && freqMax >= 1610000) + return true; + default: + if(freqMin <= 1711000 && freqMax >= 30000000) + return true; + } + + return false; +} + +void V4LRadioControl::setBand(QRadioTuner::Band b) +{ + if(freqMin <= 87500000 && freqMax >= 108000000 && b == QRadioTuner::FM) { + // FM 87.5 to 108.0 MHz, except Japan 76-90 MHz + currentBand = (QRadioTuner::Band)b; + step = 100000; // 100kHz steps + emit bandChanged(currentBand); + + } else if(freqMin <= 148500 && freqMax >= 283500 && b == QRadioTuner::LW) { + // LW 148.5 to 283.5 kHz, 9kHz channel spacing (Europe, Africa, Asia) + currentBand = (QRadioTuner::Band)b; + step = 1000; // 1kHz steps + emit bandChanged(currentBand); + + } else if(freqMin <= 520000 && freqMax >= 1610000 && b == QRadioTuner::AM) { + // AM 520 to 1610 kHz, 9 or 10kHz channel spacing, extended 1610 to 1710 kHz + currentBand = (QRadioTuner::Band)b; + step = 1000; // 1kHz steps + emit bandChanged(currentBand); + + } else if(freqMin <= 1711000 && freqMax >= 30000000 && b == QRadioTuner::SW) { + // SW 1.711 to 30.0 MHz, divided into 15 bands. 5kHz channel spacing + currentBand = (QRadioTuner::Band)b; + step = 500; // 500Hz steps + emit bandChanged(currentBand); + } + playTime.restart(); +} + +int V4LRadioControl::frequency() const +{ + return currentFreq; +} + +int V4LRadioControl::frequencyStep(QRadioTuner::Band b) const +{ + int step = 0; + + if(b == QRadioTuner::FM) + step = 100000; // 100kHz steps + else if(b == QRadioTuner::LW) + step = 1000; // 1kHz steps + else if(b == QRadioTuner::AM) + step = 1000; // 1kHz steps + else if(b == QRadioTuner::SW) + step = 500; // 500Hz steps + + return step; +} + +QPair V4LRadioControl::frequencyRange(QRadioTuner::Band b) const +{ + if(b == QRadioTuner::AM) + return qMakePair(520000,1710000); + else if(b == QRadioTuner::FM) + return qMakePair(87500000,108000000); + else if(b == QRadioTuner::SW) + return qMakePair(1711111,30000000); + else if(b == QRadioTuner::LW) + return qMakePair(148500,283500); + + return qMakePair(0,0); +} + +void V4LRadioControl::setFrequency(int frequency) +{ + qint64 f = frequency; + + v4l2_frequency freq; + + if(frequency < freqMin) + f = freqMax; + if(frequency > freqMax) + f = freqMin; + + if(fd > 0) { + memset( &freq, 0, sizeof( freq ) ); + // Use the first tuner + freq.tuner = 0; + if ( ioctl( fd, VIDIOC_G_FREQUENCY, &freq ) >= 0 ) { + if(low) { + // For low, freq in units of 62.5Hz, so convert from Hz to units. + freq.frequency = (int)(f/62.5); + } else { + // For high, freq in units of 62.5kHz, so convert from Hz to units. + freq.frequency = (int)(f/62500); + } + ioctl( fd, VIDIOC_S_FREQUENCY, &freq ); + currentFreq = f; + playTime.restart(); + emit frequencyChanged(currentFreq); + } + } + playTime.restart(); +} + +bool V4LRadioControl::isStereo() const +{ + return stereo; +} + +QRadioTuner::StereoMode V4LRadioControl::stereoMode() const +{ + return QRadioTuner::Auto; +} + +void V4LRadioControl::setStereoMode(QRadioTuner::StereoMode mode) +{ + bool stereo = true; + + if(mode == QRadioTuner::ForceMono) + stereo = false; + + v4l2_tuner tuner; + + memset( &tuner, 0, sizeof( tuner ) ); + + if ( ioctl( fd, VIDIOC_G_TUNER, &tuner ) >= 0 ) { + if(stereo) + tuner.audmode = V4L2_TUNER_MODE_STEREO; + else + tuner.audmode = V4L2_TUNER_MODE_MONO; + + if ( ioctl( fd, VIDIOC_S_TUNER, &tuner ) >= 0 ) { + emit stereoStatusChanged(stereo); + } + } +} + +int V4LRadioControl::signalStrength() const +{ + v4l2_tuner tuner; + + // Return the first tuner founds signal strength. + for ( int index = 0; index < tuners; ++index ) { + memset( &tuner, 0, sizeof( tuner ) ); + tuner.index = index; + if ( ioctl( fd, VIDIOC_G_TUNER, &tuner ) < 0 ) + continue; + if ( tuner.type != V4L2_TUNER_RADIO ) + continue; + // percentage signal strength + return tuner.signal*100/65535; + } + + return 0; +} + +int V4LRadioControl::volume() const +{ + v4l2_queryctrl queryctrl; + + if(fd > 0) { + memset( &queryctrl, 0, sizeof( queryctrl ) ); + queryctrl.id = V4L2_CID_AUDIO_VOLUME; + if ( ioctl( fd, VIDIOC_QUERYCTRL, &queryctrl ) >= 0 ) { + if(queryctrl.maximum == 0) { + return vol; + } else { + // percentage volume returned + return queryctrl.default_value*100/queryctrl.maximum; + } + } + } + return 0; +} + +void V4LRadioControl::setVolume(int volume) +{ + v4l2_queryctrl queryctrl; + + if(fd > 0) { + memset( &queryctrl, 0, sizeof( queryctrl ) ); + queryctrl.id = V4L2_CID_AUDIO_VOLUME; + if ( ioctl( fd, VIDIOC_QUERYCTRL, &queryctrl ) >= 0 ) { + v4l2_control control; + + if(queryctrl.maximum > 0) { + memset( &control, 0, sizeof( control ) ); + control.id = V4L2_CID_AUDIO_VOLUME; + control.value = volume*queryctrl.maximum/100; + ioctl( fd, VIDIOC_S_CTRL, &control ); + } else { + setVol(volume); + } + emit volumeChanged(volume); + } + } +} + +bool V4LRadioControl::isMuted() const +{ + return muted; +} + +void V4LRadioControl::setMuted(bool muted) +{ + v4l2_queryctrl queryctrl; + + if(fd > 0) { + memset( &queryctrl, 0, sizeof( queryctrl ) ); + queryctrl.id = V4L2_CID_AUDIO_MUTE; + if ( ioctl( fd, VIDIOC_QUERYCTRL, &queryctrl ) >= 0 ) { + v4l2_control control; + memset( &control, 0, sizeof( control ) ); + control.id = V4L2_CID_AUDIO_MUTE; + control.value = (muted ? queryctrl.maximum : queryctrl.minimum ); + ioctl( fd, VIDIOC_S_CTRL, &control ); + this->muted = muted; + emit mutedChanged(muted); + } + } +} + +bool V4LRadioControl::isSearching() const +{ + return scanning; +} + +void V4LRadioControl::cancelSearch() +{ + scanning = false; + timer->stop(); +} + +void V4LRadioControl::searchForward() +{ + // Scan up + if(scanning) { + cancelSearch(); + return; + } + scanning = true; + forward = true; + timer->start(); +} + +void V4LRadioControl::searchBackward() +{ + // Scan down + if(scanning) { + cancelSearch(); + return; + } + scanning = true; + forward = false; + timer->start(); +} + +void V4LRadioControl::start() +{ +} + +void V4LRadioControl::stop() +{ +} + +QRadioTuner::Error V4LRadioControl::error() const +{ + if(m_error) + return QRadioTuner::OpenError; + + return QRadioTuner::NoError; +} + +QString V4LRadioControl::errorString() const +{ + return QString(); +} + +void V4LRadioControl::search() +{ + int signal = signalStrength(); + if(sig != signal) { + sig = signal; + emit signalStrengthChanged(sig); + } + + if(!scanning) return; + + if (signal > 25) { + cancelSearch(); + return; + } + + if(forward) { + setFrequency(currentFreq+step); + } else { + setFrequency(currentFreq-step); + } +} + +bool V4LRadioControl::initRadio() +{ + v4l2_tuner tuner; + v4l2_input input; + v4l2_frequency freq; + v4l2_capability cap; + + low = false; + available = false; + freqMin = freqMax = currentFreq = 0; + + fd = ::open("/dev/radio0", O_RDWR); + + if(fd != -1) { + // Capabilities + memset( &cap, 0, sizeof( cap ) ); + if(::ioctl(fd, VIDIOC_QUERYCAP, &cap ) >= 0) { + if(((cap.capabilities & V4L2_CAP_RADIO) == 0) && ((cap.capabilities & V4L2_CAP_AUDIO) == 0)) + available = true; + } + + // Tuners + memset( &input, 0, sizeof( input ) ); + tuners = 0; + for ( ;; ) { + memset( &input, 0, sizeof( input ) ); + input.index = tuners; + if ( ioctl( fd, VIDIOC_ENUMINPUT, &input ) < 0 ) + break; + ++tuners; + } + + // Freq bands + for ( int index = 0; index < tuners; ++index ) { + memset( &tuner, 0, sizeof( tuner ) ); + tuner.index = index; + if ( ioctl( fd, VIDIOC_G_TUNER, &tuner ) < 0 ) + continue; + if ( tuner.type != V4L2_TUNER_RADIO ) + continue; + if ( ( tuner.capability & V4L2_TUNER_CAP_LOW ) != 0 ) { + // Units are 1/16th of a kHz. + low = true; + } + if(low) { + freqMin = tuner.rangelow * 62.5; + freqMax = tuner.rangehigh * 62.5; + } else { + freqMin = tuner.rangelow * 62500; + freqMax = tuner.rangehigh * 62500; + } + } + + // frequency + memset( &freq, 0, sizeof( freq ) ); + if(::ioctl(fd, VIDIOC_G_FREQUENCY, &freq ) >= 0) { + if ( ((int)freq.frequency) != -1 ) { // -1 means not set. + if(low) + currentFreq = freq.frequency * 62.5; + else + currentFreq = freq.frequency * 62500; + } + } + + // stereo + bool stereo = false; + memset( &tuner, 0, sizeof( tuner ) ); + if ( ioctl( fd, VIDIOC_G_TUNER, &tuner ) >= 0 ) { + if((tuner.rxsubchans & V4L2_TUNER_SUB_STEREO) != 0) + stereo = true; + } + + vol = getVol(); + + return true; + } + m_error = true; + emit error(); + + return false; +} + +void V4LRadioControl::setVol(int v) +{ + int fd = ::open( "/dev/mixer", O_RDWR, 0 ); + if ( fd < 0 ) + return; + int volume = v; + if ( volume < 0 ) + volume = 0; + else if ( volume > 100 ) + volume = 100; + vol = volume; + volume += volume << 8; + ::ioctl( fd, MIXER_WRITE(SOUND_MIXER_VOLUME), &volume ); + ::close( fd ); +} + +int V4LRadioControl::getVol() +{ + int fd = ::open( "/dev/mixer", O_RDWR, 0 ); + if ( fd >= 0 ) { + int volume = 0; + ::ioctl( fd, MIXER_READ(SOUND_MIXER_VOLUME), &volume ); + int left = ( volume & 0xFF ); + int right = ( ( volume >> 8 ) & 0xFF ); + if ( left > right ) + vol = left; + else + vol = right; + ::close( fd ); + return vol; + } + return 0; +} + diff --git a/src/plugins/v4l/radio/v4lradiocontrol.h b/src/plugins/v4l/radio/v4lradiocontrol.h new file mode 100644 index 000000000..3349be236 --- /dev/null +++ b/src/plugins/v4l/radio/v4lradiocontrol.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef V4LRADIOCONTROL_H +#define V4LRADIOCONTROL_H + +#include +#include +#include + +#include + +#include +#include +#include +#include + +QT_USE_NAMESPACE + +class V4LRadioService; + +class V4LRadioControl : public QRadioTunerControl +{ + Q_OBJECT +public: + V4LRadioControl(QObject *parent = 0); + ~V4LRadioControl(); + + bool isAvailable() const; + QtMultimediaKit::AvailabilityError availabilityError() const; + + QRadioTuner::State state() const; + + QRadioTuner::Band band() const; + void setBand(QRadioTuner::Band b); + bool isBandSupported(QRadioTuner::Band b) const; + + int frequency() const; + int frequencyStep(QRadioTuner::Band b) const; + QPair frequencyRange(QRadioTuner::Band b) const; + void setFrequency(int frequency); + + bool isStereo() const; + QRadioTuner::StereoMode stereoMode() const; + void setStereoMode(QRadioTuner::StereoMode mode); + + int signalStrength() const; + + int volume() const; + void setVolume(int volume); + + bool isMuted() const; + void setMuted(bool muted); + + bool isSearching() const; + void cancelSearch(); + + void searchForward(); + void searchBackward(); + + void start(); + void stop(); + + QRadioTuner::Error error() const; + QString errorString() const; + +private slots: + void search(); + +private: + bool initRadio(); + void setVol(int v); + int getVol(); + + int fd; + + bool m_error; + bool muted; + bool stereo; + bool low; + bool available; + int tuners; + int step; + int vol; + int sig; + bool scanning; + bool forward; + QTimer* timer; + QRadioTuner::Band currentBand; + qint64 freqMin; + qint64 freqMax; + qint64 currentFreq; + QTime playTime; +}; + +#endif diff --git a/src/plugins/v4l/radio/v4lradiocontrol_maemo5.cpp b/src/plugins/v4l/radio/v4lradiocontrol_maemo5.cpp new file mode 100644 index 000000000..f3dea9d63 --- /dev/null +++ b/src/plugins/v4l/radio/v4lradiocontrol_maemo5.cpp @@ -0,0 +1,755 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "v4lradiocontrol_maemo5.h" +#include "v4lradioservice.h" + +#include "linux/videodev2.h" +#include +#include +#include +#include +#include +#include +#include + +#define HEADPHONE_STATE_FILE "/sys/devices/platform/gpio-switch/headphone/state" +#define HEADPHONE_CONNECTED_STATE "connected" +#define HEADPHONE_DISCONNECTED_STATE "disconnected" + +#define FMRXENABLER_DBUS_SERVICE "de.pycage.FMRXEnabler" +#define FMRXENABLER_DBUS_OBJ_PATH "/de/pycage/FMRXEnabler" +#define FMRXENABLER_DBUS_IFACE_NAME "de.pycage.FMRXEnabler" + +gboolean +state_file_changed(GIOChannel* source, GIOCondition /*condition*/, gpointer data) +{ + V4LRadioControl* radioControl = (V4LRadioControl*)data; + gchar* result; + + g_io_channel_seek_position(source, 0, G_SEEK_SET, NULL); + g_io_channel_read_line(source, &result, NULL, NULL, NULL); + g_strstrip(result); + + if (g_ascii_strcasecmp(result, HEADPHONE_DISCONNECTED_STATE) == 0) { + radioControl->enablePipeline(false); + } else if (g_ascii_strcasecmp(result, HEADPHONE_CONNECTED_STATE) == 0) { + // Wait 400ms until audio is routed again to headphone to prevent sound coming from speakers + QTimer::singleShot(400,radioControl,SLOT(enablePipeline())); + } + +#ifdef MULTIMEDIA_MAEMO_DEBUG + qDebug() << "Headphone is now" << result; +#endif + + g_free(result); + return true; +} + +V4LRadioControl::V4LRadioControl(QObject *parent) + : QRadioTunerControl(parent) + , fd(1) + , m_error(false) + , muted(false) + , stereo(false) + , step(100000) + , sig(0) + , scanning(false) + , currentBand(QRadioTuner::FM) + , pipeline(0) +{ + if (QDBusConnection::systemBus().isConnected()) { + FMRXEnablerIFace = new QDBusInterface(FMRXENABLER_DBUS_SERVICE, + FMRXENABLER_DBUS_OBJ_PATH, + FMRXENABLER_DBUS_IFACE_NAME, + QDBusConnection::systemBus()); + } + + createGstPipeline(); + + GIOChannel* headphoneStateFile = NULL; + headphoneStateFile = g_io_channel_new_file(HEADPHONE_STATE_FILE, "r", NULL); + if (headphoneStateFile != NULL) { + g_io_add_watch(headphoneStateFile, G_IO_PRI, state_file_changed, this); + } else { +#ifdef MULTIMEDIA_MAEMO_DEBUG + qWarning() << QString("File %1 can't be read!").arg(HEADPHONE_STATE_FILE) ; + qWarning() << "Monitoring headphone state isn't possible!"; +#endif + } + + enableFMRX(); + initRadio(); + setupHeadPhone(); + + setMuted(false); + + timer = new QTimer(this); + timer->setInterval(200); + connect(timer,SIGNAL(timeout()),this,SLOT(search())); + + tickTimer = new QTimer(this); + tickTimer->setInterval(10000); + connect(tickTimer,SIGNAL(timeout()),this,SLOT(enableFMRX())); + tickTimer->start(); +} + +V4LRadioControl::~V4LRadioControl() +{ + if (pipeline) + { + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (GST_OBJECT (pipeline)); + } + + if(fd > 0) + ::close(fd); +} + +void V4LRadioControl::enablePipeline(bool enable) +{ + if (enable == true) + gst_element_set_state (pipeline, GST_STATE_PLAYING); + else + gst_element_set_state (pipeline, GST_STATE_NULL); +} + +void V4LRadioControl::enableFMRX() +{ + if (FMRXEnablerIFace && FMRXEnablerIFace->isValid()) { + FMRXEnablerIFace->call("request"); // Return value ignored + } +} + +// Workaround to capture sound from the PGA line and play it back using gstreamer +// because N900 doesn't output sound directly to speakers +bool V4LRadioControl::createGstPipeline() +{ + GstElement *source, *sink; + + gst_init (NULL, NULL); + pipeline = gst_pipeline_new("my-pipeline"); + + source = gst_element_factory_make ("pulsesrc", "source"); + sink = gst_element_factory_make ("pulsesink", "sink"); + + gst_bin_add_many (GST_BIN (pipeline), source, sink, (char *)NULL); + + if (!gst_element_link_many (source, sink, (char *)NULL)) { + return false; + } + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + + return true; +} + +bool V4LRadioControl::isAvailable() const +{ + return available; +} + +QtMultimediaKit::AvailabilityError V4LRadioControl::availabilityError() const +{ + if (fd > 0) + return QtMultimediaKit::NoError; + else + return QtMultimediaKit::ResourceError; +} + +QRadioTuner::State V4LRadioControl::state() const +{ + return fd > 0 ? QRadioTuner::ActiveState : QRadioTuner::StoppedState; +} + +QRadioTuner::Band V4LRadioControl::band() const +{ + return currentBand; +} + +bool V4LRadioControl::isBandSupported(QRadioTuner::Band b) const +{ + QRadioTuner::Band bnd = (QRadioTuner::Band)b; + switch(bnd) { + case QRadioTuner::FM: + if(freqMin <= 87500000 && freqMax >= 108000000) + return true; + break; + case QRadioTuner::LW: + if(freqMin <= 148500 && freqMax >= 283500) + return true; + case QRadioTuner::AM: + if(freqMin <= 520000 && freqMax >= 1610000) + return true; + default: + if(freqMin <= 1711000 && freqMax >= 30000000) + return true; + } + + return false; +} + +void V4LRadioControl::setBand(QRadioTuner::Band b) +{ + if(freqMin <= 87500000 && freqMax >= 108000000 && b == QRadioTuner::FM) { + // FM 87.5 to 108.0 MHz, except Japan 76-90 MHz + currentBand = (QRadioTuner::Band)b; + step = 100000; // 100kHz steps + emit bandChanged(currentBand); + + } else if(freqMin <= 148500 && freqMax >= 283500 && b == QRadioTuner::LW) { + // LW 148.5 to 283.5 kHz, 9kHz channel spacing (Europe, Africa, Asia) + currentBand = (QRadioTuner::Band)b; + step = 1000; // 1kHz steps + emit bandChanged(currentBand); + + } else if(freqMin <= 520000 && freqMax >= 1610000 && b == QRadioTuner::AM) { + // AM 520 to 1610 kHz, 9 or 10kHz channel spacing, extended 1610 to 1710 kHz + currentBand = (QRadioTuner::Band)b; + step = 1000; // 1kHz steps + emit bandChanged(currentBand); + + } else if(freqMin <= 1711000 && freqMax >= 30000000 && b == QRadioTuner::SW) { + // SW 1.711 to 30.0 MHz, divided into 15 bands. 5kHz channel spacing + currentBand = (QRadioTuner::Band)b; + step = 500; // 500Hz steps + emit bandChanged(currentBand); + } +} + +int V4LRadioControl::frequency() const +{ + return currentFreq; +} + +int V4LRadioControl::frequencyStep(QRadioTuner::Band b) const +{ + int step = 0; + + if(b == QRadioTuner::FM) + step = 100000; // 100kHz steps + else if(b == QRadioTuner::LW) + step = 1000; // 1kHz steps + else if(b == QRadioTuner::AM) + step = 1000; // 1kHz steps + else if(b == QRadioTuner::SW) + step = 500; // 500Hz steps + + return step; +} + +QPair V4LRadioControl::frequencyRange(QRadioTuner::Band b) const +{ + if(b == QRadioTuner::AM) + return qMakePair(520000,1710000); + else if(b == QRadioTuner::FM) + return qMakePair(87500000,108000000); + else if(b == QRadioTuner::SW) + return qMakePair(1711111,30000000); + else if(b == QRadioTuner::LW) + return qMakePair(148500,283500); + + return qMakePair(0,0); +} + +void V4LRadioControl::setFrequency(int frequency) +{ + qint64 f = frequency; + + v4l2_frequency freq; + + if(frequency < freqMin) + f = freqMax; + if(frequency > freqMax) + f = freqMin; + + if(fd > 0) { + memset(&freq, 0, sizeof(freq)); + // Use the first tuner + freq.tuner = 0; + if (::ioctl(fd, VIDIOC_G_FREQUENCY, &freq) >= 0) { + if(low) { + // For low, freq in units of 62.5Hz, so convert from Hz to units. + freq.frequency = (int)(f/62.5); + } else { + // For high, freq in units of 62.5kHz, so convert from Hz to units. + freq.frequency = (int)(f/62500); + } + ::ioctl(fd, VIDIOC_S_FREQUENCY, &freq); + currentFreq = f; + emit frequencyChanged(currentFreq); + + int signal = signalStrength(); + if(sig != signal) { + sig = signal; + emit signalStrengthChanged(sig); + } + } + } +} + +bool V4LRadioControl::isStereo() const +{ + return stereo; +} + +QRadioTuner::StereoMode V4LRadioControl::stereoMode() const +{ + return QRadioTuner::Auto; +} + +void V4LRadioControl::setStereoMode(QRadioTuner::StereoMode mode) +{ + bool stereo = true; + + if(mode == QRadioTuner::ForceMono) + stereo = false; + + v4l2_tuner tuner; + + memset(&tuner, 0, sizeof(tuner)); + + if (ioctl(fd, VIDIOC_G_TUNER, &tuner) >= 0) { + if(stereo) + tuner.audmode = V4L2_TUNER_MODE_STEREO; + else + tuner.audmode = V4L2_TUNER_MODE_MONO; + + if (ioctl(fd, VIDIOC_S_TUNER, &tuner) >= 0) { + emit stereoStatusChanged(stereo); + } + } +} + +int V4LRadioControl::signalStrength() const +{ + v4l2_tuner tuner; + + tuner.index = 0; + if (ioctl(fd, VIDIOC_G_TUNER, &tuner) < 0 || tuner.type != V4L2_TUNER_RADIO) + return 0; + return tuner.signal*100/65535; +} + +int V4LRadioControl::vol(snd_hctl_elem_t *elem) const +{ + const QString card("hw:0"); + int err; + snd_ctl_elem_id_t *id; + snd_ctl_elem_info_t *info; + snd_ctl_elem_value_t *control; + snd_ctl_elem_id_alloca(&id); + snd_ctl_elem_info_alloca(&info); + snd_ctl_elem_value_alloca(&control); + if ((err = snd_hctl_elem_info(elem, info)) < 0) { + return 0; + } + + snd_hctl_elem_get_id(elem, id); + snd_hctl_elem_read(elem, control); + + return snd_ctl_elem_value_get_integer(control, 0); +} + +int V4LRadioControl::volume() const +{ + const QString ctlName("Line DAC Playback Volume"); + const QString card("hw:0"); + + int volume = 0; + int err; + static snd_ctl_t *handle = NULL; + snd_ctl_elem_info_t *info; + snd_ctl_elem_id_t *id; + snd_ctl_elem_value_t *control; + + snd_ctl_elem_info_alloca(&info); + snd_ctl_elem_id_alloca(&id); + snd_ctl_elem_value_alloca(&control); + snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); /* MIXER */ + + snd_ctl_elem_id_set_name(id, ctlName.toAscii()); + + if ((err = snd_ctl_open(&handle, card.toAscii(), 0)) < 0) { + return 0; + } + + snd_ctl_elem_info_set_id(info, id); + if ((err = snd_ctl_elem_info(handle, info)) < 0) { + snd_ctl_close(handle); + handle = NULL; + return 0; + } + + snd_ctl_elem_info_get_id(info, id); /* FIXME: Remove it when hctl find works ok !!! */ + snd_ctl_elem_value_set_id(control, id); + + snd_ctl_close(handle); + handle = NULL; + + snd_hctl_t *hctl; + snd_hctl_elem_t *elem; + if ((err = snd_hctl_open(&hctl, card.toAscii(), 0)) < 0) { + return 0; + } + if ((err = snd_hctl_load(hctl)) < 0) { + return 0; + } + elem = snd_hctl_find_elem(hctl, id); + if (elem) + volume = vol(elem); + + snd_hctl_close(hctl); + + return (volume/118.0) * 100; +} + +void V4LRadioControl::setVolume(int volume) +{ + int vol = (volume / 100.0) * 118; // 118 is a headphone max setting + callAmixer("Line DAC Playback Volume", QString().setNum(vol)+QString(",")+QString().setNum(vol)); +} + +bool V4LRadioControl::isMuted() const +{ + return muted; +} + +void V4LRadioControl::setMuted(bool muted) +{ + struct v4l2_control vctrl; + vctrl.id = V4L2_CID_AUDIO_MUTE; + vctrl.value = muted ? 1 : 0; + ioctl(fd, VIDIOC_S_CTRL, &vctrl); +} + +void V4LRadioControl::setupHeadPhone() +{ + QMap settings; + + settings["Jack Function"] = "Headset"; + settings["Left DAC_L1 Mixer HP Switch"] = "off"; + settings["Right DAC_R1 Mixer HP Switch"] = "off"; + settings["Line DAC Playback Switch"] = "on"; + settings["Line DAC Playback Volume"] = "118,118"; // Volume is set to 100% + settings["HPCOM DAC Playback Switch"] = "off"; + settings["Left DAC_L1 Mixer HP Switch"] = "off"; + settings["Left DAC_L1 Mixer Line Switch"] = "on"; + settings["Right DAC_R1 Mixer HP Switch"] = "off"; + settings["Right DAC_R1 Mixer Line Switch"] = "on"; + settings["Speaker Function"] = "Off"; + + settings["Input Select"] = "ADC"; + settings["Left PGA Mixer Line1L Switch"] = "off"; + settings["Right PGA Mixer Line1L Switch"] = "off"; + settings["Right PGA Mixer Line1R Switch"] = "off"; + settings["PGA Capture Volume"] = "0,0"; + + settings["PGA Capture Switch"] = "on"; + + settings["Left PGA Mixer Line2L Switch"] = "on"; + settings["Right PGA Mixer Line2R Switch"] = "on"; + + QMapIterator i(settings); + while (i.hasNext()) { + i.next(); + callAmixer(i.key(), i.value()); + } +} + +void V4LRadioControl::callAmixer(const QString& target, const QString& value) +{ + int err; + long tmp; + unsigned int count; + static snd_ctl_t *handle = NULL; + QString card("hw:0"); + snd_ctl_elem_info_t *info; + snd_ctl_elem_id_t *id; + snd_ctl_elem_value_t *control; + snd_ctl_elem_type_t type; + + snd_ctl_elem_info_alloca(&info); + snd_ctl_elem_id_alloca(&id); + snd_ctl_elem_value_alloca(&control); + snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); /* MIXER */ + + // in amixer parse func + // char target[64]; + // e.g. PGA CAPTure Switch + snd_ctl_elem_id_set_name(id, target.toAscii()); + + if (handle == NULL && (err = snd_ctl_open(&handle, card.toAscii(), 0)) < 0) + { + return; + } + + snd_ctl_elem_info_set_id(info, id); + if ((err = snd_ctl_elem_info(handle, info)) < 0) + { + snd_ctl_close(handle); + handle = NULL; + return; + } + + snd_ctl_elem_info_get_id(info, id); /* FIXME: Remove it when hctl find works ok !!! */ + type = snd_ctl_elem_info_get_type(info); + count = snd_ctl_elem_info_get_count(info); + + snd_ctl_elem_value_set_id(control, id); + + tmp = 0; + for (uint idx = 0; idx < count && idx < 128; idx++) + { + switch (type) + { + case SND_CTL_ELEM_TYPE_BOOLEAN: +#ifdef MULTIMEDIA_MAEMO_DEBUG + qDebug() << "SND_CTL_ELEM_TYPE_BOOLEAN" << SND_CTL_ELEM_TYPE_BOOLEAN; +#endif + if ((value == "on") ||(value == "1")) + { + tmp = 1; + } + snd_ctl_elem_value_set_boolean(control, idx, tmp); + break; + case SND_CTL_ELEM_TYPE_ENUMERATED: + tmp = getEnumItemIndex(handle, info, value); + snd_ctl_elem_value_set_enumerated(control, idx, tmp); + break; + case SND_CTL_ELEM_TYPE_INTEGER: +#ifdef MULTIMEDIA_MAEMO_DEBUG + qDebug() << "SND_CTL_ELEM_TYPE_INTEGER" << SND_CTL_ELEM_TYPE_INTEGER; +#endif + tmp = atoi(value.toAscii()); + if (tmp < snd_ctl_elem_info_get_min(info)) + tmp = snd_ctl_elem_info_get_min(info); + else if (tmp > snd_ctl_elem_info_get_max(info)) + tmp = snd_ctl_elem_info_get_max(info); + snd_ctl_elem_value_set_integer(control, idx, tmp); + break; + default: + break; + + } + } + + if ((err = snd_ctl_elem_write(handle, control)) < 0) { + snd_ctl_close(handle); + handle = NULL; + return; + } + + snd_ctl_close(handle); + handle = NULL; +} + + +int V4LRadioControl::getEnumItemIndex(snd_ctl_t *handle, snd_ctl_elem_info_t *info, + const QString &value) +{ + int items, i; + + items = snd_ctl_elem_info_get_items(info); + if (items <= 0) + return -1; + + for (i = 0; i < items; i++) + { + snd_ctl_elem_info_set_item(info, i); + if (snd_ctl_elem_info(handle, info) < 0) + return -1; + QString name = snd_ctl_elem_info_get_item_name(info); + if(name == value) + { + return i; + } + } + return -1; +} + +bool V4LRadioControl::isSearching() const +{ + return scanning; +} + +void V4LRadioControl::cancelSearch() +{ + scanning = false; + timer->stop(); +} + +void V4LRadioControl::searchForward() +{ + // Scan up + if(scanning) { + cancelSearch(); + return; + } + scanning = true; + forward = true; + timer->start(); +} + +void V4LRadioControl::searchBackward() +{ + // Scan down + if(scanning) { + cancelSearch(); + return; + } + scanning = true; + forward = false; + timer->start(); +} + +void V4LRadioControl::start() +{ +} + +void V4LRadioControl::stop() +{ +} + +QRadioTuner::Error V4LRadioControl::error() const +{ + if(m_error) + return QRadioTuner::OpenError; + + return QRadioTuner::NoError; +} + +QString V4LRadioControl::errorString() const +{ + return QString(); +} + +void V4LRadioControl::search() +{ + if(!scanning) return; + + if(forward) { + setFrequency(currentFreq+step); + } else { + setFrequency(currentFreq-step); + } + + int signal = signalStrength(); + if(sig != signal) { + sig = signal; + emit signalStrengthChanged(sig); + } + + if (signal > 25) { + cancelSearch(); + return; + } +} + +bool V4LRadioControl::initRadio() +{ + v4l2_tuner tuner; + v4l2_frequency freq; + v4l2_capability cap; + + low = false; + available = false; + freqMin = freqMax = currentFreq = 0; + + fd = ::open("/dev/radio1", O_RDWR); + + if(fd != -1) { + // Capabilities + memset(&cap, 0, sizeof(cap)); + if(::ioctl(fd, VIDIOC_QUERYCAP, &cap ) >= 0) { + available = true; + } + + tuner.index = 0; + + if (ioctl(fd, VIDIOC_G_TUNER, &tuner) < 0) { + return false; + } + + if (tuner.type != V4L2_TUNER_RADIO) + return false; + + if ((tuner.capability & V4L2_TUNER_CAP_LOW) != 0) { + // Units are 1/16th of a kHz. + low = true; + } + + if(low) { + freqMin = tuner.rangelow * 62.5; + freqMax = tuner.rangehigh * 62.5; + } else { + freqMin = tuner.rangelow * 62500; + freqMax = tuner.rangehigh * 62500; + } + + // frequency + memset(&freq, 0, sizeof(freq)); + + if(::ioctl(fd, VIDIOC_G_FREQUENCY, &freq) >= 0) { + if (((int)freq.frequency) != -1) { // -1 means not set. + if(low) + currentFreq = freq.frequency * 62.5; + else + currentFreq = freq.frequency * 62500; + } + } + + // stereo + bool stereo = false; + memset(&tuner, 0, sizeof(tuner)); + if (ioctl(fd, VIDIOC_G_TUNER, &tuner) >= 0) { + if((tuner.rxsubchans & V4L2_TUNER_SUB_STEREO) != 0) + stereo = true; + } + + return true; + } + + m_error = true; + emit error(); + + return false; +} diff --git a/src/plugins/v4l/radio/v4lradiocontrol_maemo5.h b/src/plugins/v4l/radio/v4lradiocontrol_maemo5.h new file mode 100644 index 000000000..bbf64830c --- /dev/null +++ b/src/plugins/v4l/radio/v4lradiocontrol_maemo5.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef V4LRADIOCONTROL_H +#define V4LRADIOCONTROL_H + +#include +#include + +#include + +#include +#include + +#include + +QT_USE_NAMESPACE + +class V4LRadioService; + +class V4LRadioControl : public QRadioTunerControl +{ + Q_OBJECT +public: + V4LRadioControl(QObject *parent = 0); + ~V4LRadioControl(); + + bool isAvailable() const; + QtMultimediaKit::AvailabilityError availabilityError() const; + + QRadioTuner::State state() const; + + QRadioTuner::Band band() const; + void setBand(QRadioTuner::Band b); + bool isBandSupported(QRadioTuner::Band b) const; + + int frequency() const; + int frequencyStep(QRadioTuner::Band b) const; + QPair frequencyRange(QRadioTuner::Band b) const; + void setFrequency(int frequency); + + bool isStereo() const; + QRadioTuner::StereoMode stereoMode() const; + void setStereoMode(QRadioTuner::StereoMode mode); + + int signalStrength() const; + + int volume() const; + void setVolume(int volume); + + bool isMuted() const; + void setMuted(bool muted); + + bool isSearching() const; + void cancelSearch(); + + void searchForward(); + void searchBackward(); + + void start(); + void stop(); + + QRadioTuner::Error error() const; + QString errorString() const; + +public slots: + void enablePipeline(bool enable = true); + +private slots: + void search(); + void enableFMRX(); + +private: + bool initRadio(); + void setupHeadPhone(); + bool createGstPipeline(); + void callAmixer(const QString& target, const QString& value); + int getEnumItemIndex(snd_ctl_t *handle, snd_ctl_elem_info_t *info, const QString &value); + int vol(snd_hctl_elem_t *elem) const; + +private: + int fd; + + bool m_error; + bool muted; + bool stereo; + bool low; + bool available; + int tuners; + int step; + int sig; + bool scanning; + bool forward; + QTimer* timer; + QTimer* tickTimer; + QRadioTuner::Band currentBand; + qint64 freqMin; + qint64 freqMax; + qint64 currentFreq; + + GstElement *pipeline; + + QDBusInterface* FMRXEnablerIFace; +}; + +#endif diff --git a/src/plugins/v4l/radio/v4lradioservice.cpp b/src/plugins/v4l/radio/v4lradioservice.cpp new file mode 100644 index 000000000..2a67c90dd --- /dev/null +++ b/src/plugins/v4l/radio/v4lradioservice.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#include "v4lradioservice.h" +#include "v4lradiocontrol.h" + +V4LRadioService::V4LRadioService(QObject *parent): + QMediaService(parent) +{ + m_control = new V4LRadioControl(this); +} + +V4LRadioService::~V4LRadioService() +{ +} + +QMediaControl *V4LRadioService::requestControl(const char* name) +{ + if (qstrcmp(name,QRadioTunerControl_iid) == 0) + return m_control; + + return 0; +} + + +void V4LRadioService::releaseControl(QMediaControl *) +{ +} diff --git a/src/plugins/v4l/radio/v4lradioservice.h b/src/plugins/v4l/radio/v4lradioservice.h new file mode 100644 index 000000000..f8664467d --- /dev/null +++ b/src/plugins/v4l/radio/v4lradioservice.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef V4LRADIOSERVICE_H +#define V4LRADIOSERVICE_H + +#include + +#include +QT_USE_NAMESPACE + +class V4LRadioControl; + +class V4LRadioService : public QMediaService +{ + Q_OBJECT + +public: + V4LRadioService(QObject *parent = 0); + ~V4LRadioService(); + + QMediaControl *requestControl(const char* name); + void releaseControl(QMediaControl *); + +private: + V4LRadioControl *m_control; +}; + +#endif diff --git a/src/plugins/v4l/v4l.pro b/src/plugins/v4l/v4l.pro new file mode 100644 index 000000000..3242d486b --- /dev/null +++ b/src/plugins/v4l/v4l.pro @@ -0,0 +1,13 @@ +load(qt_module) + +TARGET = qtmedia_v4lengine +QT += multimediakit-private +PLUGIN_TYPE = mediaservice + +load(qt_plugin) +DESTDIR = $$QT.multimediakit.plugins/$${PLUGIN_TYPE} + +HEADERS += v4lserviceplugin.h +SOURCES += v4lserviceplugin.cpp + +include(radio/radio.pri) diff --git a/src/plugins/v4l/v4lserviceplugin.cpp b/src/plugins/v4l/v4lserviceplugin.cpp new file mode 100644 index 000000000..3e02be9fa --- /dev/null +++ b/src/plugins/v4l/v4lserviceplugin.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#include "v4lserviceplugin.h" +#include "v4lradioservice.h" + +#include + + +QStringList V4LServicePlugin::keys() const +{ + return QStringList() << + QLatin1String(Q_MEDIASERVICE_RADIO); +} + +QMediaService* V4LServicePlugin::create(QString const& key) +{ + if (key == QLatin1String(Q_MEDIASERVICE_RADIO)) + return new V4LRadioService; + + return 0; +} + +void V4LServicePlugin::release(QMediaService *service) +{ + delete service; +} + +QList V4LServicePlugin::devices(const QByteArray &service) const +{ + return QList(); +} + +QString V4LServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device) +{ + return QString(); +} + + +Q_EXPORT_PLUGIN2(qtmedia_v4lengine, V4LServicePlugin); + diff --git a/src/plugins/v4l/v4lserviceplugin.h b/src/plugins/v4l/v4lserviceplugin.h new file mode 100644 index 000000000..b95d70358 --- /dev/null +++ b/src/plugins/v4l/v4lserviceplugin.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef V4LSERVICEPLUGIN_H +#define V4LSERVICEPLUGIN_H + +#include + +QT_USE_NAMESPACE + +class V4LServicePlugin : public QMediaServiceProviderPlugin, public QMediaServiceSupportedDevicesInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceSupportedDevicesInterface) +public: + QStringList keys() const; + QMediaService* create(QString const& key); + void release(QMediaService *service); + + QList devices(const QByteArray &service) const; + QString deviceDescription(const QByteArray &service, const QByteArray &device); +}; + +#endif // V4LSERVICEPLUGIN_H diff --git a/src/plugins/wmp/qevrvideooverlay.cpp b/src/plugins/wmp/qevrvideooverlay.cpp new file mode 100644 index 000000000..ff301d109 --- /dev/null +++ b/src/plugins/wmp/qevrvideooverlay.cpp @@ -0,0 +1,357 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qevrvideooverlay.h" + +#include +#include + +QEvrVideoOverlay::QEvrVideoOverlay(HINSTANCE evrHwnd) + : m_ref(1) + , m_evrHwnd(evrHwnd) + , ptrMFCreateVideoPresenter(0) + , m_presenter(0) + , m_displayControl(0) + , m_aspectRatioMode(Qt::KeepAspectRatio) + , m_winId(0) + , m_fullScreen(0) +{ + ptrMFCreateVideoPresenter = reinterpret_cast( + GetProcAddress(m_evrHwnd, "MFCreateVideoPresenter")); +} + +QEvrVideoOverlay::~QEvrVideoOverlay() +{ + FreeLibrary(m_evrHwnd); +} + +WId QEvrVideoOverlay::winId() const +{ + return m_winId; +} + +void QEvrVideoOverlay::setWinId(WId id) +{ + m_winId = id; + + if (QWidget *widget = QWidget::find(m_winId)) { + const QColor color = widget->palette().color(QPalette::Window); + + m_windowColor = RGB(color.red(), color.green(), color.blue()); + } + + if (m_displayControl) { + m_displayControl->SetVideoWindow(id); + m_displayControl->SetAspectRatioMode(m_aspectRatioMode == Qt::KeepAspectRatio + ? MFVideoARMode_PreservePicture + : MFVideoARMode_None); + m_displayControl->SetBorderColor(m_windowColor); + + setDisplayRect(m_displayRect); + } +} + +QRect QEvrVideoOverlay::displayRect() const +{ + return m_displayRect; +} + +void QEvrVideoOverlay::setDisplayRect(const QRect &rect) +{ + if (m_displayControl) { + RECT displayRect = { rect.left(), rect.top(), rect.right() + 1, rect.bottom() + 1 }; + + if (m_aspectRatioMode == Qt::KeepAspectRatioByExpanding) { + SIZE size; + m_displayControl->GetNativeVideoSize(&size, 0); + + QSize clippedSize = rect.size(); + clippedSize.scale(size.cx, size.cy, Qt::KeepAspectRatio); + + long x = (size.cx - clippedSize.width()) / 2; + long y = (size.cy - clippedSize.height()) / 2; + + MFVideoNormalizedRect sourceRect = + { + float(x) / size.cx, + float(y) / size.cy, + float(x + clippedSize.width()) / size.cx, + float(y + clippedSize.height()) / size.cy + }; + m_displayControl->SetVideoPosition(&sourceRect, &displayRect); + } else { + m_displayControl->SetVideoPosition(0, &displayRect); + } + } + + m_displayRect = rect; +} + +bool QEvrVideoOverlay::isFullScreen() const +{ + return m_fullScreen; +} + +void QEvrVideoOverlay::setFullScreen(bool fullScreen) +{ + emit fullScreenChanged(m_fullScreen = fullScreen); +} + +QSize QEvrVideoOverlay::nativeSize() const +{ + SIZE size; + + if (m_displayControl && m_displayControl->GetNativeVideoSize(&size, 0) == S_OK) { + return QSize(size.cx, size.cy); + } else { + return QSize(); + } +} + +Qt::AspectRatioMode QEvrVideoOverlay::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void QEvrVideoOverlay::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + m_aspectRatioMode = mode; + + if (m_displayControl) { + m_displayControl->SetAspectRatioMode(mode == Qt::KeepAspectRatio + ? MFVideoARMode_PreservePicture + : MFVideoARMode_None); + setDisplayRect(m_displayRect); + } +} + +void QEvrVideoOverlay::repaint() +{ + PAINTSTRUCT paint; + + if (HDC dc = ::BeginPaint(m_winId, &paint)) { + if (m_displayControl) { + m_displayControl->RepaintVideo(); + } else { + HPEN pen = ::CreatePen(PS_SOLID, 1, m_windowColor); + HBRUSH brush = ::CreateSolidBrush(m_windowColor); + ::SelectObject(dc, pen); + ::SelectObject(dc, brush); + + ::Rectangle( + dc, + paint.rcPaint.left, + paint.rcPaint.top, + paint.rcPaint.right, + paint.rcPaint.bottom); + + ::DeleteObject(pen); + ::DeleteObject(brush); + } + + ::EndPaint(m_winId, &paint); + } +} + +int QEvrVideoOverlay::brightness() const +{ + return 0; +} + +void QEvrVideoOverlay::setBrightness(int) +{ +} + +int QEvrVideoOverlay::contrast() const +{ + return 0; +} + +void QEvrVideoOverlay::setContrast(int) +{ +} + +int QEvrVideoOverlay::hue() const +{ + return 0; +} + +void QEvrVideoOverlay::setHue(int) +{ +} + +int QEvrVideoOverlay::saturation() const +{ + return 0; +} + +void QEvrVideoOverlay::setSaturation(int) +{ +} + +void QEvrVideoOverlay::setDisplayControl(IMFVideoDisplayControl *control) +{ + if (m_displayControl) + m_displayControl->Release(); + + m_displayControl = control; + + if (m_displayControl) { + m_displayControl->AddRef(); + m_displayControl->SetVideoWindow(m_winId); + m_displayControl->SetAspectRatioMode(m_aspectRatioMode == Qt::KeepAspectRatio + ? MFVideoARMode_PreservePicture + : MFVideoARMode_None); + m_displayControl->SetBorderColor(m_windowColor); + + setDisplayRect(m_displayRect); + } +} + +void QEvrVideoOverlay::openStateChanged(long state) +{ + if (state == wmposMediaOpen) { + setDisplayRect(m_displayRect); + + emit nativeSizeChanged(); + } +}; + +// IUnknown +HRESULT QEvrVideoOverlay::QueryInterface(REFIID riid, void **object) +{ + if (!object) { + return E_POINTER; + } else if (riid == __uuidof(IUnknown) + || riid == __uuidof(IMFAttributes) + || riid == __uuidof(IMFActivate)) { + *object = static_cast(this); + } else { + return E_NOINTERFACE; + } + + AddRef(); + + return S_OK; +} + +ULONG QEvrVideoOverlay::AddRef() +{ + return InterlockedIncrement(&m_ref); +} + +ULONG QEvrVideoOverlay::Release() +{ + ULONG ref = InterlockedDecrement(&m_ref); + + Q_ASSERT(ref != 0); + + return ref; +} + +// IMFActivate +HRESULT QEvrVideoOverlay::ActivateObject(REFIID riid, void **ppv) +{ + if (riid != __uuidof(IMFVideoPresenter)) { + return E_NOINTERFACE; + } else if (!ptrMFCreateVideoPresenter) { + return E_NOINTERFACE; + } else if (m_presenter) { + *ppv = m_presenter; + + return S_OK; + } else { + IMFVideoDisplayControl *displayControl = 0; + + IMFGetService *service; + HRESULT hr; + if ((hr = (*ptrMFCreateVideoPresenter)( + 0, + __uuidof(IDirect3DDevice9), + __uuidof(IMFVideoPresenter), + reinterpret_cast(&m_presenter))) != S_OK) { + qWarning("failed to create video presenter"); + } else if ((hr = m_presenter->QueryInterface( + __uuidof(IMFGetService), reinterpret_cast(&service))) != S_OK) { + qWarning("failed to query IMFGetService interface"); + } else { + if ((hr = service->GetService( + MR_VIDEO_RENDER_SERVICE, + __uuidof(IMFVideoDisplayControl), + reinterpret_cast(&displayControl))) != S_OK) { + qWarning("failed to get IMFVideoDisplayControl service"); + } + service->Release(); + } + + setDisplayControl(displayControl); + + if (m_presenter && hr != S_OK) { + m_presenter->Release(); + m_presenter = 0; + } + + *ppv = m_presenter; + + return hr; + } +} + +HRESULT QEvrVideoOverlay::ShutdownObject() +{ + setDisplayControl(0); + + if (m_presenter) { + m_presenter->Release(); + m_presenter = 0; + } + return S_OK; +} + +HRESULT QEvrVideoOverlay::DetachObject() +{ + if (m_presenter) { + m_presenter->Release(); + m_presenter = 0; + } + + return S_OK; +} diff --git a/src/plugins/wmp/qevrvideooverlay.h b/src/plugins/wmp/qevrvideooverlay.h new file mode 100644 index 000000000..247b16e96 --- /dev/null +++ b/src/plugins/wmp/qevrvideooverlay.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEVRVIDEOOVERLAY_H +#define QEVRVIDEOOVERLAY_H + +#include + +#include "qmfactivate.h" + +#include + +QT_USE_NAMESPACE + +class QEvrVideoOverlay : public QVideoWindowControl, public QMFActivate +{ + Q_OBJECT +public: + QEvrVideoOverlay(HINSTANCE evrHwnd); + ~QEvrVideoOverlay(); + + WId winId() const; + void setWinId(WId id); + + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + QSize nativeSize() const; + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + + void repaint(); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + void setDisplayControl(IMFVideoDisplayControl *control); + + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **object); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + // IMFActivate + HRESULT STDMETHODCALLTYPE ActivateObject(REFIID riid, void **ppv); + HRESULT STDMETHODCALLTYPE ShutdownObject(); + HRESULT STDMETHODCALLTYPE DetachObject(); + +public Q_SLOTS: + void openStateChanged(long state); + +private: + typedef HRESULT (WINAPI *PtrMFCreateVideoPresenter)(IUnknown*, REFIID, REFIID, void**); + + volatile LONG m_ref; + HINSTANCE m_evrHwnd; + PtrMFCreateVideoPresenter ptrMFCreateVideoPresenter; + IMFVideoPresenter *m_presenter; + IMFVideoDisplayControl *m_displayControl; + Qt::AspectRatioMode m_aspectRatioMode; + QSize m_sizeHint; + QRect m_displayRect; + WId m_winId; + COLORREF m_windowColor; + bool m_fullScreen; +}; + +#endif diff --git a/src/plugins/wmp/qmfactivate.cpp b/src/plugins/wmp/qmfactivate.cpp new file mode 100644 index 000000000..8cd64b0e4 --- /dev/null +++ b/src/plugins/wmp/qmfactivate.cpp @@ -0,0 +1,296 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmfactivate.h" + +#include + +#include + + +// IMFAttributes + +HRESULT QMFActivate::GetItem(REFGUID guidKey, PROPVARIANT *pValue) +{ + Q_UNUSED(guidKey); + Q_UNUSED(pValue); + + return MF_E_ATTRIBUTENOTFOUND; +} + +HRESULT QMFActivate::GetItemType(REFGUID guidKey, MF_ATTRIBUTE_TYPE *pType) +{ + Q_UNUSED(guidKey); + Q_UNUSED(pType); + + return MF_E_ATTRIBUTENOTFOUND; +} + +HRESULT QMFActivate::CompareItem(REFGUID guidKey, REFPROPVARIANT Value, BOOL *pbResult) +{ + Q_UNUSED(guidKey); + Q_UNUSED(Value); + Q_UNUSED(pbResult); + + return E_NOTIMPL; +} + +HRESULT QMFActivate::Compare(IMFAttributes *pTheirs, MF_ATTRIBUTES_MATCH_TYPE MatchType, BOOL *pbResult) +{ + Q_UNUSED(pTheirs); + Q_UNUSED(MatchType); + Q_UNUSED(pbResult); + + return E_NOTIMPL; +} + +HRESULT QMFActivate::GetUINT32(REFGUID guidKey, UINT32 *punValue) +{ + Q_UNUSED(guidKey); + Q_UNUSED(punValue); + + return MF_E_ATTRIBUTENOTFOUND; +} + +HRESULT QMFActivate::GetUINT64(REFGUID guidKey, UINT64 *punValue) +{ + Q_UNUSED(guidKey); + Q_UNUSED(punValue); + + return MF_E_ATTRIBUTENOTFOUND; +} + +HRESULT QMFActivate::GetDouble(REFGUID guidKey, double *pfValue) +{ + Q_UNUSED(guidKey); + Q_UNUSED(pfValue); + + return MF_E_ATTRIBUTENOTFOUND; +} + +HRESULT QMFActivate::GetGUID(REFGUID guidKey, GUID *pguidValue) +{ + Q_UNUSED(guidKey); + Q_UNUSED(pguidValue); + + return MF_E_ATTRIBUTENOTFOUND; +} + +HRESULT QMFActivate::GetStringLength(REFGUID guidKey, UINT32 *pcchLength) +{ + Q_UNUSED(guidKey); + Q_UNUSED(pcchLength); + + return MF_E_ATTRIBUTENOTFOUND; +} + +HRESULT QMFActivate::GetString(REFGUID guidKey, LPWSTR pwszValue, UINT32 cchBufSize, UINT32 *pcchLength) +{ + Q_UNUSED(guidKey); + Q_UNUSED(pwszValue); + Q_UNUSED(cchBufSize); + Q_UNUSED(pcchLength); + + return MF_E_ATTRIBUTENOTFOUND; +} + +HRESULT QMFActivate::GetAllocatedString(REFGUID guidKey, LPWSTR *ppwszValue, UINT32 *pcchLength) +{ + Q_UNUSED(guidKey); + Q_UNUSED(ppwszValue); + Q_UNUSED(pcchLength); + + return MF_E_ATTRIBUTENOTFOUND; +} + +HRESULT QMFActivate::GetBlobSize(REFGUID guidKey, UINT32 *pcbBlobSize) +{ + Q_UNUSED(guidKey); + Q_UNUSED(pcbBlobSize); + + return MF_E_ATTRIBUTENOTFOUND; +} + +HRESULT QMFActivate::GetBlob(REFGUID guidKey, UINT8 *pBuf, UINT32 cbBufSize, UINT32 *pcbBlobSize) +{ + Q_UNUSED(guidKey); + Q_UNUSED(pBuf); + Q_UNUSED(cbBufSize); + Q_UNUSED(pcbBlobSize); + + return MF_E_ATTRIBUTENOTFOUND; +} + +HRESULT QMFActivate::GetAllocatedBlob(REFGUID guidKey, UINT8 **ppBuf, UINT32 *pcbSize) +{ + Q_UNUSED(guidKey); + Q_UNUSED(ppBuf); + Q_UNUSED(pcbSize); + + return MF_E_ATTRIBUTENOTFOUND; +} + +HRESULT QMFActivate::GetUnknown(REFGUID guidKey, REFIID riid, LPVOID *ppv) +{ + Q_UNUSED(guidKey); + Q_UNUSED(riid); + Q_UNUSED(ppv); + + return MF_E_ATTRIBUTENOTFOUND; +} + +HRESULT QMFActivate::SetItem(REFGUID guidKey, REFPROPVARIANT Value) +{ + Q_UNUSED(guidKey); + Q_UNUSED(Value); + + return E_NOTIMPL; +} + +HRESULT QMFActivate::DeleteItem(REFGUID guidKey) +{ + Q_UNUSED(guidKey); + + return E_NOTIMPL; +} + +HRESULT QMFActivate::DeleteAllItems() +{ + return E_NOTIMPL; +} + +HRESULT QMFActivate::SetUINT32(REFGUID guidKey, UINT32 unValue) +{ + Q_UNUSED(guidKey); + Q_UNUSED(unValue); + + return E_NOTIMPL; +} + +HRESULT QMFActivate::SetUINT64(REFGUID guidKey, UINT64 unValue) +{ + Q_UNUSED(guidKey); + Q_UNUSED(unValue); + + return E_NOTIMPL; +} + +HRESULT QMFActivate::SetDouble(REFGUID guidKey, double fValue) +{ + Q_UNUSED(guidKey); + Q_UNUSED(fValue); + + return E_NOTIMPL; +} + +HRESULT QMFActivate::SetGUID(REFGUID guidKey, REFGUID guidValue) +{ + Q_UNUSED(guidKey); + Q_UNUSED(guidValue); + + return E_NOTIMPL; +} + +HRESULT QMFActivate::SetString(REFGUID guidKey, LPCWSTR wszValue) +{ + Q_UNUSED(guidKey); + Q_UNUSED(wszValue); + + return E_NOTIMPL; +} + +HRESULT QMFActivate::SetBlob(REFGUID guidKey, const UINT8 *pBuf, UINT32 cbBufSize) +{ + Q_UNUSED(guidKey); + Q_UNUSED(pBuf); + Q_UNUSED(cbBufSize); + + return E_NOTIMPL; +} + +HRESULT QMFActivate::SetUnknown(REFGUID guidKey, IUnknown *pUnknown) +{ + Q_UNUSED(guidKey); + Q_UNUSED(pUnknown); + + return E_NOTIMPL; +} + +HRESULT QMFActivate::LockStore() +{ + m_mutex.lock(); + + return S_OK; +} + +HRESULT QMFActivate::UnlockStore() +{ + m_mutex.unlock(); + + return S_OK; +} + +HRESULT QMFActivate::GetCount(UINT32 *pcItems) +{ + if (!pcItems) { + return E_POINTER; + } else { + *pcItems = 0; + + return S_OK; + } +} + +HRESULT QMFActivate::GetItemByIndex(UINT32 unIndex, GUID *pguidKey, PROPVARIANT *pValue) +{ + Q_UNUSED(unIndex); + Q_UNUSED(pguidKey); + Q_UNUSED(pValue); + + return MF_E_ATTRIBUTENOTFOUND; +} + +HRESULT QMFActivate::CopyAllItems(IMFAttributes *pDest) +{ + Q_UNUSED(pDest); + + return MF_E_ATTRIBUTENOTFOUND; +} diff --git a/src/plugins/wmp/qmfactivate.h b/src/plugins/wmp/qmfactivate.h new file mode 100644 index 000000000..0e1692689 --- /dev/null +++ b/src/plugins/wmp/qmfactivate.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMFACTIVATE_H +#define QMFACTIVATE_H + +#include + +#include + +class QMFActivate : public IMFActivate +{ +public: + // IMFAttributes + HRESULT STDMETHODCALLTYPE GetItem(REFGUID guidKey, PROPVARIANT *pValue); + HRESULT STDMETHODCALLTYPE GetItemType(REFGUID guidKey, MF_ATTRIBUTE_TYPE *pType); + HRESULT STDMETHODCALLTYPE CompareItem(REFGUID guidKey, REFPROPVARIANT Value, BOOL *pbResult); + HRESULT STDMETHODCALLTYPE Compare(IMFAttributes *pTheirs, MF_ATTRIBUTES_MATCH_TYPE MatchType, BOOL *pbResult); + HRESULT STDMETHODCALLTYPE GetUINT32(REFGUID guidKey, UINT32 *punValue); + HRESULT STDMETHODCALLTYPE GetUINT64(REFGUID guidKey, UINT64 *punValue); + HRESULT STDMETHODCALLTYPE GetDouble(REFGUID guidKey, double *pfValue); + HRESULT STDMETHODCALLTYPE GetGUID(REFGUID guidKey, GUID *pguidValue); + HRESULT STDMETHODCALLTYPE GetStringLength(REFGUID guidKey, UINT32 *pcchLength); + HRESULT STDMETHODCALLTYPE GetString(REFGUID guidKey, LPWSTR pwszValue, UINT32 cchBufSize, UINT32 *pcchLength); + HRESULT STDMETHODCALLTYPE GetAllocatedString(REFGUID guidKey, LPWSTR *ppwszValue, UINT32 *pcchLength); + HRESULT STDMETHODCALLTYPE GetBlobSize(REFGUID guidKey, UINT32 *pcbBlobSize); + HRESULT STDMETHODCALLTYPE GetBlob(REFGUID guidKey, UINT8 *pBuf, UINT32 cbBufSize, UINT32 *pcbBlobSize); + HRESULT STDMETHODCALLTYPE GetAllocatedBlob(REFGUID guidKey, UINT8 **ppBuf, UINT32 *pcbSize); + HRESULT STDMETHODCALLTYPE GetUnknown(REFGUID guidKey, REFIID riid, LPVOID *ppv); + HRESULT STDMETHODCALLTYPE SetItem(REFGUID guidKey, REFPROPVARIANT Value); + HRESULT STDMETHODCALLTYPE DeleteItem(REFGUID guidKey); + HRESULT STDMETHODCALLTYPE DeleteAllItems(); + HRESULT STDMETHODCALLTYPE SetUINT32(REFGUID guidKey, UINT32 unValue); + HRESULT STDMETHODCALLTYPE SetUINT64(REFGUID guidKey, UINT64 unValue); + HRESULT STDMETHODCALLTYPE SetDouble(REFGUID guidKey, double fValue); + HRESULT STDMETHODCALLTYPE SetGUID(REFGUID guidKey, REFGUID guidValue); + HRESULT STDMETHODCALLTYPE SetString(REFGUID guidKey, LPCWSTR wszValue); + HRESULT STDMETHODCALLTYPE SetBlob(REFGUID guidKey, const UINT8 *pBuf, UINT32 cbBufSize); + HRESULT STDMETHODCALLTYPE SetUnknown(REFGUID guidKey, IUnknown *pUnknown); + HRESULT STDMETHODCALLTYPE LockStore(); + HRESULT STDMETHODCALLTYPE UnlockStore(); + HRESULT STDMETHODCALLTYPE GetCount(UINT32 *pcItems); + HRESULT STDMETHODCALLTYPE GetItemByIndex(UINT32 unIndex, GUID *pguidKey, PROPVARIANT *pValue); + HRESULT STDMETHODCALLTYPE CopyAllItems(IMFAttributes *pDest); + +private: + volatile LONG m_ref; + QMutex m_mutex; +}; + + +#endif diff --git a/src/plugins/wmp/qwmpevents.cpp b/src/plugins/wmp/qwmpevents.cpp new file mode 100644 index 000000000..66df07b4a --- /dev/null +++ b/src/plugins/wmp/qwmpevents.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwmpevents.h" + +#include "qwmpglobal.h" + +QWmpEvents::QWmpEvents(IUnknown *source, QObject *parent) + : QObject(parent) + , m_ref(1) + , m_connectionPoint(0) + , m_adviseCookie(0) +{ + HRESULT hr; + IConnectionPointContainer *container = 0; + + if ((hr = source->QueryInterface( + IID_IConnectionPointContainer, reinterpret_cast(&container))) != S_OK) { + qWarning("No connection point container, %x: %d", hr, qwmp_error_string(hr)); + } else { + if ((hr = container->FindConnectionPoint( + __uuidof(IWMPEvents), &m_connectionPoint)) != S_OK) { + qWarning("No connection point for IWMPEvents %d", hr); + } else if ((hr = m_connectionPoint->Advise( + static_cast(this), &m_adviseCookie)) != S_OK) { + qWarning("Failed to link to connection point, %x, %s", hr, qwmp_error_string(hr)); + + m_connectionPoint->Release(); + m_connectionPoint = 0; + } + container->Release(); + } +} + +QWmpEvents::~QWmpEvents() +{ + if (m_connectionPoint) { + m_connectionPoint->Unadvise(m_adviseCookie); + m_connectionPoint->Release(); + } + + Q_ASSERT(m_ref == 1); +} + +// IUnknown +HRESULT QWmpEvents::QueryInterface(REFIID riid, void **object) +{ + if (!object) { + return E_POINTER; + } else if (riid == __uuidof(IUnknown) + || riid == __uuidof(IWMPEvents) + || riid == __uuidof(IWMPEvents2) + || riid == __uuidof(IWMPEvents3)) { + *object = static_cast(this); + + AddRef(); + + return S_OK; + } else { + return E_NOINTERFACE; + } +} + +ULONG QWmpEvents::AddRef() +{ + return InterlockedIncrement(&m_ref); +} + +ULONG QWmpEvents::Release() +{ + ULONG ref = InterlockedDecrement(&m_ref); + + Q_ASSERT(ref != 0); + + return ref; +} diff --git a/src/plugins/wmp/qwmpevents.h b/src/plugins/wmp/qwmpevents.h new file mode 100644 index 000000000..1fb40309d --- /dev/null +++ b/src/plugins/wmp/qwmpevents.h @@ -0,0 +1,222 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWMPEVENTS_H +#define QWMPEVENTS_H + +#include + +#include + +class QWmpEvents : public QObject, public IWMPEvents3 +{ + Q_OBJECT +public: + QWmpEvents(IUnknown *source, QObject *parent = 0); + ~QWmpEvents(); + + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + +Q_SIGNALS: + +#ifndef Q_MOC_RUN + // IWMPEvents + void STDMETHODCALLTYPE OpenStateChange(long NewState); + void STDMETHODCALLTYPE PlayStateChange(long NewState); + void STDMETHODCALLTYPE AudioLanguageChange(long LangID); + void STDMETHODCALLTYPE StatusChange(); + void STDMETHODCALLTYPE ScriptCommand(BSTR scType, BSTR Param); + void STDMETHODCALLTYPE NewStream(); + void STDMETHODCALLTYPE Disconnect(long Result); + void STDMETHODCALLTYPE Buffering(VARIANT_BOOL Start); + void STDMETHODCALLTYPE Error(); + void STDMETHODCALLTYPE Warning(long WarningType, long Param, BSTR Description); + void STDMETHODCALLTYPE EndOfStream(long Result); + void STDMETHODCALLTYPE PositionChange(double oldPosition, double newPosition); + void STDMETHODCALLTYPE MarkerHit(long MarkerNum); + void STDMETHODCALLTYPE DurationUnitChange(long NewDurationUnit); + void STDMETHODCALLTYPE CdromMediaChange(long CdromNum); + void STDMETHODCALLTYPE PlaylistChange(IDispatch *Playlist, WMPPlaylistChangeEventType change); + void STDMETHODCALLTYPE CurrentPlaylistChange(WMPPlaylistChangeEventType change); + void STDMETHODCALLTYPE CurrentPlaylistItemAvailable(BSTR bstrItemName); + void STDMETHODCALLTYPE MediaChange(IDispatch *Item); + void STDMETHODCALLTYPE CurrentMediaItemAvailable(BSTR bstrItemName); + void STDMETHODCALLTYPE CurrentItemChange(IDispatch *pdispMedia); + void STDMETHODCALLTYPE MediaCollectionChange(); + void STDMETHODCALLTYPE MediaCollectionAttributeStringAdded( + BSTR bstrAttribName, BSTR bstrAttribVal); + void STDMETHODCALLTYPE MediaCollectionAttributeStringRemoved( + BSTR bstrAttribName, BSTR bstrAttribVal); + void STDMETHODCALLTYPE MediaCollectionAttributeStringChanged( + BSTR bstrAttribName, BSTR bstrOldAttribVal, BSTR bstrNewAttribVal); + void STDMETHODCALLTYPE PlaylistCollectionChange(); + void STDMETHODCALLTYPE PlaylistCollectionPlaylistAdded(BSTR bstrPlaylistName); + void STDMETHODCALLTYPE PlaylistCollectionPlaylistRemoved(BSTR bstrPlaylistName); + void STDMETHODCALLTYPE PlaylistCollectionPlaylistSetAsDeleted( + BSTR bstrPlaylistName, VARIANT_BOOL varfIsDeleted); + void STDMETHODCALLTYPE ModeChange(BSTR ModeName, VARIANT_BOOL NewValue); + void STDMETHODCALLTYPE MediaError(IDispatch *pMediaObject); + void STDMETHODCALLTYPE OpenPlaylistSwitch(IDispatch *pItem); + void STDMETHODCALLTYPE DomainChange(BSTR strDomain); + void STDMETHODCALLTYPE SwitchedToPlayerApplication(); + void STDMETHODCALLTYPE SwitchedToControl(); + void STDMETHODCALLTYPE PlayerDockedStateChange(); + void STDMETHODCALLTYPE PlayerReconnect(); + void STDMETHODCALLTYPE Click(short nButton, short nShiftState, long fX, long fY); + void STDMETHODCALLTYPE DoubleClick(short nButton, short nShiftState, long fX, long fY); + void STDMETHODCALLTYPE KeyDown(short nKeyCode, short nShiftState); + void STDMETHODCALLTYPE KeyPress(short nKeyAscii); + void STDMETHODCALLTYPE KeyUp(short nKeyCode, short nShiftState); + void STDMETHODCALLTYPE MouseDown(short nButton, short nShiftState, long fX, long fY); + void STDMETHODCALLTYPE MouseMove(short nButton, short nShiftState, long fX, long fY); + void STDMETHODCALLTYPE MouseUp(short nButton, short nShiftState, long fX, long fY); + + // IWMPEvents2 + void STDMETHODCALLTYPE DeviceConnect(IWMPSyncDevice *pDevice); + void STDMETHODCALLTYPE DeviceDisconnect(IWMPSyncDevice *pDevice); + void STDMETHODCALLTYPE DeviceStatusChange(IWMPSyncDevice *pDevice, WMPDeviceStatus NewStatus); + void STDMETHODCALLTYPE DeviceSyncStateChange(IWMPSyncDevice *pDevice, WMPSyncState NewState); + void STDMETHODCALLTYPE DeviceSyncError(IWMPSyncDevice *pDevice, IDispatch *pMedia); + void STDMETHODCALLTYPE CreatePartnershipComplete(IWMPSyncDevice *pDevice, HRESULT hrResult); + + // IWMPEvents3 + void STDMETHODCALLTYPE CdromRipStateChange(IWMPCdromRip *pCdromRip, WMPRipState wmprs); + void STDMETHODCALLTYPE CdromRipMediaError(IWMPCdromRip *pCdromRip, IDispatch *pMedia); + void STDMETHODCALLTYPE CdromBurnStateChange(IWMPCdromBurn *pCdromBurn, WMPBurnState wmpbs); + void STDMETHODCALLTYPE CdromBurnMediaError(IWMPCdromBurn *pCdromBurn, IDispatch *pMedia); + void STDMETHODCALLTYPE CdromBurnError(IWMPCdromBurn *pCdromBurn, HRESULT hrError); + void STDMETHODCALLTYPE LibraryConnect(IWMPLibrary *pLibrary); + void STDMETHODCALLTYPE LibraryDisconnect(IWMPLibrary *pLibrary); + void STDMETHODCALLTYPE FolderScanStateChange(WMPFolderScanState wmpfss); + void STDMETHODCALLTYPE StringCollectionChange( + IDispatch *pdispStringCollection, + WMPStringCollectionChangeEventType change, + long lCollectionIndex); + void STDMETHODCALLTYPE MediaCollectionMediaAdded(IDispatch *pdispMedia); + void STDMETHODCALLTYPE MediaCollectionMediaRemoved(IDispatch *pdispMedia); +#else + // Declare again without STDMETHODCALLTYPE for moc's benefit. + + // IWMPEvents + void OpenStateChange(long NewState); + void PlayStateChange(long NewState); + void AudioLanguageChange(long LangID); + void StatusChange(); + void ScriptCommand(BSTR scType, BSTR Param); + void NewStream(); + void Disconnect(long Result); + void Buffering(VARIANT_BOOL Start); + void Error(); + void Warning(long WarningType, long Param, BSTR Description); + void EndOfStream(long Result); + void PositionChange(double oldPosition, double newPosition); + void MarkerHit(long MarkerNum); + void DurationUnitChange(long NewDurationUnit); + void CdromMediaChange(long CdromNum); + void PlaylistChange(IDispatch *Playlist, WMPPlaylistChangeEventType change); + void CurrentPlaylistChange(WMPPlaylistChangeEventType change); + void CurrentPlaylistItemAvailable(BSTR bstrItemName); + void MediaChange(IDispatch *Item); + void CurrentMediaItemAvailable(BSTR bstrItemName); + void CurrentItemChange(IDispatch *pdispMedia); + void MediaCollectionChange(); + void MediaCollectionAttributeStringAdded( + BSTR bstrAttribName, BSTR bstrAttribVal); + void MediaCollectionAttributeStringRemoved( + BSTR bstrAttribName, BSTR bstrAttribVal); + void MediaCollectionAttributeStringChanged( + BSTR bstrAttribName, BSTR bstrOldAttribVal, BSTR bstrNewAttribVal); + void PlaylistCollectionChange(); + void PlaylistCollectionPlaylistAdded(BSTR bstrPlaylistName); + void PlaylistCollectionPlaylistRemoved(BSTR bstrPlaylistName); + void PlaylistCollectionPlaylistSetAsDeleted( + BSTR bstrPlaylistName, VARIANT_BOOL varfIsDeleted); + void ModeChange(BSTR ModeName, VARIANT_BOOL NewValue); + void MediaError(IDispatch *pMediaObject); + void OpenPlaylistSwitch(IDispatch *pItem); + void DomainChange(BSTR strDomain); + void SwitchedToPlayerApplication(); + void SwitchedToControl(); + void PlayerDockedStateChange(); + void PlayerReconnect(); + void Click(short nButton, short nShiftState, long fX, long fY); + void DoubleClick(short nButton, short nShiftState, long fX, long fY); + void KeyDown(short nKeyCode, short nShiftState); + void KeyPress(short nKeyAscii); + void KeyUp(short nKeyCode, short nShiftState); + void MouseDown(short nButton, short nShiftState, long fX, long fY); + void MouseMove(short nButton, short nShiftState, long fX, long fY); + void MouseUp(short nButton, short nShiftState, long fX, long fY); + + // IWMPEvents2 + void DeviceConnect(IWMPSyncDevice *pDevice); + void DeviceDisconnect(IWMPSyncDevice *pDevice); + void DeviceStatusChange(IWMPSyncDevice *pDevice, WMPDeviceStatus NewStatus); + void DeviceSyncStateChange(IWMPSyncDevice *pDevice, WMPSyncState NewState); + void DeviceSyncError(IWMPSyncDevice *pDevice, IDispatch *pMedia); + void CreatePartnershipComplete(IWMPSyncDevice *pDevice, HRESULT hrResult); + + // IWMPEvents3 + void CdromRipStateChange(IWMPCdromRip *pCdromRip, WMPRipState wmprs); + void CdromRipMediaError(IWMPCdromRip *pCdromRip, IDispatch *pMedia); + void CdromBurnStateChange(IWMPCdromBurn *pCdromBurn, WMPBurnState wmpbs); + void CdromBurnMediaError(IWMPCdromBurn *pCdromBurn, IDispatch *pMedia); + void CdromBurnError(IWMPCdromBurn *pCdromBurn, HRESULT hrError); + void LibraryConnect(IWMPLibrary *pLibrary); + void LibraryDisconnect(IWMPLibrary *pLibrary); + void FolderScanStateChange(WMPFolderScanState wmpfss); + void StringCollectionChange( + IDispatch *pdispStringCollection, + WMPStringCollectionChangeEventType change, + long lCollectionIndex); + void MediaCollectionMediaAdded(IDispatch *pdispMedia); + void MediaCollectionMediaRemoved(IDispatch *pdispMedia); +#endif +private: + volatile LONG m_ref; + IConnectionPoint *m_connectionPoint; + DWORD m_adviseCookie; +}; + +#endif diff --git a/src/plugins/wmp/qwmpglobal.cpp b/src/plugins/wmp/qwmpglobal.cpp new file mode 100644 index 000000000..4196bbc4f --- /dev/null +++ b/src/plugins/wmp/qwmpglobal.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwmpglobal.h" + +#include + +const char *qwmp_error_string(HRESULT hr) +{ + switch (hr) { + case S_OK: + return "OK"; + case E_NOINTERFACE: + return "No such interface supported"; + case E_POINTER: + return "Invalid pointer"; + case E_FAIL: + return "Unspecified error"; + case E_NOTIMPL: + return "Not implemented"; + case CLASS_E_NOAGGREGATION: + return "Class does not support aggregation (or class object is remote)"; + case CLASS_E_CLASSNOTAVAILABLE: + return "ClassFactory cannot supply requested class"; + case CLASS_E_NOTLICENSED: + return "Class is not licensed for use"; + default: + return "unknown error code"; + } +} diff --git a/src/plugins/wmp/qwmpglobal.h b/src/plugins/wmp/qwmpglobal.h new file mode 100644 index 000000000..f8152903f --- /dev/null +++ b/src/plugins/wmp/qwmpglobal.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWMPGLOBAL_H +#define QWMPGLOBAL_H + +#include + +#include +#include + +const char *qwmp_error_string(HRESULT hr); + +class QAutoBStr +{ +public: + inline QAutoBStr(const QString &string) + : m_string(::SysAllocString(static_cast(string.utf16()))) + { + } + + inline QAutoBStr(const QUrl &url) + : m_string(::SysAllocString(static_cast(url.toString().utf16()))) + { + } + + inline QAutoBStr(const wchar_t *string) + : m_string(::SysAllocString(string)) + { + } + + inline ~QAutoBStr() + { + ::SysFreeString(m_string); + } + + inline operator BSTR() const { return m_string; } + +private: + BSTR m_string; +}; + + + +#endif diff --git a/src/plugins/wmp/qwmpmetadata.cpp b/src/plugins/wmp/qwmpmetadata.cpp new file mode 100644 index 000000000..1f7cd0f88 --- /dev/null +++ b/src/plugins/wmp/qwmpmetadata.cpp @@ -0,0 +1,442 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwmpmetadata.h" + +#include "qwmpevents.h" +#include "qwmpglobal.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + + +struct QWmpMetaDataKeyLookup +{ + QtMultimediaKit::MetaData key; + const wchar_t *token; +}; + +static const QWmpMetaDataKeyLookup qt_wmpMetaDataKeys[] = +{ + { QtMultimediaKit::Title, L"Title" }, + { QtMultimediaKit::SubTitle, L"WM/SubTitle" }, + { QtMultimediaKit::Author, L"Author" }, + { QtMultimediaKit::Comment, L"Comment" }, + { QtMultimediaKit::Description, L"Description" }, + { QtMultimediaKit::Category, L"WM/Category" }, + { QtMultimediaKit::Genre, L"WM/Genre" }, + //{ QtMultimediaKit::Date, 0 }, + { QtMultimediaKit::Year, L"WM/Year" }, + { QtMultimediaKit::UserRating, L"UserRating" }, + //{ QtMultimediaKit::MetaDatawords, 0 }, + { QtMultimediaKit::Language, L"Language" }, + { QtMultimediaKit::Publisher, L"WM/Publisher" }, + { QtMultimediaKit::Copyright, L"Copyright" }, + { QtMultimediaKit::ParentalRating, L"ParentalRating" }, + { QtMultimediaKit::RatingOrganisation, L"RatingOrganisation" }, + + // Media + { QtMultimediaKit::Size, L"FileSize" }, + { QtMultimediaKit::MediaType, L"MediaType" }, + { QtMultimediaKit::Duration, L"Duration" }, + + // Audio + { QtMultimediaKit::AudioBitRate, L"AudioBitrate" }, + { QtMultimediaKit::AudioCodec, L"AudioCodec" }, + { QtMultimediaKit::ChannelCount, L"Channels" }, + { QtMultimediaKit::SampleRate, L"Frequency" }, + + // Music + { QtMultimediaKit::AlbumTitle, L"WM/AlbumTitle" }, + { QtMultimediaKit::AlbumArtist, L"WM/AlbumArtist" }, + { QtMultimediaKit::ContributingArtist, L"Author" }, + { QtMultimediaKit::Composer, L"WM/Composer" }, + { QtMultimediaKit::Conductor, L"WM/Conductor" }, + { QtMultimediaKit::Lyrics, L"WM/Lyrics" }, + { QtMultimediaKit::Mood, L"WM/Mood" }, + { QtMultimediaKit::TrackNumber, L"WM/TrackNumber" }, + //{ QtMultimediaKit::TrackCount, 0 }, + //{ QtMultimediaKit::CoverArtUrlSmall, 0 }, + //{ QtMultimediaKit::CoverArtUrlLarge, 0 }, + + // Image/Video + //{ QtMultimediaKit::Resolution, 0 }, + //{ QtMultimediaKit::PixelAspectRatio, 0 }, + + // Video + //{ QtMultimediaKit::FrameRate, 0 }, + { QtMultimediaKit::VideoBitRate, L"VideoBitRate" }, + { QtMultimediaKit::VideoCodec, L"VideoCodec" }, + + //{ QtMultimediaKit::PosterUrl, 0 }, + + // Movie + { QtMultimediaKit::ChapterNumber, L"ChapterNumber" }, + { QtMultimediaKit::Director, L"WM/Director" }, + { QtMultimediaKit::LeadPerformer, L"LeadPerformer" }, + { QtMultimediaKit::Writer, L"WM/Writer" }, + + // Photos + { QtMultimediaKit::CameraManufacturer, L"CameraManufacturer" }, + { QtMultimediaKit::CameraModel, L"CameraModel" }, + { QtMultimediaKit::Event, L"Event" }, + { QtMultimediaKit::Subject, L"Subject" } +}; + +QWmpMetaData::QWmpMetaData(IWMPCore3 *player, QWmpEvents *events, QObject *parent) + : QMetaDataReaderControl(parent) + , m_media(0) +{ + player->get_currentMedia(&m_media); + + connect(events, SIGNAL(CurrentItemChange(IDispatch*)), + this, SLOT(currentItemChangeEvent(IDispatch*))); + connect(events, SIGNAL(MediaChange(IDispatch*)), this, SLOT(mediaChangeEvent(IDispatch*))); +} + +QWmpMetaData::~QWmpMetaData() +{ + if (m_media) + m_media->Release(); +} + +bool QWmpMetaData::isMetaDataAvailable() const +{ + return m_media != 0; +} + +bool QWmpMetaData::isWritable() const +{ + return m_media != 0; +} + +QVariant QWmpMetaData::metaData(QtMultimediaKit::MetaData key) const +{ + static const int count = sizeof(qt_wmpMetaDataKeys) / sizeof(QWmpMetaDataKeyLookup); + + switch (key) { + case QtMultimediaKit::Date: + { + QVariant day = value(m_media, QAutoBStr(L"ReleaseDateDay")); + QVariant month = value(m_media, QAutoBStr(L"ReleaseDateMonth")); + QVariant year = value(m_media, QAutoBStr(L"ReleaseDateYear")); + + if (!day.isNull() && !month.isNull() && !year.isNull()) + return QDate(year.toInt(), month.toInt(), day.toInt()); + } + break; + case QtMultimediaKit::CoverArtUrlSmall: + return albumArtUrl(m_media, "_Small.jpg"); + case QtMultimediaKit::CoverArtUrlLarge: + return albumArtUrl(m_media, "_Large.jpg"); + case QtMultimediaKit::Resolution: + { + QVariant width = value(m_media, QAutoBStr(L"WM/VideoWidth")); + QVariant height = value(m_media, QAutoBStr(L"WM/VideoHeight")); + + if (!width.isNull() && !height.isNull()) + return QSize(width.toInt(), height.toInt()); + } + break; + case QtMultimediaKit::PixelAspectRatio: + { + QVariant x = value(m_media, QAutoBStr(L"PixelAspectRatioX")); + QVariant y = value(m_media, QAutoBStr(L"PixelAspectRatioY")); + + if (!x.isNull() && !y.isNull()) + return QSize(x.toInt(), y.toInt()); + } + break; + case QtMultimediaKit::VideoFrameRate: + break; + default: + for (int i = 0; i < count; ++i) { + if (qt_wmpMetaDataKeys[i].key == key) + return value(m_media, QAutoBStr(qt_wmpMetaDataKeys[i].token)); + } + break; + } + return QVariant(); +} + +QList QWmpMetaData::availableMetaData() const +{ + QList keys; + + if (m_media) { + // WMP will return a list of all possible keys so there's no point in filtering the keys + // in the lookup table. + static const int count = sizeof(qt_wmpMetaDataKeys) / sizeof(QWmpMetaDataKeyLookup); + for (int i = 0; i < count; ++i) + keys.append(qt_wmpMetaDataKeys[i].key); + + BSTR string = 0; + if (m_media->get_sourceURL(&string) == S_OK) { + QString url = QString::fromWCharArray(static_cast(string)); + ::SysFreeString(string); + + if (m_media->getItemInfo(QAutoBStr(L"WM/WMCollectionGroupID"), &string) == S_OK) { + QString uuid = QString::fromWCharArray(static_cast(string)); + ::SysFreeString(string); + + QString albumArtLarge = QLatin1String("AlbumArt_") + uuid + QLatin1String("_Large.jpg"); + QString albumArtSmall = QLatin1String("AlbumArt_") + uuid + QLatin1String("_Small.jpg"); + + QDir dir = QFileInfo(url).absoluteDir(); + + if (dir.exists(albumArtLarge)) + keys.append(QtMultimediaKit::CoverArtUrlLarge); + if (dir.exists(albumArtSmall)) + keys.append(QtMultimediaKit::CoverArtUrlSmall); + } + } + } + return keys; +} + +QVariant QWmpMetaData::extendedMetaData(const QString &key) const +{ + return value(m_media, QAutoBStr(key)); +} + +QStringList QWmpMetaData::availableExtendedMetaData() const +{ + return keys(m_media); +} + +void QWmpMetaData::currentItemChangeEvent(IDispatch *dispatch) +{ + IWMPMedia *media = m_media; + + m_media = 0; + if (dispatch) + dispatch->QueryInterface(__uuidof(IWMPMedia), reinterpret_cast(&m_media)); + + if (media) { + if (m_media) + emit metaDataChanged(); + else + emit metaDataAvailableChanged(false); + + media->Release(); + } else { + if (m_media) + emit metaDataAvailableChanged(false); + } +} + +void QWmpMetaData::mediaChangeEvent(IDispatch *dispatch) +{ + IWMPMedia *media = 0; + if (dispatch && dispatch->QueryInterface( + __uuidof(IWMPMedia), reinterpret_cast(&media)) == S_OK) { + VARIANT_BOOL isEqual = VARIANT_FALSE; + if (media->get_isIdentical(m_media, &isEqual) == S_OK && isEqual) + emit metaDataChanged(); + media->Release(); + } +} + + +QStringList QWmpMetaData::keys(IWMPMedia *media) +{ + QStringList keys; + + long count = 0; + if (media && media->get_attributeCount(&count) == S_OK) { + for (long i = 0; i < count; ++i) { + BSTR string; + if (media->getAttributeName(i, &string) == S_OK) { + keys.append(QString::fromWCharArray(string, ::SysStringLen(string))); + + ::SysFreeString(string); + } + } + } + return keys; +} + +QVariant QWmpMetaData::value(IWMPMedia *media, BSTR key) +{ + QVariantList values; + IWMPMedia3 *media3 = 0; + if (media && media->QueryInterface( + __uuidof(IWMPMedia3), reinterpret_cast(&media3)) == S_OK) { + long count = 0; + media3->getAttributeCountByType(key, 0, &count); + + // The count appears to only be valid for static properties, dynamic properties like + // PlaylistIndex will have a count of zero but return a value for index 0. + if (count == 0) + count = 1; + + for (long i = 0; i < count; ++i) { + VARIANT var; + VariantInit(&var); + + if (media3->getItemInfoByType(key, 0, i, &var) == S_OK) { + QVariant value = convertVariant(var); + + if (!value.isNull()) + values.append(value); + + VariantClear(&var); + } + } + media3->Release(); + } + + switch (values.count()) { + case 0: + return QVariant(); + case 1: + return values.first(); + default: + return values; + } +} + +QMediaContent QWmpMetaData::resources(IWMPMedia *media) +{ + QMediaContent content; + + BSTR string = 0; + if (media->get_sourceURL(&string) == S_OK) { + QString url = QString::fromWCharArray(static_cast(string)); + ::SysFreeString(string); + + content = QMediaContent(QUrl(url)); + } + + return content; +} + +QVariant QWmpMetaData::convertVariant(const VARIANT &variant) +{ + switch (variant.vt) { + case VT_I2: + return variant.iVal; + case VT_I4: + return variant.lVal; + case VT_I8: + return variant.llVal; + case VT_UI2: + return variant.uiVal; + case VT_UI4: + return quint32(variant.ulVal); + case VT_UI8: + return variant.ullVal; + case VT_INT: + return variant.intVal; + case VT_UINT: + return variant.uintVal; + case VT_BSTR: + return QString::fromWCharArray(variant.bstrVal, ::SysStringLen(variant.bstrVal)); + case VT_DISPATCH: + { + IWMPMetadataPicture *picture = 0; + IWMPMetadataText *text = 0; + + if (variant.pdispVal->QueryInterface( + __uuidof(IWMPMetadataPicture), reinterpret_cast(&picture)) == S_OK) { + QUrl url; + BSTR string; + if (picture->get_URL(&string) == S_OK) { + url = QUrl(QString::fromWCharArray(string, ::SysStringLen(string))); + + ::SysFreeString(string); + } + picture->Release(); + return qVariantFromValue(url); + } else if (variant.pdispVal->QueryInterface( + __uuidof(IWMPMetadataText), reinterpret_cast(&text)) == S_OK) { + QString description; + BSTR string; + if (text->get_description(&string) == S_OK) { + description = QString::fromWCharArray(string, SysStringLen(string)); + + ::SysFreeString(string); + } + text->Release(); + return description; + } else { + qWarning("Unknown dispatch type"); + } + } + break; + default: + qWarning("Unsupported Type %d %x", variant.vt, variant.vt); + break; + } + + return QVariant(); +} + +QVariant QWmpMetaData::albumArtUrl(IWMPMedia *media, const char *suffix) +{ + BSTR string = 0; + if (media && media->get_sourceURL(&string) == S_OK) { + QString url = QString::fromWCharArray(static_cast(string)); + ::SysFreeString(string); + + if (media->getItemInfo(QAutoBStr(L"WM/WMCollectionGroupID"), &string) == S_OK) { + QString uuid = QString::fromWCharArray(static_cast(string)); + ::SysFreeString(string); + + QString fileName = QLatin1String("AlbumArt_") + uuid + QLatin1String(suffix); + + QDir dir = QFileInfo(url).absoluteDir(); + + if (dir.exists(fileName)) { + return qVariantFromValue( + QUrl(QLatin1String("file:///") + dir.absoluteFilePath(fileName))); + } + } + } + return QVariant(); +} diff --git a/src/plugins/wmp/qwmpmetadata.h b/src/plugins/wmp/qwmpmetadata.h new file mode 100644 index 000000000..b01a05c4e --- /dev/null +++ b/src/plugins/wmp/qwmpmetadata.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWMPMETADATA_H +#define QWMPMETADATA_H + +#include +#include + +#include + +QT_BEGIN_NAMESPACE +class QMediaContent; +QT_END_NAMESPACE + +class QWmpEvents; + +QT_USE_NAMESPACE + +class QWmpMetaData : public QMetaDataReaderControl +{ + Q_OBJECT +public: + QWmpMetaData(IWMPCore3 *player, QWmpEvents *events, QObject *parent = 0); + ~QWmpMetaData(); + + bool isMetaDataAvailable() const; + bool isWritable() const; + + QVariant metaData(QtMultimediaKit::MetaData key) const; + QList availableMetaData() const; + + QVariant extendedMetaData(const QString &key) const ; + QStringList availableExtendedMetaData() const; + + static QStringList keys(IWMPMedia *media); + static QVariant value(IWMPMedia *media, BSTR key); + static QMediaContent resources(IWMPMedia *media); + static QVariant convertVariant(const VARIANT &variant); + static QVariant albumArtUrl(IWMPMedia *media, const char *suffix); + +private Q_SLOTS: + void currentItemChangeEvent(IDispatch *dispatch); + void mediaChangeEvent(IDispatch *dispatch); + +private: + IWMPMedia *m_media; +}; + +#endif diff --git a/src/plugins/wmp/qwmpplayercontrol.cpp b/src/plugins/wmp/qwmpplayercontrol.cpp new file mode 100644 index 000000000..be8f107b8 --- /dev/null +++ b/src/plugins/wmp/qwmpplayercontrol.cpp @@ -0,0 +1,465 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwmpplayercontrol.h" + +#include "qwmpevents.h" +#include "qwmpglobal.h" +#include "qwmpmetadata.h" +#include "qwmpplaylist.h" + +#include +#include + +#include +#include +#include +#include + +QWmpPlayerControl::QWmpPlayerControl(IWMPCore3 *player, QWmpEvents *events, QObject *parent) + : QMediaPlayerControl(parent) + , m_player(player) + , m_controls(0) + , m_settings(0) + , m_state(QMediaPlayer::StoppedState) + , m_changes(0) + , m_buffering(false) + , m_audioAvailable(false) + , m_videoAvailable(false) +{ + m_player->get_controls(&m_controls); + m_player->get_settings(&m_settings); + m_player->get_network(&m_network); + + if (m_settings) + m_settings->put_autoStart(FALSE); + + WMPPlayState state = wmppsUndefined; + if (m_player->get_playState(&state) == S_OK) + playStateChangeEvent(state); + + connect(events, SIGNAL(Buffering(VARIANT_BOOL)), this, SLOT(bufferingEvent(VARIANT_BOOL))); + connect(events, SIGNAL(PositionChange(double,double)), + this, SLOT(positionChangeEvent(double,double))); + connect(events, SIGNAL(PlayStateChange(long)), this, SLOT(playStateChangeEvent(long))); + connect(events, SIGNAL(CurrentItemChange(IDispatch*)), + this, SLOT(currentItemChangeEvent(IDispatch*))); + connect(events, SIGNAL(MediaChange(IDispatch*)), this, SLOT(mediaChangeEvent(IDispatch*))); +} + +QWmpPlayerControl::~QWmpPlayerControl() +{ + if (m_controls) m_controls->Release(); + if (m_settings) m_settings->Release(); + if (m_network) m_network->Release(); +} + +QMediaPlayer::State QWmpPlayerControl::state() const +{ + return m_state; +} + +QMediaPlayer::MediaStatus QWmpPlayerControl::mediaStatus() const +{ + return m_status; +} + +qint64 QWmpPlayerControl::duration() const +{ + double duration = 0.; + + IWMPMedia *media = 0; + if (m_controls && m_controls->get_currentItem(&media) == S_OK) { + media->get_duration(&duration); + media->Release(); + } + + return duration * 1000; +} + +qint64 QWmpPlayerControl::position() const +{ + double position = 0.0; + + if (m_controls) + m_controls->get_currentPosition(&position); + + return position * 1000; +} + +void QWmpPlayerControl::setPosition(qint64 position) +{ + if (m_controls) + m_controls->put_currentPosition(double(position) / 1000.); +} + +int QWmpPlayerControl::volume() const +{ + long volume = 0; + + if (m_settings) + m_settings->get_volume(&volume); + + return volume; +} + +void QWmpPlayerControl::setVolume(int volume) +{ + if (m_settings && m_settings->put_volume(volume) == S_OK) + emit volumeChanged(volume); +} + +bool QWmpPlayerControl::isMuted() const +{ + VARIANT_BOOL mute = FALSE; + + if (m_settings) + m_settings->get_mute(&mute); + + return mute; +} + +void QWmpPlayerControl::setMuted(bool muted) +{ + if (m_settings && m_settings->put_mute(muted ? TRUE : FALSE) == S_OK) + emit mutedChanged(muted); + +} + +int QWmpPlayerControl::bufferStatus() const +{ + long progress = 0; + + if (m_network) + m_network->get_bufferingProgress(&progress); + + return progress; +} + +bool QWmpPlayerControl::isVideoAvailable() const +{ + return m_videoAvailable; +} + +bool QWmpPlayerControl::isAudioAvailable() const +{ + return m_audioAvailable; +} + +void QWmpPlayerControl::setAudioAvailable(bool available) +{ + if (m_audioAvailable != available) + emit audioAvailableChanged(m_audioAvailable = available); +} + +void QWmpPlayerControl::setVideoAvailable(bool available) +{ + if (m_videoAvailable != available) + emit videoAvailableChanged(m_videoAvailable = available); +} + +bool QWmpPlayerControl::isSeekable() const +{ + return true; +} + +QMediaTimeRange QWmpPlayerControl::availablePlaybackRanges() const +{ + QMediaTimeRange ranges; + + IWMPMedia *media = 0; + if (m_controls && m_controls->get_currentItem(&media) == S_OK) { + double duration = 0; + media->get_duration(&duration); + media->Release(); + + if(duration > 0) + ranges.addInterval(0, duration * 1000); + } + + return ranges; +} + +qreal QWmpPlayerControl::playbackRate() const +{ + double rate = 0.; + + if (m_settings) + m_settings->get_rate(&rate); + + return rate; +} + +void QWmpPlayerControl::setPlaybackRate(qreal rate) +{ + if (m_settings) + m_settings->put_rate(rate); +} + +void QWmpPlayerControl::play() +{ + if (m_controls) + m_controls->play(); +} + +void QWmpPlayerControl::pause() +{ + if (m_controls) + m_controls->pause(); +} + +void QWmpPlayerControl::stop() +{ + if (m_controls) + m_controls->stop(); +} + +QMediaContent QWmpPlayerControl::media() const +{ + QMediaResourceList resources; + + QUrl tmpUrl = url(); + + if (!tmpUrl.isEmpty()) + resources << QMediaResource(tmpUrl); + + return resources; +} + +const QIODevice *QWmpPlayerControl::mediaStream() const +{ + return 0; +} + +void QWmpPlayerControl::setMedia(const QMediaContent &content, QIODevice *stream) +{ + if (!content.isNull() && !stream) + setUrl(content.canonicalUrl()); + else + setUrl(QUrl()); +} + +bool QWmpPlayerControl::event(QEvent *event) +{ + if (event->type() == QEvent::UpdateRequest) { + const int changes = m_changes; + m_changes = 0; + + if (changes & DurationChanged) + emit durationChanged(duration()); + if (changes & PositionChanged) + emit positionChanged(position()); + if (changes & StatusChanged) + emit mediaStatusChanged(m_status); + if (changes & StateChanged) + emit stateChanged(m_state); + + return true; + } else { + return QMediaPlayerControl::event(event); + } +} + +void QWmpPlayerControl::scheduleUpdate(int change) +{ + if (m_changes == 0) + QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); + + m_changes |= change; +} + +void QWmpPlayerControl::bufferingEvent(VARIANT_BOOL buffering) +{ + if (m_state != QMediaPlayer::StoppedState) { + m_status = buffering + ? QMediaPlayer::BufferingMedia + : QMediaPlayer::BufferedMedia; + + scheduleUpdate(StatusChanged); + } +} + +void QWmpPlayerControl::currentItemChangeEvent(IDispatch *) +{ + scheduleUpdate(DurationChanged); +} + +void QWmpPlayerControl::mediaChangeEvent(IDispatch *dispatch) +{ + IWMPMedia *media = 0; + if (dispatch && dispatch->QueryInterface( + __uuidof(IWMPMedia), reinterpret_cast(&media)) == S_OK) { + IWMPMedia *currentMedia = 0; + if (m_controls && m_controls->get_currentItem(¤tMedia) == S_OK) { + VARIANT_BOOL isEqual = VARIANT_FALSE; + if (media->get_isIdentical(currentMedia, &isEqual) == S_OK && isEqual) + scheduleUpdate(DurationChanged); + + currentMedia->Release(); + } + media->Release(); + } +} + +void QWmpPlayerControl::positionChangeEvent(double , double) +{ + scheduleUpdate(PositionChanged); +} + +void QWmpPlayerControl::playStateChangeEvent(long state) +{ + switch (state) { + case wmppsUndefined: + m_state = QMediaPlayer::StoppedState; + m_status = QMediaPlayer::UnknownMediaStatus; + scheduleUpdate(StatusChanged | StateChanged); + break; + case wmppsStopped: + if (m_state != QMediaPlayer::StoppedState) { + m_state = QMediaPlayer::StoppedState; + scheduleUpdate(StateChanged); + + if (m_status != QMediaPlayer::EndOfMedia) { + m_status = QMediaPlayer::LoadedMedia; + scheduleUpdate(StatusChanged); + } + } + break; + case wmppsPaused: + if (m_state != QMediaPlayer::PausedState && m_status != QMediaPlayer::BufferedMedia) { + m_state = QMediaPlayer::PausedState; + m_status = QMediaPlayer::BufferedMedia; + scheduleUpdate(StatusChanged | StateChanged); + } else if (m_state != QMediaPlayer::PausedState) { + m_state = QMediaPlayer::PausedState; + scheduleUpdate(StateChanged); + } else if (m_status != QMediaPlayer::BufferedMedia) { + m_status = QMediaPlayer::BufferedMedia; + + scheduleUpdate(StatusChanged); + } + break; + case wmppsPlaying: + case wmppsScanForward: + case wmppsScanReverse: + if (m_state != QMediaPlayer::PlayingState && m_status != QMediaPlayer::BufferedMedia) { + m_state = QMediaPlayer::PlayingState; + m_status = QMediaPlayer::BufferedMedia; + scheduleUpdate(StatusChanged | StateChanged); + } else if (m_state != QMediaPlayer::PlayingState) { + m_state = QMediaPlayer::PlayingState; + scheduleUpdate(StateChanged); + } else if (m_status != QMediaPlayer::BufferedMedia) { + m_status = QMediaPlayer::BufferedMedia; + scheduleUpdate(StatusChanged); + } + + if (m_state != QMediaPlayer::PlayingState) { + m_state = QMediaPlayer::PlayingState; + scheduleUpdate(StateChanged); + } + if (m_status != QMediaPlayer::BufferedMedia) { + m_status = QMediaPlayer::BufferedMedia; + scheduleUpdate(StatusChanged); + } + break; + case wmppsBuffering: + case wmppsWaiting: + if (m_status != QMediaPlayer::StalledMedia && m_state != QMediaPlayer::StoppedState) { + m_status = QMediaPlayer::StalledMedia; + scheduleUpdate(StatusChanged); + } + break; + case wmppsMediaEnded: + if (m_status != QMediaPlayer::EndOfMedia && m_state != QMediaPlayer::StoppedState) { + m_state = QMediaPlayer::StoppedState; + m_status = QMediaPlayer::EndOfMedia; + scheduleUpdate(StatusChanged | StateChanged); + } + break; + case wmppsTransitioning: + break; + case wmppsReady: + if (m_status != QMediaPlayer::LoadedMedia) { + m_status = QMediaPlayer::LoadedMedia; + scheduleUpdate(StatusChanged); + } + + if (m_state != QMediaPlayer::StoppedState) { + m_state = QMediaPlayer::StoppedState; + scheduleUpdate(StateChanged); + } + break; + case wmppsReconnecting: + if (m_status != QMediaPlayer::StalledMedia && m_state != QMediaPlayer::StoppedState) { + m_status = QMediaPlayer::StalledMedia; + scheduleUpdate(StatusChanged); + } + break; + default: + break; + } +} + +QUrl QWmpPlayerControl::url() const +{ + BSTR string; + if (m_player && m_player->get_URL(&string) == S_OK) { + QUrl url(QString::fromWCharArray(string, SysStringLen(string)), QUrl::StrictMode); + + SysFreeString(string); + + return url; + } else { + return QUrl(); + } +} + +void QWmpPlayerControl::setUrl(const QUrl &url) +{ + if (url != QWmpPlayerControl::url() && m_player) { + BSTR string = SysAllocString(reinterpret_cast(url.toString().unicode())); + + m_player->put_URL(string); + + SysFreeString(string); + } +} diff --git a/src/plugins/wmp/qwmpplayercontrol.h b/src/plugins/wmp/qwmpplayercontrol.h new file mode 100644 index 000000000..d966b38b2 --- /dev/null +++ b/src/plugins/wmp/qwmpplayercontrol.h @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWMPPLAYERCONTROL_H +#define QWMPPLAYERCONTROL_H + +#include + +#include + +class QWmpEvents; +class QWmpPlaylist; + +QT_USE_NAMESPACE +class QWmpPlayerControl : public QMediaPlayerControl +{ + Q_OBJECT +public: + QWmpPlayerControl( + IWMPCore3 *player, QWmpEvents *events, QObject *parent = 0); + ~QWmpPlayerControl(); + + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + + QMediaPlaylist* mediaPlaylist() const; + bool setMediaPlaylist(QMediaPlaylist *playlist); + + qint64 duration() const; + + qint64 position() const; + void setPosition(qint64 position); + + int playlistPosition() const; + void setPlaylistPosition(int position); + + int volume() const; + void setVolume(int volume); + + bool isMuted() const; + void setMuted(bool muted); + + int bufferStatus() const; + + bool isAudioAvailable() const; + void setAudioAvailable(bool available); + + bool isVideoAvailable() const; + void setVideoAvailable(bool available); + + qreal playbackRate() const; + void setPlaybackRate(qreal rate); + + bool isSeekable() const; + QMediaTimeRange availablePlaybackRanges() const; + + void play(); + void pause(); + void stop(); + + QMediaContent media() const; + const QIODevice *mediaStream() const; + void setMedia(const QMediaContent &content, QIODevice *stream); + + QUrl url() const; + void setUrl(const QUrl &url); + + bool event(QEvent *event); + + using QMediaPlayerControl::positionChanged; + +private Q_SLOTS: + + void bufferingEvent(VARIANT_BOOL buffering); + void currentItemChangeEvent(IDispatch *dispatch); + void mediaChangeEvent(IDispatch *dispatch); + void positionChangeEvent(double from, double to); + void playStateChangeEvent(long state); + +private: + enum Change + { + StateChanged = 0x01, + StatusChanged = 0x02, + PositionChanged = 0x04, + DurationChanged = 0x08 + }; + + void scheduleUpdate(int change); + + IWMPCore3 *m_player; + IWMPControls *m_controls; + IWMPSettings *m_settings; + IWMPNetwork *m_network; + QMediaPlayer::State m_state; + QMediaPlayer::MediaStatus m_status; + int m_changes; + bool m_buffering; + bool m_audioAvailable; + bool m_videoAvailable; +}; + +#endif diff --git a/src/plugins/wmp/qwmpplayerservice.cpp b/src/plugins/wmp/qwmpplayerservice.cpp new file mode 100644 index 000000000..e185aaf46 --- /dev/null +++ b/src/plugins/wmp/qwmpplayerservice.cpp @@ -0,0 +1,355 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwmpplayerservice.h" + +#ifdef QWMP_EVR +#include "qevrvideooverlay.h" +#endif + +#include "qwmpglobal.h" +#include "qwmpmetadata.h" +#include "qwmpplayercontrol.h" +#include "qwmpplaylist.h" +#include "qwmpplaylistcontrol.h" +#include "qwmpvideooverlay.h" + +#include + +#include +#include +#include +#include + +#include +#include + +QWmpPlayerService::QWmpPlayerService(EmbedMode mode, QObject *parent) + : QMediaService(parent) + , m_ref(1) + , m_embedMode(mode) + , m_player(0) + , m_oleObject(0) + , m_events(0) + , m_control(0) + , m_metaData(0) + , m_playlist(0) + , m_activeVideoOverlay(0) + , m_oleVideoOverlay(0) +#ifdef QWMP_EVR + , m_evrVideoOverlay(0) +#endif +{ + HRESULT hr; + + if ((hr = CoCreateInstance( + __uuidof(WindowsMediaPlayer), + 0, + CLSCTX_INPROC_SERVER, + __uuidof(IWMPPlayer4), + reinterpret_cast(&m_player))) != S_OK) { + qWarning("failed to create media player control, %x: %s", hr, qwmp_error_string(hr)); + } else { + m_events = new QWmpEvents(m_player); + + if ((hr = m_player->QueryInterface( + __uuidof(IOleObject), reinterpret_cast(&m_oleObject))) != S_OK) { + qWarning("No IOleObject interface, %x: %s", hr, qwmp_error_string(hr)); + } else if ((hr = m_oleObject->SetClientSite(this)) != S_OK) { + qWarning("Failed to set site, %x: %s", hr, qwmp_error_string(hr)); + } + + if (m_embedMode == LocalEmbed) + m_oleVideoOverlay = new QWmpVideoOverlay(m_player, m_oleObject, this); + + m_metaData = new QWmpMetaData(m_player, m_events); + m_playlist = new QWmpPlaylistControl(m_player, m_events); + m_control = new QWmpPlayerControl(m_player, m_events); + } +} + +QWmpPlayerService::~QWmpPlayerService() +{ + delete m_control; + delete m_metaData; + delete m_playlist; + delete m_events; + + if (m_oleObject) { + m_oleObject->SetClientSite(0); + m_oleObject->Release(); + delete m_oleVideoOverlay; + } + +#ifdef QWMP_EVR + delete m_evrVideoOverlay; +#endif + + + if (m_player) + m_player->Release(); + + Q_ASSERT(m_ref == 1); +} + +QMediaControl *QWmpPlayerService::requestControl(const char *name) +{ + if (qstrcmp(name, QMediaPlayerControl_iid) == 0) { + return m_control; + } else if (qstrcmp(name, QMetaDataReaderControl_iid) == 0) { + return m_metaData; + } else if (qstrcmp(name, QMediaPlaylistControl_iid) == 0) { + return m_playlist; + } else if (qstrcmp(name, QVideoWindowControl_iid) == 0 + && m_embedMode == LocalEmbed + && m_player + && !m_activeVideoOverlay) { +#ifdef QWMP_EVR + IWMPVideoRenderConfig *config = 0; + if (m_player->QueryInterface( + __uuidof(IWMPVideoRenderConfig), reinterpret_cast(&config)) == S_OK) { + if (HINSTANCE evrHwnd = LoadLibrary(L"evr")) { + m_evrVideoOverlay = new QEvrVideoOverlay(evrHwnd); + + if (SUCCEEDED(config->put_presenterActivate( + static_cast(m_evrVideoOverlay)))) { + connect(m_events, SIGNAL(OpenStateChange(long)), + m_evrVideoOverlay, SLOT(openStateChanged(long))); + } else { + delete m_evrVideoOverlay; + + m_evrVideoOverlay = 0; + } + } + config->Release(); + } + + if (m_evrVideoOverlay) { + m_activeVideoOverlay = m_evrVideoOverlay; + + return m_evrVideoOverlay; + } else +#endif + if (SUCCEEDED(m_player->put_uiMode(QAutoBStr(L"none")))) { + m_activeVideoOverlay = m_oleVideoOverlay; + + return m_oleVideoOverlay; + } + } + return 0; +} + +void QWmpPlayerService::releaseControl(QMediaControl *control) +{ + if (!control) { + qWarning("QMediaService::releaseControl():" + " Attempted release of null control"); +#ifdef QWMP_EVR + } else if (control == m_evrVideoOverlay) { + + IWMPVideoRenderConfig *config = 0; + if (m_player->QueryInterface( + __uuidof(IWMPVideoRenderConfig), reinterpret_cast(&config)) == S_OK) { + config->put_presenterActivate(0); + config->Release(); + } + + delete m_evrVideoOverlay; + + m_evrVideoOverlay = 0; + m_activeVideoOverlay = 0; +#endif + } else if (control == m_oleVideoOverlay) { + m_player->put_uiMode(QAutoBStr(L"invisible")); + m_oleVideoOverlay->setWinId(0); + + m_activeVideoOverlay = 0; + } +} + +// IUnknown +HRESULT QWmpPlayerService::QueryInterface(REFIID riid, void **object) +{ + if (!object) { + return E_POINTER; + } else if (riid == __uuidof(IUnknown) + || riid == __uuidof(IOleClientSite)) { + *object = static_cast(this); + } else if (riid == __uuidof(IServiceProvider)) { + *object = static_cast(this); + } else if (riid == __uuidof(IWMPRemoteMediaServices)) { + *object = static_cast(this); + } else if (riid == __uuidof(IOleWindow) + || riid == __uuidof(IOleInPlaceSite)) { + *object = static_cast(m_oleVideoOverlay); + } else if (riid == __uuidof(IOleInPlaceUIWindow) + || riid == __uuidof(IOleInPlaceFrame)) { + *object = static_cast(m_oleVideoOverlay); + } else { + *object = 0; + } + + if (*object) { + AddRef(); + + return S_OK; + } else { + return E_NOINTERFACE; + } +} + +ULONG QWmpPlayerService::AddRef() +{ + return InterlockedIncrement(&m_ref); +} + +ULONG QWmpPlayerService::Release() +{ + ULONG ref = InterlockedDecrement(&m_ref); + + Q_ASSERT(ref != 0); + + return ref; +} + +// IOleClientSite +HRESULT QWmpPlayerService::SaveObject() +{ + return E_NOTIMPL; +} + +HRESULT QWmpPlayerService::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppmk) +{ + Q_UNUSED(dwAssign); + Q_UNUSED(dwWhichMoniker); + Q_UNUSED(ppmk); + + return E_NOTIMPL; +} + +HRESULT QWmpPlayerService::GetContainer(IOleContainer **ppContainer) +{ + if (!ppContainer) { + return E_POINTER; + } else { + *ppContainer = 0; + + return E_NOINTERFACE; + } +} + +HRESULT QWmpPlayerService::ShowObject() +{ + return S_OK; +} + +HRESULT QWmpPlayerService::OnShowWindow(BOOL fShow) +{ + Q_UNUSED(fShow); + + return S_OK; +} + +HRESULT QWmpPlayerService::RequestNewObjectLayout() +{ + return E_NOTIMPL; +} + +// IServiceProvider +HRESULT QWmpPlayerService::QueryService(REFGUID guidService, REFIID riid, void **ppvObject) +{ + Q_UNUSED(guidService); + + if (!ppvObject) { + return E_POINTER; + } else if (riid == __uuidof(IWMPRemoteMediaServices)) { + *ppvObject = static_cast(this); + + AddRef(); + + return S_OK; + } else { + return E_NOINTERFACE; + } +} + +// IWMPRemoteMediaServices +HRESULT QWmpPlayerService::GetServiceType(BSTR *pbstrType) +{ + if (!pbstrType) { + return E_POINTER; + } else if (m_embedMode == RemoteEmbed) { + *pbstrType = ::SysAllocString(L"Remote"); + + return S_OK; + } else { + *pbstrType = ::SysAllocString(L"Local"); + + return S_OK; + } +} + +HRESULT QWmpPlayerService::GetApplicationName(BSTR *pbstrName) +{ + if (!pbstrName) { + return E_POINTER; + } else { + *pbstrName = ::SysAllocString(static_cast( + QCoreApplication::applicationName().utf16())); + + return S_OK; + } +} + +HRESULT QWmpPlayerService::GetScriptableObject(BSTR *pbstrName, IDispatch **ppDispatch) +{ + Q_UNUSED(pbstrName); + Q_UNUSED(ppDispatch); + + return E_NOTIMPL; +} + +HRESULT QWmpPlayerService::GetCustomUIMode(BSTR *pbstrFile) +{ + Q_UNUSED(pbstrFile); + + return E_NOTIMPL; +} diff --git a/src/plugins/wmp/qwmpplayerservice.h b/src/plugins/wmp/qwmpplayerservice.h new file mode 100644 index 000000000..ba79a9a68 --- /dev/null +++ b/src/plugins/wmp/qwmpplayerservice.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWMPPLAYERSERVICE_H +#define QWMPPLAYERSERVICE_H + +#include "qwmpevents.h" + +#include + +QT_BEGIN_NAMESPACE +class QMediaMetaData; +class QMediaPlayerControl; +class QMediaPlaylist; +class QVideoWindowControl; +QT_END_NAMESPACE + +#ifdef QWMP_EVR +class QEvrVideoOverlay; +#endif + +class QWmpMetaData; +class QWmpPlayerControl; +class QWmpPlaylist; +class QWmpPlaylistControl; +class QWmpVideoOverlay; + +QT_USE_NAMESPACE +class QWmpPlayerService + : public QMediaService + , public IOleClientSite + , public IServiceProvider + , public IWMPRemoteMediaServices +{ + Q_OBJECT +public: + enum EmbedMode + { + LocalEmbed, + RemoteEmbed + }; + + QWmpPlayerService(EmbedMode mode, QObject *parent = 0); + ~QWmpPlayerService(); + + QMediaControl *requestControl(const char *name); + void releaseControl(QMediaControl *control); + + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **object); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + // IOleClientSite + HRESULT STDMETHODCALLTYPE SaveObject(); + HRESULT STDMETHODCALLTYPE GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppmk); + HRESULT STDMETHODCALLTYPE GetContainer(IOleContainer **ppContainer); + HRESULT STDMETHODCALLTYPE ShowObject(); + HRESULT STDMETHODCALLTYPE OnShowWindow(BOOL fShow); + HRESULT STDMETHODCALLTYPE RequestNewObjectLayout(); + + // IServiceProvider + HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject); + + // IWMPRemoteMediaServices + HRESULT STDMETHODCALLTYPE GetServiceType(BSTR *pbstrType); + HRESULT STDMETHODCALLTYPE GetApplicationName(BSTR *pbstrName); + HRESULT STDMETHODCALLTYPE GetScriptableObject(BSTR *pbstrName, IDispatch **ppDispatch); + HRESULT STDMETHODCALLTYPE GetCustomUIMode(BSTR *pbstrFile); + +private: + volatile LONG m_ref; + const EmbedMode m_embedMode; + IWMPPlayer4 *m_player; + IOleObject *m_oleObject; + QWmpEvents *m_events; + QWmpPlayerControl *m_control; + QWmpMetaData *m_metaData; + QWmpPlaylistControl *m_playlist; + QVideoWindowControl *m_activeVideoOverlay; + QWmpVideoOverlay *m_oleVideoOverlay; +#ifdef QWMP_EVR + QEvrVideoOverlay *m_evrVideoOverlay; +#endif +}; + +#endif diff --git a/src/plugins/wmp/qwmpplaylist.cpp b/src/plugins/wmp/qwmpplaylist.cpp new file mode 100644 index 000000000..10ce753b1 --- /dev/null +++ b/src/plugins/wmp/qwmpplaylist.cpp @@ -0,0 +1,296 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwmpplaylist.h" + +#include "qwmpevents.h" +#include "qwmpmetadata.h" +#include "qwmpglobal.h" + +#include +#include +#include + +QWmpPlaylist::QWmpPlaylist(IWMPCore3 *player, QWmpEvents *events, QObject *parent) + : QMediaPlaylistProvider(parent) + , m_player(player) + , m_playlist(0) + , m_count(0) +{ + if (m_player && m_player->get_currentPlaylist(&m_playlist) == S_OK) + m_playlist->get_count(&m_count); + + connect(events, SIGNAL(CurrentPlaylistChange(WMPPlaylistChangeEventType)), + this, SLOT(currentPlaylistChangeEvent(WMPPlaylistChangeEventType))); + connect(events, SIGNAL(OpenPlaylistSwitch(IDispatch*)), + this, SLOT(openPlaylistChangeEvent(IDispatch*))); + connect(events, SIGNAL(MediaChange(IDispatch*)), this, SLOT(mediaChangeEvent(IDispatch*))); +} + +QWmpPlaylist::~QWmpPlaylist() +{ + if (m_playlist) + m_playlist->Release(); +} + +bool QWmpPlaylist::load(const QString &location, const char *format) +{ + Q_UNUSED(location); + Q_UNUSED(format); + + return false; +} + +bool QWmpPlaylist::load(QIODevice * device, const char *format) +{ + Q_UNUSED(device); + Q_UNUSED(format); + + return false; +} + +bool QWmpPlaylist::save(const QString &location, const char *format) +{ + Q_UNUSED(location); + Q_UNUSED(format); + + return false; +} + +bool QWmpPlaylist::save(QIODevice * device, const char *format) +{ + Q_UNUSED(device); + Q_UNUSED(format); + + return false; +} + +int QWmpPlaylist::mediaCount() const +{ + return m_count; +} + +QMediaContent QWmpPlaylist::media(int pos) const +{ + QMediaContent content; + + IWMPMedia *media = 0; + if (m_playlist && m_playlist->get_item(pos, &media) == S_OK) { + content = QWmpMetaData::resources(media); + + media->Release(); + } + + return content; +} + +bool QWmpPlaylist::isReadOnly() const +{ + return false; +} + +bool QWmpPlaylist::addMedia(const QMediaContent &content) +{ + bool appended = false; + + IWMPMedia *media = 0; + if (!content.isNull() && m_playlist && m_player && m_player->newMedia( + QAutoBStr(content.canonicalUrl()), &media) == S_OK) { + appended = m_playlist->appendItem(media) == S_OK; + + media->Release(); + } + + return appended; +} + +bool QWmpPlaylist::insertMedia(int pos, const QMediaContent &content) +{ + bool inserted = false; + + IWMPMedia *media = 0; + if (m_playlist && m_player && m_player->newMedia( + QAutoBStr(content.canonicalUrl()), &media) == S_OK) { + inserted = m_playlist->insertItem(pos, media) == S_OK; + + media->Release(); + } + + return inserted; +} + +bool QWmpPlaylist::removeMedia(int pos) +{ + IWMPMedia *media = 0; + if (m_playlist->get_item(pos, &media) == S_OK) { + bool removed = m_playlist->removeItem(media) == S_OK; + + media->Release(); + + return removed; + } else { + return false; + } +} + +bool QWmpPlaylist::removeMedia(int start, int end) +{ + if (!m_playlist) + return false; + + for (int i = start; i <= end; ++i) { + IWMPMedia *media = 0; + if (m_playlist->get_item(start, &media) == S_OK) { + bool removed = m_playlist->removeItem(media) == S_OK; + + media->Release(); + + if (!removed) + return false; + } + } + return true; +} + +bool QWmpPlaylist::clear() +{ + return m_playlist && m_playlist->clear() == S_OK; +} + +QStringList QWmpPlaylist::keys(int index) const +{ + QStringList keys; + + IWMPMedia *media = 0; + if (m_playlist && m_playlist->get_item(index, &media) == S_OK) { + keys = QWmpMetaData::keys(media); + + media->Release(); + } + + return keys; +} + +QVariant QWmpPlaylist::value(int index, const QString &key) const +{ + QVariant v; + + IWMPMedia *media = 0; + if (m_playlist && m_playlist->get_item(index, &media) == S_OK) { + v = QWmpMetaData::value(media, QAutoBStr(key)); + + media->Release(); + } + + return v; +} + +void QWmpPlaylist::shuffle() +{ +} + + +void QWmpPlaylist::currentPlaylistChangeEvent(WMPPlaylistChangeEventType change) +{ + Q_UNUSED(change); + + long count = 0; + if (m_playlist && m_playlist->get_count(&count) == S_OK && count > 0) { + if (count > m_count) { + emit mediaAboutToBeInserted(m_count, count - 1); + m_count = count; + emit mediaInserted(count, m_count - 1); + } else if (count < m_count) { + emit mediaAboutToBeRemoved(count, m_count - 1); + m_count = count; + emit mediaRemoved(count, m_count - 1); + } + } + if (m_count > 0) + emit mediaChanged(0, m_count - 1); +} + +void QWmpPlaylist::openPlaylistChangeEvent(IDispatch *dispatch) +{ + if (m_playlist && m_count > 0) { + emit mediaAboutToBeRemoved(0, m_count - 1); + m_playlist->Release(); + m_playlist = 0; + m_count = 0; + emit mediaRemoved(0, m_count - 1); + } else if (m_playlist) { + m_playlist->Release(); + m_playlist = 0; + } + + IWMPPlaylist *playlist = 0; + if (dispatch && dispatch->QueryInterface( + __uuidof(IWMPPlaylist), reinterpret_cast(&playlist))) { + + long count = 0; + if (playlist->get_count(&count) == S_OK && count > 0) { + emit mediaAboutToBeInserted(0, count - 1); + m_playlist = playlist; + m_count = count; + emit mediaInserted(0, count - 1); + } else { + m_playlist = playlist; + } + } +} + +void QWmpPlaylist::mediaChangeEvent(IDispatch *dispatch) +{ + + IWMPMedia *media = 0; + if (dispatch && dispatch->QueryInterface( + __uuidof(IWMPMedia), reinterpret_cast(&media)) == S_OK) { + VARIANT_BOOL isMember = VARIANT_FALSE; + + if (media->isMemberOf(m_playlist, &isMember) == S_OK && isMember) { + int index = QWmpMetaData::value(media, QAutoBStr(L"PlaylistIndex")).toInt(); + + if (index >= 0) + emit mediaChanged(index, index); + } + media->Release(); + } +} diff --git a/src/plugins/wmp/qwmpplaylist.h b/src/plugins/wmp/qwmpplaylist.h new file mode 100644 index 000000000..be168a7b5 --- /dev/null +++ b/src/plugins/wmp/qwmpplaylist.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWMPPLAYLIST_H +#define QWMPPLAYLIST_H + +#include + +#include + +#include + +class QWmpEvents; + +QT_USE_NAMESPACE +class QWmpPlaylist : public QMediaPlaylistProvider +{ + Q_OBJECT +public: + QWmpPlaylist(IWMPCore3 *player, QWmpEvents *events, QObject *parent = 0); + ~QWmpPlaylist(); + + bool load(const QString &location, const char *format = 0); + bool load(QIODevice * device, const char *format = 0); + bool save(const QString &location, const char *format = 0); + bool save(QIODevice * device, const char *format); + + int mediaCount() const; + QMediaContent media(int pos) const; + + bool isReadOnly() const; + + bool addMedia(const QMediaContent &content); + bool insertMedia(int pos, const QMediaContent &content); + bool removeMedia(int pos); + bool removeMedia(int start, int end); + bool clear(); + + QStringList keys(int index) const; + QVariant value(int index, const QString &key) const; + +public Q_SLOTS: + virtual void shuffle(); + +private Q_SLOTS: + void currentPlaylistChangeEvent(WMPPlaylistChangeEventType change); + void openPlaylistChangeEvent(IDispatch *dispatch); + void mediaChangeEvent(IDispatch *dispatch); + +private: + IWMPCore3 *m_player; + IWMPPlaylist *m_playlist; + long m_count; +}; + +#endif diff --git a/src/plugins/wmp/qwmpplaylistcontrol.cpp b/src/plugins/wmp/qwmpplaylistcontrol.cpp new file mode 100644 index 000000000..f4cc12f7f --- /dev/null +++ b/src/plugins/wmp/qwmpplaylistcontrol.cpp @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwmpplaylistcontrol.h" + +#include "qwmpevents.h" +#include "qwmpglobal.h" +#include "qwmpmetadata.h" +#include "qwmpplaylist.h" + +QWmpPlaylistControl::QWmpPlaylistControl(IWMPCore3 *player, QWmpEvents *events, QObject *parent) + : QMediaPlaylistControl(parent) + , m_player(player) + , m_controls(0) + , m_playlist(new QWmpPlaylist(player, events)) + , m_playbackMode(QMediaPlaylist::Sequential) +{ + m_player->get_controls(&m_controls); + + connect(events, SIGNAL(CurrentItemChange(IDispatch*)), + this, SLOT(currentItemChangeEvent(IDispatch*))); +} + +QWmpPlaylistControl::~QWmpPlaylistControl() +{ + if (m_controls) + m_controls->Release(); + + delete m_playlist; +} + +QMediaPlaylistProvider *QWmpPlaylistControl::playlistProvider() const +{ + return m_playlist; +} + +bool QWmpPlaylistControl::setPlaylistProvider(QMediaPlaylistProvider *playlist) +{ + Q_UNUSED(playlist); + + return false; +} + +int QWmpPlaylistControl::currentIndex() const +{ + int position = 0; + + IWMPMedia *media = 0; + if (m_controls && m_player->get_currentMedia(&media) == S_OK) { + position = QWmpMetaData::value(media, QAutoBStr(L"PlaylistIndex")).toInt(); + + media->Release(); + } + + return position; +} + +void QWmpPlaylistControl::setCurrentIndex(int position) +{ + + IWMPPlaylist *playlist = 0; + if (m_player->get_currentPlaylist(&playlist) == S_OK) { + IWMPMedia *media = 0; + if (playlist->get_item(position, &media) == S_OK) { + m_player->put_currentMedia(media); + + media->Release(); + } + playlist->Release(); + } +} + +int QWmpPlaylistControl::nextIndex(int steps) const +{ + return currentIndex() + steps; +} + +int QWmpPlaylistControl::previousIndex(int steps) const +{ + return currentIndex() - steps; +} + +void QWmpPlaylistControl::next() +{ + if (m_controls) + m_controls->next(); +} + +void QWmpPlaylistControl::previous() +{ + if (m_controls) + m_controls->previous(); +} + +QMediaPlaylist::PlaybackMode QWmpPlaylistControl::playbackMode() const +{ + return m_playbackMode; +} + +void QWmpPlaylistControl::setPlaybackMode(QMediaPlaylist::PlaybackMode mode) +{ + m_playbackMode = mode; +} + +void QWmpPlaylistControl::currentItemChangeEvent(IDispatch *dispatch) +{ + IWMPMedia *media = 0; + if (dispatch && dispatch->QueryInterface( + __uuidof(IWMPMedia), reinterpret_cast(&media)) == S_OK) { + int index = QWmpMetaData::value(media, QAutoBStr(L"PlaylistIndex")).toInt(); + + emit currentIndexChanged(index); + emit currentMediaChanged(m_playlist->media(index)); + } +} diff --git a/src/plugins/wmp/qwmpplaylistcontrol.h b/src/plugins/wmp/qwmpplaylistcontrol.h new file mode 100644 index 000000000..cf519aebb --- /dev/null +++ b/src/plugins/wmp/qwmpplaylistcontrol.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWMPPLAYLISTCONTROL_H +#define QWMPPLAYLISTCONTROL_H + +#include + +#include + +class QWmpEvents; +class QWmpPlaylist; + +QT_USE_NAMESPACE +class QWmpPlaylistControl : public QMediaPlaylistControl +{ + Q_OBJECT +public: + QWmpPlaylistControl(IWMPCore3 *player, QWmpEvents *events, QObject *parent = 0); + ~QWmpPlaylistControl(); + + QMediaPlaylistProvider *playlistProvider() const; + bool setPlaylistProvider(QMediaPlaylistProvider *playlist); + + int currentIndex() const; + void setCurrentIndex(int position); + + int nextIndex(int steps) const; + int previousIndex(int steps) const; + + void next(); + void previous(); + + QMediaPlaylist::PlaybackMode playbackMode() const; + void setPlaybackMode(QMediaPlaylist::PlaybackMode mode); + +private slots: + void currentItemChangeEvent(IDispatch *dispatch); + +private: + IWMPCore3 *m_player; + IWMPControls *m_controls; + QWmpPlaylist *m_playlist; + QMediaPlaylist::PlaybackMode m_playbackMode; +}; + +#endif diff --git a/src/plugins/wmp/qwmpserviceprovider.cpp b/src/plugins/wmp/qwmpserviceprovider.cpp new file mode 100644 index 000000000..eec06008e --- /dev/null +++ b/src/plugins/wmp/qwmpserviceprovider.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwmpserviceprovider.h" + +#include "qwmpplayerservice.h" + +QStringList QWmpServiceProviderPlugin::keys() const +{ + return QStringList() + << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER) + << QLatin1String("windowsmediaplayer"); +} + +QMediaService *QWmpServiceProviderPlugin::create(const QString &key) +{ + if (QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER) == key) { + QByteArray providerKey = qgetenv("QT_MEDIAPLAYER_PROVIDER"); + if (!providerKey.isNull() && qstrcmp(providerKey.constData(), "windowsmediaplayer") == 0) + return new QWmpPlayerService(QWmpPlayerService::RemoteEmbed); + + return new QWmpPlayerService(QWmpPlayerService::LocalEmbed); + } + else if (QLatin1String("windowsmediaplayer") == key) + return new QWmpPlayerService(QWmpPlayerService::RemoteEmbed); + + return 0; +} + +void QWmpServiceProviderPlugin::release(QMediaService *service) +{ + delete service; +} + + +Q_EXPORT_PLUGIN2(qtmedia_wmp, QWmpServiceProviderPlugin); diff --git a/src/plugins/wmp/qwmpserviceprovider.h b/src/plugins/wmp/qwmpserviceprovider.h new file mode 100644 index 000000000..d58fb3bc8 --- /dev/null +++ b/src/plugins/wmp/qwmpserviceprovider.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWMPSERVICEPROVIDER_H +#define QWMPSERVICEPROVIDER_H + +#include +#include + +QT_USE_NAMESPACE +class QWmpServiceProviderPlugin : public QMediaServiceProviderPlugin +{ + Q_OBJECT +public: + QStringList keys() const; + QMediaService *create(const QString &key); + void release(QMediaService *service); +}; + +#endif diff --git a/src/plugins/wmp/qwmpvideooverlay.cpp b/src/plugins/wmp/qwmpvideooverlay.cpp new file mode 100644 index 000000000..95ff77b6b --- /dev/null +++ b/src/plugins/wmp/qwmpvideooverlay.cpp @@ -0,0 +1,462 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwmpvideooverlay.h" + +#include "qwmpglobal.h" + +QWmpVideoOverlay::QWmpVideoOverlay(IWMPPlayer4 *player, IOleObject *object, QWmpPlayerService *service) + : m_service(service) + , m_player(player) + , m_object(object) + , m_inPlaceObject(0) + , m_winId(0) + , m_aspectRatioMode(Qt::KeepAspectRatio) + , m_fullScreen(false) +{ + HRESULT hr; + + if ((hr = m_object->QueryInterface( + __uuidof(IOleInPlaceObject), + reinterpret_cast(&m_inPlaceObject))) != S_OK) { + qWarning("No IOleInPlaceObject interface, %x: %s", hr, qwmp_error_string(hr)); + } +} + +QWmpVideoOverlay::~QWmpVideoOverlay() +{ + if (m_inPlaceObject) + m_inPlaceObject->Release(); +} + +WId QWmpVideoOverlay::winId() const +{ + return m_winId; +} + +void QWmpVideoOverlay::setWinId(WId id) +{ + m_winId = id; + + if (QWidget *widget = QWidget::find(m_winId)) { + const QColor color = widget->palette().color(QPalette::Window); + + m_windowColor = RGB(color.red(), color.green(), color.blue()); + } + + if (m_inPlaceObject && m_winId) { + RECT rcPos = + { + m_displayRect.left(), + m_displayRect.top(), + m_displayRect.right(), + m_displayRect.bottom() + }; + + m_inPlaceObject->InPlaceDeactivate(); + m_object->DoVerb(OLEIVERB_INPLACEACTIVATE, 0, m_service, 0, m_winId, &rcPos); + } + + +} + +extern HDC Q_GUI_EXPORT qt_win_display_dc(); + +#define HIMETRIC_PER_INCH 2540 +#define MAP_PIX_TO_LOGHIM(x,ppli) ((HIMETRIC_PER_INCH*(x) + ((ppli)>>1)) / (ppli)) +#define MAP_LOGHIM_TO_PIX(x,ppli) (((ppli)*(x) + HIMETRIC_PER_INCH/2) / HIMETRIC_PER_INCH) + +QRect QWmpVideoOverlay::displayRect() const +{ + return m_displayRect; +} + +void QWmpVideoOverlay::setDisplayRect(const QRect &rect) +{ + m_displayRect = rect; + + if (m_inPlaceObject) { + HDC gdc = QT_PREPEND_NAMESPACE(qt_win_display_dc)(); + + SIZEL hmSize = { + MAP_PIX_TO_LOGHIM(rect.width(), GetDeviceCaps(gdc, LOGPIXELSX)), + MAP_PIX_TO_LOGHIM(rect.height(), GetDeviceCaps(gdc, LOGPIXELSY)) }; + + m_object->SetExtent(DVASPECT_CONTENT, &hmSize); + + RECT rcClip = { rect.left(), rect.top(), rect.right(), rect.bottom() }; + + if (m_aspectRatioMode == Qt::KeepAspectRatioByExpanding) { + QSize size = m_sizeHint; + size.scale(rect.width(), rect.height(), Qt::KeepAspectRatioByExpanding); + + QRect positionRect(QPoint(0, 0), size); + positionRect.moveCenter(rect.center()); + + RECT rcPos = + { + positionRect.left(), + positionRect.top(), + positionRect.right(), + positionRect.bottom() + }; + + m_inPlaceObject->SetObjectRects(&rcPos, &rcClip); + } else { + m_inPlaceObject->SetObjectRects(&rcClip, &rcClip); + } + } +} + +bool QWmpVideoOverlay::isFullScreen() const +{ + return m_fullScreen; +} + +void QWmpVideoOverlay::setFullScreen(bool fullScreen) +{ + m_player->put_fullScreen(fullScreen); + + emit fullScreenChanged(m_fullScreen = fullScreen); +} + +QSize QWmpVideoOverlay::nativeSize() const +{ + return m_sizeHint; +} + +void QWmpVideoOverlay::setNativeSize(const QSize &size) +{ + if (m_sizeHint != size) { + m_sizeHint = size; + + emit nativeSizeChanged(); + } +} + +Qt::AspectRatioMode QWmpVideoOverlay::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void QWmpVideoOverlay::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + m_aspectRatioMode = mode; + + m_player->put_stretchToFit(mode != Qt::KeepAspectRatio); + + setDisplayRect(m_displayRect); +} + +void QWmpVideoOverlay::repaint() +{ + PAINTSTRUCT paint; + + if (HDC dc = ::BeginPaint(m_winId, &paint)) { + HPEN pen = ::CreatePen(PS_SOLID, 1, m_windowColor); + HBRUSH brush = ::CreateSolidBrush(m_windowColor); + ::SelectObject(dc, pen); + ::SelectObject(dc, brush); + + ::Rectangle( + dc, + m_displayRect.left(), + m_displayRect.top(), + m_displayRect.right() + 1, + m_displayRect.bottom() + 1); + + ::DeleteObject(pen); + ::DeleteObject(brush); + + ::EndPaint(m_winId, &paint); + } +} + +int QWmpVideoOverlay::brightness() const +{ + return 0; +} + +void QWmpVideoOverlay::setBrightness(int) +{ +} + +int QWmpVideoOverlay::contrast() const +{ + return 0; +} + +void QWmpVideoOverlay::setContrast(int) +{ +} + +int QWmpVideoOverlay::hue() const +{ + return 0; +} + +void QWmpVideoOverlay::setHue(int) +{ +} + +int QWmpVideoOverlay::saturation() const +{ + return 0; +} + +void QWmpVideoOverlay::setSaturation(int) +{ +} + +// IUnknown +HRESULT QWmpVideoOverlay::QueryInterface(REFIID riid, void **object) +{ + return m_service->QueryInterface(riid, object); +} + +ULONG QWmpVideoOverlay::AddRef() +{ + return m_service->AddRef(); +} + +ULONG QWmpVideoOverlay::Release() +{ + return m_service->Release(); +} + +// IOleWindow +HRESULT QWmpVideoOverlay::GetWindow(HWND *phwnd) +{ + if (!phwnd) { + return E_POINTER; + } else { + *phwnd = m_winId; + return S_OK; + } +} + +HRESULT QWmpVideoOverlay::ContextSensitiveHelp(BOOL fEnterMode) +{ + Q_UNUSED(fEnterMode); + + return E_NOTIMPL; +} + +// IOleInPlaceSite +HRESULT QWmpVideoOverlay::CanInPlaceActivate() +{ + return S_OK; +} + +HRESULT QWmpVideoOverlay::OnInPlaceActivate() +{ + return S_OK; +} + +HRESULT QWmpVideoOverlay::OnUIActivate() +{ + return S_OK; +} + +HRESULT QWmpVideoOverlay::GetWindowContext( + IOleInPlaceFrame **ppFrame, + IOleInPlaceUIWindow **ppDoc, + LPRECT lprcPosRect, + LPRECT lprcClipRect, + LPOLEINPLACEFRAMEINFO lpFrameInfo) +{ + if (!ppFrame || !ppDoc || !lprcPosRect || !lprcClipRect || !lpFrameInfo) + return E_POINTER; + + QueryInterface(IID_IOleInPlaceFrame, reinterpret_cast(ppFrame)); + QueryInterface(IID_IOleInPlaceUIWindow, reinterpret_cast(ppDoc)); + + if (m_winId) { + SetRect(lprcClipRect, + m_displayRect.left(), + m_displayRect.top(), + m_displayRect.right(), + m_displayRect.bottom()); + + if (m_aspectRatioMode == Qt::KeepAspectRatioByExpanding) { + QSize size = m_sizeHint; + size.scale( + m_displayRect.width(), + m_displayRect.height(), + Qt::KeepAspectRatioByExpanding); + + QRect positionRect(QPoint(0, 0), size); + positionRect.moveCenter(m_displayRect.center()); + + SetRect(lprcPosRect, + positionRect.left(), + positionRect.top(), + positionRect.right(), + positionRect.bottom()); + } else { + *lprcPosRect = *lprcClipRect; + } + } else { + SetRectEmpty(lprcPosRect); + SetRectEmpty(lprcClipRect); + } + + lpFrameInfo->fMDIApp = FALSE; + lpFrameInfo->haccel = 0; + lpFrameInfo->cAccelEntries = 0; + lpFrameInfo->hwndFrame = m_winId; + + return S_OK; +} + +HRESULT QWmpVideoOverlay::Scroll(SIZE scrollExtant) +{ + Q_UNUSED(scrollExtant); + + return S_FALSE; +} + +HRESULT QWmpVideoOverlay::OnUIDeactivate(BOOL fUndoable) +{ + Q_UNUSED(fUndoable); + + return S_OK; +} + +HRESULT QWmpVideoOverlay::OnInPlaceDeactivate() +{ + return S_OK; +} + +HRESULT QWmpVideoOverlay::DiscardUndoState() +{ + return S_OK; +} + +HRESULT QWmpVideoOverlay::DeactivateAndUndo() +{ + if (m_inPlaceObject) + m_inPlaceObject->UIDeactivate(); + + return S_OK; +} + +HRESULT QWmpVideoOverlay::OnPosRectChange(LPCRECT lprcPosRect) +{ + Q_UNUSED(lprcPosRect); + + return S_OK; +} + +// IOleInPlaceUIWindow +HRESULT QWmpVideoOverlay::GetBorder(LPRECT lprectBorder) +{ + Q_UNUSED(lprectBorder); + + return INPLACE_E_NOTOOLSPACE; +} + +HRESULT QWmpVideoOverlay::RequestBorderSpace(LPCBORDERWIDTHS pborderwidths) +{ + Q_UNUSED(pborderwidths); + + return INPLACE_E_NOTOOLSPACE; +} + +HRESULT QWmpVideoOverlay::SetBorderSpace(LPCBORDERWIDTHS pborderwidths) +{ + Q_UNUSED(pborderwidths); + + return OLE_E_INVALIDRECT; +} + +HRESULT QWmpVideoOverlay::SetActiveObject( + IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName) +{ + Q_UNUSED(pActiveObject); + Q_UNUSED(pszObjName); + + return S_OK; +} + +// IOleInPlaceFrame +HRESULT QWmpVideoOverlay::InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths) +{ + Q_UNUSED(hmenuShared); + Q_UNUSED(lpMenuWidths); + + return E_NOTIMPL; +} + +HRESULT QWmpVideoOverlay::SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject) +{ + Q_UNUSED(hmenuShared); + Q_UNUSED(holemenu); + Q_UNUSED(hwndActiveObject); + + return E_NOTIMPL; +} + +HRESULT QWmpVideoOverlay::RemoveMenus(HMENU hmenuShared) +{ + Q_UNUSED(hmenuShared); + + return E_NOTIMPL; +} + +HRESULT QWmpVideoOverlay::SetStatusText(LPCOLESTR pszStatusText) +{ + Q_UNUSED(pszStatusText); + + return E_NOTIMPL; +} + +HRESULT QWmpVideoOverlay::EnableModeless(BOOL fEnable) +{ + Q_UNUSED(fEnable); + + return E_NOTIMPL; +} + +HRESULT QWmpVideoOverlay::TranslateAccelerator(LPMSG lpmsg, WORD wID) +{ + return TranslateAccelerator(lpmsg, static_cast(wID)); +} diff --git a/src/plugins/wmp/qwmpvideooverlay.h b/src/plugins/wmp/qwmpvideooverlay.h new file mode 100644 index 000000000..3bc1005a7 --- /dev/null +++ b/src/plugins/wmp/qwmpvideooverlay.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWMPVIDEOOVERLAY_H +#define QWMPVIDEOOVERLAY_H + +#include + +#include "qwmpplayerservice.h" + +#include + +QT_USE_NAMESPACE +class QWmpVideoOverlay + : public QVideoWindowControl + , public IOleInPlaceSite + , public IOleInPlaceFrame +{ + Q_OBJECT +public: + QWmpVideoOverlay(IWMPPlayer4 *player, IOleObject *object, QWmpPlayerService *service); + ~QWmpVideoOverlay(); + + WId winId() const; + void setWinId(WId id); + + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + void repaint(); + + QSize nativeSize() const; + void setNativeSize(const QSize &size); + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **object); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + // IOleWindow + HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd); + HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode); + + // IOleInPlaceSite + HRESULT STDMETHODCALLTYPE CanInPlaceActivate(); + HRESULT STDMETHODCALLTYPE OnInPlaceActivate(); + HRESULT STDMETHODCALLTYPE OnUIActivate(); + HRESULT STDMETHODCALLTYPE GetWindowContext( + IOleInPlaceFrame **ppFrame, + IOleInPlaceUIWindow **ppDoc, + LPRECT lprcPosRect, + LPRECT lprcClipRect, + LPOLEINPLACEFRAMEINFO lpFrameInfo); + HRESULT STDMETHODCALLTYPE Scroll(SIZE scrollExtant); + HRESULT STDMETHODCALLTYPE OnUIDeactivate(BOOL fUndoable); + HRESULT STDMETHODCALLTYPE OnInPlaceDeactivate(); + HRESULT STDMETHODCALLTYPE DiscardUndoState(); + HRESULT STDMETHODCALLTYPE DeactivateAndUndo(); + HRESULT STDMETHODCALLTYPE OnPosRectChange(LPCRECT lprcPosRect); + + // IOleInPlaceUIWindow + HRESULT STDMETHODCALLTYPE GetBorder(LPRECT lprectBorder); + HRESULT STDMETHODCALLTYPE RequestBorderSpace(LPCBORDERWIDTHS pborderwidths); + HRESULT STDMETHODCALLTYPE SetBorderSpace(LPCBORDERWIDTHS pborderwidths); + HRESULT STDMETHODCALLTYPE SetActiveObject( + IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName); + + // IOleInPlaceFrame + HRESULT STDMETHODCALLTYPE InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths); + HRESULT STDMETHODCALLTYPE SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject); + HRESULT STDMETHODCALLTYPE RemoveMenus(HMENU hmenuShared); + HRESULT STDMETHODCALLTYPE SetStatusText(LPCOLESTR pszStatusText); + HRESULT STDMETHODCALLTYPE EnableModeless(BOOL fEnable); + HRESULT STDMETHODCALLTYPE TranslateAccelerator(LPMSG lpmsg, WORD wID); + +private: + QWmpPlayerService *m_service; + IWMPPlayer4 *m_player; + IOleObject *m_object; + IOleInPlaceObject *m_inPlaceObject; + WId m_winId; + COLORREF m_windowColor; + Qt::AspectRatioMode m_aspectRatioMode; + QSize m_sizeHint; + QRect m_displayRect; + bool m_fullScreen; +}; + +#endif diff --git a/src/plugins/wmp/wmp.pro b/src/plugins/wmp/wmp.pro new file mode 100644 index 000000000..1b544bbeb --- /dev/null +++ b/src/plugins/wmp/wmp.pro @@ -0,0 +1,47 @@ +TEMPLATE = lib +CONFIG += plugin +TARGET = $$qtLibraryTarget(qtmedia_wmp) + +PLUGIN_TYPE=mediaservice + +INCLUDEPATH+=../../../src/multimedia +include(../../../common.pri) + +CONFIG += mobility +MOBILITY = multimedia +LIBS += -lstrmiids -lole32 -lOleaut32 -luser32 -lgdi32 + +HEADERS = \ + qmfactivate.h \ + qwmpevents.h \ + qwmpglobal.h \ + qwmpmetadata.h \ + qwmpplayercontrol.h \ + qwmpplayerservice.h \ + qwmpplaylist.h \ + qwmpplaylistcontrol.h \ + qwmpserviceprovider.h \ + qwmpvideooverlay.h + +SOURCES = \ + qmfactivate.cpp \ + qwmpevents.cpp \ + qwmpglobal.cpp \ + qwmpmetadata.cpp \ + qwmpplayercontrol.cpp \ + qwmpplayerservice.cpp \ + qwmpplaylist.cpp \ + qwmpplaylistcontrol.cpp \ + qwmpserviceprovider.cpp \ + qwmpvideooverlay.cpp + +contains(evr_enabled, yes) { + HEADERS += \ + qevrvideooverlay.h + + SOURCES += \ + qevrvideooverlay.cpp + + DEFINES += \ + QWMP_EVR +} diff --git a/src/s60installs/backup_registration.xml b/src/s60installs/backup_registration.xml new file mode 100644 index 000000000..37d61681c --- /dev/null +++ b/src/s60installs/backup_registration.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/s60installs/bwins/QtMultimediaKitu.def b/src/s60installs/bwins/QtMultimediaKitu.def new file mode 100644 index 000000000..c1cff0781 --- /dev/null +++ b/src/s60installs/bwins/QtMultimediaKitu.def @@ -0,0 +1,1624 @@ +EXPORTS + ?tr@QMediaRecorderControl@@SA?AVQString@@PBD0H@Z @ 1 NONAME ; class QString QMediaRecorderControl::tr(char const *, char const *, int) + ?tr@QAbstractVideoSurface@@SA?AVQString@@PBD0@Z @ 2 NONAME ; class QString QAbstractVideoSurface::tr(char const *, char const *) + ?stop@QRadioTuner@@QAEXXZ @ 3 NONAME ; void QRadioTuner::stop(void) + ?setSampleRate@QAudioFormat@@QAEXH@Z @ 4 NONAME ; void QAudioFormat::setSampleRate(int) + ??1QMediaServiceProvider@@UAE@XZ @ 5 NONAME ; QMediaServiceProvider::~QMediaServiceProvider(void) + ??0QMediaTimeInterval@@QAE@XZ @ 6 NONAME ; QMediaTimeInterval::QMediaTimeInterval(void) + ?metaObject@QAbstractAudioDeviceInfo@@UBEPBUQMetaObject@@XZ @ 7 NONAME ; struct QMetaObject const * QAbstractAudioDeviceInfo::metaObject(void) const + ?tr@QAbstractAudioOutput@@SA?AVQString@@PBD0@Z @ 8 NONAME ; class QString QAbstractAudioOutput::tr(char const *, char const *) + ?qt_metacall@QAudioCaptureSource@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 9 NONAME ; int QAudioCaptureSource::qt_metacall(enum QMetaObject::Call, int, void * *) + ?mediaRemoved@QMediaPlaylist@@IAEXHH@Z @ 10 NONAME ; void QMediaPlaylist::mediaRemoved(int, int) + ?isSearching@QRadioTuner@@QBE_NXZ @ 11 NONAME ; bool QRadioTuner::isSearching(void) const + ??0QMediaResource@@QAE@ABVQNetworkRequest@@ABVQString@@@Z @ 12 NONAME ; QMediaResource::QMediaResource(class QNetworkRequest const &, class QString const &) + ?devicesChanged@QVideoDeviceControl@@IAEXXZ @ 13 NONAME ; void QVideoDeviceControl::devicesChanged(void) + ?supportedVideoCodecs@QMediaRecorder@@QBE?AVQStringList@@XZ @ 14 NONAME ; class QStringList QMediaRecorder::supportedVideoCodecs(void) const + ?searchForward@QRadioTuner@@QAEXXZ @ 15 NONAME ; void QRadioTuner::searchForward(void) + ?saturation@QVideoWidget@@QBEHXZ @ 16 NONAME ; int QVideoWidget::saturation(void) const + ?mediaInserted@QMediaPlaylistProvider@@IAEXHH@Z @ 17 NONAME ; void QMediaPlaylistProvider::mediaInserted(int, int) + ?insertMedia@QMediaPlaylist@@QAE_NHABVQMediaContent@@@Z @ 18 NONAME ; bool QMediaPlaylist::insertMedia(int, class QMediaContent const &) + ?availableMetaData@QMediaRecorder@@QBE?AV?$QList@W4MetaData@QtMultimediaKit@@@@XZ @ 19 NONAME ; class QList QMediaRecorder::availableMetaData(void) const + ?staticMetaObject@QGraphicsVideoItem@@2UQMetaObject@@B @ 20 NONAME ; struct QMetaObject const QGraphicsVideoItem::staticMetaObject + ?qt_metacall@QAbstractAudioDeviceInfo@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 21 NONAME ; int QAbstractAudioDeviceInfo::qt_metacall(enum QMetaObject::Call, int, void * *) + ??_EQMediaServiceSupportedFormatsInterface@@UAE@I@Z @ 22 NONAME ; QMediaServiceSupportedFormatsInterface::~QMediaServiceSupportedFormatsInterface(unsigned int) + ??0QAbstractVideoBuffer@@IAE@AAVQAbstractVideoBufferPrivate@@W4HandleType@0@@Z @ 23 NONAME ; QAbstractVideoBuffer::QAbstractVideoBuffer(class QAbstractVideoBufferPrivate &, enum QAbstractVideoBuffer::HandleType) + ?staticMetaObject@QVideoDeviceControl@@2UQMetaObject@@B @ 24 NONAME ; struct QMetaObject const QVideoDeviceControl::staticMetaObject + ?tr@QImageEncoderControl@@SA?AVQString@@PBD0H@Z @ 25 NONAME ; class QString QImageEncoderControl::tr(char const *, char const *, int) + ??1QAbstractVideoBuffer@@UAE@XZ @ 26 NONAME ; QAbstractVideoBuffer::~QAbstractVideoBuffer(void) + ?stop@QAudioOutput@@QAEXXZ @ 27 NONAME ; void QAudioOutput::stop(void) + ?stateChanged@QMediaRecorder@@IAEXW4State@1@@Z @ 28 NONAME ; void QMediaRecorder::stateChanged(enum QMediaRecorder::State) + ?isEmpty@QMediaPlaylist@@QBE_NXZ @ 29 NONAME ; bool QMediaPlaylist::isEmpty(void) const + ?insertMedia@QMediaPlaylist@@QAE_NHABV?$QList@VQMediaContent@@@@@Z @ 30 NONAME ; bool QMediaPlaylist::insertMedia(int, class QList const &) + ?bytesFree@QAudioOutput@@QBEHXZ @ 31 NONAME ; int QAudioOutput::bytesFree(void) const + ??1QMediaTimeRange@@QAE@XZ @ 32 NONAME ; QMediaTimeRange::~QMediaTimeRange(void) + ?trUtf8@QAbstractAudioOutput@@SA?AVQString@@PBD0H@Z @ 33 NONAME ; class QString QAbstractAudioOutput::trUtf8(char const *, char const *, int) + ?playlistChanged@QMediaPlaylistSourceControl@@IAEXPAVQMediaPlaylist@@@Z @ 34 NONAME ; void QMediaPlaylistSourceControl::playlistChanged(class QMediaPlaylist *) + ?staticMetaObject@QSoundEffect@@2UQMetaObject@@B @ 35 NONAME ; struct QMetaObject const QSoundEffect::staticMetaObject + ?error@QMediaPlayerControl@@IAEXHABVQString@@@Z @ 36 NONAME ; void QMediaPlayerControl::error(int, class QString const &) + ?d_func@QMediaPlaylist@@ABEPBVQMediaPlaylistPrivate@@XZ @ 37 NONAME ; class QMediaPlaylistPrivate const * QMediaPlaylist::d_func(void) const + ?metaObject@QRadioTuner@@UBEPBUQMetaObject@@XZ @ 38 NONAME ; struct QMetaObject const * QRadioTuner::metaObject(void) const + ?bits@QVideoFrame@@QBEPBEXZ @ 39 NONAME ; unsigned char const * QVideoFrame::bits(void) const + ?staticMetaObject@QVideoWidget@@2UQMetaObject@@B @ 40 NONAME ; struct QMetaObject const QVideoWidget::staticMetaObject + ??_EQMediaControl@@UAE@I@Z @ 41 NONAME ; QMediaControl::~QMediaControl(unsigned int) + ?media@QMediaPlaylist@@QBE?AVQMediaContent@@H@Z @ 42 NONAME ; class QMediaContent QMediaPlaylist::media(int) const + ?mapMode@QVideoFrame@@QBE?AW4MapMode@QAbstractVideoBuffer@@XZ @ 43 NONAME ; enum QAbstractVideoBuffer::MapMode QVideoFrame::mapMode(void) const + ??0QAudioCaptureSource@@QAE@PAVQObject@@PAVQMediaServiceProvider@@@Z @ 44 NONAME ; QAudioCaptureSource::QAudioCaptureSource(class QObject *, class QMediaServiceProvider *) + ??1QMediaControl@@UAE@XZ @ 45 NONAME ; QMediaControl::~QMediaControl(void) + ?staticMetaObject@QMediaObject@@2UQMetaObject@@B @ 46 NONAME ; struct QMetaObject const QMediaObject::staticMetaObject + ?qt_metacast@QMediaPlaylistProvider@@UAEPAXPBD@Z @ 47 NONAME ; void * QMediaPlaylistProvider::qt_metacast(char const *) + ??0QMediaServiceProviderHint@@QAE@ABVQByteArray@@@Z @ 48 NONAME ; QMediaServiceProviderHint::QMediaServiceProviderHint(class QByteArray const &) + ?trUtf8@QAudioOutput@@SA?AVQString@@PBD0@Z @ 49 NONAME ; class QString QAudioOutput::trUtf8(char const *, char const *) + ?qt_metacast@QSoundEffect@@UAEPAXPBD@Z @ 50 NONAME ; void * QSoundEffect::qt_metacast(char const *) + ?searchingChanged@QRadioTunerControl@@IAEX_N@Z @ 51 NONAME ; void QRadioTunerControl::searchingChanged(bool) + ?tr@QMediaObject@@SA?AVQString@@PBD0@Z @ 52 NONAME ; class QString QMediaObject::tr(char const *, char const *) + ?trUtf8@QMediaPlaylistControl@@SA?AVQString@@PBD0H@Z @ 53 NONAME ; class QString QMediaPlaylistControl::trUtf8(char const *, char const *, int) + ?end@QMediaTimeInterval@@QBE_JXZ @ 54 NONAME ; long long QMediaTimeInterval::end(void) const + ??0QImageEncoderControl@@IAE@PAVQObject@@@Z @ 55 NONAME ; QImageEncoderControl::QImageEncoderControl(class QObject *) + ?format@QAudioOutput@@QBE?AVQAudioFormat@@XZ @ 56 NONAME ; class QAudioFormat QAudioOutput::format(void) const + ?d_func@QGraphicsVideoItem@@AAEPAVQGraphicsVideoItemPrivate@@XZ @ 57 NONAME ; class QGraphicsVideoItemPrivate * QGraphicsVideoItem::d_func(void) + ?d_func@QRadioTuner@@AAEPAVQRadioTunerPrivate@@XZ @ 58 NONAME ; class QRadioTunerPrivate * QRadioTuner::d_func(void) + ?trUtf8@QMediaPlaylistProvider@@SA?AVQString@@PBD0H@Z @ 59 NONAME ; class QString QMediaPlaylistProvider::trUtf8(char const *, char const *, int) + ?staticMetaObject@QMediaPlaylistIOPlugin@@2UQMetaObject@@B @ 60 NONAME ; struct QMetaObject const QMediaPlaylistIOPlugin::staticMetaObject + ?isStereo@QRadioTuner@@QBE_NXZ @ 61 NONAME ; bool QRadioTuner::isStereo(void) const + ?tr@QAudioEndpointSelector@@SA?AVQString@@PBD0H@Z @ 62 NONAME ; class QString QAudioEndpointSelector::tr(char const *, char const *, int) + ?tr@QMediaImageViewer@@SA?AVQString@@PBD0@Z @ 63 NONAME ; class QString QMediaImageViewer::tr(char const *, char const *) + ??_EQMediaServiceProvider@@UAE@I@Z @ 64 NONAME ; QMediaServiceProvider::~QMediaServiceProvider(unsigned int) + ?setStereoMode@QRadioTuner@@QAEXW4StereoMode@1@@Z @ 65 NONAME ; void QRadioTuner::setStereoMode(enum QRadioTuner::StereoMode) + ?qt_metacall@QMediaServiceProvider@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 66 NONAME ; int QMediaServiceProvider::qt_metacall(enum QMetaObject::Call, int, void * *) + ?trUtf8@QMediaObject@@SA?AVQString@@PBD0H@Z @ 67 NONAME ; class QString QMediaObject::trUtf8(char const *, char const *, int) + ?supportedSampleTypes@QAudioDeviceInfo@@QBE?AV?$QList@W4SampleType@QAudioFormat@@@@XZ @ 68 NONAME ; class QList QAudioDeviceInfo::supportedSampleTypes(void) const + ?metaObject@QVideoEncoderControl@@UBEPBUQMetaObject@@XZ @ 69 NONAME ; struct QMetaObject const * QVideoEncoderControl::metaObject(void) const + ??_EQVideoEncoderControl@@UAE@I@Z @ 70 NONAME ; QVideoEncoderControl::~QVideoEncoderControl(unsigned int) + ?getStaticMetaObject@QGraphicsVideoItem@@SAABUQMetaObject@@XZ @ 71 NONAME ; struct QMetaObject const & QGraphicsVideoItem::getStaticMetaObject(void) + ?isWritable@QVideoFrame@@QBE_NXZ @ 72 NONAME ; bool QVideoFrame::isWritable(void) const + ??0QAudioOutput@@QAE@ABVQAudioFormat@@PAVQObject@@@Z @ 73 NONAME ; QAudioOutput::QAudioOutput(class QAudioFormat const &, class QObject *) + ??1QAudioEncoderSettings@@QAE@XZ @ 74 NONAME ; QAudioEncoderSettings::~QAudioEncoderSettings(void) + ?metaDataChanged@QMediaRecorder@@IAEXXZ @ 75 NONAME ; void QMediaRecorder::metaDataChanged(void) + ??1QMediaBindableInterface@@UAE@XZ @ 76 NONAME ; QMediaBindableInterface::~QMediaBindableInterface(void) + ??1QRadioTunerControl@@UAE@XZ @ 77 NONAME ; QRadioTunerControl::~QRadioTunerControl(void) + ?staticMetaObject@QAbstractAudioInput@@2UQMetaObject@@B @ 78 NONAME ; struct QMetaObject const QAbstractAudioInput::staticMetaObject + ?tr@QAbstractAudioInput@@SA?AVQString@@PBD0@Z @ 79 NONAME ; class QString QAbstractAudioInput::tr(char const *, char const *) + ??1QMediaContainerControl@@UAE@XZ @ 80 NONAME ; QMediaContainerControl::~QMediaContainerControl(void) + ?channelCount@QAudioFormat@@QBEHXZ @ 81 NONAME ; int QAudioFormat::channelCount(void) const + ?previousIndex@QMediaPlaylistNavigator@@QBEHH@Z @ 82 NONAME ; int QMediaPlaylistNavigator::previousIndex(int) const + ?trUtf8@QGraphicsVideoItem@@SA?AVQString@@PBD0H@Z @ 83 NONAME ; class QString QGraphicsVideoItem::trUtf8(char const *, char const *, int) + ?positionChanged@QMediaPlayerControl@@IAEX_J@Z @ 84 NONAME ; void QMediaPlayerControl::positionChanged(long long) + ?metaObject@QMediaServiceProviderPlugin@@UBEPBUQMetaObject@@XZ @ 85 NONAME ; struct QMetaObject const * QMediaServiceProviderPlugin::metaObject(void) const + ?currentMediaChanged@QMediaPlaylist@@IAEXABVQMediaContent@@@Z @ 86 NONAME ; void QMediaPlaylist::currentMediaChanged(class QMediaContent const &) + ?searchBackward@QRadioTuner@@QAEXXZ @ 87 NONAME ; void QRadioTuner::searchBackward(void) + ?getStaticMetaObject@QMediaPlaylist@@SAABUQMetaObject@@XZ @ 88 NONAME ; struct QMetaObject const & QMediaPlaylist::getStaticMetaObject(void) + ?setPixelAspectRatio@QVideoSurfaceFormat@@QAEXABVQSize@@@Z @ 89 NONAME ; void QVideoSurfaceFormat::setPixelAspectRatio(class QSize const &) + ?qt_metacast@QMediaPlaylistControl@@UAEPAXPBD@Z @ 90 NONAME ; void * QMediaPlaylistControl::qt_metacast(char const *) + ?audioSettings@QMediaRecorder@@QBE?AVQAudioEncoderSettings@@XZ @ 91 NONAME ; class QAudioEncoderSettings QMediaRecorder::audioSettings(void) const + ?yCbCrColorSpace@QVideoSurfaceFormat@@QBE?AW4YCbCrColorSpace@1@XZ @ 92 NONAME ; enum QVideoSurfaceFormat::YCbCrColorSpace QVideoSurfaceFormat::yCbCrColorSpace(void) const + ?qt_metacast@QVideoEncoderControl@@UAEPAXPBD@Z @ 93 NONAME ; void * QVideoEncoderControl::qt_metacast(char const *) + ?staticMetaObject@QAbstractAudioOutput@@2UQMetaObject@@B @ 94 NONAME ; struct QMetaObject const QAbstractAudioOutput::staticMetaObject + ??_EQAbstractAudioOutput@@UAE@I@Z @ 95 NONAME ; QAbstractAudioOutput::~QAbstractAudioOutput(unsigned int) + ?addMedia@QLocalMediaPlaylistProvider@@UAE_NABV?$QList@VQMediaContent@@@@@Z @ 96 NONAME ; bool QLocalMediaPlaylistProvider::addMedia(class QList const &) + ?staticMetaObject@QLocalMediaPlaylistProvider@@2UQMetaObject@@B @ 97 NONAME ; struct QMetaObject const QLocalMediaPlaylistProvider::staticMetaObject + ?supportedSampleSizes@QAudioDeviceInfo@@QBE?AV?$QList@H@@XZ @ 98 NONAME ; class QList QAudioDeviceInfo::supportedSampleSizes(void) const + ?addMedia@QMediaPlaylist@@QAE_NABV?$QList@VQMediaContent@@@@@Z @ 99 NONAME ; bool QMediaPlaylist::addMedia(class QList const &) + ?hueChanged@QVideoWidget@@IAEXH@Z @ 100 NONAME ; void QVideoWidget::hueChanged(int) + ??4QVideoEncoderSettings@@QAEAAV0@ABV0@@Z @ 101 NONAME ; class QVideoEncoderSettings & QVideoEncoderSettings::operator=(class QVideoEncoderSettings const &) + ?qt_metacast@QVideoWidget@@UAEPAXPBD@Z @ 102 NONAME ; void * QVideoWidget::qt_metacast(char const *) + ?activeAudioInput@QAudioCaptureSource@@QBE?AVQString@@XZ @ 103 NONAME ; class QString QAudioCaptureSource::activeAudioInput(void) const + ??0QVideoSurfaceFormat@@QAE@XZ @ 104 NONAME ; QVideoSurfaceFormat::QVideoSurfaceFormat(void) + ?supportedChannelCounts@QAudioDeviceInfo@@QBE?AV?$QList@H@@XZ @ 105 NONAME ; class QList QAudioDeviceInfo::supportedChannelCounts(void) const + ?getStaticMetaObject@QMediaPlaylistControl@@SAABUQMetaObject@@XZ @ 106 NONAME ; struct QMetaObject const & QMediaPlaylistControl::getStaticMetaObject(void) + ?setMuted@QMediaRecorder@@QAEX_N@Z @ 107 NONAME ; void QMediaRecorder::setMuted(bool) + ?qt_metacall@QMetaDataReaderControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 108 NONAME ; int QMetaDataReaderControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ??H@YA?AVQMediaTimeRange@@ABV0@0@Z @ 109 NONAME ; class QMediaTimeRange operator+(class QMediaTimeRange const &, class QMediaTimeRange const &) + ?record@QMediaRecorder@@QAEXXZ @ 110 NONAME ; void QMediaRecorder::record(void) + ?metaObject@QMediaService@@UBEPBUQMetaObject@@XZ @ 111 NONAME ; struct QMetaObject const * QMediaService::metaObject(void) const + ?isMuted@QRadioTuner@@QBE_NXZ @ 112 NONAME ; bool QRadioTuner::isMuted(void) const + ?availabilityChanged@QMediaObject@@IAEX_N@Z @ 113 NONAME ; void QMediaObject::availabilityChanged(bool) + ?trUtf8@QVideoEncoderControl@@SA?AVQString@@PBD0@Z @ 114 NONAME ; class QString QVideoEncoderControl::trUtf8(char const *, char const *) + ?trUtf8@QMetaDataReaderControl@@SA?AVQString@@PBD0@Z @ 115 NONAME ; class QString QMetaDataReaderControl::trUtf8(char const *, char const *) + ?setLanguage@QMediaResource@@QAEXABVQString@@@Z @ 116 NONAME ; void QMediaResource::setLanguage(class QString const &) + ??0QMediaResource@@QAE@ABVQUrl@@ABVQString@@@Z @ 117 NONAME ; QMediaResource::QMediaResource(class QUrl const &, class QString const &) + ?volume@QSoundEffect@@QBEMXZ @ 118 NONAME ; float QSoundEffect::volume(void) const + ?mutedChanged@QRadioTuner@@IAEX_N@Z @ 119 NONAME ; void QRadioTuner::mutedChanged(bool) + ?currentIndex@QMediaPlaylist@@QBEHXZ @ 120 NONAME ; int QMediaPlaylist::currentIndex(void) const + ?setNotifyInterval@QAudioInput@@QAEXH@Z @ 121 NONAME ; void QAudioInput::setNotifyInterval(int) + ?aspectRatioMode@QGraphicsVideoItem@@QBE?AW4AspectRatioMode@Qt@@XZ @ 122 NONAME ; enum Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode(void) const + ??0QMediaTimeRange@@QAE@ABVQMediaTimeInterval@@@Z @ 123 NONAME ; QMediaTimeRange::QMediaTimeRange(class QMediaTimeInterval const &) + ?qt_metacall@QMediaPlaylistProvider@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 124 NONAME ; int QMediaPlaylistProvider::qt_metacall(enum QMetaObject::Call, int, void * *) + ??_EQVideoWidgetControl@@UAE@I@Z @ 125 NONAME ; QVideoWidgetControl::~QVideoWidgetControl(unsigned int) + ?trUtf8@QVideoDeviceControl@@SA?AVQString@@PBD0H@Z @ 126 NONAME ; class QString QVideoDeviceControl::trUtf8(char const *, char const *, int) + ?seekableChanged@QMediaPlayer@@IAEX_N@Z @ 127 NONAME ; void QMediaPlayer::seekableChanged(bool) + ?unbind@QMediaPlayer@@UAEXPAVQObject@@@Z @ 128 NONAME ; void QMediaPlayer::unbind(class QObject *) + ?tr@QMediaPlaylistControl@@SA?AVQString@@PBD0@Z @ 129 NONAME ; class QString QMediaPlaylistControl::tr(char const *, char const *) + ?setVolume@QMediaPlayer@@QAEXH@Z @ 130 NONAME ; void QMediaPlayer::setVolume(int) + ?setPlaylist@QMediaPlaylistNavigator@@QAEXPAVQMediaPlaylistProvider@@@Z @ 131 NONAME ; void QMediaPlaylistNavigator::setPlaylist(class QMediaPlaylistProvider *) + ?setMuted@QSoundEffect@@QAEX_N@Z @ 132 NONAME ; void QSoundEffect::setMuted(bool) + ?trUtf8@QAudioEncoderControl@@SA?AVQString@@PBD0@Z @ 133 NONAME ; class QString QAudioEncoderControl::trUtf8(char const *, char const *) + ?sampleRate@QAudioFormat@@QBEHXZ @ 134 NONAME ; int QAudioFormat::sampleRate(void) const + ?staticMetaObject@QAudioOutput@@2UQMetaObject@@B @ 135 NONAME ; struct QMetaObject const QAudioOutput::staticMetaObject + ?setQuality@QAudioEncoderSettings@@QAEXW4EncodingQuality@QtMultimediaKit@@@Z @ 136 NONAME ; void QAudioEncoderSettings::setQuality(enum QtMultimediaKit::EncodingQuality) + ?getStaticMetaObject@QMediaObject@@SAABUQMetaObject@@XZ @ 137 NONAME ; struct QMetaObject const & QMediaObject::getStaticMetaObject(void) + ??1QMediaServiceProviderHint@@QAE@XZ @ 138 NONAME ; QMediaServiceProviderHint::~QMediaServiceProviderHint(void) + ?mediaCount@QMediaPlaylist@@QBEHXZ @ 139 NONAME ; int QMediaPlaylist::mediaCount(void) const + ?load@QMediaPlaylist@@QAEXABVQUrl@@PBD@Z @ 140 NONAME ; void QMediaPlaylist::load(class QUrl const &, char const *) + ?earliestTime@QMediaTimeRange@@QBE_JXZ @ 141 NONAME ; long long QMediaTimeRange::earliestTime(void) const + ?frameSize@QVideoSurfaceFormat@@QBE?AVQSize@@XZ @ 142 NONAME ; class QSize QVideoSurfaceFormat::frameSize(void) const + ?tr@QMediaContainerControl@@SA?AVQString@@PBD0H@Z @ 143 NONAME ; class QString QMediaContainerControl::tr(char const *, char const *, int) + ?bits@QVideoFrame@@QAEPAEXZ @ 144 NONAME ; unsigned char * QVideoFrame::bits(void) + ?setSource@QSoundEffect@@QAEXABVQUrl@@@Z @ 145 NONAME ; void QSoundEffect::setSource(class QUrl const &) + ?setExtendedMetaData@QMediaRecorder@@QAEXABVQString@@ABVQVariant@@@Z @ 146 NONAME ; void QMediaRecorder::setExtendedMetaData(class QString const &, class QVariant const &) + ??0QMediaPlaylistSourceControl@@IAE@PAVQObject@@@Z @ 147 NONAME ; QMediaPlaylistSourceControl::QMediaPlaylistSourceControl(class QObject *) + ?qt_metacast@QMetaDataReaderControl@@UAEPAXPBD@Z @ 148 NONAME ; void * QMetaDataReaderControl::qt_metacast(char const *) + ?tr@QVideoWidget@@SA?AVQString@@PBD0@Z @ 149 NONAME ; class QString QVideoWidget::tr(char const *, char const *) + ?getStaticMetaObject@QMediaPlaylistNavigator@@SAABUQMetaObject@@XZ @ 150 NONAME ; struct QMetaObject const & QMediaPlaylistNavigator::getStaticMetaObject(void) + ??0QMediaControl@@IAE@AAVQMediaControlPrivate@@PAVQObject@@@Z @ 151 NONAME ; QMediaControl::QMediaControl(class QMediaControlPrivate &, class QObject *) + ?videoAvailableChanged@QMediaPlayerControl@@IAEX_N@Z @ 152 NONAME ; void QMediaPlayerControl::videoAvailableChanged(bool) + ?tr@QLocalMediaPlaylistProvider@@SA?AVQString@@PBD0@Z @ 153 NONAME ; class QString QLocalMediaPlaylistProvider::tr(char const *, char const *) + ?supportedResolutions@QMediaRecorder@@QBE?AV?$QList@VQSize@@@@ABVQVideoEncoderSettings@@PA_N@Z @ 154 NONAME ; class QList QMediaRecorder::supportedResolutions(class QVideoEncoderSettings const &, bool *) const + ?removeMedia@QLocalMediaPlaylistProvider@@UAE_NH@Z @ 155 NONAME ; bool QLocalMediaPlaylistProvider::removeMedia(int) + ?qt_metacast@QMediaImageViewer@@UAEPAXPBD@Z @ 156 NONAME ; void * QMediaImageViewer::qt_metacast(char const *) + ?contrast@QVideoWidget@@QBEHXZ @ 157 NONAME ; int QVideoWidget::contrast(void) const + ??_EQMetaDataWriterControl@@UAE@I@Z @ 158 NONAME ; QMetaDataWriterControl::~QMetaDataWriterControl(unsigned int) + ?previous@QMediaPlaylistNavigator@@QAEXXZ @ 159 NONAME ; void QMediaPlaylistNavigator::previous(void) + ?qt_metacall@QAudioSystemPlugin@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 160 NONAME ; int QAudioSystemPlugin::qt_metacall(enum QMetaObject::Call, int, void * *) + ?start@QAudioInput@@QAEXPAVQIODevice@@@Z @ 161 NONAME ; void QAudioInput::start(class QIODevice *) + ?isValid@QVideoFrame@@QBE_NXZ @ 162 NONAME ; bool QVideoFrame::isValid(void) const + ?fullScreenChanged@QVideoWidget@@IAEX_N@Z @ 163 NONAME ; void QVideoWidget::fullScreenChanged(bool) + ?setSaturation@QVideoWidget@@QAEXH@Z @ 164 NONAME ; void QVideoWidget::setSaturation(int) + ?bandChanged@QRadioTuner@@IAEXW4Band@1@@Z @ 165 NONAME ; void QRadioTuner::bandChanged(enum QRadioTuner::Band) + ?d_func@QMediaPlayer@@ABEPBVQMediaPlayerPrivate@@XZ @ 166 NONAME ; class QMediaPlayerPrivate const * QMediaPlayer::d_func(void) const + ?notify@QAudioInput@@IAEXXZ @ 167 NONAME ; void QAudioInput::notify(void) + ?loadFailed@QMediaPlaylistProvider@@IAEXW4Error@QMediaPlaylist@@ABVQString@@@Z @ 168 NONAME ; void QMediaPlaylistProvider::loadFailed(enum QMediaPlaylist::Error, class QString const &) + ??_EQMediaPlayer@@UAE@I@Z @ 169 NONAME ; QMediaPlayer::~QMediaPlayer(unsigned int) + ?tr@QSoundEffect@@SA?AVQString@@PBD0@Z @ 170 NONAME ; class QString QSoundEffect::tr(char const *, char const *) + ?mimeType@QMediaResource@@QBE?AVQString@@XZ @ 171 NONAME ; class QString QMediaResource::mimeType(void) const + ??0QAudioEncoderSettings@@QAE@ABV0@@Z @ 172 NONAME ; QAudioEncoderSettings::QAudioEncoderSettings(class QAudioEncoderSettings const &) + ?videoAvailableChanged@QMediaPlayer@@IAEX_N@Z @ 173 NONAME ; void QMediaPlayer::videoAvailableChanged(bool) + ?stateChanged@QMediaRecorderControl@@IAEXW4State@QMediaRecorder@@@Z @ 174 NONAME ; void QMediaRecorderControl::stateChanged(enum QMediaRecorder::State) + ?pixelFormat@QVideoSurfaceFormat@@QBE?AW4PixelFormat@QVideoFrame@@XZ @ 175 NONAME ; enum QVideoFrame::PixelFormat QVideoSurfaceFormat::pixelFormat(void) const + ?map@QMemoryVideoBuffer@@UAEPAEW4MapMode@QAbstractVideoBuffer@@PAH1@Z @ 176 NONAME ; unsigned char * QMemoryVideoBuffer::map(enum QAbstractVideoBuffer::MapMode, int *, int *) + ?sampleRate@QMediaResource@@QBEHXZ @ 177 NONAME ; int QMediaResource::sampleRate(void) const + ??0QRadioTunerControl@@IAE@PAVQObject@@@Z @ 178 NONAME ; QRadioTunerControl::QRadioTunerControl(class QObject *) + ?staticMetaObject@QMediaPlaylist@@2UQMetaObject@@B @ 179 NONAME ; struct QMetaObject const QMediaPlaylist::staticMetaObject + ?state@QAudioInput@@QBE?AW4State@QAudio@@XZ @ 180 NONAME ; enum QAudio::State QAudioInput::state(void) const + ??0QMediaContent@@QAE@ABV?$QList@VQMediaResource@@@@@Z @ 181 NONAME ; QMediaContent::QMediaContent(class QList const &) + ?qt_metacast@QMediaServiceProviderPlugin@@UAEPAXPBD@Z @ 182 NONAME ; void * QMediaServiceProviderPlugin::qt_metacast(char const *) + ??0QVideoSurfaceFormat@@QAE@ABV0@@Z @ 183 NONAME ; QVideoSurfaceFormat::QVideoSurfaceFormat(class QVideoSurfaceFormat const &) + ?deviceDescription@QMediaServiceProvider@@UAE?AVQString@@ABVQByteArray@@0@Z @ 184 NONAME ; class QString QMediaServiceProvider::deviceDescription(class QByteArray const &, class QByteArray const &) + ??9@YA_NABVQMediaTimeInterval@@0@Z @ 185 NONAME ; bool operator!=(class QMediaTimeInterval const &, class QMediaTimeInterval const &) + ??_EQVideoRendererControl@@UAE@I@Z @ 186 NONAME ; QVideoRendererControl::~QVideoRendererControl(unsigned int) + ?setAudioBitRate@QMediaResource@@QAEXH@Z @ 187 NONAME ; void QMediaResource::setAudioBitRate(int) + ?setFullScreen@QVideoWidget@@QAEX_N@Z @ 188 NONAME ; void QVideoWidget::setFullScreen(bool) + ?metaObject@QGraphicsVideoItem@@UBEPBUQMetaObject@@XZ @ 189 NONAME ; struct QMetaObject const * QGraphicsVideoItem::metaObject(void) const + ??0QVideoWidget@@QAE@PAVQWidget@@@Z @ 190 NONAME ; QVideoWidget::QVideoWidget(class QWidget *) + ?metaObject@QAbstractAudioOutput@@UBEPBUQMetaObject@@XZ @ 191 NONAME ; struct QMetaObject const * QAbstractAudioOutput::metaObject(void) const + ??_EQMediaPlayerControl@@UAE@I@Z @ 192 NONAME ; QMediaPlayerControl::~QMediaPlayerControl(unsigned int) + ?setLoops@QSoundEffect@@QAEXH@Z @ 193 NONAME ABSENT ; void QSoundEffect::setLoops(int) + ?viewport@QVideoSurfaceFormat@@QBE?AVQRect@@XZ @ 194 NONAME ; class QRect QVideoSurfaceFormat::viewport(void) const + ?d_func@QMediaService@@AAEPAVQMediaServicePrivate@@XZ @ 195 NONAME ; class QMediaServicePrivate * QMediaService::d_func(void) + ?resume@QAudioInput@@QAEXXZ @ 196 NONAME ; void QAudioInput::resume(void) + ?audioCodecDescription@QMediaRecorder@@QBE?AVQString@@ABV2@@Z @ 197 NONAME ; class QString QMediaRecorder::audioCodecDescription(class QString const &) const + ?setAspectRatioMode@QGraphicsVideoItem@@QAEXW4AspectRatioMode@Qt@@@Z @ 198 NONAME ; void QGraphicsVideoItem::setAspectRatioMode(enum Qt::AspectRatioMode) + ?encodingMode@QAudioEncoderSettings@@QBE?AW4EncodingMode@QtMultimediaKit@@XZ @ 199 NONAME ; enum QtMultimediaKit::EncodingMode QAudioEncoderSettings::encodingMode(void) const + ?isVideoAvailable@QMediaPlayer@@QBE_NXZ @ 200 NONAME ; bool QMediaPlayer::isVideoAvailable(void) const + ?playbackMode@QMediaPlaylist@@QBE?AW4PlaybackMode@1@XZ @ 201 NONAME ; enum QMediaPlaylist::PlaybackMode QMediaPlaylist::playbackMode(void) const + ?metaDataChanged@QMediaObject@@IAEXXZ @ 202 NONAME ; void QMediaObject::metaDataChanged(void) + ??0QVideoSurfaceFormat@@QAE@ABVQSize@@W4PixelFormat@QVideoFrame@@W4HandleType@QAbstractVideoBuffer@@@Z @ 203 NONAME ; QVideoSurfaceFormat::QVideoSurfaceFormat(class QSize const &, enum QVideoFrame::PixelFormat, enum QAbstractVideoBuffer::HandleType) + ?trUtf8@QAudioCaptureSource@@SA?AVQString@@PBD0@Z @ 204 NONAME ; class QString QAudioCaptureSource::trUtf8(char const *, char const *) + ?frameHeight@QVideoSurfaceFormat@@QBEHXZ @ 205 NONAME ; int QVideoSurfaceFormat::frameHeight(void) const + ?unmap@QImageVideoBuffer@@UAEXXZ @ 206 NONAME ; void QImageVideoBuffer::unmap(void) + ?translated@QMediaTimeInterval@@QBE?AV1@_J@Z @ 207 NONAME ; class QMediaTimeInterval QMediaTimeInterval::translated(long long) const + ?trUtf8@QGraphicsVideoItem@@SA?AVQString@@PBD0@Z @ 208 NONAME ; class QString QGraphicsVideoItem::trUtf8(char const *, char const *) + ??1QAbstractAudioInput@@UAE@XZ @ 209 NONAME ; QAbstractAudioInput::~QAbstractAudioInput(void) + ?supportedAudioSampleRates@QMediaRecorder@@QBE?AV?$QList@H@@ABVQAudioEncoderSettings@@PA_N@Z @ 210 NONAME ; class QList QMediaRecorder::supportedAudioSampleRates(class QAudioEncoderSettings const &, bool *) const + ?save@QMediaPlaylist@@QAE_NPAVQIODevice@@PBD@Z @ 211 NONAME ; bool QMediaPlaylist::save(class QIODevice *, char const *) + ?setFrameSize@QVideoSurfaceFormat@@QAEXABVQSize@@@Z @ 212 NONAME ; void QVideoSurfaceFormat::setFrameSize(class QSize const &) + ?setPlaylist@QMediaPlayer@@QAEXPAVQMediaPlaylist@@@Z @ 213 NONAME ; void QMediaPlayer::setPlaylist(class QMediaPlaylist *) + ?setMediaObject@QMediaRecorder@@MAE_NPAVQMediaObject@@@Z @ 214 NONAME ; bool QMediaRecorder::setMediaObject(class QMediaObject *) + ?metaObject@QMetaDataReaderControl@@UBEPBUQMetaObject@@XZ @ 215 NONAME ; struct QMetaObject const * QMetaDataReaderControl::metaObject(void) const + ?itemAt@QMediaPlaylistNavigator@@QBE?AVQMediaContent@@H@Z @ 216 NONAME ; class QMediaContent QMediaPlaylistNavigator::itemAt(int) const + ?start@QAudioOutput@@QAEPAVQIODevice@@XZ @ 217 NONAME ; class QIODevice * QAudioOutput::start(void) + ?mediaStatus@QMediaPlayer@@QBE?AW4MediaStatus@1@XZ @ 218 NONAME ; enum QMediaPlayer::MediaStatus QMediaPlayer::mediaStatus(void) const + ?bitRate@QVideoEncoderSettings@@QBEHXZ @ 219 NONAME ; int QVideoEncoderSettings::bitRate(void) const + ?d_func@QMediaControl@@ABEPBVQMediaControlPrivate@@XZ @ 220 NONAME ; class QMediaControlPrivate const * QMediaControl::d_func(void) const + ?staticMetaObject@QAbstractAudioDeviceInfo@@2UQMetaObject@@B @ 221 NONAME ; struct QMetaObject const QAbstractAudioDeviceInfo::staticMetaObject + ??1QAudioInput@@UAE@XZ @ 222 NONAME ; QAudioInput::~QAudioInput(void) + ?setEndTime@QVideoFrame@@QAEX_J@Z @ 223 NONAME ; void QVideoFrame::setEndTime(long long) + ?tr@QMediaPlaylistIOPlugin@@SA?AVQString@@PBD0H@Z @ 224 NONAME ; class QString QMediaPlaylistIOPlugin::tr(char const *, char const *, int) + ?extendedMetaData@QMediaObject@@QBE?AVQVariant@@ABVQString@@@Z @ 225 NONAME ; class QVariant QMediaObject::extendedMetaData(class QString const &) const + ?duration@QMediaPlayer@@QBE_JXZ @ 226 NONAME ; long long QMediaPlayer::duration(void) const + ?audioAvailableChanged@QMediaPlayer@@IAEX_N@Z @ 227 NONAME ; void QMediaPlayer::audioAvailableChanged(bool) + ?mutedChanged@QMediaPlayerControl@@IAEX_N@Z @ 228 NONAME ; void QMediaPlayerControl::mutedChanged(bool) + ?getStaticMetaObject@QMediaServiceProviderPlugin@@SAABUQMetaObject@@XZ @ 229 NONAME ; struct QMetaObject const & QMediaServiceProviderPlugin::getStaticMetaObject(void) + ??9QAudioEncoderSettings@@QBE_NABV0@@Z @ 230 NONAME ; bool QAudioEncoderSettings::operator!=(class QAudioEncoderSettings const &) const + ?bufferSize@QAudioOutput@@QBEHXZ @ 231 NONAME ; int QAudioOutput::bufferSize(void) const + ?getStaticMetaObject@QVideoWidget@@SAABUQMetaObject@@XZ @ 232 NONAME ; struct QMetaObject const & QVideoWidget::getStaticMetaObject(void) + ??1QMediaPlaylistSourceControl@@UAE@XZ @ 233 NONAME ; QMediaPlaylistSourceControl::~QMediaPlaylistSourceControl(void) + ?tr@QVideoWindowControl@@SA?AVQString@@PBD0@Z @ 234 NONAME ; class QString QVideoWindowControl::tr(char const *, char const *) + ??1QMediaContent@@QAE@XZ @ 235 NONAME ; QMediaContent::~QMediaContent(void) + ??0QRadioTuner@@QAE@PAVQObject@@PAVQMediaServiceProvider@@@Z @ 236 NONAME ; QRadioTuner::QRadioTuner(class QObject *, class QMediaServiceProvider *) + ?tr@QAbstractVideoSurface@@SA?AVQString@@PBD0H@Z @ 237 NONAME ; class QString QAbstractVideoSurface::tr(char const *, char const *, int) + ?qt_metacall@QVideoWidget@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 238 NONAME ; int QVideoWidget::qt_metacall(enum QMetaObject::Call, int, void * *) + ?setSampleRate@QAudioEncoderSettings@@QAEXH@Z @ 239 NONAME ; void QAudioEncoderSettings::setSampleRate(int) + ?setFrameRate@QVideoSurfaceFormat@@QAEXM@Z @ 240 NONAME ; void QVideoSurfaceFormat::setFrameRate(float) + ?qt_metacall@QMediaServiceProviderPlugin@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 241 NONAME ; int QMediaServiceProviderPlugin::qt_metacall(enum QMetaObject::Call, int, void * *) + ?tr@QVideoRendererControl@@SA?AVQString@@PBD0H@Z @ 242 NONAME ; class QString QVideoRendererControl::tr(char const *, char const *, int) + ?type@QMediaServiceProviderHint@@QBE?AW4Type@1@XZ @ 243 NONAME ; enum QMediaServiceProviderHint::Type QMediaServiceProviderHint::type(void) const + ?staticMetaObject@QVideoWidgetControl@@2UQMetaObject@@B @ 244 NONAME ; struct QMetaObject const QVideoWidgetControl::staticMetaObject + ?isNormal@QMediaTimeInterval@@QBE_NXZ @ 245 NONAME ; bool QMediaTimeInterval::isNormal(void) const + ??_EQMediaService@@UAE@I@Z @ 246 NONAME ; QMediaService::~QMediaService(unsigned int) + ?setChannelCount@QAudioEncoderSettings@@QAEXH@Z @ 247 NONAME ; void QAudioEncoderSettings::setChannelCount(int) + ?qt_metacall@QRadioTunerControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 248 NONAME ; int QRadioTunerControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ?sampleSize@QAudioFormat@@QBEHXZ @ 249 NONAME ; int QAudioFormat::sampleSize(void) const + ?height@QVideoFrame@@QBEHXZ @ 250 NONAME ; int QVideoFrame::height(void) const + ?activeAudioInputChanged@QAudioCaptureSource@@IAEXABVQString@@@Z @ 251 NONAME ; void QAudioCaptureSource::activeAudioInputChanged(class QString const &) + ?d_func@QMediaObject@@ABEPBVQMediaObjectPrivate@@XZ @ 252 NONAME ; class QMediaObjectPrivate const * QMediaObject::d_func(void) const + ??0QAudioFormat@@QAE@XZ @ 253 NONAME ; QAudioFormat::QAudioFormat(void) + ?startTime@QVideoFrame@@QBE_JXZ @ 254 NONAME ; long long QVideoFrame::startTime(void) const + ??_EQAudioSystemPlugin@@UAE@I@Z @ 255 NONAME ; QAudioSystemPlugin::~QAudioSystemPlugin(unsigned int) + ?errorString@QMediaPlaylist@@QBE?AVQString@@XZ @ 256 NONAME ; class QString QMediaPlaylist::errorString(void) const + ?trUtf8@QRadioTunerControl@@SA?AVQString@@PBD0H@Z @ 257 NONAME ; class QString QRadioTunerControl::trUtf8(char const *, char const *, int) + ?getStaticMetaObject@QSoundEffect@@SAABUQMetaObject@@XZ @ 258 NONAME ; struct QMetaObject const & QSoundEffect::getStaticMetaObject(void) + ?trUtf8@QAudioSystemPlugin@@SA?AVQString@@PBD0H@Z @ 259 NONAME ; class QString QAudioSystemPlugin::trUtf8(char const *, char const *, int) + ?trUtf8@QMediaPlayerControl@@SA?AVQString@@PBD0@Z @ 260 NONAME ; class QString QMediaPlayerControl::trUtf8(char const *, char const *) + ?bytesPerLine@QVideoFrame@@QBEHXZ @ 261 NONAME ; int QVideoFrame::bytesPerLine(void) const + ??1QMediaPlayer@@UAE@XZ @ 262 NONAME ; QMediaPlayer::~QMediaPlayer(void) + ?isBandSupported@QRadioTuner@@QBE_NW4Band@1@@Z @ 263 NONAME ; bool QRadioTuner::isBandSupported(enum QRadioTuner::Band) const + ?trUtf8@QMediaPlayer@@SA?AVQString@@PBD0H@Z @ 264 NONAME ; class QString QMediaPlayer::trUtf8(char const *, char const *, int) + ?supportedAudioCodecs@QMediaRecorder@@QBE?AVQStringList@@XZ @ 265 NONAME ; class QStringList QMediaRecorder::supportedAudioCodecs(void) const + ??0QMediaContainerControl@@IAE@PAVQObject@@@Z @ 266 NONAME ; QMediaContainerControl::QMediaContainerControl(class QObject *) + ??0QMediaContent@@QAE@ABVQUrl@@@Z @ 267 NONAME ; QMediaContent::QMediaContent(class QUrl const &) + ?mediaStatusChanged@QMediaPlayerControl@@IAEXW4MediaStatus@QMediaPlayer@@@Z @ 268 NONAME ; void QMediaPlayerControl::mediaStatusChanged(enum QMediaPlayer::MediaStatus) + ?trUtf8@QRadioTuner@@SA?AVQString@@PBD0H@Z @ 269 NONAME ; class QString QRadioTuner::trUtf8(char const *, char const *, int) + ?trUtf8@QMediaPlaylist@@SA?AVQString@@PBD0H@Z @ 270 NONAME ; class QString QMediaPlaylist::trUtf8(char const *, char const *, int) + ??_EQMediaPlaylistReader@@UAE@I@Z @ 271 NONAME ; QMediaPlaylistReader::~QMediaPlaylistReader(unsigned int) + ?channelCount@QMediaResource@@QBEHXZ @ 272 NONAME ; int QMediaResource::channelCount(void) const + ?tr@QSoundEffect@@SA?AVQString@@PBD0H@Z @ 273 NONAME ; class QString QSoundEffect::tr(char const *, char const *, int) + ?qt_metacall@QMediaRecorderControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 274 NONAME ; int QMediaRecorderControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ?setHue@QVideoWidget@@QAEXH@Z @ 275 NONAME ; void QVideoWidget::setHue(int) + ?tr@QGraphicsVideoItem@@SA?AVQString@@PBD0@Z @ 276 NONAME ; class QString QGraphicsVideoItem::tr(char const *, char const *) + ?activeChanged@QAbstractVideoSurface@@IAEX_N@Z @ 277 NONAME ; void QAbstractVideoSurface::activeChanged(bool) + ?imageFormatFromPixelFormat@QVideoFrame@@SA?AW4Format@QImage@@W4PixelFormat@1@@Z @ 278 NONAME ; enum QImage::Format QVideoFrame::imageFormatFromPixelFormat(enum QVideoFrame::PixelFormat) + ?contrastChanged@QVideoWindowControl@@IAEXH@Z @ 279 NONAME ; void QVideoWindowControl::contrastChanged(int) + ?stateChanged@QAudioOutput@@IAEXW4State@QAudio@@@Z @ 280 NONAME ; void QAudioOutput::stateChanged(enum QAudio::State) + ?addMedia@QMediaPlaylistProvider@@UAE_NABV?$QList@VQMediaContent@@@@@Z @ 281 NONAME ; bool QMediaPlaylistProvider::addMedia(class QList const &) + ?error@QMediaRecorderControl@@IAEXHABVQString@@@Z @ 282 NONAME ; void QMediaRecorderControl::error(int, class QString const &) + ??0QMediaTimeInterval@@QAE@_J0@Z @ 283 NONAME ; QMediaTimeInterval::QMediaTimeInterval(long long, long long) + ??0QMediaPlaylistNavigator@@QAE@PAVQMediaPlaylistProvider@@PAVQObject@@@Z @ 284 NONAME ; QMediaPlaylistNavigator::QMediaPlaylistNavigator(class QMediaPlaylistProvider *, class QObject *) + ?latestTime@QMediaTimeRange@@QBE_JXZ @ 285 NONAME ; long long QMediaTimeRange::latestTime(void) const + ??_EQAbstractVideoBuffer@@UAE@I@Z @ 286 NONAME ; QAbstractVideoBuffer::~QAbstractVideoBuffer(unsigned int) + ??_EQAudioCaptureSource@@UAE@I@Z @ 287 NONAME ; QAudioCaptureSource::~QAudioCaptureSource(unsigned int) + ?d_func@QMediaRecorder@@ABEPBVQMediaRecorderPrivate@@XZ @ 288 NONAME ; class QMediaRecorderPrivate const * QMediaRecorder::d_func(void) const + ?setChannelCount@QAudioFormat@@QAEXH@Z @ 289 NONAME ; void QAudioFormat::setChannelCount(int) + ??0QMediaRecorder@@QAE@PAVQMediaObject@@PAVQObject@@@Z @ 290 NONAME ; QMediaRecorder::QMediaRecorder(class QMediaObject *, class QObject *) + ?qt_metacall@QMediaPlayerControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 291 NONAME ; int QMediaPlayerControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ?reset@QAudioOutput@@QAEXXZ @ 292 NONAME ; void QAudioOutput::reset(void) + ?d_func@QMediaPlaylist@@AAEPAVQMediaPlaylistPrivate@@XZ @ 293 NONAME ; class QMediaPlaylistPrivate * QMediaPlaylist::d_func(void) + ?trUtf8@QAudioEndpointSelector@@SA?AVQString@@PBD0@Z @ 294 NONAME ; class QString QAudioEndpointSelector::trUtf8(char const *, char const *) + ?shuffle@QMediaPlaylist@@QAEXXZ @ 295 NONAME ; void QMediaPlaylist::shuffle(void) + ?metaObject@QSoundEffect@@UBEPBUQMetaObject@@XZ @ 296 NONAME ; struct QMetaObject const * QSoundEffect::metaObject(void) const + ?loops@QSoundEffect@@QBEHXZ @ 297 NONAME ABSENT ; int QSoundEffect::loops(void) const + ??_EQMediaPlaylist@@UAE@I@Z @ 298 NONAME ; QMediaPlaylist::~QMediaPlaylist(unsigned int) + ??0QVideoWindowControl@@IAE@PAVQObject@@@Z @ 299 NONAME ; QVideoWindowControl::QVideoWindowControl(class QObject *) + ?trUtf8@QMediaPlaylistIOPlugin@@SA?AVQString@@PBD0@Z @ 300 NONAME ; class QString QMediaPlaylistIOPlugin::trUtf8(char const *, char const *) + ?stateChanged@QRadioTunerControl@@IAEXW4State@QRadioTuner@@@Z @ 301 NONAME ; void QRadioTunerControl::stateChanged(enum QRadioTuner::State) + ?addMedia@QLocalMediaPlaylistProvider@@UAE_NABVQMediaContent@@@Z @ 302 NONAME ; bool QLocalMediaPlaylistProvider::addMedia(class QMediaContent const &) + ?qt_metacast@QMediaStreamsControl@@UAEPAXPBD@Z @ 303 NONAME ; void * QMediaStreamsControl::qt_metacast(char const *) + ?searchingChanged@QRadioTuner@@IAEX_N@Z @ 304 NONAME ; void QRadioTuner::searchingChanged(bool) + ?seekableChanged@QMediaPlayerControl@@IAEX_N@Z @ 305 NONAME ; void QMediaPlayerControl::seekableChanged(bool) + ?getStaticMetaObject@QRadioTunerControl@@SAABUQMetaObject@@XZ @ 306 NONAME ; struct QMetaObject const & QRadioTunerControl::getStaticMetaObject(void) + ?isValid@QAudioFormat@@QBE_NXZ @ 307 NONAME ; bool QAudioFormat::isValid(void) const + ??0QMediaServiceProviderHint@@QAE@ABV0@@Z @ 308 NONAME ; QMediaServiceProviderHint::QMediaServiceProviderHint(class QMediaServiceProviderHint const &) + ??_EQMediaPlaylistNavigator@@UAE@I@Z @ 309 NONAME ; QMediaPlaylistNavigator::~QMediaPlaylistNavigator(unsigned int) + ?qt_metacall@QMediaRecorder@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 310 NONAME ; int QMediaRecorder::qt_metacall(enum QMetaObject::Call, int, void * *) + ??0QAudioEncoderSettings@@QAE@XZ @ 311 NONAME ; QAudioEncoderSettings::QAudioEncoderSettings(void) + ?supportedFrequencies@QAudioDeviceInfo@@QBE?AV?$QList@H@@XZ @ 312 NONAME ; class QList QAudioDeviceInfo::supportedFrequencies(void) const + ?setCodec@QImageEncoderSettings@@QAEXABVQString@@@Z @ 313 NONAME ; void QImageEncoderSettings::setCodec(class QString const &) + ?getStaticMetaObject@QMediaPlaylistSourceControl@@SAABUQMetaObject@@XZ @ 314 NONAME ; struct QMetaObject const & QMediaPlaylistSourceControl::getStaticMetaObject(void) + ??1QVideoFrame@@QAE@XZ @ 315 NONAME ; QVideoFrame::~QVideoFrame(void) + ?notifyInterval@QAudioInput@@QBEHXZ @ 316 NONAME ; int QAudioInput::notifyInterval(void) const + ?metaObject@QMediaServiceProvider@@UBEPBUQMetaObject@@XZ @ 317 NONAME ; struct QMetaObject const * QMediaServiceProvider::metaObject(void) const + ?setTimeout@QMediaImageViewer@@QAEXH@Z @ 318 NONAME ; void QMediaImageViewer::setTimeout(int) + ??0QMediaRecorderControl@@IAE@PAVQObject@@@Z @ 319 NONAME ; QMediaRecorderControl::QMediaRecorderControl(class QObject *) + ?staticMetaObject@QVideoWindowControl@@2UQMetaObject@@B @ 320 NONAME ; struct QMetaObject const QVideoWindowControl::staticMetaObject + ?channels@QAudioFormat@@QBEHXZ @ 321 NONAME ; int QAudioFormat::channels(void) const + ?setVolume@QRadioTuner@@QAEXH@Z @ 322 NONAME ; void QRadioTuner::setVolume(int) + ?qt_metacall@QAudioEndpointSelector@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 323 NONAME ; int QAudioEndpointSelector::qt_metacall(enum QMetaObject::Call, int, void * *) + ?setFrequency@QRadioTuner@@QAEXH@Z @ 324 NONAME ; void QRadioTuner::setFrequency(int) + ?cancelSearch@QRadioTuner@@QAEXXZ @ 325 NONAME ; void QRadioTuner::cancelSearch(void) + ?metaObject@QMediaPlaylistProvider@@UBEPBUQMetaObject@@XZ @ 326 NONAME ; struct QMetaObject const * QMediaPlaylistProvider::metaObject(void) const + ?mediaCount@QLocalMediaPlaylistProvider@@UBEHXZ @ 327 NONAME ; int QLocalMediaPlaylistProvider::mediaCount(void) const + ?tr@QMediaServiceProviderPlugin@@SA?AVQString@@PBD0H@Z @ 328 NONAME ; class QString QMediaServiceProviderPlugin::tr(char const *, char const *, int) + ?staticMetaObject@QImageEncoderControl@@2UQMetaObject@@B @ 329 NONAME ; struct QMetaObject const QImageEncoderControl::staticMetaObject + ?stop@QMediaPlayer@@QAEXXZ @ 330 NONAME ; void QMediaPlayer::stop(void) + ?tr@QMediaService@@SA?AVQString@@PBD0@Z @ 331 NONAME ; class QString QMediaService::tr(char const *, char const *) + ?bind@QMediaPlayer@@UAE_NPAVQObject@@@Z @ 332 NONAME ; bool QMediaPlayer::bind(class QObject *) + ?writableChanged@QMetaDataWriterControl@@IAEX_N@Z @ 333 NONAME ; void QMetaDataWriterControl::writableChanged(bool) + ?staticMetaObject@QMediaPlaylistSourceControl@@2UQMetaObject@@B @ 334 NONAME ; struct QMetaObject const QMediaPlaylistSourceControl::staticMetaObject + ?availableExtendedMetaData@QMediaRecorder@@QBE?AVQStringList@@XZ @ 335 NONAME ; class QStringList QMediaRecorder::availableExtendedMetaData(void) const + ?trUtf8@QAbstractAudioDeviceInfo@@SA?AVQString@@PBD0@Z @ 336 NONAME ; class QString QAbstractAudioDeviceInfo::trUtf8(char const *, char const *) + ?qt_metacast@QMediaObject@@UAEPAXPBD@Z @ 337 NONAME ; void * QMediaObject::qt_metacast(char const *) + ??0QVideoFrame@@QAE@XZ @ 338 NONAME ; QVideoFrame::QVideoFrame(void) + ?qt_metacast@QMediaPlaylistIOPlugin@@UAEPAXPBD@Z @ 339 NONAME ; void * QMediaPlaylistIOPlugin::qt_metacast(char const *) + ?media@QMediaImageViewer@@QBE?AVQMediaContent@@XZ @ 340 NONAME ; class QMediaContent QMediaImageViewer::media(void) const + ?isNull@QMediaServiceProviderHint@@QBE_NXZ @ 341 NONAME ; bool QMediaServiceProviderHint::isNull(void) const + ?setBufferSize@QAudioOutput@@QAEXH@Z @ 342 NONAME ; void QAudioOutput::setBufferSize(int) + ?metaObject@QRadioTunerControl@@UBEPBUQMetaObject@@XZ @ 343 NONAME ; struct QMetaObject const * QRadioTunerControl::metaObject(void) const + ?metaObject@QMediaRecorderControl@@UBEPBUQMetaObject@@XZ @ 344 NONAME ; struct QMetaObject const * QMediaRecorderControl::metaObject(void) const + ??1QMediaObject@@UAE@XZ @ 345 NONAME ; QMediaObject::~QMediaObject(void) + ?metaObject@QAudioSystemPlugin@@UBEPBUQMetaObject@@XZ @ 346 NONAME ; struct QMetaObject const * QAudioSystemPlugin::metaObject(void) const + ??_EQRadioTunerControl@@UAE@I@Z @ 347 NONAME ; QRadioTunerControl::~QRadioTunerControl(unsigned int) + ?paintEvent@QVideoWidget@@MAEXPAVQPaintEvent@@@Z @ 348 NONAME ; void QVideoWidget::paintEvent(class QPaintEvent *) + ?bufferStatusChanged@QMediaPlayerControl@@IAEXH@Z @ 349 NONAME ; void QMediaPlayerControl::bufferStatusChanged(int) + ?addMedia@QMediaPlaylistProvider@@UAE_NABVQMediaContent@@@Z @ 350 NONAME ; bool QMediaPlaylistProvider::addMedia(class QMediaContent const &) + ??0QMediaPlaylistIOPlugin@@QAE@PAVQObject@@@Z @ 351 NONAME ; QMediaPlaylistIOPlugin::QMediaPlaylistIOPlugin(class QObject *) + ??4QMediaServiceProviderHint@@QAEAAV0@ABV0@@Z @ 352 NONAME ; class QMediaServiceProviderHint & QMediaServiceProviderHint::operator=(class QMediaServiceProviderHint const &) + ?qt_metacast@QVideoRendererControl@@UAEPAXPBD@Z @ 353 NONAME ; void * QVideoRendererControl::qt_metacast(char const *) + ?containerMimeType@QMediaRecorder@@QBE?AVQString@@XZ @ 354 NONAME ; class QString QMediaRecorder::containerMimeType(void) const + ??YQMediaTimeRange@@QAEAAV0@ABVQMediaTimeInterval@@@Z @ 355 NONAME ; class QMediaTimeRange & QMediaTimeRange::operator+=(class QMediaTimeInterval const &) + ??9QVideoEncoderSettings@@QBE_NABV0@@Z @ 356 NONAME ; bool QVideoEncoderSettings::operator!=(class QVideoEncoderSettings const &) const + ?error@QMediaPlaylist@@QBE?AW4Error@1@XZ @ 357 NONAME ; enum QMediaPlaylist::Error QMediaPlaylist::error(void) const + ??8@YA_NABVQMediaTimeRange@@0@Z @ 358 NONAME ; bool operator==(class QMediaTimeRange const &, class QMediaTimeRange const &) + ?qt_metacall@QImageEncoderControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 359 NONAME ; int QImageEncoderControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ??0QVideoEncoderSettings@@QAE@ABV0@@Z @ 360 NONAME ; QVideoEncoderSettings::QVideoEncoderSettings(class QVideoEncoderSettings const &) + ??0QMediaImageViewer@@QAE@PAVQObject@@@Z @ 361 NONAME ; QMediaImageViewer::QMediaImageViewer(class QObject *) + ?device@QMediaServiceProviderHint@@QBE?AVQByteArray@@XZ @ 362 NONAME ; class QByteArray QMediaServiceProviderHint::device(void) const + ?qt_metacast@QMediaRecorder@@UAEPAXPBD@Z @ 363 NONAME ; void * QMediaRecorder::qt_metacast(char const *) + ?supportedFormatsChanged@QAbstractVideoSurface@@IAEXXZ @ 364 NONAME ; void QAbstractVideoSurface::supportedFormatsChanged(void) + ?trUtf8@QAbstractAudioInput@@SA?AVQString@@PBD0@Z @ 365 NONAME ; class QString QAbstractAudioInput::trUtf8(char const *, char const *) + ??0QMediaServiceProviderHint@@QAE@ABVQString@@ABVQStringList@@@Z @ 366 NONAME ; QMediaServiceProviderHint::QMediaServiceProviderHint(class QString const &, class QStringList const &) + ?staticMetaObject@QRadioTuner@@2UQMetaObject@@B @ 367 NONAME ; struct QMetaObject const QRadioTuner::staticMetaObject + ?mutedChanged@QMediaRecorder@@IAEX_N@Z @ 368 NONAME ; void QMediaRecorder::mutedChanged(bool) + ?trUtf8@QVideoWidget@@SA?AVQString@@PBD0H@Z @ 369 NONAME ; class QString QVideoWidget::trUtf8(char const *, char const *, int) + ?playbackModeChanged@QMediaPlaylistControl@@IAEXW4PlaybackMode@QMediaPlaylist@@@Z @ 370 NONAME ; void QMediaPlaylistControl::playbackModeChanged(enum QMediaPlaylist::PlaybackMode) + ??1QImageEncoderControl@@UAE@XZ @ 371 NONAME ; QImageEncoderControl::~QImageEncoderControl(void) + ?volume@QRadioTuner@@QBEHXZ @ 372 NONAME ; int QRadioTuner::volume(void) const + ?trUtf8@QMediaStreamsControl@@SA?AVQString@@PBD0H@Z @ 373 NONAME ; class QString QMediaStreamsControl::trUtf8(char const *, char const *, int) + ??1QAudioSystemPlugin@@UAE@XZ @ 374 NONAME ; QAudioSystemPlugin::~QAudioSystemPlugin(void) + ?load@QMediaPlaylistProvider@@UAE_NABVQUrl@@PBD@Z @ 375 NONAME ; bool QMediaPlaylistProvider::load(class QUrl const &, char const *) + ??9QMediaContent@@QBE_NABV0@@Z @ 376 NONAME ; bool QMediaContent::operator!=(class QMediaContent const &) const + ?sizeHint@QVideoSurfaceFormat@@QBE?AVQSize@@XZ @ 377 NONAME ; class QSize QVideoSurfaceFormat::sizeHint(void) const + ?setError@QAbstractVideoSurface@@IAEXW4Error@1@@Z @ 378 NONAME ; void QAbstractVideoSurface::setError(enum QAbstractVideoSurface::Error) + ?hueChanged@QVideoWidgetControl@@IAEXH@Z @ 379 NONAME ; void QVideoWidgetControl::hueChanged(int) + ?tr@QMediaPlaylistControl@@SA?AVQString@@PBD0H@Z @ 380 NONAME ; class QString QMediaPlaylistControl::tr(char const *, char const *, int) + ?sampleType@QAudioFormat@@QBE?AW4SampleType@1@XZ @ 381 NONAME ; enum QAudioFormat::SampleType QAudioFormat::sampleType(void) const + ?setChannelCount@QMediaResource@@QAEXH@Z @ 382 NONAME ; void QMediaResource::setChannelCount(int) + ?qt_metacast@QRadioTuner@@UAEPAXPBD@Z @ 383 NONAME ; void * QRadioTuner::qt_metacast(char const *) + ?isReadOnly@QMediaPlaylistProvider@@UBE_NXZ @ 384 NONAME ; bool QMediaPlaylistProvider::isReadOnly(void) const + ?trUtf8@QMediaPlaylistProvider@@SA?AVQString@@PBD0@Z @ 385 NONAME ; class QString QMediaPlaylistProvider::trUtf8(char const *, char const *) + ?pixelFormat@QVideoFrame@@QBE?AW4PixelFormat@1@XZ @ 386 NONAME ; enum QVideoFrame::PixelFormat QVideoFrame::pixelFormat(void) const + ?audioAvailableChanged@QMediaPlayerControl@@IAEX_N@Z @ 387 NONAME ; void QMediaPlayerControl::audioAvailableChanged(bool) + ?timerEvent@QGraphicsVideoItem@@MAEXPAVQTimerEvent@@@Z @ 388 NONAME ; void QGraphicsVideoItem::timerEvent(class QTimerEvent *) + ?nextIndex@QMediaPlaylistNavigator@@QBEHH@Z @ 389 NONAME ; int QMediaPlaylistNavigator::nextIndex(int) const + ??8QAudioEncoderSettings@@QBE_NABV0@@Z @ 390 NONAME ; bool QAudioEncoderSettings::operator==(class QAudioEncoderSettings const &) const + ?qt_metacall@QMediaStreamsControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 391 NONAME ; int QMediaStreamsControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ?mediaObject@QGraphicsVideoItem@@UBEPAVQMediaObject@@XZ @ 392 NONAME ; class QMediaObject * QGraphicsVideoItem::mediaObject(void) const + ?tr@QVideoEncoderControl@@SA?AVQString@@PBD0H@Z @ 393 NONAME ; class QString QVideoEncoderControl::tr(char const *, char const *, int) + ?trUtf8@QMediaPlaylist@@SA?AVQString@@PBD0@Z @ 394 NONAME ; class QString QMediaPlaylist::trUtf8(char const *, char const *) + ?availableMetaData@QMediaObject@@QBE?AV?$QList@W4MetaData@QtMultimediaKit@@@@XZ @ 395 NONAME ; class QList QMediaObject::availableMetaData(void) const + ?getStaticMetaObject@QAudioCaptureSource@@SAABUQMetaObject@@XZ @ 396 NONAME ; struct QMetaObject const & QAudioCaptureSource::getStaticMetaObject(void) + ?isContinuous@QMediaTimeRange@@QBE_NXZ @ 397 NONAME ; bool QMediaTimeRange::isContinuous(void) const + ?insertMedia@QMediaPlaylistProvider@@UAE_NHABV?$QList@VQMediaContent@@@@@Z @ 398 NONAME ; bool QMediaPlaylistProvider::insertMedia(int, class QList const &) + ?staticMetaObject@QMediaStreamsControl@@2UQMetaObject@@B @ 399 NONAME ; struct QMetaObject const QMediaStreamsControl::staticMetaObject + ?qt_metacast@QMediaPlaylistNavigator@@UAEPAXPBD@Z @ 400 NONAME ; void * QMediaPlaylistNavigator::qt_metacast(char const *) + ?activeEndpointChanged@QAudioEndpointSelector@@IAEXABVQString@@@Z @ 401 NONAME ; void QAudioEndpointSelector::activeEndpointChanged(class QString const &) + ?save@QMediaPlaylist@@QAE_NABVQUrl@@PBD@Z @ 402 NONAME ; bool QMediaPlaylist::save(class QUrl const &, char const *) + ?supportedChannels@QAudioDeviceInfo@@QBE?AV?$QList@H@@XZ @ 403 NONAME ; class QList QAudioDeviceInfo::supportedChannels(void) const + ?setCodec@QVideoEncoderSettings@@QAEXABVQString@@@Z @ 404 NONAME ; void QVideoEncoderSettings::setCodec(class QString const &) + ?d_func@QAudioCaptureSource@@ABEPBVQAudioCaptureSourcePrivate@@XZ @ 405 NONAME ; class QAudioCaptureSourcePrivate const * QAudioCaptureSource::d_func(void) const + ?trUtf8@QMediaImageViewer@@SA?AVQString@@PBD0@Z @ 406 NONAME ; class QString QMediaImageViewer::trUtf8(char const *, char const *) + ?pause@QMediaPlayer@@QAEXXZ @ 407 NONAME ; void QMediaPlayer::pause(void) + ?staticMetaObject@QMediaControl@@2UQMetaObject@@B @ 408 NONAME ; struct QMetaObject const QMediaControl::staticMetaObject + ?isAvailable@QRadioTuner@@UBE_NXZ @ 409 NONAME ; bool QRadioTuner::isAvailable(void) const + ??G@YA?AVQMediaTimeRange@@ABV0@0@Z @ 410 NONAME ; class QMediaTimeRange operator-(class QMediaTimeRange const &, class QMediaTimeRange const &) + ?unmap@QVideoFrame@@QAEXXZ @ 411 NONAME ; void QVideoFrame::unmap(void) + ?qt_metacast@QImageEncoderControl@@UAEPAXPBD@Z @ 412 NONAME ; void * QImageEncoderControl::qt_metacast(char const *) + ??0QMediaServiceProviderHint@@QAE@XZ @ 413 NONAME ; QMediaServiceProviderHint::QMediaServiceProviderHint(void) + ??9QImageEncoderSettings@@QBE_NABV0@@Z @ 414 NONAME ; bool QImageEncoderSettings::operator!=(class QImageEncoderSettings const &) const + ?play@QMediaImageViewer@@QAEXXZ @ 415 NONAME ; void QMediaImageViewer::play(void) + ?setPosition@QMediaPlayer@@QAEX_J@Z @ 416 NONAME ; void QMediaPlayer::setPosition(long long) + ?setResolution@QMediaResource@@QAEXHH@Z @ 417 NONAME ; void QMediaResource::setResolution(int, int) + ??_EQVideoDeviceControl@@UAE@I@Z @ 418 NONAME ; QVideoDeviceControl::~QVideoDeviceControl(unsigned int) + ?addInterval@QMediaTimeRange@@QAEX_J0@Z @ 419 NONAME ; void QMediaTimeRange::addInterval(long long, long long) + ??0QMediaContent@@QAE@ABV0@@Z @ 420 NONAME ; QMediaContent::QMediaContent(class QMediaContent const &) + ?videoBitRate@QMediaResource@@QBEHXZ @ 421 NONAME ; int QMediaResource::videoBitRate(void) const + ?statusChanged@QAudioCaptureSource@@AAEXXZ @ 422 NONAME ; void QAudioCaptureSource::statusChanged(void) + ?trUtf8@QAudioOutput@@SA?AVQString@@PBD0H@Z @ 423 NONAME ; class QString QAudioOutput::trUtf8(char const *, char const *, int) + ?availabilityError@QMediaRecorder@@QBE?AW4AvailabilityError@QtMultimediaKit@@XZ @ 424 NONAME ; enum QtMultimediaKit::AvailabilityError QMediaRecorder::availabilityError(void) const + ?setMediaObject@QGraphicsVideoItem@@MAE_NPAVQMediaObject@@@Z @ 425 NONAME ; bool QGraphicsVideoItem::setMediaObject(class QMediaObject *) + ?isFormatSupported@QAbstractVideoSurface@@UBE_NABVQVideoSurfaceFormat@@@Z @ 426 NONAME ; bool QAbstractVideoSurface::isFormatSupported(class QVideoSurfaceFormat const &) const + ??0QMetaDataWriterControl@@IAE@PAVQObject@@@Z @ 427 NONAME ; QMetaDataWriterControl::QMetaDataWriterControl(class QObject *) + ?frequencyChanged@QRadioTuner@@IAEXH@Z @ 428 NONAME ; void QRadioTuner::frequencyChanged(int) + ?hideEvent@QVideoWidget@@MAEXPAVQHideEvent@@@Z @ 429 NONAME ; void QVideoWidget::hideEvent(class QHideEvent *) + ?supportedMimeTypes@QMediaServiceProvider@@UBE?AVQStringList@@ABVQByteArray@@H@Z @ 430 NONAME ; class QStringList QMediaServiceProvider::supportedMimeTypes(class QByteArray const &, int) const + ?qt_metacast@QMediaPlayer@@UAEPAXPBD@Z @ 431 NONAME ; void * QMediaPlayer::qt_metacast(char const *) + ?metaDataAvailableChanged@QMediaRecorder@@IAEX_N@Z @ 432 NONAME ; void QMediaRecorder::metaDataAvailableChanged(bool) + ?metaDataAvailableChanged@QMediaObject@@IAEX_N@Z @ 433 NONAME ; void QMediaObject::metaDataAvailableChanged(bool) + ?stop@QAudioInput@@QAEXXZ @ 434 NONAME ; void QAudioInput::stop(void) + ??0QVideoFrame@@QAE@ABVQImage@@@Z @ 435 NONAME ; QVideoFrame::QVideoFrame(class QImage const &) + ?realm@QAudioDeviceInfo@@ABE?AVQString@@XZ @ 436 NONAME ; class QString QAudioDeviceInfo::realm(void) const + ?trUtf8@QRadioTunerControl@@SA?AVQString@@PBD0@Z @ 437 NONAME ; class QString QRadioTunerControl::trUtf8(char const *, char const *) + ?notify@QAbstractAudioInput@@IAEXXZ @ 438 NONAME ; void QAbstractAudioInput::notify(void) + ?metaDataAvailableChanged@QMetaDataReaderControl@@IAEX_N@Z @ 439 NONAME ; void QMetaDataReaderControl::metaDataAvailableChanged(bool) + ?request@QMediaResource@@QBE?AVQNetworkRequest@@XZ @ 440 NONAME ; class QNetworkRequest QMediaResource::request(void) const + ?handle@QVideoFrame@@QBE?AVQVariant@@XZ @ 441 NONAME ; class QVariant QVideoFrame::handle(void) const + ?setEncodingMode@QVideoEncoderSettings@@QAEXW4EncodingMode@QtMultimediaKit@@@Z @ 442 NONAME ; void QVideoEncoderSettings::setEncodingMode(enum QtMultimediaKit::EncodingMode) + ??1QMediaService@@UAE@XZ @ 443 NONAME ; QMediaService::~QMediaService(void) + ?volume@QMediaPlayer@@QBEHXZ @ 444 NONAME ; int QMediaPlayer::volume(void) const + ?tr@QMetaDataReaderControl@@SA?AVQString@@PBD0@Z @ 445 NONAME ; class QString QMetaDataReaderControl::tr(char const *, char const *) + ?supportedContainers@QMediaRecorder@@QBE?AVQStringList@@XZ @ 446 NONAME ; class QStringList QMediaRecorder::supportedContainers(void) const + ??0QVideoFrame@@QAE@PAVQAbstractVideoBuffer@@ABVQSize@@W4PixelFormat@0@@Z @ 447 NONAME ; QVideoFrame::QVideoFrame(class QAbstractVideoBuffer *, class QSize const &, enum QVideoFrame::PixelFormat) + ?d_func@QVideoWidget@@ABEPBVQVideoWidgetPrivate@@XZ @ 448 NONAME ; class QVideoWidgetPrivate const * QVideoWidget::d_func(void) const + ?durationChanged@QMediaRecorder@@IAEX_J@Z @ 449 NONAME ; void QMediaRecorder::durationChanged(long long) + ?trUtf8@QVideoWidgetControl@@SA?AVQString@@PBD0H@Z @ 450 NONAME ; class QString QVideoWidgetControl::trUtf8(char const *, char const *, int) + ?errorString@QMediaRecorder@@QBE?AVQString@@XZ @ 451 NONAME ; class QString QMediaRecorder::errorString(void) const + ?getStaticMetaObject@QMediaPlayerControl@@SAABUQMetaObject@@XZ @ 452 NONAME ; struct QMetaObject const & QMediaPlayerControl::getStaticMetaObject(void) + ?propertyNames@QVideoSurfaceFormat@@QBE?AV?$QList@VQByteArray@@@@XZ @ 453 NONAME ; class QList QVideoSurfaceFormat::propertyNames(void) const + ?trUtf8@QMetaDataWriterControl@@SA?AVQString@@PBD0H@Z @ 454 NONAME ; class QString QMetaDataWriterControl::trUtf8(char const *, char const *, int) + ??0QImageVideoBuffer@@QAE@ABVQImage@@@Z @ 455 NONAME ; QImageVideoBuffer::QImageVideoBuffer(class QImage const &) + ?pixelFormatFromImageFormat@QVideoFrame@@SA?AW4PixelFormat@1@W4Format@QImage@@@Z @ 456 NONAME ; enum QVideoFrame::PixelFormat QVideoFrame::pixelFormatFromImageFormat(enum QImage::Format) + ?defaultServiceProvider@QMediaServiceProvider@@SAPAV1@XZ @ 457 NONAME ; class QMediaServiceProvider * QMediaServiceProvider::defaultServiceProvider(void) + ?tr@QAudioCaptureSource@@SA?AVQString@@PBD0H@Z @ 458 NONAME ; class QString QAudioCaptureSource::tr(char const *, char const *, int) + ?start@QMediaTimeInterval@@QBE_JXZ @ 459 NONAME ; long long QMediaTimeInterval::start(void) const + ?staticMetaObject@QMediaPlaylistProvider@@2UQMetaObject@@B @ 460 NONAME ; struct QMetaObject const QMediaPlaylistProvider::staticMetaObject + ?isEmpty@QMediaTimeRange@@QBE_NXZ @ 461 NONAME ; bool QMediaTimeRange::isEmpty(void) const + ?staticMetaObject@QMediaPlaylistNavigator@@2UQMetaObject@@B @ 462 NONAME ; struct QMetaObject const QMediaPlaylistNavigator::staticMetaObject + ?features@QMediaServiceProviderHint@@QBE?AV?$QFlags@W4Feature@QMediaServiceProviderHint@@@@XZ @ 463 NONAME ; class QFlags QMediaServiceProviderHint::features(void) const + ?isNull@QMediaResource@@QBE_NXZ @ 464 NONAME ; bool QMediaResource::isNull(void) const + ??8QMediaResource@@QBE_NABV0@@Z @ 465 NONAME ; bool QMediaResource::operator==(class QMediaResource const &) const + ?bufferStatusChanged@QMediaPlayer@@IAEXH@Z @ 466 NONAME ; void QMediaPlayer::bufferStatusChanged(int) + ?error@QAudioOutput@@QBE?AW4Error@QAudio@@XZ @ 467 NONAME ; enum QAudio::Error QAudioOutput::error(void) const + ?d_func@QRadioTuner@@ABEPBVQRadioTunerPrivate@@XZ @ 468 NONAME ; class QRadioTunerPrivate const * QRadioTuner::d_func(void) const + ?d_func@QMemoryVideoBuffer@@ABEPBVQMemoryVideoBufferPrivate@@XZ @ 469 NONAME ; class QMemoryVideoBufferPrivate const * QMemoryVideoBuffer::d_func(void) const + ?trUtf8@QAudioEncoderControl@@SA?AVQString@@PBD0H@Z @ 470 NONAME ; class QString QAudioEncoderControl::trUtf8(char const *, char const *, int) + ?trUtf8@QMediaPlayer@@SA?AVQString@@PBD0@Z @ 471 NONAME ; class QString QMediaPlayer::trUtf8(char const *, char const *) + ?elapsedUSecs@QAudioOutput@@QBE_JXZ @ 472 NONAME ; long long QAudioOutput::elapsedUSecs(void) const + ??8@YA_NABVQMediaTimeInterval@@0@Z @ 473 NONAME ; bool operator==(class QMediaTimeInterval const &, class QMediaTimeInterval const &) + ?containerDescription@QMediaRecorder@@QBE?AVQString@@ABV2@@Z @ 474 NONAME ; class QString QMediaRecorder::containerDescription(class QString const &) const + ?trUtf8@QVideoWindowControl@@SA?AVQString@@PBD0H@Z @ 475 NONAME ; class QString QVideoWindowControl::trUtf8(char const *, char const *, int) + ?isMuted@QSoundEffect@@QBE_NXZ @ 476 NONAME ; bool QSoundEffect::isMuted(void) const + ?volumeChanged@QMediaPlayer@@IAEXH@Z @ 477 NONAME ; void QMediaPlayer::volumeChanged(int) + ??1QVideoWidgetControl@@UAE@XZ @ 478 NONAME ; QVideoWidgetControl::~QVideoWidgetControl(void) + ??_EQMediaRecorderControl@@UAE@I@Z @ 479 NONAME ; QMediaRecorderControl::~QMediaRecorderControl(unsigned int) + ?volumeChanged@QRadioTunerControl@@IAEXH@Z @ 480 NONAME ; void QRadioTunerControl::volumeChanged(int) + ??_EQMediaContainerControl@@UAE@I@Z @ 481 NONAME ; QMediaContainerControl::~QMediaContainerControl(unsigned int) + ?tr@QAudioInput@@SA?AVQString@@PBD0H@Z @ 482 NONAME ; class QString QAudioInput::tr(char const *, char const *, int) + ??8QMediaContent@@QBE_NABV0@@Z @ 483 NONAME ; bool QMediaContent::operator==(class QMediaContent const &) const + ?getStaticMetaObject@QImageEncoderControl@@SAABUQMetaObject@@XZ @ 484 NONAME ; struct QMetaObject const & QImageEncoderControl::getStaticMetaObject(void) + ?durationChanged@QMediaRecorderControl@@IAEX_J@Z @ 485 NONAME ; void QMediaRecorderControl::durationChanged(long long) + ?getStaticMetaObject@QMetaDataReaderControl@@SAABUQMetaObject@@XZ @ 486 NONAME ; struct QMetaObject const & QMetaDataReaderControl::getStaticMetaObject(void) + ?hue@QVideoWidget@@QBEHXZ @ 487 NONAME ; int QVideoWidget::hue(void) const + ?handleType@QVideoSurfaceFormat@@QBE?AW4HandleType@QAbstractVideoBuffer@@XZ @ 488 NONAME ; enum QAbstractVideoBuffer::HandleType QVideoSurfaceFormat::handleType(void) const + ?setNotifyInterval@QAudioOutput@@QAEXH@Z @ 489 NONAME ; void QAudioOutput::setNotifyInterval(int) + ?start@QAbstractVideoSurface@@UAE_NABVQVideoSurfaceFormat@@@Z @ 490 NONAME ; bool QAbstractVideoSurface::start(class QVideoSurfaceFormat const &) + ?processedUSecs@QAudioInput@@QBE_JXZ @ 491 NONAME ; long long QAudioInput::processedUSecs(void) const + ?tr@QMediaObject@@SA?AVQString@@PBD0H@Z @ 492 NONAME ; class QString QMediaObject::tr(char const *, char const *, int) + ?fullScreenChanged@QVideoWindowControl@@IAEX_N@Z @ 493 NONAME ; void QVideoWindowControl::fullScreenChanged(bool) + ?play@QSoundEffect@@QAEXXZ @ 494 NONAME ; void QSoundEffect::play(void) + ?stop@QAbstractVideoSurface@@UAEXXZ @ 495 NONAME ; void QAbstractVideoSurface::stop(void) + ?contains@QMediaTimeRange@@QBE_N_J@Z @ 496 NONAME ; bool QMediaTimeRange::contains(long long) const + ?setMuted@QMediaPlayer@@QAEX_N@Z @ 497 NONAME ; void QMediaPlayer::setMuted(bool) + ?tr@QRadioTunerControl@@SA?AVQString@@PBD0@Z @ 498 NONAME ; class QString QRadioTunerControl::tr(char const *, char const *) + ?surfaceFormat@QAbstractVideoSurface@@QBE?AVQVideoSurfaceFormat@@XZ @ 499 NONAME ; class QVideoSurfaceFormat QAbstractVideoSurface::surfaceFormat(void) const + ?addPropertyWatch@QMediaObject@@IAEXABVQByteArray@@@Z @ 500 NONAME ; void QMediaObject::addPropertyWatch(class QByteArray const &) + ??_EQMediaPlaylistIOPlugin@@UAE@I@Z @ 501 NONAME ; QMediaPlaylistIOPlugin::~QMediaPlaylistIOPlugin(unsigned int) + ?trUtf8@QMediaPlayerControl@@SA?AVQString@@PBD0H@Z @ 502 NONAME ; class QString QMediaPlayerControl::trUtf8(char const *, char const *, int) + ?setVideoBitRate@QMediaResource@@QAEXH@Z @ 503 NONAME ; void QMediaResource::setVideoBitRate(int) + ?qt_metacall@QRadioTuner@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 504 NONAME ; int QRadioTuner::qt_metacall(enum QMetaObject::Call, int, void * *) + ?frequencyChanged@QRadioTunerControl@@IAEXH@Z @ 505 NONAME ; void QRadioTunerControl::frequencyChanged(int) + ?pause@QMediaRecorder@@QAEXXZ @ 506 NONAME ; void QMediaRecorder::pause(void) + ?fullScreenChanged@QVideoWidgetControl@@IAEX_N@Z @ 507 NONAME ; void QVideoWidgetControl::fullScreenChanged(bool) + ?intervals@QMediaTimeRange@@QBE?AV?$QList@VQMediaTimeInterval@@@@XZ @ 508 NONAME ; class QList QMediaTimeRange::intervals(void) const + ?bytesReady@QAudioInput@@QBEHXZ @ 509 NONAME ; int QAudioInput::bytesReady(void) const + ?tr@QMediaServiceProviderPlugin@@SA?AVQString@@PBD0@Z @ 510 NONAME ; class QString QMediaServiceProviderPlugin::tr(char const *, char const *) + ?stateChanged@QMediaPlayerControl@@IAEXW4State@QMediaPlayer@@@Z @ 511 NONAME ; void QMediaPlayerControl::stateChanged(enum QMediaPlayer::State) + ?tr@QAbstractAudioOutput@@SA?AVQString@@PBD0H@Z @ 512 NONAME ; class QString QAbstractAudioOutput::tr(char const *, char const *, int) + ?previous@QMediaPlaylist@@QAEXXZ @ 513 NONAME ; void QMediaPlaylist::previous(void) + ?stereoMode@QRadioTuner@@QBE?AW4StereoMode@1@XZ @ 514 NONAME ; enum QRadioTuner::StereoMode QRadioTuner::stereoMode(void) const + ?metaObject@QMediaPlaylist@@UBEPBUQMetaObject@@XZ @ 515 NONAME ; struct QMetaObject const * QMediaPlaylist::metaObject(void) const + ?trUtf8@QVideoWindowControl@@SA?AVQString@@PBD0@Z @ 516 NONAME ; class QString QVideoWindowControl::trUtf8(char const *, char const *) + ?stop@QMediaRecorder@@QAEXXZ @ 517 NONAME ; void QMediaRecorder::stop(void) + ?setViewport@QVideoSurfaceFormat@@QAEXABVQRect@@@Z @ 518 NONAME ; void QVideoSurfaceFormat::setViewport(class QRect const &) + ?setPlaybackMode@QMediaPlaylistNavigator@@QAEXW4PlaybackMode@QMediaPlaylist@@@Z @ 519 NONAME ; void QMediaPlaylistNavigator::setPlaybackMode(enum QMediaPlaylist::PlaybackMode) + ?tr@QMediaPlaylist@@SA?AVQString@@PBD0@Z @ 520 NONAME ; class QString QMediaPlaylist::tr(char const *, char const *) + ?playbackRate@QMediaPlayer@@QBEMXZ @ 521 NONAME ; float QMediaPlayer::playbackRate(void) const + ?metaObject@QMediaStreamsControl@@UBEPBUQMetaObject@@XZ @ 522 NONAME ; struct QMetaObject const * QMediaStreamsControl::metaObject(void) const + ?metaObject@QMediaObject@@UBEPBUQMetaObject@@XZ @ 523 NONAME ; struct QMetaObject const * QMediaObject::metaObject(void) const + ?d_func@QMediaRecorder@@AAEPAVQMediaRecorderPrivate@@XZ @ 524 NONAME ; class QMediaRecorderPrivate * QMediaRecorder::d_func(void) + ?brightnessChanged@QVideoWindowControl@@IAEXH@Z @ 525 NONAME ; void QVideoWindowControl::brightnessChanged(int) + ?stereoStatusChanged@QRadioTuner@@IAEX_N@Z @ 526 NONAME ; void QRadioTuner::stereoStatusChanged(bool) + ?setQuality@QVideoEncoderSettings@@QAEXW4EncodingQuality@QtMultimediaKit@@@Z @ 527 NONAME ; void QVideoEncoderSettings::setQuality(enum QtMultimediaKit::EncodingQuality) + ?staticMetaObject@QMetaDataReaderControl@@2UQMetaObject@@B @ 528 NONAME ; struct QMetaObject const QMetaDataReaderControl::staticMetaObject + ?isNull@QAudioEncoderSettings@@QBE_NXZ @ 529 NONAME ; bool QAudioEncoderSettings::isNull(void) const + ?handleType@QVideoFrame@@QBE?AW4HandleType@QAbstractVideoBuffer@@XZ @ 530 NONAME ; enum QAbstractVideoBuffer::HandleType QVideoFrame::handleType(void) const + ?setAudioInput@QAudioCaptureSource@@QAEXABVQString@@@Z @ 531 NONAME ; void QAudioCaptureSource::setAudioInput(class QString const &) + ?mapMode@QImageVideoBuffer@@UBE?AW4MapMode@QAbstractVideoBuffer@@XZ @ 532 NONAME ; enum QAbstractVideoBuffer::MapMode QImageVideoBuffer::mapMode(void) const + ?mediaAboutToBeRemoved@QMediaPlaylist@@IAEXHH@Z @ 533 NONAME ; void QMediaPlaylist::mediaAboutToBeRemoved(int, int) + ??8QVideoEncoderSettings@@QBE_NABV0@@Z @ 534 NONAME ; bool QVideoEncoderSettings::operator==(class QVideoEncoderSettings const &) const + ??0QMediaResource@@QAE@XZ @ 535 NONAME ; QMediaResource::QMediaResource(void) + ?staticMetaObject@QAudioEncoderControl@@2UQMetaObject@@B @ 536 NONAME ; struct QMetaObject const QAudioEncoderControl::staticMetaObject + ?isAvailable@QMediaObject@@UBE_NXZ @ 537 NONAME ; bool QMediaObject::isAvailable(void) const + ?trUtf8@QVideoRendererControl@@SA?AVQString@@PBD0@Z @ 538 NONAME ; class QString QVideoRendererControl::trUtf8(char const *, char const *) + ??0QAudioEncoderControl@@IAE@PAVQObject@@@Z @ 539 NONAME ; QAudioEncoderControl::QAudioEncoderControl(class QObject *) + ?supportedCodecs@QAudioDeviceInfo@@QBE?AVQStringList@@XZ @ 540 NONAME ; class QStringList QAudioDeviceInfo::supportedCodecs(void) const + ?playlistProviderChanged@QMediaPlaylistControl@@IAEXXZ @ 541 NONAME ; void QMediaPlaylistControl::playlistProviderChanged(void) + ??4QMediaContent@@QAEAAV0@ABV0@@Z @ 542 NONAME ; class QMediaContent & QMediaContent::operator=(class QMediaContent const &) + ?getStaticMetaObject@QMediaStreamsControl@@SAABUQMetaObject@@XZ @ 543 NONAME ; struct QMetaObject const & QMediaStreamsControl::getStaticMetaObject(void) + ??1QAudioEncoderControl@@UAE@XZ @ 544 NONAME ; QAudioEncoderControl::~QAudioEncoderControl(void) + ?trUtf8@QLocalMediaPlaylistProvider@@SA?AVQString@@PBD0H@Z @ 545 NONAME ; class QString QLocalMediaPlaylistProvider::trUtf8(char const *, char const *, int) + ?availabilityError@QRadioTuner@@UBE?AW4AvailabilityError@QtMultimediaKit@@XZ @ 546 NONAME ; enum QtMultimediaKit::AvailabilityError QRadioTuner::availabilityError(void) const + ??0QVideoFrame@@QAE@HABVQSize@@HW4PixelFormat@0@@Z @ 547 NONAME ; QVideoFrame::QVideoFrame(int, class QSize const &, int, enum QVideoFrame::PixelFormat) + ?trUtf8@QMediaPlaylistSourceControl@@SA?AVQString@@PBD0H@Z @ 548 NONAME ; class QString QMediaPlaylistSourceControl::trUtf8(char const *, char const *, int) + ?handle@QAbstractVideoBuffer@@UBE?AVQVariant@@XZ @ 549 NONAME ; class QVariant QAbstractVideoBuffer::handle(void) const + ?setOutputLocation@QMediaRecorder@@QAE_NABVQUrl@@@Z @ 550 NONAME ; bool QMediaRecorder::setOutputLocation(class QUrl const &) + ?canonicalRequest@QMediaContent@@QBE?AVQNetworkRequest@@XZ @ 551 NONAME ; class QNetworkRequest QMediaContent::canonicalRequest(void) const + ?error@QRadioTuner@@QBE?AW4Error@1@XZ @ 552 NONAME ; enum QRadioTuner::Error QRadioTuner::error(void) const + ?codec@QVideoEncoderSettings@@QBE?AVQString@@XZ @ 553 NONAME ; class QString QVideoEncoderSettings::codec(void) const + ?qt_metacall@QAudioEncoderControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 554 NONAME ; int QAudioEncoderControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ?trUtf8@QMediaService@@SA?AVQString@@PBD0H@Z @ 555 NONAME ; class QString QMediaService::trUtf8(char const *, char const *, int) + ?removeMedia@QMediaPlaylistProvider@@UAE_NHH@Z @ 556 NONAME ; bool QMediaPlaylistProvider::removeMedia(int, int) + ?saturationChanged@QVideoWindowControl@@IAEXH@Z @ 557 NONAME ; void QVideoWindowControl::saturationChanged(int) + ??0QMediaPlaylistControl@@IAE@PAVQObject@@@Z @ 558 NONAME ; QMediaPlaylistControl::QMediaPlaylistControl(class QObject *) + ?error@QMediaRecorder@@QBE?AW4Error@1@XZ @ 559 NONAME ; enum QMediaRecorder::Error QMediaRecorder::error(void) const + ?canonicalResource@QMediaContent@@QBE?AVQMediaResource@@XZ @ 560 NONAME ; class QMediaResource QMediaContent::canonicalResource(void) const + ?metaObject@QAbstractVideoSurface@@UBEPBUQMetaObject@@XZ @ 561 NONAME ; struct QMetaObject const * QAbstractVideoSurface::metaObject(void) const + ??0QMediaService@@IAE@AAVQMediaServicePrivate@@PAVQObject@@@Z @ 562 NONAME ; QMediaService::QMediaService(class QMediaServicePrivate &, class QObject *) + ?playlist@QMediaPlaylistNavigator@@QBEPAVQMediaPlaylistProvider@@XZ @ 563 NONAME ; class QMediaPlaylistProvider * QMediaPlaylistNavigator::playlist(void) const + ?metaObject@QAudioCaptureSource@@UBEPBUQMetaObject@@XZ @ 564 NONAME ; struct QMetaObject const * QAudioCaptureSource::metaObject(void) const + ?staticMetaObject@QMetaDataWriterControl@@2UQMetaObject@@B @ 565 NONAME ; struct QMetaObject const QMetaDataWriterControl::staticMetaObject + ?getStaticMetaObject@QAbstractAudioInput@@SAABUQMetaObject@@XZ @ 566 NONAME ; struct QMetaObject const & QAbstractAudioInput::getStaticMetaObject(void) + ?d_func@QAbstractVideoBuffer@@AAEPAVQAbstractVideoBufferPrivate@@XZ @ 567 NONAME ; class QAbstractVideoBufferPrivate * QAbstractVideoBuffer::d_func(void) + ?staticMetaObject@QMediaPlaylistControl@@2UQMetaObject@@B @ 568 NONAME ; struct QMetaObject const QMediaPlaylistControl::staticMetaObject + ?qt_metacast@QVideoDeviceControl@@UAEPAXPBD@Z @ 569 NONAME ; void * QVideoDeviceControl::qt_metacast(char const *) + ?metaObject@QVideoRendererControl@@UBEPBUQMetaObject@@XZ @ 570 NONAME ; struct QMetaObject const * QVideoRendererControl::metaObject(void) const + ??1QMediaPlaylistReader@@UAE@XZ @ 571 NONAME ; QMediaPlaylistReader::~QMediaPlaylistReader(void) + ?getStaticMetaObject@QAbstractAudioOutput@@SAABUQMetaObject@@XZ @ 572 NONAME ; struct QMetaObject const & QAbstractAudioOutput::getStaticMetaObject(void) + ?qt_metacast@QAbstractVideoSurface@@UAEPAXPBD@Z @ 573 NONAME ; void * QAbstractVideoSurface::qt_metacast(char const *) + ?qt_metacall@QMetaDataWriterControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 574 NONAME ; int QMetaDataWriterControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ??0QAbstractVideoSurface@@IAE@AAVQAbstractVideoSurfacePrivate@@PAVQObject@@@Z @ 575 NONAME ; QAbstractVideoSurface::QAbstractVideoSurface(class QAbstractVideoSurfacePrivate &, class QObject *) + ?tr@QMediaPlaylist@@SA?AVQString@@PBD0H@Z @ 576 NONAME ; class QString QMediaPlaylist::tr(char const *, char const *, int) + ??1QMediaServiceFeaturesInterface@@UAE@XZ @ 577 NONAME ; QMediaServiceFeaturesInterface::~QMediaServiceFeaturesInterface(void) + ?frequency@QAudioFormat@@QBEHXZ @ 578 NONAME ; int QAudioFormat::frequency(void) const + ?errorString@QMediaPlayer@@QBE?AVQString@@XZ @ 579 NONAME ; class QString QMediaPlayer::errorString(void) const + ?map@QImageVideoBuffer@@UAEPAEW4MapMode@QAbstractVideoBuffer@@PAH1@Z @ 580 NONAME ; unsigned char * QImageVideoBuffer::map(enum QAbstractVideoBuffer::MapMode, int *, int *) + ?setBufferSize@QAudioInput@@QAEXH@Z @ 581 NONAME ; void QAudioInput::setBufferSize(int) + ?loadFailed@QMediaPlaylist@@IAEXXZ @ 582 NONAME ; void QMediaPlaylist::loadFailed(void) + ?elapsedTime@QMediaImageViewer@@QBEHXZ @ 583 NONAME ; int QMediaImageViewer::elapsedTime(void) const + ?loaded@QMediaPlaylist@@IAEXXZ @ 584 NONAME ; void QMediaPlaylist::loaded(void) + ?mediaObject@QVideoWidget@@UBEPAVQMediaObject@@XZ @ 585 NONAME ; class QMediaObject * QVideoWidget::mediaObject(void) const + ??8QImageEncoderSettings@@QBE_NABV0@@Z @ 586 NONAME ; bool QImageEncoderSettings::operator==(class QImageEncoderSettings const &) const + ??1QMediaPlaylistNavigator@@UAE@XZ @ 587 NONAME ; QMediaPlaylistNavigator::~QMediaPlaylistNavigator(void) + ??0QAudioDeviceInfo@@QAE@ABV0@@Z @ 588 NONAME ; QAudioDeviceInfo::QAudioDeviceInfo(class QAudioDeviceInfo const &) + ?tr@QVideoEncoderControl@@SA?AVQString@@PBD0@Z @ 589 NONAME ; class QString QVideoEncoderControl::tr(char const *, char const *) + ?qt_metacast@QMediaRecorderControl@@UAEPAXPBD@Z @ 590 NONAME ; void * QMediaRecorderControl::qt_metacast(char const *) + ?tr@QAudioInput@@SA?AVQString@@PBD0@Z @ 591 NONAME ; class QString QAudioInput::tr(char const *, char const *) + ?devices@QMediaServiceProvider@@UBE?AV?$QList@VQByteArray@@@@ABVQByteArray@@@Z @ 592 NONAME ; class QList QMediaServiceProvider::devices(class QByteArray const &) const + ?staticMetaObject@QMediaRecorderControl@@2UQMetaObject@@B @ 593 NONAME ; struct QMetaObject const QMediaRecorderControl::staticMetaObject + ?qt_metacall@QMediaPlaylist@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 594 NONAME ; int QMediaPlaylist::qt_metacall(enum QMetaObject::Call, int, void * *) + ?setBrightness@QVideoWidget@@QAEXH@Z @ 595 NONAME ; void QVideoWidget::setBrightness(int) + ??4QImageEncoderSettings@@QAEAAV0@ABV0@@Z @ 596 NONAME ; class QImageEncoderSettings & QImageEncoderSettings::operator=(class QImageEncoderSettings const &) + ?qt_metacall@QVideoWidgetControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 597 NONAME ; int QVideoWidgetControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ??_EQAudioSystemFactoryInterface@@UAE@I@Z @ 598 NONAME ; QAudioSystemFactoryInterface::~QAudioSystemFactoryInterface(unsigned int) + ?isNull@QMediaContent@@QBE_NXZ @ 599 NONAME ; bool QMediaContent::isNull(void) const + ?qt_metacall@QAbstractVideoSurface@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 600 NONAME ; int QAbstractVideoSurface::qt_metacall(enum QMetaObject::Call, int, void * *) + ??1QVideoDeviceControl@@UAE@XZ @ 601 NONAME ; QVideoDeviceControl::~QVideoDeviceControl(void) + ?isValid@QVideoSurfaceFormat@@QBE_NXZ @ 602 NONAME ; bool QVideoSurfaceFormat::isValid(void) const + ?defaultInputDevice@QAudioDeviceInfo@@SA?AV1@XZ @ 603 NONAME ; class QAudioDeviceInfo QAudioDeviceInfo::defaultInputDevice(void) + ?tr@QVideoDeviceControl@@SA?AVQString@@PBD0H@Z @ 604 NONAME ; class QString QVideoDeviceControl::tr(char const *, char const *, int) + ?pause@QMediaImageViewer@@QAEXXZ @ 605 NONAME ; void QMediaImageViewer::pause(void) + ?qt_metacast@QAudioInput@@UAEPAXPBD@Z @ 606 NONAME ; void * QAudioInput::qt_metacast(char const *) + ?trUtf8@QMediaServiceProvider@@SA?AVQString@@PBD0@Z @ 607 NONAME ; class QString QMediaServiceProvider::trUtf8(char const *, char const *) + ?tr@QMediaPlaylistSourceControl@@SA?AVQString@@PBD0@Z @ 608 NONAME ; class QString QMediaPlaylistSourceControl::tr(char const *, char const *) + ?state@QMediaPlayer@@QBE?AW4State@1@XZ @ 609 NONAME ; enum QMediaPlayer::State QMediaPlayer::state(void) const + ?tr@QAudioEncoderControl@@SA?AVQString@@PBD0@Z @ 610 NONAME ; class QString QAudioEncoderControl::tr(char const *, char const *) + ??1QAudioFormat@@QAE@XZ @ 611 NONAME ; QAudioFormat::~QAudioFormat(void) + ?bind@QMediaObject@@UAE_NPAVQObject@@@Z @ 612 NONAME ; bool QMediaObject::bind(class QObject *) + ?metaDataChanged@QMetaDataReaderControl@@IAEXXZ @ 613 NONAME ; void QMetaDataReaderControl::metaDataChanged(void) + ?playlist@QMediaPlayer@@QBEPAVQMediaPlaylist@@XZ @ 614 NONAME ; class QMediaPlaylist * QMediaPlayer::playlist(void) const + ?trUtf8@QAudioInput@@SA?AVQString@@PBD0@Z @ 615 NONAME ; class QString QAudioInput::trUtf8(char const *, char const *) + ?metaObject@QAudioEncoderControl@@UBEPBUQMetaObject@@XZ @ 616 NONAME ; struct QMetaObject const * QAudioEncoderControl::metaObject(void) const + ?getStaticMetaObject@QAudioInput@@SAABUQMetaObject@@XZ @ 617 NONAME ; struct QMetaObject const & QAudioInput::getStaticMetaObject(void) + ?previousItem@QMediaPlaylistNavigator@@QBE?AVQMediaContent@@H@Z @ 618 NONAME ; class QMediaContent QMediaPlaylistNavigator::previousItem(int) const + ??0QMediaTimeInterval@@QAE@ABV0@@Z @ 619 NONAME ; QMediaTimeInterval::QMediaTimeInterval(class QMediaTimeInterval const &) + ?tr@QAudioEndpointSelector@@SA?AVQString@@PBD0@Z @ 620 NONAME ; class QString QAudioEndpointSelector::tr(char const *, char const *) + ?qt_metacall@QGraphicsVideoItem@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 621 NONAME ; int QGraphicsVideoItem::qt_metacall(enum QMetaObject::Call, int, void * *) + ?tr@QMetaDataReaderControl@@SA?AVQString@@PBD0H@Z @ 622 NONAME ; class QString QMetaDataReaderControl::tr(char const *, char const *, int) + ?mediaChanged@QMediaPlaylistProvider@@IAEXHH@Z @ 623 NONAME ; void QMediaPlaylistProvider::mediaChanged(int, int) + ?service@QMediaObject@@UBEPAVQMediaService@@XZ @ 624 NONAME ; class QMediaService * QMediaObject::service(void) const + ?mappedBytes@QVideoFrame@@QBEHXZ @ 625 NONAME ; int QVideoFrame::mappedBytes(void) const + ?tr@QMediaPlaylistIOPlugin@@SA?AVQString@@PBD0@Z @ 626 NONAME ; class QString QMediaPlaylistIOPlugin::tr(char const *, char const *) + ?removePropertyWatch@QMediaObject@@IAEXABVQByteArray@@@Z @ 627 NONAME ; void QMediaObject::removePropertyWatch(class QByteArray const &) + ?metaObject@QMediaControl@@UBEPBUQMetaObject@@XZ @ 628 NONAME ; struct QMetaObject const * QMediaControl::metaObject(void) const + ??1QMediaStreamsControl@@UAE@XZ @ 629 NONAME ; QMediaStreamsControl::~QMediaStreamsControl(void) + ?codec@QImageEncoderSettings@@QBE?AVQString@@XZ @ 630 NONAME ; class QString QImageEncoderSettings::codec(void) const + ?frequencyStep@QRadioTuner@@QBEHW4Band@1@@Z @ 631 NONAME ; int QRadioTuner::frequencyStep(enum QRadioTuner::Band) const + ??1QVideoRendererControl@@UAE@XZ @ 632 NONAME ; QVideoRendererControl::~QVideoRendererControl(void) + ?setNotifyInterval@QMediaObject@@QAEXH@Z @ 633 NONAME ; void QMediaObject::setNotifyInterval(int) + ?metaDataChanged@QMetaDataWriterControl@@IAEXXZ @ 634 NONAME ; void QMetaDataWriterControl::metaDataChanged(void) + ??_EQMetaDataReaderControl@@UAE@I@Z @ 635 NONAME ; QMetaDataReaderControl::~QMetaDataReaderControl(unsigned int) + ?surfaceFormatChanged@QAbstractVideoSurface@@IAEXABVQVideoSurfaceFormat@@@Z @ 636 NONAME ; void QAbstractVideoSurface::surfaceFormatChanged(class QVideoSurfaceFormat const &) + ?clear@QMediaTimeRange@@QAEXXZ @ 637 NONAME ; void QMediaTimeRange::clear(void) + ?setOffset@QGraphicsVideoItem@@QAEXABVQPointF@@@Z @ 638 NONAME ; void QGraphicsVideoItem::setOffset(class QPointF const &) + ??_EQAudioEncoderControl@@UAE@I@Z @ 639 NONAME ; QAudioEncoderControl::~QAudioEncoderControl(unsigned int) + ?qt_metacast@QLocalMediaPlaylistProvider@@UAEPAXPBD@Z @ 640 NONAME ; void * QLocalMediaPlaylistProvider::qt_metacast(char const *) + ?resizeEvent@QVideoWidget@@MAEXPAVQResizeEvent@@@Z @ 641 NONAME ; void QVideoWidget::resizeEvent(class QResizeEvent *) + ?isReadOnly@QLocalMediaPlaylistProvider@@UBE_NXZ @ 642 NONAME ; bool QLocalMediaPlaylistProvider::isReadOnly(void) const + ?d_func@QMediaPlayer@@AAEPAVQMediaPlayerPrivate@@XZ @ 643 NONAME ; class QMediaPlayerPrivate * QMediaPlayer::d_func(void) + ?elapsedTimeChanged@QMediaImageViewer@@IAEXH@Z @ 644 NONAME ; void QMediaImageViewer::elapsedTimeChanged(int) + ?isMapped@QVideoFrame@@QBE_NXZ @ 645 NONAME ; bool QVideoFrame::isMapped(void) const + ?tr@QAudioOutput@@SA?AVQString@@PBD0@Z @ 646 NONAME ; class QString QAudioOutput::tr(char const *, char const *) + ?metaDataWritableChanged@QMediaRecorder@@IAEX_N@Z @ 647 NONAME ; void QMediaRecorder::metaDataWritableChanged(bool) + ?loopsChanged@QSoundEffect@@IAEXXZ @ 648 NONAME ABSENT ; void QSoundEffect::loopsChanged(void) + ?trUtf8@QAbstractAudioInput@@SA?AVQString@@PBD0H@Z @ 649 NONAME ; class QString QAbstractAudioInput::trUtf8(char const *, char const *, int) + ?setDataSize@QMediaResource@@QAEX_J@Z @ 650 NONAME ; void QMediaResource::setDataSize(long long) + ?trUtf8@QAudioEndpointSelector@@SA?AVQString@@PBD0H@Z @ 651 NONAME ; class QString QAudioEndpointSelector::trUtf8(char const *, char const *, int) + ?setFieldType@QVideoFrame@@QAEXW4FieldType@1@@Z @ 652 NONAME ; void QVideoFrame::setFieldType(enum QVideoFrame::FieldType) + ?metaData@QMediaRecorder@@QBE?AVQVariant@@W4MetaData@QtMultimediaKit@@@Z @ 653 NONAME ; class QVariant QMediaRecorder::metaData(enum QtMultimediaKit::MetaData) const + ?audioDescription@QAudioCaptureSource@@QBE?AVQString@@ABV2@@Z @ 654 NONAME ; class QString QAudioCaptureSource::audioDescription(class QString const &) const + ?media@QLocalMediaPlaylistProvider@@UBE?AVQMediaContent@@H@Z @ 655 NONAME ; class QMediaContent QLocalMediaPlaylistProvider::media(int) const + ??0QVideoWidgetControl@@IAE@PAVQObject@@@Z @ 656 NONAME ; QVideoWidgetControl::QVideoWidgetControl(class QObject *) + ??1QImageEncoderSettings@@QAE@XZ @ 657 NONAME ; QImageEncoderSettings::~QImageEncoderSettings(void) + ?deviceName@QAudioDeviceInfo@@QBE?AVQString@@XZ @ 658 NONAME ; class QString QAudioDeviceInfo::deviceName(void) const + ?isAvailable@QAudioCaptureSource@@UBE_NXZ @ 659 NONAME ; bool QAudioCaptureSource::isAvailable(void) const + ?getStaticMetaObject@QAudioEndpointSelector@@SAABUQMetaObject@@XZ @ 660 NONAME ; struct QMetaObject const & QAudioEndpointSelector::getStaticMetaObject(void) + ??0QMediaObject@@IAE@PAVQObject@@PAVQMediaService@@@Z @ 661 NONAME ; QMediaObject::QMediaObject(class QObject *, class QMediaService *) + ?addTimeRange@QMediaTimeRange@@QAEXABV1@@Z @ 662 NONAME ; void QMediaTimeRange::addTimeRange(class QMediaTimeRange const &) + ?timerEvent@QMediaImageViewer@@MAEXPAVQTimerEvent@@@Z @ 663 NONAME ; void QMediaImageViewer::timerEvent(class QTimerEvent *) + ?getStaticMetaObject@QMediaPlaylistIOPlugin@@SAABUQMetaObject@@XZ @ 664 NONAME ; struct QMetaObject const & QMediaPlaylistIOPlugin::getStaticMetaObject(void) + ?metaObject@QLocalMediaPlaylistProvider@@UBEPBUQMetaObject@@XZ @ 665 NONAME ; struct QMetaObject const * QLocalMediaPlaylistProvider::metaObject(void) const + ?currentIndexChanged@QMediaPlaylist@@IAEXH@Z @ 666 NONAME ; void QMediaPlaylist::currentIndexChanged(int) + ?videoCodecDescription@QMediaRecorder@@QBE?AVQString@@ABV2@@Z @ 667 NONAME ; class QString QMediaRecorder::videoCodecDescription(class QString const &) const + ?trUtf8@QMediaImageViewer@@SA?AVQString@@PBD0H@Z @ 668 NONAME ; class QString QMediaImageViewer::trUtf8(char const *, char const *, int) + ?stop@QMediaImageViewer@@QAEXXZ @ 669 NONAME ; void QMediaImageViewer::stop(void) + ?metaObject@QMediaPlaylistSourceControl@@UBEPBUQMetaObject@@XZ @ 670 NONAME ; struct QMetaObject const * QMediaPlaylistSourceControl::metaObject(void) const + ?qt_metacall@QAudioInput@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 671 NONAME ; int QAudioInput::qt_metacall(enum QMetaObject::Call, int, void * *) + ?availableEndpointsChanged@QAudioEndpointSelector@@IAEXXZ @ 672 NONAME ; void QAudioEndpointSelector::availableEndpointsChanged(void) + ?isNull@QVideoEncoderSettings@@QBE_NXZ @ 673 NONAME ; bool QVideoEncoderSettings::isNull(void) const + ?qt_metacast@QMediaPlayerControl@@UAEPAXPBD@Z @ 674 NONAME ; void * QMediaPlayerControl::qt_metacast(char const *) + ?setMediaObject@QMediaPlaylist@@MAE_NPAVQMediaObject@@@Z @ 675 NONAME ; bool QMediaPlaylist::setMediaObject(class QMediaObject *) + ?supportedMimeTypes@QMediaPlayer@@SA?AVQStringList@@V?$QFlags@W4Flag@QMediaPlayer@@@@@Z @ 676 NONAME ; class QStringList QMediaPlayer::supportedMimeTypes(class QFlags) + ?source@QSoundEffect@@QBE?AVQUrl@@XZ @ 677 NONAME ; class QUrl QSoundEffect::source(void) const + ?addMedia@QMediaPlaylist@@QAE_NABVQMediaContent@@@Z @ 678 NONAME ; bool QMediaPlaylist::addMedia(class QMediaContent const &) + ?metaObject@QMediaPlaylistNavigator@@UBEPBUQMetaObject@@XZ @ 679 NONAME ; struct QMetaObject const * QMediaPlaylistNavigator::metaObject(void) const + ?size@QVideoFrame@@QBE?AVQSize@@XZ @ 680 NONAME ; class QSize QVideoFrame::size(void) const + ?tr@QMediaPlayer@@SA?AVQString@@PBD0H@Z @ 681 NONAME ; class QString QMediaPlayer::tr(char const *, char const *, int) + ?d_func@QAbstractVideoSurface@@AAEPAVQAbstractVideoSurfacePrivate@@XZ @ 682 NONAME ; class QAbstractVideoSurfacePrivate * QAbstractVideoSurface::d_func(void) + ?dataSize@QMediaResource@@QBE_JXZ @ 683 NONAME ; long long QMediaResource::dataSize(void) const + ?staticMetaObject@QRadioTunerControl@@2UQMetaObject@@B @ 684 NONAME ; struct QMetaObject const QRadioTunerControl::staticMetaObject + ?tr@QMediaPlaylistNavigator@@SA?AVQString@@PBD0@Z @ 685 NONAME ; class QString QMediaPlaylistNavigator::tr(char const *, char const *) + ?tr@QMediaService@@SA?AVQString@@PBD0H@Z @ 686 NONAME ; class QString QMediaService::tr(char const *, char const *, int) + ?resolution@QVideoEncoderSettings@@QBE?AVQSize@@XZ @ 687 NONAME ; class QSize QVideoEncoderSettings::resolution(void) const + ?setContrast@QVideoWidget@@QAEXH@Z @ 688 NONAME ; void QVideoWidget::setContrast(int) + ??1QMediaServiceSupportedFormatsInterface@@UAE@XZ @ 689 NONAME ; QMediaServiceSupportedFormatsInterface::~QMediaServiceSupportedFormatsInterface(void) + ?activeStreamsChanged@QMediaStreamsControl@@IAEXXZ @ 690 NONAME ; void QMediaStreamsControl::activeStreamsChanged(void) + ?aspectRatioMode@QVideoWidget@@QBE?AW4AspectRatioMode@Qt@@XZ @ 691 NONAME ; enum Qt::AspectRatioMode QVideoWidget::aspectRatioMode(void) const + ??1QMediaRecorder@@UAE@XZ @ 692 NONAME ; QMediaRecorder::~QMediaRecorder(void) + ?setSampleType@QAudioFormat@@QAEXW4SampleType@1@@Z @ 693 NONAME ; void QAudioFormat::setSampleType(enum QAudioFormat::SampleType) + ?next@QMediaPlaylistNavigator@@QAEXXZ @ 694 NONAME ; void QMediaPlaylistNavigator::next(void) + ?setMedia@QMediaPlayer@@QAEXABVQMediaContent@@PAVQIODevice@@@Z @ 695 NONAME ; void QMediaPlayer::setMedia(class QMediaContent const &, class QIODevice *) + ??_EQMediaPlaylistControl@@UAE@I@Z @ 696 NONAME ; QMediaPlaylistControl::~QMediaPlaylistControl(unsigned int) + ??1QMetaDataReaderControl@@UAE@XZ @ 697 NONAME ; QMetaDataReaderControl::~QMetaDataReaderControl(void) + ?qt_metacall@QVideoEncoderControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 698 NONAME ; int QVideoEncoderControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ?hasSupport@QMediaServiceProvider@@UBE?AW4SupportEstimate@QtMultimediaKit@@ABVQByteArray@@ABVQString@@ABVQStringList@@H@Z @ 699 NONAME ; enum QtMultimediaKit::SupportEstimate QMediaServiceProvider::hasSupport(class QByteArray const &, class QString const &, class QStringList const &, int) const + ??_EQAudioOutput@@UAE@I@Z @ 700 NONAME ; QAudioOutput::~QAudioOutput(unsigned int) + ?mediaInserted@QMediaPlaylist@@IAEXHH@Z @ 701 NONAME ; void QMediaPlaylist::mediaInserted(int, int) + ?currentIndex@QMediaPlaylistNavigator@@QBEHXZ @ 702 NONAME ; int QMediaPlaylistNavigator::currentIndex(void) const + ?volumeChanged@QSoundEffect@@IAEXXZ @ 703 NONAME ; void QSoundEffect::volumeChanged(void) + ?duration@QMediaRecorder@@QBE_JXZ @ 704 NONAME ; long long QMediaRecorder::duration(void) const + ??0QMediaContent@@QAE@XZ @ 705 NONAME ; QMediaContent::QMediaContent(void) + ?mapMode@QMemoryVideoBuffer@@UBE?AW4MapMode@QAbstractVideoBuffer@@XZ @ 706 NONAME ; enum QAbstractVideoBuffer::MapMode QMemoryVideoBuffer::mapMode(void) const + ?setProperty@QVideoSurfaceFormat@@QAEXPBDABVQVariant@@@Z @ 707 NONAME ; void QVideoSurfaceFormat::setProperty(char const *, class QVariant const &) + ?metaObject@QMediaPlayer@@UBEPBUQMetaObject@@XZ @ 708 NONAME ; struct QMetaObject const * QMediaPlayer::metaObject(void) const + ?qt_metacall@QAudioOutput@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 709 NONAME ; int QAudioOutput::qt_metacall(enum QMetaObject::Call, int, void * *) + ?fieldType@QVideoFrame@@QBE?AW4FieldType@1@XZ @ 710 NONAME ; enum QVideoFrame::FieldType QVideoFrame::fieldType(void) const + ?language@QMediaResource@@QBE?AVQString@@XZ @ 711 NONAME ; class QString QMediaResource::language(void) const + ?trUtf8@QLocalMediaPlaylistProvider@@SA?AVQString@@PBD0@Z @ 712 NONAME ; class QString QLocalMediaPlaylistProvider::trUtf8(char const *, char const *) + ?isMetaDataAvailable@QMediaRecorder@@QBE_NXZ @ 713 NONAME ; bool QMediaRecorder::isMetaDataAvailable(void) const + ??1QGraphicsVideoItem@@UAE@XZ @ 714 NONAME ; QGraphicsVideoItem::~QGraphicsVideoItem(void) + ?setByteOrder@QAudioFormat@@QAEXW4Endian@1@@Z @ 715 NONAME ; void QAudioFormat::setByteOrder(enum QAudioFormat::Endian) + ?tr@QVideoDeviceControl@@SA?AVQString@@PBD0@Z @ 716 NONAME ; class QString QVideoDeviceControl::tr(char const *, char const *) + ??0QVideoDeviceControl@@IAE@PAVQObject@@@Z @ 717 NONAME ; QVideoDeviceControl::QVideoDeviceControl(class QObject *) + ?frequency@QRadioTuner@@QBEHXZ @ 718 NONAME ; int QRadioTuner::frequency(void) const + ?qt_metacast@QAbstractAudioDeviceInfo@@UAEPAXPBD@Z @ 719 NONAME ; void * QAbstractAudioDeviceInfo::qt_metacast(char const *) + ?trUtf8@QMediaContainerControl@@SA?AVQString@@PBD0@Z @ 720 NONAME ; class QString QMediaContainerControl::trUtf8(char const *, char const *) + ?tr@QMediaPlaylistProvider@@SA?AVQString@@PBD0@Z @ 721 NONAME ; class QString QMediaPlaylistProvider::tr(char const *, char const *) + ?metaObject@QMetaDataWriterControl@@UBEPBUQMetaObject@@XZ @ 722 NONAME ; struct QMetaObject const * QMetaDataWriterControl::metaObject(void) const + ?metaObject@QVideoDeviceControl@@UBEPBUQMetaObject@@XZ @ 723 NONAME ; struct QMetaObject const * QVideoDeviceControl::metaObject(void) const + ?removeMedia@QMediaPlaylist@@QAE_NH@Z @ 724 NONAME ; bool QMediaPlaylist::removeMedia(int) + ??1QMetaDataWriterControl@@UAE@XZ @ 725 NONAME ; QMetaDataWriterControl::~QMetaDataWriterControl(void) + ?trUtf8@QImageEncoderControl@@SA?AVQString@@PBD0@Z @ 726 NONAME ; class QString QImageEncoderControl::trUtf8(char const *, char const *) + ?d_func@QMediaObject@@AAEPAVQMediaObjectPrivate@@XZ @ 727 NONAME ; class QMediaObjectPrivate * QMediaObject::d_func(void) + ?getStaticMetaObject@QVideoWindowControl@@SAABUQMetaObject@@XZ @ 728 NONAME ; struct QMetaObject const & QVideoWindowControl::getStaticMetaObject(void) + ??0QAudioEndpointSelector@@IAE@PAVQObject@@@Z @ 729 NONAME ; QAudioEndpointSelector::QAudioEndpointSelector(class QObject *) + ?mediaStatus@QMediaImageViewer@@QBE?AW4MediaStatus@1@XZ @ 730 NONAME ; enum QMediaImageViewer::MediaStatus QMediaImageViewer::mediaStatus(void) const + ?tr@QVideoWidgetControl@@SA?AVQString@@PBD0@Z @ 731 NONAME ; class QString QVideoWidgetControl::tr(char const *, char const *) + ?trUtf8@QMediaRecorderControl@@SA?AVQString@@PBD0@Z @ 732 NONAME ; class QString QMediaRecorderControl::trUtf8(char const *, char const *) + ?getStaticMetaObject@QAudioOutput@@SAABUQMetaObject@@XZ @ 733 NONAME ; struct QMetaObject const & QAudioOutput::getStaticMetaObject(void) + ?qt_metacall@QMediaPlaylistNavigator@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 734 NONAME ; int QMediaPlaylistNavigator::qt_metacall(enum QMetaObject::Call, int, void * *) + ?metaObject@QMediaPlaylistControl@@UBEPBUQMetaObject@@XZ @ 735 NONAME ; struct QMetaObject const * QMediaPlaylistControl::metaObject(void) const + ?normalized@QMediaTimeInterval@@QBE?AV1@XZ @ 736 NONAME ; class QMediaTimeInterval QMediaTimeInterval::normalized(void) const + ?durationChanged@QMediaPlayerControl@@IAEX_J@Z @ 737 NONAME ; void QMediaPlayerControl::durationChanged(long long) + ?d_func@QImageVideoBuffer@@AAEPAVQImageVideoBufferPrivate@@XZ @ 738 NONAME ; class QImageVideoBufferPrivate * QImageVideoBuffer::d_func(void) + ?stateChanged@QAbstractAudioOutput@@IAEXW4State@QAudio@@@Z @ 739 NONAME ; void QAbstractAudioOutput::stateChanged(enum QAudio::State) + ?trUtf8@QMediaContainerControl@@SA?AVQString@@PBD0H@Z @ 740 NONAME ; class QString QMediaContainerControl::trUtf8(char const *, char const *, int) + ?byteOrder@QAudioFormat@@QBE?AW4Endian@1@XZ @ 741 NONAME ; enum QAudioFormat::Endian QAudioFormat::byteOrder(void) const + ?qt_metacast@QAbstractAudioInput@@UAEPAXPBD@Z @ 742 NONAME ; void * QAbstractAudioInput::qt_metacast(char const *) + ?mediaChanged@QMediaImageViewer@@IAEXABVQMediaContent@@@Z @ 743 NONAME ; void QMediaImageViewer::mediaChanged(class QMediaContent const &) + ?errorString@QRadioTuner@@QBE?AVQString@@XZ @ 744 NONAME ; class QString QRadioTuner::errorString(void) const + ?d_func@QMediaPlaylistNavigator@@ABEPBVQMediaPlaylistNavigatorPrivate@@XZ @ 745 NONAME ; class QMediaPlaylistNavigatorPrivate const * QMediaPlaylistNavigator::d_func(void) const + ?error@QAbstractVideoSurface@@QBE?AW4Error@1@XZ @ 746 NONAME ; enum QAbstractVideoSurface::Error QAbstractVideoSurface::error(void) const + ?contrastChanged@QVideoWidgetControl@@IAEXH@Z @ 747 NONAME ; void QVideoWidgetControl::contrastChanged(int) + ?d_func@QAbstractVideoBuffer@@ABEPBVQAbstractVideoBufferPrivate@@XZ @ 748 NONAME ; class QAbstractVideoBufferPrivate const * QAbstractVideoBuffer::d_func(void) const + ?setScanLineDirection@QVideoSurfaceFormat@@QAEXW4Direction@1@@Z @ 749 NONAME ; void QVideoSurfaceFormat::setScanLineDirection(enum QVideoSurfaceFormat::Direction) + ??0QVideoRendererControl@@IAE@PAVQObject@@@Z @ 750 NONAME ; QVideoRendererControl::QVideoRendererControl(class QObject *) + ?trUtf8@QMediaObject@@SA?AVQString@@PBD0@Z @ 751 NONAME ; class QString QMediaObject::trUtf8(char const *, char const *) + ?tr@QMediaImageViewer@@SA?AVQString@@PBD0H@Z @ 752 NONAME ; class QString QMediaImageViewer::tr(char const *, char const *, int) + ??1QAudioDeviceInfo@@QAE@XZ @ 753 NONAME ; QAudioDeviceInfo::~QAudioDeviceInfo(void) + ?videoSettings@QMediaRecorder@@QBE?AVQVideoEncoderSettings@@XZ @ 754 NONAME ; class QVideoEncoderSettings QMediaRecorder::videoSettings(void) const + ?nearestFormat@QAudioDeviceInfo@@QBE?AVQAudioFormat@@ABV2@@Z @ 755 NONAME ; class QAudioFormat QAudioDeviceInfo::nearestFormat(class QAudioFormat const &) const + ?playbackModeChanged@QMediaPlaylist@@IAEXW4PlaybackMode@1@@Z @ 756 NONAME ; void QMediaPlaylist::playbackModeChanged(enum QMediaPlaylist::PlaybackMode) + ?setMediaObject@QVideoWidget@@MAE_NPAVQMediaObject@@@Z @ 757 NONAME ; bool QVideoWidget::setMediaObject(class QMediaObject *) + ?isFormatSupported@QAudioDeviceInfo@@QBE_NABVQAudioFormat@@@Z @ 758 NONAME ; bool QAudioDeviceInfo::isFormatSupported(class QAudioFormat const &) const + ??1QMediaPlaylistProvider@@UAE@XZ @ 759 NONAME ; QMediaPlaylistProvider::~QMediaPlaylistProvider(void) + ?qt_metacall@QMediaImageViewer@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 760 NONAME ; int QMediaImageViewer::qt_metacall(enum QMetaObject::Call, int, void * *) + ?tr@QMediaPlaylistProvider@@SA?AVQString@@PBD0H@Z @ 761 NONAME ; class QString QMediaPlaylistProvider::tr(char const *, char const *, int) + ?tr@QMediaPlaylistNavigator@@SA?AVQString@@PBD0H@Z @ 762 NONAME ; class QString QMediaPlaylistNavigator::tr(char const *, char const *, int) + ?isNull@QAudioDeviceInfo@@QBE_NXZ @ 763 NONAME ; bool QAudioDeviceInfo::isNull(void) const + ?supportedByteOrders@QAudioDeviceInfo@@QBE?AV?$QList@W4Endian@QAudioFormat@@@@XZ @ 764 NONAME ; class QList QAudioDeviceInfo::supportedByteOrders(void) const + ?showEvent@QVideoWidget@@MAEXPAVQShowEvent@@@Z @ 765 NONAME ; void QVideoWidget::showEvent(class QShowEvent *) + ?codecs@QMediaServiceProviderHint@@QBE?AVQStringList@@XZ @ 766 NONAME ; class QStringList QMediaServiceProviderHint::codecs(void) const + ?error@QMediaPlayer@@QBE?AW4Error@1@XZ @ 767 NONAME ; enum QMediaPlayer::Error QMediaPlayer::error(void) const + ?insertMedia@QLocalMediaPlaylistProvider@@UAE_NHABV?$QList@VQMediaContent@@@@@Z @ 768 NONAME ; bool QLocalMediaPlaylistProvider::insertMedia(int, class QList const &) + ?mediaStream@QMediaPlayer@@QBEPBVQIODevice@@XZ @ 769 NONAME ; class QIODevice const * QMediaPlayer::mediaStream(void) const + ??0QMediaPlaylistProvider@@IAE@AAVQMediaPlaylistProviderPrivate@@PAVQObject@@@Z @ 770 NONAME ; QMediaPlaylistProvider::QMediaPlaylistProvider(class QMediaPlaylistProviderPrivate &, class QObject *) + ?audioInputs@QAudioCaptureSource@@QBE?AV?$QList@VQString@@@@XZ @ 771 NONAME ; class QList QAudioCaptureSource::audioInputs(void) const + ?setResolution@QImageEncoderSettings@@QAEXABVQSize@@@Z @ 772 NONAME ; void QImageEncoderSettings::setResolution(class QSize const &) + ??0QImageEncoderSettings@@QAE@ABV0@@Z @ 773 NONAME ; QImageEncoderSettings::QImageEncoderSettings(class QImageEncoderSettings const &) + ?state@QMediaImageViewer@@QBE?AW4State@1@XZ @ 774 NONAME ; enum QMediaImageViewer::State QMediaImageViewer::state(void) const + ?encodingMode@QVideoEncoderSettings@@QBE?AW4EncodingMode@QtMultimediaKit@@XZ @ 775 NONAME ; enum QtMultimediaKit::EncodingMode QVideoEncoderSettings::encodingMode(void) const + ?errorChanged@QAbstractAudioOutput@@IAEXW4Error@QAudio@@@Z @ 776 NONAME ; void QAbstractAudioOutput::errorChanged(enum QAudio::Error) + ?nearestFormat@QAbstractVideoSurface@@UBE?AVQVideoSurfaceFormat@@ABV2@@Z @ 777 NONAME ; class QVideoSurfaceFormat QAbstractVideoSurface::nearestFormat(class QVideoSurfaceFormat const &) const + ?setPixelAspectRatio@QVideoSurfaceFormat@@QAEXHH@Z @ 778 NONAME ; void QVideoSurfaceFormat::setPixelAspectRatio(int, int) + ?getStaticMetaObject@QAbstractAudioDeviceInfo@@SAABUQMetaObject@@XZ @ 779 NONAME ; struct QMetaObject const & QAbstractAudioDeviceInfo::getStaticMetaObject(void) + ?clear@QMediaPlaylist@@QAE_NXZ @ 780 NONAME ; bool QMediaPlaylist::clear(void) + ?surroundingItemsChanged@QMediaPlaylistNavigator@@IAEXXZ @ 781 NONAME ; void QMediaPlaylistNavigator::surroundingItemsChanged(void) + ?availableDevices@QAudioDeviceInfo@@SA?AV?$QList@VQAudioDeviceInfo@@@@W4Mode@QAudio@@@Z @ 782 NONAME ; class QList QAudioDeviceInfo::availableDevices(enum QAudio::Mode) + ?d_func@QMediaService@@ABEPBVQMediaServicePrivate@@XZ @ 783 NONAME ; class QMediaServicePrivate const * QMediaService::d_func(void) const + ?getStaticMetaObject@QMediaPlaylistProvider@@SAABUQMetaObject@@XZ @ 784 NONAME ; struct QMetaObject const & QMediaPlaylistProvider::getStaticMetaObject(void) + ?availablePlaybackRangesChanged@QMediaPlayerControl@@IAEXABVQMediaTimeRange@@@Z @ 785 NONAME ; void QMediaPlayerControl::availablePlaybackRangesChanged(class QMediaTimeRange const &) + ??1QImageVideoBuffer@@UAE@XZ @ 786 NONAME ; QImageVideoBuffer::~QImageVideoBuffer(void) + ?notifyInterval@QAudioOutput@@QBEHXZ @ 787 NONAME ; int QAudioOutput::notifyInterval(void) const + ??1QAbstractAudioDeviceInfo@@UAE@XZ @ 788 NONAME ; QAbstractAudioDeviceInfo::~QAbstractAudioDeviceInfo(void) + ??1QVideoEncoderSettings@@QAE@XZ @ 789 NONAME ; QVideoEncoderSettings::~QVideoEncoderSettings(void) + ?clear@QLocalMediaPlaylistProvider@@UAE_NXZ @ 790 NONAME ; bool QLocalMediaPlaylistProvider::clear(void) + ?setSampleRate@QMediaResource@@QAEXH@Z @ 791 NONAME ; void QMediaResource::setSampleRate(int) + ?setBand@QRadioTuner@@QAEXW4Band@1@@Z @ 792 NONAME ; void QRadioTuner::setBand(enum QRadioTuner::Band) + ?mediaChanged@QMediaPlayerControl@@IAEXABVQMediaContent@@@Z @ 793 NONAME ; void QMediaPlayerControl::mediaChanged(class QMediaContent const &) + ?removeMedia@QMediaPlaylist@@QAE_NHH@Z @ 794 NONAME ; bool QMediaPlaylist::removeMedia(int, int) + ?setMetaData@QMediaRecorder@@QAEXW4MetaData@QtMultimediaKit@@ABVQVariant@@@Z @ 795 NONAME ; void QMediaRecorder::setMetaData(enum QtMultimediaKit::MetaData, class QVariant const &) + ?d_func@QGraphicsVideoItem@@ABEPBVQGraphicsVideoItemPrivate@@XZ @ 796 NONAME ; class QGraphicsVideoItemPrivate const * QGraphicsVideoItem::d_func(void) const + ?setPlaylist@QMediaImageViewer@@QAEXPAVQMediaPlaylist@@@Z @ 797 NONAME ; void QMediaImageViewer::setPlaylist(class QMediaPlaylist *) + ?itemChange@QGraphicsVideoItem@@MAE?AVQVariant@@W4GraphicsItemChange@QGraphicsItem@@ABV2@@Z @ 798 NONAME ; class QVariant QGraphicsVideoItem::itemChange(enum QGraphicsItem::GraphicsItemChange, class QVariant const &) + ?stateChanged@QRadioTuner@@IAEXW4State@1@@Z @ 799 NONAME ; void QRadioTuner::stateChanged(enum QRadioTuner::State) + ?getStaticMetaObject@QMediaControl@@SAABUQMetaObject@@XZ @ 800 NONAME ; struct QMetaObject const & QMediaControl::getStaticMetaObject(void) + ?qt_metacall@QMediaService@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 801 NONAME ; int QMediaService::qt_metacall(enum QMetaObject::Call, int, void * *) + ?bitRate@QAudioEncoderSettings@@QBEHXZ @ 802 NONAME ; int QAudioEncoderSettings::bitRate(void) const + ?mediaObject@QMediaRecorder@@UBEPAVQMediaObject@@XZ @ 803 NONAME ; class QMediaObject * QMediaRecorder::mediaObject(void) const + ?trUtf8@QMediaStreamsControl@@SA?AVQString@@PBD0@Z @ 804 NONAME ; class QString QMediaStreamsControl::trUtf8(char const *, char const *) + ??0QMediaResource@@QAE@ABV0@@Z @ 805 NONAME ; QMediaResource::QMediaResource(class QMediaResource const &) + ?d_func@QMediaPlaylistNavigator@@AAEPAVQMediaPlaylistNavigatorPrivate@@XZ @ 806 NONAME ; class QMediaPlaylistNavigatorPrivate * QMediaPlaylistNavigator::d_func(void) + ?save@QMediaPlaylistProvider@@UAE_NABVQUrl@@PBD@Z @ 807 NONAME ; bool QMediaPlaylistProvider::save(class QUrl const &, char const *) + ?frequencyRange@QRadioTuner@@QBE?AU?$QPair@HH@@W4Band@1@@Z @ 808 NONAME ; struct QPair QRadioTuner::frequencyRange(enum QRadioTuner::Band) const + ?setResolution@QMediaResource@@QAEXABVQSize@@@Z @ 809 NONAME ; void QMediaResource::setResolution(class QSize const &) + ??1QAudioCaptureSource@@UAE@XZ @ 810 NONAME ; QAudioCaptureSource::~QAudioCaptureSource(void) + ?positionChanged@QMediaPlayer@@IAEX_J@Z @ 811 NONAME ; void QMediaPlayer::positionChanged(long long) + ?qt_metacall@QAbstractAudioOutput@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 812 NONAME ; int QAbstractAudioOutput::qt_metacall(enum QMetaObject::Call, int, void * *) + ??0QAudioOutput@@QAE@ABVQAudioDeviceInfo@@ABVQAudioFormat@@PAVQObject@@@Z @ 813 NONAME ; QAudioOutput::QAudioOutput(class QAudioDeviceInfo const &, class QAudioFormat const &, class QObject *) + ?staticMetaObject@QMediaRecorder@@2UQMetaObject@@B @ 814 NONAME ; struct QMetaObject const QMediaRecorder::staticMetaObject + ?setMuted@QRadioTuner@@QAEX_N@Z @ 815 NONAME ; void QRadioTuner::setMuted(bool) + ?getStaticMetaObject@QMediaRecorder@@SAABUQMetaObject@@XZ @ 816 NONAME ; struct QMetaObject const & QMediaRecorder::getStaticMetaObject(void) + ?streamsChanged@QMediaStreamsControl@@IAEXXZ @ 817 NONAME ; void QMediaStreamsControl::streamsChanged(void) + ??0QMediaServiceProviderHint@@QAE@V?$QFlags@W4Feature@QMediaServiceProviderHint@@@@@Z @ 818 NONAME ; QMediaServiceProviderHint::QMediaServiceProviderHint(class QFlags) + ?mediaStatusChanged@QMediaPlayer@@IAEXW4MediaStatus@1@@Z @ 819 NONAME ; void QMediaPlayer::mediaStatusChanged(enum QMediaPlayer::MediaStatus) + ?trUtf8@QMediaPlaylistIOPlugin@@SA?AVQString@@PBD0H@Z @ 820 NONAME ; class QString QMediaPlaylistIOPlugin::trUtf8(char const *, char const *, int) + ?tr@QVideoWidget@@SA?AVQString@@PBD0H@Z @ 821 NONAME ; class QString QVideoWidget::tr(char const *, char const *, int) + ?nextIndex@QMediaPlaylist@@QBEHH@Z @ 822 NONAME ; int QMediaPlaylist::nextIndex(int) const + ??0QMediaService@@IAE@PAVQObject@@@Z @ 823 NONAME ; QMediaService::QMediaService(class QObject *) + ?qt_metacall@QMediaPlayer@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 824 NONAME ; int QMediaPlayer::qt_metacall(enum QMetaObject::Call, int, void * *) + ??4QAudioEncoderSettings@@QAEAAV0@ABV0@@Z @ 825 NONAME ; class QAudioEncoderSettings & QAudioEncoderSettings::operator=(class QAudioEncoderSettings const &) + ?staticMetaObject@QAbstractVideoSurface@@2UQMetaObject@@B @ 826 NONAME ; struct QMetaObject const QAbstractVideoSurface::staticMetaObject + ?trUtf8@QAbstractVideoSurface@@SA?AVQString@@PBD0@Z @ 827 NONAME ; class QString QAbstractVideoSurface::trUtf8(char const *, char const *) + ??_EQMediaStreamsControl@@UAE@I@Z @ 828 NONAME ; QMediaStreamsControl::~QMediaStreamsControl(unsigned int) + ?playbackModeChanged@QMediaPlaylistNavigator@@IAEXW4PlaybackMode@QMediaPlaylist@@@Z @ 829 NONAME ; void QMediaPlaylistNavigator::playbackModeChanged(enum QMediaPlaylist::PlaybackMode) + ?staticMetaObject@QAudioCaptureSource@@2UQMetaObject@@B @ 830 NONAME ; struct QMetaObject const QAudioCaptureSource::staticMetaObject + ?staticMetaObject@QMediaContainerControl@@2UQMetaObject@@B @ 831 NONAME ; struct QMetaObject const QMediaContainerControl::staticMetaObject + ?trUtf8@QAbstractAudioOutput@@SA?AVQString@@PBD0@Z @ 832 NONAME ; class QString QAbstractAudioOutput::trUtf8(char const *, char const *) + ?sourceChanged@QSoundEffect@@IAEXXZ @ 833 NONAME ; void QSoundEffect::sourceChanged(void) + ??9@YA_NABVQMediaTimeRange@@0@Z @ 834 NONAME ; bool operator!=(class QMediaTimeRange const &, class QMediaTimeRange const &) + ?availableAudioInputsChanged@QAudioCaptureSource@@IAEXXZ @ 835 NONAME ; void QAudioCaptureSource::availableAudioInputsChanged(void) + ??_EQAbstractAudioDeviceInfo@@UAE@I@Z @ 836 NONAME ; QAbstractAudioDeviceInfo::~QAbstractAudioDeviceInfo(unsigned int) + ?load@QMediaPlaylist@@QAEXPAVQIODevice@@PBD@Z @ 837 NONAME ; void QMediaPlaylist::load(class QIODevice *, char const *) + ?currentMediaChanged@QMediaPlaylistControl@@IAEXABVQMediaContent@@@Z @ 838 NONAME ; void QMediaPlaylistControl::currentMediaChanged(class QMediaContent const &) + ?setSampleSize@QAudioFormat@@QAEXH@Z @ 839 NONAME ; void QAudioFormat::setSampleSize(int) + ?isReadOnly@QMediaPlaylist@@QBE_NXZ @ 840 NONAME ; bool QMediaPlaylist::isReadOnly(void) const + ?supportedFrameRates@QMediaRecorder@@QBE?AV?$QList@M@@ABVQVideoEncoderSettings@@PA_N@Z @ 841 NONAME ; class QList QMediaRecorder::supportedFrameRates(class QVideoEncoderSettings const &, bool *) const + ?mediaObject@QMediaPlaylist@@UBEPAVQMediaObject@@XZ @ 842 NONAME ; class QMediaObject * QMediaPlaylist::mediaObject(void) const + ?start@QRadioTuner@@QAEXXZ @ 843 NONAME ; void QRadioTuner::start(void) + ?play@QMediaPlayer@@QAEXXZ @ 844 NONAME ; void QMediaPlayer::play(void) + ??1QAudioEndpointSelector@@UAE@XZ @ 845 NONAME ; QAudioEndpointSelector::~QAudioEndpointSelector(void) + ?mode@QAudioDeviceInfo@@ABE?AW4Mode@QAudio@@XZ @ 846 NONAME ; enum QAudio::Mode QAudioDeviceInfo::mode(void) const + ?trUtf8@QVideoWidget@@SA?AVQString@@PBD0@Z @ 847 NONAME ; class QString QVideoWidget::trUtf8(char const *, char const *) + ?trUtf8@QAbstractAudioDeviceInfo@@SA?AVQString@@PBD0H@Z @ 848 NONAME ; class QString QAbstractAudioDeviceInfo::trUtf8(char const *, char const *, int) + ?stereoStatusChanged@QRadioTunerControl@@IAEX_N@Z @ 849 NONAME ; void QRadioTunerControl::stereoStatusChanged(bool) + ??4QMediaResource@@QAEAAV0@ABV0@@Z @ 850 NONAME ; class QMediaResource & QMediaResource::operator=(class QMediaResource const &) + ?d_func@QImageVideoBuffer@@ABEPBVQImageVideoBufferPrivate@@XZ @ 851 NONAME ; class QImageVideoBufferPrivate const * QImageVideoBuffer::d_func(void) const + ?qt_metacast@QAudioCaptureSource@@UAEPAXPBD@Z @ 852 NONAME ; void * QAudioCaptureSource::qt_metacast(char const *) + ?metaObject@QVideoWidget@@UBEPBUQMetaObject@@XZ @ 853 NONAME ; struct QMetaObject const * QVideoWidget::metaObject(void) const + ?defaultAudioInput@QAudioCaptureSource@@QBE?AVQString@@XZ @ 854 NONAME ; class QString QAudioCaptureSource::defaultAudioInput(void) const + ??0QAbstractVideoSurface@@QAE@PAVQObject@@@Z @ 855 NONAME ; QAbstractVideoSurface::QAbstractVideoSurface(class QObject *) + ?trUtf8@QImageEncoderControl@@SA?AVQString@@PBD0H@Z @ 856 NONAME ; class QString QImageEncoderControl::trUtf8(char const *, char const *, int) + ??1QMediaPlaylistWriter@@UAE@XZ @ 857 NONAME ; QMediaPlaylistWriter::~QMediaPlaylistWriter(void) + ?position@QMediaPlayer@@QBE_JXZ @ 858 NONAME ; long long QMediaPlayer::position(void) const + ?staticMetaObject@QAudioSystemPlugin@@2UQMetaObject@@B @ 859 NONAME ; struct QMetaObject const QAudioSystemPlugin::staticMetaObject + ??_EQMediaPlaylistIOInterface@@UAE@I@Z @ 860 NONAME ; QMediaPlaylistIOInterface::~QMediaPlaylistIOInterface(unsigned int) + ??_EQVideoWidget@@UAE@I@Z @ 861 NONAME ; QVideoWidget::~QVideoWidget(unsigned int) + ?contains@QMediaTimeInterval@@QBE_N_J@Z @ 862 NONAME ; bool QMediaTimeInterval::contains(long long) const + ?errorChanged@QAbstractAudioInput@@IAEXW4Error@QAudio@@@Z @ 863 NONAME ; void QAbstractAudioInput::errorChanged(enum QAudio::Error) + ??_EQMediaServiceSupportedDevicesInterface@@UAE@I@Z @ 864 NONAME ; QMediaServiceSupportedDevicesInterface::~QMediaServiceSupportedDevicesInterface(unsigned int) + ?brightnessChanged@QVideoWidget@@IAEXH@Z @ 865 NONAME ; void QVideoWidget::brightnessChanged(int) + ??_EQMediaPlaylistProvider@@UAE@I@Z @ 866 NONAME ; QMediaPlaylistProvider::~QMediaPlaylistProvider(unsigned int) + ?setResolution@QVideoEncoderSettings@@QAEXHH@Z @ 867 NONAME ; void QVideoEncoderSettings::setResolution(int, int) + ?trUtf8@QMediaControl@@SA?AVQString@@PBD0@Z @ 868 NONAME ; class QString QMediaControl::trUtf8(char const *, char const *) + ?supportedSampleRates@QAudioDeviceInfo@@QBE?AV?$QList@H@@XZ @ 869 NONAME ; class QList QAudioDeviceInfo::supportedSampleRates(void) const + ??_EQMediaObject@@UAE@I@Z @ 870 NONAME ; QMediaObject::~QMediaObject(unsigned int) + ?trUtf8@QSoundEffect@@SA?AVQString@@PBD0@Z @ 871 NONAME ; class QString QSoundEffect::trUtf8(char const *, char const *) + ?qt_metacast@QGraphicsVideoItem@@UAEPAXPBD@Z @ 872 NONAME ; void * QGraphicsVideoItem::qt_metacast(char const *) + ??0QVideoFrame@@QAE@ABV0@@Z @ 873 NONAME ; QVideoFrame::QVideoFrame(class QVideoFrame const &) + ?tr@QRadioTuner@@SA?AVQString@@PBD0H@Z @ 874 NONAME ; class QString QRadioTuner::tr(char const *, char const *, int) + ?notifyIntervalChanged@QMediaObject@@IAEXH@Z @ 875 NONAME ; void QMediaObject::notifyIntervalChanged(int) + ?setMedia@QMediaImageViewer@@QAEXABVQMediaContent@@@Z @ 876 NONAME ; void QMediaImageViewer::setMedia(class QMediaContent const &) + ?tr@QMediaStreamsControl@@SA?AVQString@@PBD0H@Z @ 877 NONAME ; class QString QMediaStreamsControl::tr(char const *, char const *, int) + ?tr@QAudioOutput@@SA?AVQString@@PBD0H@Z @ 878 NONAME ; class QString QAudioOutput::tr(char const *, char const *, int) + ??YQMediaTimeRange@@QAEAAV0@ABV0@@Z @ 879 NONAME ; class QMediaTimeRange & QMediaTimeRange::operator+=(class QMediaTimeRange const &) + ?hasSupport@QMediaPlayer@@SA?AW4SupportEstimate@QtMultimediaKit@@ABVQString@@ABVQStringList@@V?$QFlags@W4Flag@QMediaPlayer@@@@@Z @ 880 NONAME ; enum QtMultimediaKit::SupportEstimate QMediaPlayer::hasSupport(class QString const &, class QStringList const &, class QFlags) + ?qt_metacast@QAudioSystemPlugin@@UAEPAXPBD@Z @ 881 NONAME ; void * QAudioSystemPlugin::qt_metacast(char const *) + ?setVideoOutput@QMediaPlayer@@QAEXPAVQVideoWidget@@@Z @ 882 NONAME ; void QMediaPlayer::setVideoOutput(class QVideoWidget *) + ?mutedChanged@QMediaRecorderControl@@IAEX_N@Z @ 883 NONAME ; void QMediaRecorderControl::mutedChanged(bool) + ??1QMediaPlaylistIOInterface@@UAE@XZ @ 884 NONAME ; QMediaPlaylistIOInterface::~QMediaPlaylistIOInterface(void) + ?map@QVideoFrame@@QAE_NW4MapMode@QAbstractVideoBuffer@@@Z @ 885 NONAME ; bool QVideoFrame::map(enum QAbstractVideoBuffer::MapMode) + ?periodSize@QAudioInput@@QBEHXZ @ 886 NONAME ; int QAudioInput::periodSize(void) const + ?handle@QAudioDeviceInfo@@ABE?AVQByteArray@@XZ @ 887 NONAME ; class QByteArray QAudioDeviceInfo::handle(void) const + ?isMetaDataWritable@QMediaRecorder@@QBE_NXZ @ 888 NONAME ; bool QMediaRecorder::isMetaDataWritable(void) const + ?qt_metacall@QMediaPlaylistSourceControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 889 NONAME ; int QMediaPlaylistSourceControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ??0QMediaPlayer@@QAE@PAVQObject@@V?$QFlags@W4Flag@QMediaPlayer@@@@PAVQMediaServiceProvider@@@Z @ 890 NONAME ; QMediaPlayer::QMediaPlayer(class QObject *, class QFlags, class QMediaServiceProvider *) + ?mediaRemoved@QMediaPlaylistProvider@@IAEXHH@Z @ 891 NONAME ; void QMediaPlaylistProvider::mediaRemoved(int, int) + ?quality@QAudioEncoderSettings@@QBE?AW4EncodingQuality@QtMultimediaKit@@XZ @ 892 NONAME ; enum QtMultimediaKit::EncodingQuality QAudioEncoderSettings::quality(void) const + ?handleType@QAbstractVideoBuffer@@QBE?AW4HandleType@1@XZ @ 893 NONAME ; enum QAbstractVideoBuffer::HandleType QAbstractVideoBuffer::handleType(void) const + ?audioBitRate@QMediaResource@@QBEHXZ @ 894 NONAME ; int QMediaResource::audioBitRate(void) const + ?qt_metacast@QMetaDataWriterControl@@UAEPAXPBD@Z @ 895 NONAME ; void * QMetaDataWriterControl::qt_metacast(char const *) + ?trUtf8@QMediaRecorder@@SA?AVQString@@PBD0H@Z @ 896 NONAME ; class QString QMediaRecorder::trUtf8(char const *, char const *, int) + ??0QSoundEffect@@QAE@PAVQObject@@@Z @ 897 NONAME ; QSoundEffect::QSoundEffect(class QObject *) + ?bufferStatus@QMediaPlayer@@QBEHXZ @ 898 NONAME ; int QMediaPlayer::bufferStatus(void) const + ??0QAudioDeviceInfo@@AAE@ABVQString@@ABVQByteArray@@W4Mode@QAudio@@@Z @ 899 NONAME ; QAudioDeviceInfo::QAudioDeviceInfo(class QString const &, class QByteArray const &, enum QAudio::Mode) + ?metaObject@QAudioOutput@@UBEPBUQMetaObject@@XZ @ 900 NONAME ; struct QMetaObject const * QAudioOutput::metaObject(void) const + ??0QMediaTimeRange@@QAE@_J0@Z @ 901 NONAME ; QMediaTimeRange::QMediaTimeRange(long long, long long) + ?mediaAboutToBeInserted@QMediaPlaylistProvider@@IAEXHH@Z @ 902 NONAME ; void QMediaPlaylistProvider::mediaAboutToBeInserted(int, int) + ?setAspectRatioMode@QVideoWidget@@QAEXW4AspectRatioMode@Qt@@@Z @ 903 NONAME ; void QVideoWidget::setAspectRatioMode(enum Qt::AspectRatioMode) + ?qt_metacall@QVideoWindowControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 904 NONAME ; int QVideoWindowControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ?codec@QAudioFormat@@QBE?AVQString@@XZ @ 905 NONAME ; class QString QAudioFormat::codec(void) const + ??0QMemoryVideoBuffer@@QAE@ABVQByteArray@@H@Z @ 906 NONAME ; QMemoryVideoBuffer::QMemoryVideoBuffer(class QByteArray const &, int) + ?currentIndexChanged@QMediaPlaylistNavigator@@IAEXH@Z @ 907 NONAME ; void QMediaPlaylistNavigator::currentIndexChanged(int) + ?qt_metacall@QVideoRendererControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 908 NONAME ; int QVideoRendererControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ?setResolution@QVideoEncoderSettings@@QAEXABVQSize@@@Z @ 909 NONAME ; void QVideoEncoderSettings::setResolution(class QSize const &) + ??0QImageEncoderSettings@@QAE@XZ @ 910 NONAME ; QImageEncoderSettings::QImageEncoderSettings(void) + ?d_func@QMediaPlaylistProvider@@ABEPBVQMediaPlaylistProviderPrivate@@XZ @ 911 NONAME ; class QMediaPlaylistProviderPrivate const * QMediaPlaylistProvider::d_func(void) const + ??0QMediaTimeRange@@QAE@XZ @ 912 NONAME ; QMediaTimeRange::QMediaTimeRange(void) + ?shuffle@QMediaPlaylistProvider@@UAEXXZ @ 913 NONAME ; void QMediaPlaylistProvider::shuffle(void) + ?reset@QAudioInput@@QAEXXZ @ 914 NONAME ; void QAudioInput::reset(void) + ?trUtf8@QMetaDataWriterControl@@SA?AVQString@@PBD0@Z @ 915 NONAME ; class QString QMetaDataWriterControl::trUtf8(char const *, char const *) + ??_EQImageVideoBuffer@@UAE@I@Z @ 916 NONAME ; QImageVideoBuffer::~QImageVideoBuffer(unsigned int) + ?staticMetaObject@QAudioEndpointSelector@@2UQMetaObject@@B @ 917 NONAME ; struct QMetaObject const QAudioEndpointSelector::staticMetaObject + ??1QMediaPlayerControl@@UAE@XZ @ 918 NONAME ; QMediaPlayerControl::~QMediaPlayerControl(void) + ?d_func@QMediaControl@@AAEPAVQMediaControlPrivate@@XZ @ 919 NONAME ; class QMediaControlPrivate * QMediaControl::d_func(void) + ?metaDataAvailableChanged@QMetaDataWriterControl@@IAEX_N@Z @ 920 NONAME ; void QMetaDataWriterControl::metaDataAvailableChanged(bool) + ?notify@QAudioOutput@@IAEXXZ @ 921 NONAME ; void QAudioOutput::notify(void) + ?tr@QLocalMediaPlaylistProvider@@SA?AVQString@@PBD0H@Z @ 922 NONAME ; class QString QLocalMediaPlaylistProvider::tr(char const *, char const *, int) + ?removeMedia@QLocalMediaPlaylistProvider@@UAE_NHH@Z @ 923 NONAME ; bool QLocalMediaPlaylistProvider::removeMedia(int, int) + ?trUtf8@QMediaServiceProvider@@SA?AVQString@@PBD0H@Z @ 924 NONAME ; class QString QMediaServiceProvider::trUtf8(char const *, char const *, int) + ?isMuted@QMediaPlayer@@QBE_NXZ @ 925 NONAME ; bool QMediaPlayer::isMuted(void) const + ?tr@QMediaPlaylistSourceControl@@SA?AVQString@@PBD0H@Z @ 926 NONAME ; class QString QMediaPlaylistSourceControl::tr(char const *, char const *, int) + ?metaObject@QAudioEndpointSelector@@UBEPBUQMetaObject@@XZ @ 927 NONAME ; struct QMetaObject const * QAudioEndpointSelector::metaObject(void) const + ??0QAudioInput@@QAE@ABVQAudioFormat@@PAVQObject@@@Z @ 928 NONAME ; QAudioInput::QAudioInput(class QAudioFormat const &, class QObject *) + ??9QMediaResource@@QBE_NABV0@@Z @ 929 NONAME ; bool QMediaResource::operator!=(class QMediaResource const &) const + ??0QMediaStreamsControl@@IAE@PAVQObject@@@Z @ 930 NONAME ; QMediaStreamsControl::QMediaStreamsControl(class QObject *) + ?url@QMediaResource@@QBE?AVQUrl@@XZ @ 931 NONAME ; class QUrl QMediaResource::url(void) const + ??ZQMediaTimeRange@@QAEAAV0@ABVQMediaTimeInterval@@@Z @ 932 NONAME ; class QMediaTimeRange & QMediaTimeRange::operator-=(class QMediaTimeInterval const &) + ?canonicalUrl@QMediaContent@@QBE?AVQUrl@@XZ @ 933 NONAME ; class QUrl QMediaContent::canonicalUrl(void) const + ?tr@QVideoWidgetControl@@SA?AVQString@@PBD0H@Z @ 934 NONAME ; class QString QVideoWidgetControl::tr(char const *, char const *, int) + ?d_func@QLocalMediaPlaylistProvider@@ABEPBVQLocalMediaPlaylistProviderPrivate@@XZ @ 935 NONAME ; class QLocalMediaPlaylistProviderPrivate const * QLocalMediaPlaylistProvider::d_func(void) const + ?quality@QImageEncoderSettings@@QBE?AW4EncodingQuality@QtMultimediaKit@@XZ @ 936 NONAME ; enum QtMultimediaKit::EncodingQuality QImageEncoderSettings::quality(void) const + ?timeout@QMediaImageViewer@@QBEHXZ @ 937 NONAME ; int QMediaImageViewer::timeout(void) const + ?trUtf8@QMediaPlaylistControl@@SA?AVQString@@PBD0@Z @ 938 NONAME ; class QString QMediaPlaylistControl::trUtf8(char const *, char const *) + ?d_func@QVideoWidget@@AAEPAVQVideoWidgetPrivate@@XZ @ 939 NONAME ; class QVideoWidgetPrivate * QVideoWidget::d_func(void) + ?playbackMode@QMediaPlaylistNavigator@@QBE?AW4PlaybackMode@QMediaPlaylist@@XZ @ 940 NONAME ; enum QMediaPlaylist::PlaybackMode QMediaPlaylistNavigator::playbackMode(void) const + ?qt_metacast@QMediaPlaylist@@UAEPAXPBD@Z @ 941 NONAME ; void * QMediaPlaylist::qt_metacast(char const *) + ?elapsedUSecs@QAudioInput@@QBE_JXZ @ 942 NONAME ; long long QAudioInput::elapsedUSecs(void) const + ?frameWidth@QVideoSurfaceFormat@@QBEHXZ @ 943 NONAME ; int QVideoSurfaceFormat::frameWidth(void) const + ?resume@QAudioOutput@@QAEXXZ @ 944 NONAME ; void QAudioOutput::resume(void) + ?d_func@QMediaImageViewer@@AAEPAVQMediaImageViewerPrivate@@XZ @ 945 NONAME ; class QMediaImageViewerPrivate * QMediaImageViewer::d_func(void) + ??_EQVideoWindowControl@@UAE@I@Z @ 946 NONAME ; QVideoWindowControl::~QVideoWindowControl(unsigned int) + ?error@QRadioTuner@@IAEXW4Error@1@@Z @ 947 NONAME ; void QRadioTuner::error(enum QRadioTuner::Error) + ??_EQAudioEndpointSelector@@UAE@I@Z @ 948 NONAME ; QAudioEndpointSelector::~QAudioEndpointSelector(unsigned int) + ?isAvailable@QMediaRecorder@@QBE_NXZ @ 949 NONAME ; bool QMediaRecorder::isAvailable(void) const + ?staticMetaObject@QMediaService@@2UQMetaObject@@B @ 950 NONAME ; struct QMetaObject const QMediaService::staticMetaObject + ?d_func@QAbstractVideoSurface@@ABEPBVQAbstractVideoSurfacePrivate@@XZ @ 951 NONAME ; class QAbstractVideoSurfacePrivate const * QAbstractVideoSurface::d_func(void) const + ?d_func@QAudioCaptureSource@@AAEPAVQAudioCaptureSourcePrivate@@XZ @ 952 NONAME ; class QAudioCaptureSourcePrivate * QAudioCaptureSource::d_func(void) + ?tr@QAudioEncoderControl@@SA?AVQString@@PBD0H@Z @ 953 NONAME ; class QString QAudioEncoderControl::tr(char const *, char const *, int) + ?addInterval@QMediaTimeRange@@QAEXABVQMediaTimeInterval@@@Z @ 954 NONAME ; void QMediaTimeRange::addInterval(class QMediaTimeInterval const &) + ??_EQMediaPlaylistSourceControl@@UAE@I@Z @ 955 NONAME ; QMediaPlaylistSourceControl::~QMediaPlaylistSourceControl(unsigned int) + ??4QVideoFrame@@QAEAAV0@ABV0@@Z @ 956 NONAME ; class QVideoFrame & QVideoFrame::operator=(class QVideoFrame const &) + ?trUtf8@QMediaRecorderControl@@SA?AVQString@@PBD0H@Z @ 957 NONAME ; class QString QMediaRecorderControl::trUtf8(char const *, char const *, int) + ?nextItem@QMediaPlaylistNavigator@@QBE?AVQMediaContent@@H@Z @ 958 NONAME ; class QMediaContent QMediaPlaylistNavigator::nextItem(int) const + ?clear@QMediaPlaylistProvider@@UAE_NXZ @ 959 NONAME ; bool QMediaPlaylistProvider::clear(void) + ?isNull@QImageEncoderSettings@@QBE_NXZ @ 960 NONAME ; bool QImageEncoderSettings::isNull(void) const + ?saturationChanged@QVideoWidget@@IAEXH@Z @ 961 NONAME ; void QVideoWidget::saturationChanged(int) + ??4QMediaTimeRange@@QAEAAV0@ABVQMediaTimeInterval@@@Z @ 962 NONAME ; class QMediaTimeRange & QMediaTimeRange::operator=(class QMediaTimeInterval const &) + ?qt_metacast@QVideoWindowControl@@UAEPAXPBD@Z @ 963 NONAME ; void * QVideoWindowControl::qt_metacast(char const *) + ?metaObject@QAudioInput@@UBEPBUQMetaObject@@XZ @ 964 NONAME ; struct QMetaObject const * QAudioInput::metaObject(void) const + ?nativeSizeChanged@QVideoWindowControl@@IAEXXZ @ 965 NONAME ; void QVideoWindowControl::nativeSizeChanged(void) + ?sampleRate@QAudioEncoderSettings@@QBEHXZ @ 966 NONAME ; int QAudioEncoderSettings::sampleRate(void) const + ?stateChanged@QAudioInput@@IAEXW4State@QAudio@@@Z @ 967 NONAME ; void QAudioInput::stateChanged(enum QAudio::State) + ?tr@QVideoWindowControl@@SA?AVQString@@PBD0H@Z @ 968 NONAME ; class QString QVideoWindowControl::tr(char const *, char const *, int) + ??1QAbstractAudioOutput@@UAE@XZ @ 969 NONAME ; QAbstractAudioOutput::~QAbstractAudioOutput(void) + ?signalStrengthChanged@QRadioTunerControl@@IAEXH@Z @ 970 NONAME ; void QRadioTunerControl::signalStrengthChanged(int) + ?jump@QMediaPlaylistNavigator@@QAEXH@Z @ 971 NONAME ; void QMediaPlaylistNavigator::jump(int) + ?preferredFormat@QAudioDeviceInfo@@QBE?AVQAudioFormat@@XZ @ 972 NONAME ; class QAudioFormat QAudioDeviceInfo::preferredFormat(void) const + ?format@QAudioInput@@QBE?AVQAudioFormat@@XZ @ 973 NONAME ; class QAudioFormat QAudioInput::format(void) const + ??8QMediaServiceProviderHint@@QBE_NABV0@@Z @ 974 NONAME ; bool QMediaServiceProviderHint::operator==(class QMediaServiceProviderHint const &) const + ?qt_metacall@QMediaPlaylistIOPlugin@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 975 NONAME ; int QMediaPlaylistIOPlugin::qt_metacall(enum QMetaObject::Call, int, void * *) + ??9QAudioFormat@@QBE_NABV0@@Z @ 976 NONAME ; bool QAudioFormat::operator!=(class QAudioFormat const &) const + ?qt_metacast@QAudioEndpointSelector@@UAEPAXPBD@Z @ 977 NONAME ; void * QAudioEndpointSelector::qt_metacast(char const *) + ??0QMediaContent@@QAE@ABVQNetworkRequest@@@Z @ 978 NONAME ; QMediaContent::QMediaContent(class QNetworkRequest const &) + ?availabilityError@QAudioCaptureSource@@UBE?AW4AvailabilityError@QtMultimediaKit@@XZ @ 979 NONAME ; enum QtMultimediaKit::AvailabilityError QAudioCaptureSource::availabilityError(void) const + ?staticMetaObject@QAudioInput@@2UQMetaObject@@B @ 980 NONAME ; struct QMetaObject const QAudioInput::staticMetaObject + ??8QAudioFormat@@QBE_NABV0@@Z @ 981 NONAME ; bool QAudioFormat::operator==(class QAudioFormat const &) const + ?width@QVideoFrame@@QBEHXZ @ 982 NONAME ; int QVideoFrame::width(void) const + ?durationChanged@QMediaPlayer@@IAEX_J@Z @ 983 NONAME ; void QMediaPlayer::durationChanged(long long) + ?qt_metacall@QSoundEffect@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 984 NONAME ; int QSoundEffect::qt_metacall(enum QMetaObject::Call, int, void * *) + ?setVolume@QSoundEffect@@QAEXM@Z @ 985 NONAME ; void QSoundEffect::setVolume(float) + ?setCurrentIndex@QMediaPlaylist@@QAEXH@Z @ 986 NONAME ; void QMediaPlaylist::setCurrentIndex(int) + ?size@QGraphicsVideoItem@@QBE?AVQSizeF@@XZ @ 987 NONAME ; class QSizeF QGraphicsVideoItem::size(void) const + ??4QAudioDeviceInfo@@QAEAAV0@ABV0@@Z @ 988 NONAME ; class QAudioDeviceInfo & QAudioDeviceInfo::operator=(class QAudioDeviceInfo const &) + ?signalStrengthChanged@QRadioTuner@@IAEXH@Z @ 989 NONAME ; void QRadioTuner::signalStrengthChanged(int) + ?selectedDeviceChanged@QVideoDeviceControl@@IAEXH@Z @ 990 NONAME ; void QVideoDeviceControl::selectedDeviceChanged(int) + ?metaObject@QImageEncoderControl@@UBEPBUQMetaObject@@XZ @ 991 NONAME ; struct QMetaObject const * QImageEncoderControl::metaObject(void) const + ?state@QAudioOutput@@QBE?AW4State@QAudio@@XZ @ 992 NONAME ; enum QAudio::State QAudioOutput::state(void) const + ?extendedMetaData@QMediaRecorder@@QBE?AVQVariant@@ABVQString@@@Z @ 993 NONAME ; class QVariant QMediaRecorder::extendedMetaData(class QString const &) const + ?mutedChanged@QRadioTunerControl@@IAEX_N@Z @ 994 NONAME ; void QRadioTunerControl::mutedChanged(bool) + ?staticMetaObject@QMediaImageViewer@@2UQMetaObject@@B @ 995 NONAME ; struct QMetaObject const QMediaImageViewer::staticMetaObject + ?paint@QGraphicsVideoItem@@UAEXPAVQPainter@@PBVQStyleOptionGraphicsItem@@PAVQWidget@@@Z @ 996 NONAME ; void QGraphicsVideoItem::paint(class QPainter *, class QStyleOptionGraphicsItem const *, class QWidget *) + ??6@YA?AVQDebug@@V0@ABVQVideoSurfaceFormat@@@Z @ 997 NONAME ; class QDebug operator<<(class QDebug, class QVideoSurfaceFormat const &) + ?start@QAudioOutput@@QAEXPAVQIODevice@@@Z @ 998 NONAME ; void QAudioOutput::start(class QIODevice *) + ?tr@QMediaPlayerControl@@SA?AVQString@@PBD0H@Z @ 999 NONAME ; class QString QMediaPlayerControl::tr(char const *, char const *, int) + ??_EQAbstractVideoSurface@@UAE@I@Z @ 1000 NONAME ; QAbstractVideoSurface::~QAbstractVideoSurface(unsigned int) + ?mediaStatusChanged@QMediaImageViewer@@IAEXW4MediaStatus@1@@Z @ 1001 NONAME ; void QMediaImageViewer::mediaStatusChanged(enum QMediaImageViewer::MediaStatus) + ?setVideoCodec@QMediaResource@@QAEXABVQString@@@Z @ 1002 NONAME ; void QMediaResource::setVideoCodec(class QString const &) + ?brightnessChanged@QVideoWidgetControl@@IAEXH@Z @ 1003 NONAME ; void QVideoWidgetControl::brightnessChanged(int) + ?staticMetaObject@QVideoRendererControl@@2UQMetaObject@@B @ 1004 NONAME ; struct QMetaObject const QVideoRendererControl::staticMetaObject + ??0QMediaPlaylist@@QAE@PAVQObject@@@Z @ 1005 NONAME ; QMediaPlaylist::QMediaPlaylist(class QObject *) + ??4QVideoSurfaceFormat@@QAEAAV0@ABV0@@Z @ 1006 NONAME ; class QVideoSurfaceFormat & QVideoSurfaceFormat::operator=(class QVideoSurfaceFormat const &) + ?qt_metacall@QLocalMediaPlaylistProvider@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1007 NONAME ; int QLocalMediaPlaylistProvider::qt_metacall(enum QMetaObject::Call, int, void * *) + ?getStaticMetaObject@QVideoRendererControl@@SAABUQMetaObject@@XZ @ 1008 NONAME ; struct QMetaObject const & QVideoRendererControl::getStaticMetaObject(void) + ?metaObject@QMediaContainerControl@@UBEPBUQMetaObject@@XZ @ 1009 NONAME ; struct QMetaObject const * QMediaContainerControl::metaObject(void) const + ??9QVideoSurfaceFormat@@QBE_NABV0@@Z @ 1010 NONAME ; bool QVideoSurfaceFormat::operator!=(class QVideoSurfaceFormat const &) const + ??_EQSoundEffect@@UAE@I@Z @ 1011 NONAME ; QSoundEffect::~QSoundEffect(unsigned int) + ??_EQMemoryVideoBuffer@@UAE@I@Z @ 1012 NONAME ; QMemoryVideoBuffer::~QMemoryVideoBuffer(unsigned int) + ??1QMediaPlaylistIOPlugin@@UAE@XZ @ 1013 NONAME ; QMediaPlaylistIOPlugin::~QMediaPlaylistIOPlugin(void) + ?quality@QVideoEncoderSettings@@QBE?AW4EncodingQuality@QtMultimediaKit@@XZ @ 1014 NONAME ; enum QtMultimediaKit::EncodingQuality QVideoEncoderSettings::quality(void) const + ?playbackRateChanged@QMediaPlayerControl@@IAEXM@Z @ 1015 NONAME ; void QMediaPlayerControl::playbackRateChanged(float) + ??0QVideoEncoderSettings@@QAE@XZ @ 1016 NONAME ; QVideoEncoderSettings::QVideoEncoderSettings(void) + ?staticMetaObject@QMediaPlayerControl@@2UQMetaObject@@B @ 1017 NONAME ; struct QMetaObject const QMediaPlayerControl::staticMetaObject + ?trUtf8@QVideoDeviceControl@@SA?AVQString@@PBD0@Z @ 1018 NONAME ; class QString QVideoDeviceControl::trUtf8(char const *, char const *) + ??0QMediaControl@@IAE@PAVQObject@@@Z @ 1019 NONAME ; QMediaControl::QMediaControl(class QObject *) + ?currentItem@QMediaPlaylistNavigator@@QBE?AVQMediaContent@@XZ @ 1020 NONAME ; class QMediaContent QMediaPlaylistNavigator::currentItem(void) const + ?mediaAboutToBeRemoved@QMediaPlaylistProvider@@IAEXHH@Z @ 1021 NONAME ; void QMediaPlaylistProvider::mediaAboutToBeRemoved(int, int) + ?tr@QVideoRendererControl@@SA?AVQString@@PBD0@Z @ 1022 NONAME ; class QString QVideoRendererControl::tr(char const *, char const *) + ?boundingRect@QGraphicsVideoItem@@UBE?AVQRectF@@XZ @ 1023 NONAME ; class QRectF QGraphicsVideoItem::boundingRect(void) const + ?qt_metacast@QAudioEncoderControl@@UAEPAXPBD@Z @ 1024 NONAME ; void * QAudioEncoderControl::qt_metacast(char const *) + ?property@QVideoSurfaceFormat@@QBE?AVQVariant@@PBD@Z @ 1025 NONAME ; class QVariant QVideoSurfaceFormat::property(char const *) const + ?qt_metacast@QMediaContainerControl@@UAEPAXPBD@Z @ 1026 NONAME ; void * QMediaContainerControl::qt_metacast(char const *) + ?trUtf8@QVideoWidgetControl@@SA?AVQString@@PBD0@Z @ 1027 NONAME ; class QString QVideoWidgetControl::trUtf8(char const *, char const *) + ?qt_metacast@QAudioOutput@@UAEPAXPBD@Z @ 1028 NONAME ; void * QAudioOutput::qt_metacast(char const *) + ??1QMediaServiceSupportedDevicesInterface@@UAE@XZ @ 1029 NONAME ; QMediaServiceSupportedDevicesInterface::~QMediaServiceSupportedDevicesInterface(void) + ?qt_metacall@QAbstractAudioInput@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1030 NONAME ; int QAbstractAudioInput::qt_metacall(enum QMetaObject::Call, int, void * *) + ??1QAudioSystemFactoryInterface@@UAE@XZ @ 1031 NONAME ; QAudioSystemFactoryInterface::~QAudioSystemFactoryInterface(void) + ?qt_metacast@QRadioTunerControl@@UAEPAXPBD@Z @ 1032 NONAME ; void * QRadioTunerControl::qt_metacast(char const *) + ?d_func@QMemoryVideoBuffer@@AAEPAVQMemoryVideoBufferPrivate@@XZ @ 1033 NONAME ; class QMemoryVideoBufferPrivate * QMemoryVideoBuffer::d_func(void) + ?qt_metacall@QMediaContainerControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1034 NONAME ; int QMediaContainerControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ?qt_metacast@QMediaPlaylistSourceControl@@UAEPAXPBD@Z @ 1035 NONAME ; void * QMediaPlaylistSourceControl::qt_metacast(char const *) + ?qt_metacast@QMediaServiceProvider@@UAEPAXPBD@Z @ 1036 NONAME ; void * QMediaServiceProvider::qt_metacast(char const *) + ??1QMediaRecorderControl@@UAE@XZ @ 1037 NONAME ; QMediaRecorderControl::~QMediaRecorderControl(void) + ?isMetaDataAvailable@QMediaObject@@QBE_NXZ @ 1038 NONAME ; bool QMediaObject::isMetaDataAvailable(void) const + ?saturationChanged@QVideoWidgetControl@@IAEXH@Z @ 1039 NONAME ; void QVideoWidgetControl::saturationChanged(int) + ?channelCount@QAudioEncoderSettings@@QBEHXZ @ 1040 NONAME ; int QAudioEncoderSettings::channelCount(void) const + ?d_func@QMediaImageViewer@@ABEPBVQMediaImageViewerPrivate@@XZ @ 1041 NONAME ; class QMediaImageViewerPrivate const * QMediaImageViewer::d_func(void) const + ?getStaticMetaObject@QAudioSystemPlugin@@SAABUQMetaObject@@XZ @ 1042 NONAME ; struct QMetaObject const & QAudioSystemPlugin::getStaticMetaObject(void) + ??1QLocalMediaPlaylistProvider@@UAE@XZ @ 1043 NONAME ; QLocalMediaPlaylistProvider::~QLocalMediaPlaylistProvider(void) + ??_EQAudioInput@@UAE@I@Z @ 1044 NONAME ; QAudioInput::~QAudioInput(unsigned int) + ?state@QRadioTuner@@QBE?AW4State@1@XZ @ 1045 NONAME ; enum QRadioTuner::State QRadioTuner::state(void) const + ?metaObject@QVideoWidgetControl@@UBEPBUQMetaObject@@XZ @ 1046 NONAME ; struct QMetaObject const * QVideoWidgetControl::metaObject(void) const + ??0QMetaDataReaderControl@@IAE@PAVQObject@@@Z @ 1047 NONAME ; QMetaDataReaderControl::QMetaDataReaderControl(class QObject *) + ?qt_metacall@QMediaControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1048 NONAME ; int QMediaControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ?frameRate@QVideoEncoderSettings@@QBEMXZ @ 1049 NONAME ; float QVideoEncoderSettings::frameRate(void) const + ?tr@QMediaContainerControl@@SA?AVQString@@PBD0@Z @ 1050 NONAME ; class QString QMediaContainerControl::tr(char const *, char const *) + ??4QMediaTimeRange@@QAEAAV0@ABV0@@Z @ 1051 NONAME ; class QMediaTimeRange & QMediaTimeRange::operator=(class QMediaTimeRange const &) + ?qt_metacast@QVideoWidgetControl@@UAEPAXPBD@Z @ 1052 NONAME ; void * QVideoWidgetControl::qt_metacast(char const *) + ?unbind@QMediaImageViewer@@UAEXPAVQObject@@@Z @ 1053 NONAME ; void QMediaImageViewer::unbind(class QObject *) + ?signalStrength@QRadioTuner@@QBEHXZ @ 1054 NONAME ; int QRadioTuner::signalStrength(void) const + ?videoCodec@QMediaResource@@QBE?AVQString@@XZ @ 1055 NONAME ; class QString QMediaResource::videoCodec(void) const + ?band@QRadioTuner@@QBE?AW4Band@1@XZ @ 1056 NONAME ; enum QRadioTuner::Band QRadioTuner::band(void) const + ?staticMetaObject@QMediaServiceProviderPlugin@@2UQMetaObject@@B @ 1057 NONAME ; struct QMetaObject const QMediaServiceProviderPlugin::staticMetaObject + ?insertMedia@QMediaPlaylistProvider@@UAE_NHABVQMediaContent@@@Z @ 1058 NONAME ; bool QMediaPlaylistProvider::insertMedia(int, class QMediaContent const &) + ??1QMemoryVideoBuffer@@UAE@XZ @ 1059 NONAME ; QMemoryVideoBuffer::~QMemoryVideoBuffer(void) + ??1QRadioTuner@@UAE@XZ @ 1060 NONAME ; QRadioTuner::~QRadioTuner(void) + ?error@QMediaPlayer@@IAEXW4Error@1@@Z @ 1061 NONAME ; void QMediaPlayer::error(enum QMediaPlayer::Error) + ?tr@QGraphicsVideoItem@@SA?AVQString@@PBD0H@Z @ 1062 NONAME ; class QString QGraphicsVideoItem::tr(char const *, char const *, int) + ?getStaticMetaObject@QMediaServiceProvider@@SAABUQMetaObject@@XZ @ 1063 NONAME ; struct QMetaObject const & QMediaServiceProvider::getStaticMetaObject(void) + ?setBitRate@QAudioEncoderSettings@@QAEXH@Z @ 1064 NONAME ; void QAudioEncoderSettings::setBitRate(int) + ?isSeekable@QMediaPlayer@@QBE_NXZ @ 1065 NONAME ; bool QMediaPlayer::isSeekable(void) const + ?metaObject@QMediaPlaylistIOPlugin@@UBEPBUQMetaObject@@XZ @ 1066 NONAME ; struct QMetaObject const * QMediaPlaylistIOPlugin::metaObject(void) const + ?tr@QMediaPlayer@@SA?AVQString@@PBD0@Z @ 1067 NONAME ; class QString QMediaPlayer::tr(char const *, char const *) + ?setCodec@QAudioEncoderSettings@@QAEXABVQString@@@Z @ 1068 NONAME ; void QAudioEncoderSettings::setCodec(class QString const &) + ?isActive@QAbstractVideoSurface@@QBE_NXZ @ 1069 NONAME ; bool QAbstractVideoSurface::isActive(void) const + ??_EQMediaBindableInterface@@UAE@I@Z @ 1070 NONAME ; QMediaBindableInterface::~QMediaBindableInterface(unsigned int) + ?setYCbCrColorSpace@QVideoSurfaceFormat@@QAEXW4YCbCrColorSpace@1@@Z @ 1071 NONAME ; void QVideoSurfaceFormat::setYCbCrColorSpace(enum QVideoSurfaceFormat::YCbCrColorSpace) + ?setPlaybackMode@QMediaPlaylist@@QAEXW4PlaybackMode@1@@Z @ 1072 NONAME ; void QMediaPlaylist::setPlaybackMode(enum QMediaPlaylist::PlaybackMode) + ?volumeChanged@QRadioTuner@@IAEXH@Z @ 1073 NONAME ; void QRadioTuner::volumeChanged(int) + ?metaObject@QVideoWindowControl@@UBEPBUQMetaObject@@XZ @ 1074 NONAME ; struct QMetaObject const * QVideoWindowControl::metaObject(void) const + ?setFrequency@QAudioFormat@@QAEXH@Z @ 1075 NONAME ; void QAudioFormat::setFrequency(int) + ?trUtf8@QMediaControl@@SA?AVQString@@PBD0H@Z @ 1076 NONAME ; class QString QMediaControl::trUtf8(char const *, char const *, int) + ?selectedDeviceChanged@QVideoDeviceControl@@IAEXABVQString@@@Z @ 1077 NONAME ; void QVideoDeviceControl::selectedDeviceChanged(class QString const &) + ?setFrameRate@QVideoEncoderSettings@@QAEXM@Z @ 1078 NONAME ; void QVideoEncoderSettings::setFrameRate(float) + ?notify@QAbstractAudioOutput@@IAEXXZ @ 1079 NONAME ; void QAbstractAudioOutput::notify(void) + ?getStaticMetaObject@QMediaImageViewer@@SAABUQMetaObject@@XZ @ 1080 NONAME ; struct QMetaObject const & QMediaImageViewer::getStaticMetaObject(void) + ??_EQMediaImageViewer@@UAE@I@Z @ 1081 NONAME ; QMediaImageViewer::~QMediaImageViewer(unsigned int) + ??0QMediaPlaylistProvider@@QAE@PAVQObject@@@Z @ 1082 NONAME ; QMediaPlaylistProvider::QMediaPlaylistProvider(class QObject *) + ?trUtf8@QMediaServiceProviderPlugin@@SA?AVQString@@PBD0@Z @ 1083 NONAME ; class QString QMediaServiceProviderPlugin::trUtf8(char const *, char const *) + ?tr@QMediaServiceProvider@@SA?AVQString@@PBD0@Z @ 1084 NONAME ; class QString QMediaServiceProvider::tr(char const *, char const *) + ?loaded@QMediaPlaylistProvider@@IAEXXZ @ 1085 NONAME ; void QMediaPlaylistProvider::loaded(void) + ?staticMetaObject@QMediaPlayer@@2UQMetaObject@@B @ 1086 NONAME ; struct QMetaObject const QMediaPlayer::staticMetaObject + ??1QMediaPlaylist@@UAE@XZ @ 1087 NONAME ; QMediaPlaylist::~QMediaPlaylist(void) + ?error@QRadioTunerControl@@IAEXW4Error@QRadioTuner@@@Z @ 1088 NONAME ; void QRadioTunerControl::error(enum QRadioTuner::Error) + ?playbackRateChanged@QMediaPlayer@@IAEXM@Z @ 1089 NONAME ; void QMediaPlayer::playbackRateChanged(float) + ?setFrameSize@QVideoSurfaceFormat@@QAEXHH@Z @ 1090 NONAME ; void QVideoSurfaceFormat::setFrameSize(int, int) + ?getStaticMetaObject@QMediaContainerControl@@SAABUQMetaObject@@XZ @ 1091 NONAME ; struct QMetaObject const & QMediaContainerControl::getStaticMetaObject(void) + ?metaData@QMediaObject@@QBE?AVQVariant@@W4MetaData@QtMultimediaKit@@@Z @ 1092 NONAME ; class QVariant QMediaObject::metaData(enum QtMultimediaKit::MetaData) const + ?mimeType@QMediaServiceProviderHint@@QBE?AVQString@@XZ @ 1093 NONAME ; class QString QMediaServiceProviderHint::mimeType(void) const + ?outputLocation@QMediaRecorder@@QBE?AVQUrl@@XZ @ 1094 NONAME ; class QUrl QMediaRecorder::outputLocation(void) const + ?load@QMediaPlaylistProvider@@UAE_NPAVQIODevice@@PBD@Z @ 1095 NONAME ; bool QMediaPlaylistProvider::load(class QIODevice *, char const *) + ?error@QMediaRecorder@@IAEXW4Error@1@@Z @ 1096 NONAME ; void QMediaRecorder::error(enum QMediaRecorder::Error) + ?metaObject@QMediaPlayerControl@@UBEPBUQMetaObject@@XZ @ 1097 NONAME ; struct QMetaObject const * QMediaPlayerControl::metaObject(void) const + ??_EQMediaServiceFeaturesInterface@@UAE@I@Z @ 1098 NONAME ; QMediaServiceFeaturesInterface::~QMediaServiceFeaturesInterface(unsigned int) + ??_EQAbstractAudioInput@@UAE@I@Z @ 1099 NONAME ; QAbstractAudioInput::~QAbstractAudioInput(unsigned int) + ?moveEvent@QVideoWidget@@MAEXPAVQMoveEvent@@@Z @ 1100 NONAME ; void QVideoWidget::moveEvent(class QMoveEvent *) + ?audioCodec@QMediaResource@@QBE?AVQString@@XZ @ 1101 NONAME ; class QString QMediaResource::audioCodec(void) const + ??_EQGraphicsVideoItem@@UAE@I@Z @ 1102 NONAME ; QGraphicsVideoItem::~QGraphicsVideoItem(unsigned int) + ?staticMetaObject@QVideoEncoderControl@@2UQMetaObject@@B @ 1103 NONAME ; struct QMetaObject const QVideoEncoderControl::staticMetaObject + ?start@QAudioInput@@QAEPAVQIODevice@@XZ @ 1104 NONAME ; class QIODevice * QAudioInput::start(void) + ?pixelAspectRatio@QVideoSurfaceFormat@@QBE?AVQSize@@XZ @ 1105 NONAME ; class QSize QVideoSurfaceFormat::pixelAspectRatio(void) const + ??_EQLocalMediaPlaylistProvider@@UAE@I@Z @ 1106 NONAME ; QLocalMediaPlaylistProvider::~QLocalMediaPlaylistProvider(unsigned int) + ?trUtf8@QSoundEffect@@SA?AVQString@@PBD0H@Z @ 1107 NONAME ; class QString QSoundEffect::trUtf8(char const *, char const *, int) + ?getStaticMetaObject@QMediaService@@SAABUQMetaObject@@XZ @ 1108 NONAME ; struct QMetaObject const & QMediaService::getStaticMetaObject(void) + ??4QAudioFormat@@QAEAAV0@ABV0@@Z @ 1109 NONAME ; class QAudioFormat & QAudioFormat::operator=(class QAudioFormat const &) + ?isReadable@QVideoFrame@@QBE_NXZ @ 1110 NONAME ; bool QVideoFrame::isReadable(void) const + ?trUtf8@QMediaRecorder@@SA?AVQString@@PBD0@Z @ 1111 NONAME ; class QString QMediaRecorder::trUtf8(char const *, char const *) + ?setResolution@QImageEncoderSettings@@QAEXHH@Z @ 1112 NONAME ; void QImageEncoderSettings::setResolution(int, int) + ??_EQRadioTuner@@UAE@I@Z @ 1113 NONAME ; QRadioTuner::~QRadioTuner(unsigned int) + ?setVideoOutput@QMediaPlayer@@QAEXPAVQGraphicsVideoItem@@@Z @ 1114 NONAME ; void QMediaPlayer::setVideoOutput(class QGraphicsVideoItem *) + ??0QAudioInput@@QAE@ABVQAudioDeviceInfo@@ABVQAudioFormat@@PAVQObject@@@Z @ 1115 NONAME ; QAudioInput::QAudioInput(class QAudioDeviceInfo const &, class QAudioFormat const &, class QObject *) + ?setSize@QGraphicsVideoItem@@QAEXABVQSizeF@@@Z @ 1116 NONAME ; void QGraphicsVideoItem::setSize(class QSizeF const &) + ?codec@QAudioEncoderSettings@@QBE?AVQString@@XZ @ 1117 NONAME ; class QString QAudioEncoderSettings::codec(void) const + ?periodSize@QAudioOutput@@QBEHXZ @ 1118 NONAME ; int QAudioOutput::periodSize(void) const + ?trUtf8@QMediaPlaylistNavigator@@SA?AVQString@@PBD0H@Z @ 1119 NONAME ; class QString QMediaPlaylistNavigator::trUtf8(char const *, char const *, int) + ??1QMediaImageViewer@@UAE@XZ @ 1120 NONAME ; QMediaImageViewer::~QMediaImageViewer(void) + ??0QAudioDeviceInfo@@QAE@XZ @ 1121 NONAME ; QAudioDeviceInfo::QAudioDeviceInfo(void) + ?setCodec@QAudioFormat@@QAEXABVQString@@@Z @ 1122 NONAME ; void QAudioFormat::setCodec(class QString const &) + ?getStaticMetaObject@QLocalMediaPlaylistProvider@@SAABUQMetaObject@@XZ @ 1123 NONAME ; struct QMetaObject const & QLocalMediaPlaylistProvider::getStaticMetaObject(void) + ??1QMediaResource@@QAE@XZ @ 1124 NONAME ; QMediaResource::~QMediaResource(void) + ?tr@QAbstractAudioInput@@SA?AVQString@@PBD0H@Z @ 1125 NONAME ; class QString QAbstractAudioInput::tr(char const *, char const *, int) + ?save@QMediaPlaylistProvider@@UAE_NPAVQIODevice@@PBD@Z @ 1126 NONAME ; bool QMediaPlaylistProvider::save(class QIODevice *, char const *) + ?removeTimeRange@QMediaTimeRange@@QAEXABV1@@Z @ 1127 NONAME ; void QMediaTimeRange::removeTimeRange(class QMediaTimeRange const &) + ?setStartTime@QVideoFrame@@QAEX_J@Z @ 1128 NONAME ; void QVideoFrame::setStartTime(long long) + ?d_func@QLocalMediaPlaylistProvider@@AAEPAVQLocalMediaPlaylistProviderPrivate@@XZ @ 1129 NONAME ; class QLocalMediaPlaylistProviderPrivate * QLocalMediaPlaylistProvider::d_func(void) + ?metaObject@QMediaRecorder@@UBEPBUQMetaObject@@XZ @ 1130 NONAME ; struct QMetaObject const * QMediaRecorder::metaObject(void) const + ?unmap@QMemoryVideoBuffer@@UAEXXZ @ 1131 NONAME ; void QMemoryVideoBuffer::unmap(void) + ?d_func@QMediaPlaylistProvider@@AAEPAVQMediaPlaylistProviderPrivate@@XZ @ 1132 NONAME ; class QMediaPlaylistProviderPrivate * QMediaPlaylistProvider::d_func(void) + ??0QMediaObject@@IAE@AAVQMediaObjectPrivate@@PAVQObject@@PAVQMediaService@@@Z @ 1133 NONAME ; QMediaObject::QMediaObject(class QMediaObjectPrivate &, class QObject *, class QMediaService *) + ?tr@QMetaDataWriterControl@@SA?AVQString@@PBD0H@Z @ 1134 NONAME ; class QString QMetaDataWriterControl::tr(char const *, char const *, int) + ?isAudioAvailable@QMediaPlayer@@QBE_NXZ @ 1135 NONAME ; bool QMediaPlayer::isAudioAvailable(void) const + ?mediaAboutToBeInserted@QMediaPlaylist@@IAEXHH@Z @ 1136 NONAME ; void QMediaPlaylist::mediaAboutToBeInserted(int, int) + ??0QAudioFormat@@QAE@ABV0@@Z @ 1137 NONAME ; QAudioFormat::QAudioFormat(class QAudioFormat const &) + ?qt_metacall@QMediaObject@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1138 NONAME ; int QMediaObject::qt_metacall(enum QMetaObject::Call, int, void * *) + ?getStaticMetaObject@QMediaPlayer@@SAABUQMetaObject@@XZ @ 1139 NONAME ; struct QMetaObject const & QMediaPlayer::getStaticMetaObject(void) + ?bufferSize@QAudioInput@@QBEHXZ @ 1140 NONAME ; int QAudioInput::bufferSize(void) const + ?staticMetaObject@QMediaServiceProvider@@2UQMetaObject@@B @ 1141 NONAME ; struct QMetaObject const QMediaServiceProvider::staticMetaObject + ?error@QAudioInput@@QBE?AW4Error@QAudio@@XZ @ 1142 NONAME ; enum QAudio::Error QAudioInput::error(void) const + ?getStaticMetaObject@QVideoEncoderControl@@SAABUQMetaObject@@XZ @ 1143 NONAME ; struct QMetaObject const & QVideoEncoderControl::getStaticMetaObject(void) + ?qt_metacall@QMediaPlaylistControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1144 NONAME ; int QMediaPlaylistControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ??0QLocalMediaPlaylistProvider@@QAE@PAVQObject@@@Z @ 1145 NONAME ; QLocalMediaPlaylistProvider::QLocalMediaPlaylistProvider(class QObject *) + ?notifyInterval@QMediaObject@@QBEHXZ @ 1146 NONAME ; int QMediaObject::notifyInterval(void) const + ??0QMediaContent@@QAE@ABVQMediaResource@@@Z @ 1147 NONAME ; QMediaContent::QMediaContent(class QMediaResource const &) + ?qt_metacall@QVideoDeviceControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1148 NONAME ; int QVideoDeviceControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ?tr@QAbstractAudioDeviceInfo@@SA?AVQString@@PBD0H@Z @ 1149 NONAME ; class QString QAbstractAudioDeviceInfo::tr(char const *, char const *, int) + ??_EQMediaPlaylistWriter@@UAE@I@Z @ 1150 NONAME ; QMediaPlaylistWriter::~QMediaPlaylistWriter(unsigned int) + ?trUtf8@QAudioInput@@SA?AVQString@@PBD0H@Z @ 1151 NONAME ; class QString QAudioInput::trUtf8(char const *, char const *, int) + ?trUtf8@QAudioSystemPlugin@@SA?AVQString@@PBD0@Z @ 1152 NONAME ; class QString QAudioSystemPlugin::trUtf8(char const *, char const *) + ?getStaticMetaObject@QAudioEncoderControl@@SAABUQMetaObject@@XZ @ 1153 NONAME ; struct QMetaObject const & QAudioEncoderControl::getStaticMetaObject(void) + ?resources@QMediaContent@@QBE?AV?$QList@VQMediaResource@@@@XZ @ 1154 NONAME ; class QList QMediaContent::resources(void) const + ?trUtf8@QAbstractVideoSurface@@SA?AVQString@@PBD0H@Z @ 1155 NONAME ; class QString QAbstractVideoSurface::trUtf8(char const *, char const *, int) + ?shuffle@QLocalMediaPlaylistProvider@@UAEXXZ @ 1156 NONAME ; void QLocalMediaPlaylistProvider::shuffle(void) + ?nativeSize@QGraphicsVideoItem@@QBE?AVQSizeF@@XZ @ 1157 NONAME ; class QSizeF QGraphicsVideoItem::nativeSize(void) const + ?setEncodingSettings@QMediaRecorder@@QAEXABVQAudioEncoderSettings@@ABVQVideoEncoderSettings@@ABVQString@@@Z @ 1158 NONAME ; void QMediaRecorder::setEncodingSettings(class QAudioEncoderSettings const &, class QVideoEncoderSettings const &, class QString const &) + ?event@QVideoWidget@@MAE_NPAVQEvent@@@Z @ 1159 NONAME ; bool QVideoWidget::event(class QEvent *) + ?processedUSecs@QAudioOutput@@QBE_JXZ @ 1160 NONAME ; long long QAudioOutput::processedUSecs(void) const + ?setChannels@QAudioFormat@@QAEXH@Z @ 1161 NONAME ; void QAudioFormat::setChannels(int) + ?tr@QAudioCaptureSource@@SA?AVQString@@PBD0@Z @ 1162 NONAME ; class QString QAudioCaptureSource::tr(char const *, char const *) + ?volumeChanged@QMediaPlayerControl@@IAEXH@Z @ 1163 NONAME ; void QMediaPlayerControl::volumeChanged(int) + ?trUtf8@QVideoRendererControl@@SA?AVQString@@PBD0H@Z @ 1164 NONAME ; class QString QVideoRendererControl::trUtf8(char const *, char const *, int) + ?trUtf8@QMediaPlaylistSourceControl@@SA?AVQString@@PBD0@Z @ 1165 NONAME ; class QString QMediaPlaylistSourceControl::trUtf8(char const *, char const *) + ?isMuted@QMediaRecorder@@QBE_NXZ @ 1166 NONAME ; bool QMediaRecorder::isMuted(void) const + ?trUtf8@QMediaService@@SA?AVQString@@PBD0@Z @ 1167 NONAME ; class QString QMediaService::trUtf8(char const *, char const *) + ?getStaticMetaObject@QMediaRecorderControl@@SAABUQMetaObject@@XZ @ 1168 NONAME ; struct QMetaObject const & QMediaRecorderControl::getStaticMetaObject(void) + ??0QAudioSystemPlugin@@QAE@PAVQObject@@@Z @ 1169 NONAME ; QAudioSystemPlugin::QAudioSystemPlugin(class QObject *) + ?resolution@QImageEncoderSettings@@QBE?AVQSize@@XZ @ 1170 NONAME ; class QSize QImageEncoderSettings::resolution(void) const + ?setPlaybackRate@QMediaPlayer@@QAEXM@Z @ 1171 NONAME ; void QMediaPlayer::setPlaybackRate(float) + ?availableExtendedMetaData@QMediaObject@@QBE?AVQStringList@@XZ @ 1172 NONAME ; class QStringList QMediaObject::availableExtendedMetaData(void) const + ??ZQMediaTimeRange@@QAEAAV0@ABV0@@Z @ 1173 NONAME ; class QMediaTimeRange & QMediaTimeRange::operator-=(class QMediaTimeRange const &) + ?brightness@QVideoWidget@@QBEHXZ @ 1174 NONAME ; int QVideoWidget::brightness(void) const + ??0QMediaTimeRange@@QAE@ABV0@@Z @ 1175 NONAME ; QMediaTimeRange::QMediaTimeRange(class QMediaTimeRange const &) + ?state@QMediaRecorder@@QBE?AW4State@1@XZ @ 1176 NONAME ; enum QMediaRecorder::State QMediaRecorder::state(void) const + ?tr@QMediaRecorder@@SA?AVQString@@PBD0H@Z @ 1177 NONAME ; class QString QMediaRecorder::tr(char const *, char const *, int) + ?trUtf8@QVideoEncoderControl@@SA?AVQString@@PBD0H@Z @ 1178 NONAME ; class QString QVideoEncoderControl::trUtf8(char const *, char const *, int) + ?hueChanged@QVideoWindowControl@@IAEXH@Z @ 1179 NONAME ; void QVideoWindowControl::hueChanged(int) + ?qt_metacast@QMediaService@@UAEPAXPBD@Z @ 1180 NONAME ; void * QMediaService::qt_metacast(char const *) + ?endTime@QVideoFrame@@QBE_JXZ @ 1181 NONAME ; long long QVideoFrame::endTime(void) const + ??0QAbstractVideoBuffer@@QAE@W4HandleType@0@@Z @ 1182 NONAME ; QAbstractVideoBuffer::QAbstractVideoBuffer(enum QAbstractVideoBuffer::HandleType) + ?defaultOutputDevice@QAudioDeviceInfo@@SA?AV1@XZ @ 1183 NONAME ; class QAudioDeviceInfo QAudioDeviceInfo::defaultOutputDevice(void) + ?tr@QMediaRecorderControl@@SA?AVQString@@PBD0@Z @ 1184 NONAME ; class QString QMediaRecorderControl::tr(char const *, char const *) + ?suspend@QAudioOutput@@QAEXXZ @ 1185 NONAME ; void QAudioOutput::suspend(void) + ??1QAbstractVideoSurface@@UAE@XZ @ 1186 NONAME ; QAbstractVideoSurface::~QAbstractVideoSurface(void) + ?previousIndex@QMediaPlaylist@@QBEHH@Z @ 1187 NONAME ; int QMediaPlaylist::previousIndex(int) const + ?tr@QMediaControl@@SA?AVQString@@PBD0H@Z @ 1188 NONAME ; class QString QMediaControl::tr(char const *, char const *, int) + ?tr@QImageEncoderControl@@SA?AVQString@@PBD0@Z @ 1189 NONAME ; class QString QImageEncoderControl::tr(char const *, char const *) + ?nativeSizeChanged@QGraphicsVideoItem@@IAEXABVQSizeF@@@Z @ 1190 NONAME ; void QGraphicsVideoItem::nativeSizeChanged(class QSizeF const &) + ??1QSoundEffect@@UAE@XZ @ 1191 NONAME ; QSoundEffect::~QSoundEffect(void) + ?stateChanged@QAbstractAudioInput@@IAEXW4State@QAudio@@@Z @ 1192 NONAME ; void QAbstractAudioInput::stateChanged(enum QAudio::State) + ?media@QMediaPlayer@@QBE?AVQMediaContent@@XZ @ 1193 NONAME ; class QMediaContent QMediaPlayer::media(void) const + ?bind@QMediaImageViewer@@UAE_NPAVQObject@@@Z @ 1194 NONAME ; bool QMediaImageViewer::bind(class QObject *) + ?resolution@QMediaResource@@QBE?AVQSize@@XZ @ 1195 NONAME ; class QSize QMediaResource::resolution(void) const + ?setBitRate@QVideoEncoderSettings@@QAEXH@Z @ 1196 NONAME ; void QVideoEncoderSettings::setBitRate(int) + ?qt_metacast@QMediaControl@@UAEPAXPBD@Z @ 1197 NONAME ; void * QMediaControl::qt_metacast(char const *) + ?sizeHint@QVideoWidget@@UBE?AVQSize@@XZ @ 1198 NONAME ; class QSize QVideoWidget::sizeHint(void) const + ?bandChanged@QRadioTunerControl@@IAEXW4Band@QRadioTuner@@@Z @ 1199 NONAME ; void QRadioTunerControl::bandChanged(enum QRadioTuner::Band) + ?trUtf8@QMetaDataReaderControl@@SA?AVQString@@PBD0H@Z @ 1200 NONAME ; class QString QMetaDataReaderControl::trUtf8(char const *, char const *, int) + ?getStaticMetaObject@QVideoDeviceControl@@SAABUQMetaObject@@XZ @ 1201 NONAME ; struct QMetaObject const & QVideoDeviceControl::getStaticMetaObject(void) + ?stateChanged@QMediaPlayer@@IAEXW4State@1@@Z @ 1202 NONAME ; void QMediaPlayer::stateChanged(enum QMediaPlayer::State) + ??0QMediaPlayerControl@@IAE@PAVQObject@@@Z @ 1203 NONAME ; QMediaPlayerControl::QMediaPlayerControl(class QObject *) + ?availabilityError@QMediaObject@@UBE?AW4AvailabilityError@QtMultimediaKit@@XZ @ 1204 NONAME ; enum QtMultimediaKit::AvailabilityError QMediaObject::availabilityError(void) const + ?tr@QRadioTunerControl@@SA?AVQString@@PBD0H@Z @ 1205 NONAME ; class QString QRadioTunerControl::tr(char const *, char const *, int) + ?getStaticMetaObject@QVideoWidgetControl@@SAABUQMetaObject@@XZ @ 1206 NONAME ; struct QMetaObject const & QVideoWidgetControl::getStaticMetaObject(void) + ??9QMediaServiceProviderHint@@QBE_NABV0@@Z @ 1207 NONAME ; bool QMediaServiceProviderHint::operator!=(class QMediaServiceProviderHint const &) const + ?tr@QRadioTuner@@SA?AVQString@@PBD0@Z @ 1208 NONAME ; class QString QRadioTuner::tr(char const *, char const *) + ?tr@QAudioSystemPlugin@@SA?AVQString@@PBD0H@Z @ 1209 NONAME ; class QString QAudioSystemPlugin::tr(char const *, char const *, int) + ?stateChanged@QMediaImageViewer@@IAEXW4State@1@@Z @ 1210 NONAME ; void QMediaImageViewer::stateChanged(enum QMediaImageViewer::State) + ?next@QMediaPlaylist@@QAEXXZ @ 1211 NONAME ; void QMediaPlaylist::next(void) + ?tr@QMediaPlayerControl@@SA?AVQString@@PBD0@Z @ 1212 NONAME ; class QString QMediaPlayerControl::tr(char const *, char const *) + ??1QMediaPlaylistControl@@UAE@XZ @ 1213 NONAME ; QMediaPlaylistControl::~QMediaPlaylistControl(void) + ??1QAudioOutput@@UAE@XZ @ 1214 NONAME ; QAudioOutput::~QAudioOutput(void) + ?setupMetaData@QMediaObject@@AAEXXZ @ 1215 NONAME ; void QMediaObject::setupMetaData(void) + ??_EQImageEncoderControl@@UAE@I@Z @ 1216 NONAME ; QImageEncoderControl::~QImageEncoderControl(unsigned int) + ??_EQMediaRecorder@@UAE@I@Z @ 1217 NONAME ; QMediaRecorder::~QMediaRecorder(unsigned int) + ?tr@QMetaDataWriterControl@@SA?AVQString@@PBD0@Z @ 1218 NONAME ; class QString QMetaDataWriterControl::tr(char const *, char const *) + ?tr@QAbstractAudioDeviceInfo@@SA?AVQString@@PBD0@Z @ 1219 NONAME ; class QString QAbstractAudioDeviceInfo::tr(char const *, char const *) + ?tr@QMediaRecorder@@SA?AVQString@@PBD0@Z @ 1220 NONAME ; class QString QMediaRecorder::tr(char const *, char const *) + ??1QVideoWidget@@UAE@XZ @ 1221 NONAME ; QVideoWidget::~QVideoWidget(void) + ?tr@QAudioSystemPlugin@@SA?AVQString@@PBD0@Z @ 1222 NONAME ; class QString QAudioSystemPlugin::tr(char const *, char const *) + ?setEncodingMode@QAudioEncoderSettings@@QAEXW4EncodingMode@QtMultimediaKit@@@Z @ 1223 NONAME ; void QAudioEncoderSettings::setEncodingMode(enum QtMultimediaKit::EncodingMode) + ??1QVideoWindowControl@@UAE@XZ @ 1224 NONAME ; QVideoWindowControl::~QVideoWindowControl(void) + ?trUtf8@QMediaServiceProviderPlugin@@SA?AVQString@@PBD0H@Z @ 1225 NONAME ; class QString QMediaServiceProviderPlugin::trUtf8(char const *, char const *, int) + ?currentIndexChanged@QMediaPlaylistControl@@IAEXH@Z @ 1226 NONAME ; void QMediaPlaylistControl::currentIndexChanged(int) + ?suspend@QAudioInput@@QAEXXZ @ 1227 NONAME ; void QAudioInput::suspend(void) + ?mutedChanged@QMediaPlayer@@IAEX_N@Z @ 1228 NONAME ; void QMediaPlayer::mutedChanged(bool) + ?metaObject@QAbstractAudioInput@@UBEPBUQMetaObject@@XZ @ 1229 NONAME ; struct QMetaObject const * QAbstractAudioInput::metaObject(void) const + ?mediaChanged@QMediaPlayer@@IAEXABVQMediaContent@@@Z @ 1230 NONAME ; void QMediaPlayer::mediaChanged(class QMediaContent const &) + ?mediaChanged@QMediaPlaylist@@IAEXHH@Z @ 1231 NONAME ; void QMediaPlaylist::mediaChanged(int, int) + ?tr@QMediaServiceProvider@@SA?AVQString@@PBD0H@Z @ 1232 NONAME ; class QString QMediaServiceProvider::tr(char const *, char const *, int) + ?mutedChanged@QSoundEffect@@IAEXXZ @ 1233 NONAME ; void QSoundEffect::mutedChanged(void) + ?trUtf8@QRadioTuner@@SA?AVQString@@PBD0@Z @ 1234 NONAME ; class QString QRadioTuner::trUtf8(char const *, char const *) + ?getStaticMetaObject@QRadioTuner@@SAABUQMetaObject@@XZ @ 1235 NONAME ; struct QMetaObject const & QRadioTuner::getStaticMetaObject(void) + ?frameRate@QVideoSurfaceFormat@@QBEMXZ @ 1236 NONAME ; float QVideoSurfaceFormat::frameRate(void) const + ?offset@QGraphicsVideoItem@@QBE?AVQPointF@@XZ @ 1237 NONAME ; class QPointF QGraphicsVideoItem::offset(void) const + ?trUtf8@QAudioCaptureSource@@SA?AVQString@@PBD0H@Z @ 1238 NONAME ; class QString QAudioCaptureSource::trUtf8(char const *, char const *, int) + ?removeMedia@QMediaPlaylistProvider@@UAE_NH@Z @ 1239 NONAME ; bool QMediaPlaylistProvider::removeMedia(int) + ??0QVideoEncoderControl@@IAE@PAVQObject@@@Z @ 1240 NONAME ; QVideoEncoderControl::QVideoEncoderControl(class QObject *) + ?setQuality@QImageEncoderSettings@@QAEXW4EncodingQuality@QtMultimediaKit@@@Z @ 1241 NONAME ; void QImageEncoderSettings::setQuality(enum QtMultimediaKit::EncodingQuality) + ?contrastChanged@QVideoWidget@@IAEXH@Z @ 1242 NONAME ; void QVideoWidget::contrastChanged(int) + ?unbind@QMediaObject@@UAEXPAVQObject@@@Z @ 1243 NONAME ; void QMediaObject::unbind(class QObject *) + ?metaObject@QMediaImageViewer@@UBEPBUQMetaObject@@XZ @ 1244 NONAME ; struct QMetaObject const * QMediaImageViewer::metaObject(void) const + ?scanLineDirection@QVideoSurfaceFormat@@QBE?AW4Direction@1@XZ @ 1245 NONAME ; enum QVideoSurfaceFormat::Direction QVideoSurfaceFormat::scanLineDirection(void) const + ?tr@QMediaStreamsControl@@SA?AVQString@@PBD0@Z @ 1246 NONAME ; class QString QMediaStreamsControl::tr(char const *, char const *) + ?getStaticMetaObject@QAbstractVideoSurface@@SAABUQMetaObject@@XZ @ 1247 NONAME ; struct QMetaObject const & QAbstractVideoSurface::getStaticMetaObject(void) + ??0QGraphicsVideoItem@@QAE@PAVQGraphicsItem@@@Z @ 1248 NONAME ; QGraphicsVideoItem::QGraphicsVideoItem(class QGraphicsItem *) + ??1QVideoEncoderControl@@UAE@XZ @ 1249 NONAME ; QVideoEncoderControl::~QVideoEncoderControl(void) + ?removeInterval@QMediaTimeRange@@QAEXABVQMediaTimeInterval@@@Z @ 1250 NONAME ; void QMediaTimeRange::removeInterval(class QMediaTimeInterval const &) + ?insertMedia@QLocalMediaPlaylistProvider@@UAE_NHABVQMediaContent@@@Z @ 1251 NONAME ; bool QLocalMediaPlaylistProvider::insertMedia(int, class QMediaContent const &) + ?currentMedia@QMediaPlaylist@@QBE?AVQMediaContent@@XZ @ 1252 NONAME ; class QMediaContent QMediaPlaylist::currentMedia(void) const + ?setAudioCodec@QMediaResource@@QAEXABVQString@@@Z @ 1253 NONAME ; void QMediaResource::setAudioCodec(class QString const &) + ?activated@QMediaPlaylistNavigator@@IAEXABVQMediaContent@@@Z @ 1254 NONAME ; void QMediaPlaylistNavigator::activated(class QMediaContent const &) + ?trUtf8@QMediaPlaylistNavigator@@SA?AVQString@@PBD0@Z @ 1255 NONAME ; class QString QMediaPlaylistNavigator::trUtf8(char const *, char const *) + ?tr@QMediaControl@@SA?AVQString@@PBD0@Z @ 1256 NONAME ; class QString QMediaControl::tr(char const *, char const *) + ?getStaticMetaObject@QMetaDataWriterControl@@SAABUQMetaObject@@XZ @ 1257 NONAME ; struct QMetaObject const & QMetaDataWriterControl::getStaticMetaObject(void) + ??8QVideoSurfaceFormat@@QBE_NABV0@@Z @ 1258 NONAME ; bool QVideoSurfaceFormat::operator==(class QVideoSurfaceFormat const &) const + ?removeInterval@QMediaTimeRange@@QAEX_J0@Z @ 1259 NONAME ; void QMediaTimeRange::removeInterval(long long, long long) + ?qt_metacast@QAbstractAudioOutput@@UAEPAXPBD@Z @ 1260 NONAME ; void * QAbstractAudioOutput::qt_metacast(char const *) + ??1QVideoSurfaceFormat@@QAE@XZ @ 1261 NONAME ; QVideoSurfaceFormat::~QVideoSurfaceFormat(void) + ?nativeResolutionChanged@QAbstractVideoSurface@@IAEXABVQSize@@@Z @ 1262 NONAME ; void QAbstractVideoSurface::nativeResolutionChanged(class QSize const &) + ??1QCameraControl@@UAE@XZ @ 1263 NONAME ; QCameraControl::~QCameraControl(void) + ?opticalZoomChanged@QCameraFocusControl@@IAEXM@Z @ 1264 NONAME ; void QCameraFocusControl::opticalZoomChanged(float) + ?trUtf8@QCameraFocusControl@@SA?AVQString@@PBD0@Z @ 1265 NONAME ; class QString QCameraFocusControl::trUtf8(char const *, char const *) + ?qt_metacast@QCamera@@UAEPAXPBD@Z @ 1266 NONAME ; void * QCamera::qt_metacast(char const *) + ??4QCameraFocusZone@@QAEAAV0@ABV0@@Z @ 1267 NONAME ; class QCameraFocusZone & QCameraFocusZone::operator=(class QCameraFocusZone const &) + ?errorString@QCameraImageCapture@@QBE?AVQString@@XZ @ 1268 NONAME ; class QString QCameraImageCapture::errorString(void) const + ?readyForCaptureChanged@QCameraImageCaptureControl@@IAEX_N@Z @ 1269 NONAME ; void QCameraImageCaptureControl::readyForCaptureChanged(bool) + ??1QCameraImageCaptureControl@@UAE@XZ @ 1270 NONAME ; QCameraImageCaptureControl::~QCameraImageCaptureControl(void) + ?metaObject@QCameraViewfinder@@UBEPBUQMetaObject@@XZ @ 1271 NONAME ; struct QMetaObject const * QCameraViewfinder::metaObject(void) const + ?saturation@QCameraImageProcessing@@QBEHXZ @ 1272 NONAME ; int QCameraImageProcessing::saturation(void) const + ?trUtf8@QCameraExposure@@SA?AVQString@@PBD0@Z @ 1273 NONAME ; class QString QCameraExposure::trUtf8(char const *, char const *) + ?availableDevices@QCamera@@SA?AV?$QList@VQByteArray@@@@XZ @ 1274 NONAME ; class QList QCamera::availableDevices(void) + ?tr@QCameraImageCaptureControl@@SA?AVQString@@PBD0H@Z @ 1275 NONAME ; class QString QCameraImageCaptureControl::tr(char const *, char const *, int) + ?exposure@QCamera@@QBEPAVQCameraExposure@@XZ @ 1276 NONAME ; class QCameraExposure * QCamera::exposure(void) const + ??_EQCameraViewfinder@@UAE@I@Z @ 1277 NONAME ; QCameraViewfinder::~QCameraViewfinder(unsigned int) + ?setViewfinder@QCamera@@QAEXPAVQGraphicsVideoItem@@@Z @ 1278 NONAME ; void QCamera::setViewfinder(class QGraphicsVideoItem *) + ?exposureCompensationChanged@QCameraExposure@@IAEXM@Z @ 1279 NONAME ; void QCameraExposure::exposureCompensationChanged(float) + ?imageSaved@QCameraImageCaptureControl@@IAEXHABVQString@@@Z @ 1280 NONAME ; void QCameraImageCaptureControl::imageSaved(int, class QString const &) + ?isFocusPointModeSupported@QCameraFocus@@QBE_NW4FocusPointMode@1@@Z @ 1281 NONAME ; bool QCameraFocus::isFocusPointModeSupported(enum QCameraFocus::FocusPointMode) const + ?error@QCamera@@QBE?AW4Error@1@XZ @ 1282 NONAME ; enum QCamera::Error QCamera::error(void) const + ?getStaticMetaObject@QCameraLocksControl@@SAABUQMetaObject@@XZ @ 1283 NONAME ; struct QMetaObject const & QCameraLocksControl::getStaticMetaObject(void) + ?metaObject@QCameraImageCaptureControl@@UBEPBUQMetaObject@@XZ @ 1284 NONAME ; struct QMetaObject const * QCameraImageCaptureControl::metaObject(void) const + ?unlock@QCamera@@QAEXV?$QFlags@W4LockType@QCamera@@@@@Z @ 1285 NONAME ; void QCamera::unlock(class QFlags) + ?qt_metacall@QCameraExposure@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1286 NONAME ; int QCameraExposure::qt_metacall(enum QMetaObject::Call, int, void * *) + ?staticMetaObject@QCameraLocksControl@@2UQMetaObject@@B @ 1287 NONAME ; struct QMetaObject const QCameraLocksControl::staticMetaObject + ?focus@QCamera@@QBEPAVQCameraFocus@@XZ @ 1288 NONAME ; class QCameraFocus * QCamera::focus(void) const + ?staticMetaObject@QCameraFocus@@2UQMetaObject@@B @ 1289 NONAME ; struct QMetaObject const QCameraFocus::staticMetaObject + ?qt_metacall@QCameraImageProcessing@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1290 NONAME ; int QCameraImageProcessing::qt_metacall(enum QMetaObject::Call, int, void * *) + ??0QCameraFocus@@AAE@PAVQCamera@@@Z @ 1291 NONAME ; QCameraFocus::QCameraFocus(class QCamera *) + ?error@QCameraImageCaptureControl@@IAEXHHABVQString@@@Z @ 1292 NONAME ; void QCameraImageCaptureControl::error(int, int, class QString const &) + ?staticMetaObject@QCameraControl@@2UQMetaObject@@B @ 1293 NONAME ; struct QMetaObject const QCameraControl::staticMetaObject + ?isReadyForCapture@QCameraImageCapture@@QBE_NXZ @ 1294 NONAME ; bool QCameraImageCapture::isReadyForCapture(void) const + ?exposureCompensation@QCameraExposure@@QBEMXZ @ 1295 NONAME ; float QCameraExposure::exposureCompensation(void) const + ?getStaticMetaObject@QCameraImageCapture@@SAABUQMetaObject@@XZ @ 1296 NONAME ; struct QMetaObject const & QCameraImageCapture::getStaticMetaObject(void) + ?getStaticMetaObject@QCameraImageCaptureControl@@SAABUQMetaObject@@XZ @ 1297 NONAME ; struct QMetaObject const & QCameraImageCaptureControl::getStaticMetaObject(void) + ?isAvailable@QCameraImageProcessing@@QBE_NXZ @ 1298 NONAME ; bool QCameraImageProcessing::isAvailable(void) const + ?lockStatusChanged@QCamera@@IAEXW4LockType@1@W4LockStatus@1@W4LockChangeReason@1@@Z @ 1299 NONAME ; void QCamera::lockStatusChanged(enum QCamera::LockType, enum QCamera::LockStatus, enum QCamera::LockChangeReason) + ?qt_metacall@QCameraControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1300 NONAME ; int QCameraControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ?qt_metacast@QCameraFlashControl@@UAEPAXPBD@Z @ 1301 NONAME ; void * QCameraFlashControl::qt_metacast(char const *) + ??1QCamera@@UAE@XZ @ 1302 NONAME ; QCamera::~QCamera(void) + ??0QCameraViewfinder@@QAE@PAVQWidget@@@Z @ 1303 NONAME ; QCameraViewfinder::QCameraViewfinder(class QWidget *) + ??1QCameraExposureControl@@UAE@XZ @ 1304 NONAME ; QCameraExposureControl::~QCameraExposureControl(void) + ?exposureParameterChanged@QCameraExposureControl@@IAEXH@Z @ 1305 NONAME ; void QCameraExposureControl::exposureParameterChanged(int) + ?tr@QCameraExposureControl@@SA?AVQString@@PBD0@Z @ 1306 NONAME ; class QString QCameraExposureControl::tr(char const *, char const *) + ?d_func@QCameraImageCapture@@ABEPBVQCameraImageCapturePrivate@@XZ @ 1307 NONAME ; class QCameraImageCapturePrivate const * QCameraImageCapture::d_func(void) const + ??9QCameraFocusZone@@QBE_NABV0@@Z @ 1308 NONAME ; bool QCameraFocusZone::operator!=(class QCameraFocusZone const &) const + ??1QCameraFocusControl@@UAE@XZ @ 1309 NONAME ; QCameraFocusControl::~QCameraFocusControl(void) + ?setContrast@QCameraImageProcessing@@QAEXH@Z @ 1310 NONAME ; void QCameraImageProcessing::setContrast(int) + ?error@QCameraImageCapture@@IAEXHW4Error@1@ABVQString@@@Z @ 1311 NONAME ; void QCameraImageCapture::error(int, enum QCameraImageCapture::Error, class QString const &) + ?encodingSettings@QCameraImageCapture@@QBE?AVQImageEncoderSettings@@XZ @ 1312 NONAME ; class QImageEncoderSettings QCameraImageCapture::encodingSettings(void) const + ?opticalZoom@QCameraFocus@@QBEMXZ @ 1313 NONAME ; float QCameraFocus::opticalZoom(void) const + ?setCaptureMode@QCamera@@QAEXW4CaptureMode@1@@Z @ 1314 NONAME ; void QCamera::setCaptureMode(enum QCamera::CaptureMode) + ?d_func@QCameraFocus@@AAEPAVQCameraFocusPrivate@@XZ @ 1315 NONAME ; class QCameraFocusPrivate * QCameraFocus::d_func(void) + ?metaObject@QCameraExposureControl@@UBEPBUQMetaObject@@XZ @ 1316 NONAME ; struct QMetaObject const * QCameraExposureControl::metaObject(void) const + ?trUtf8@QCameraFocusControl@@SA?AVQString@@PBD0H@Z @ 1317 NONAME ; class QString QCameraFocusControl::trUtf8(char const *, char const *, int) + ??_EQCameraLocksControl@@UAE@I@Z @ 1318 NONAME ; QCameraLocksControl::~QCameraLocksControl(unsigned int) + ?trUtf8@QCameraFlashControl@@SA?AVQString@@PBD0H@Z @ 1319 NONAME ; class QString QCameraFlashControl::trUtf8(char const *, char const *, int) + ?tr@QCameraImageCapture@@SA?AVQString@@PBD0H@Z @ 1320 NONAME ; class QString QCameraImageCapture::tr(char const *, char const *, int) + ?tr@QCameraImageProcessing@@SA?AVQString@@PBD0@Z @ 1321 NONAME ; class QString QCameraImageProcessing::tr(char const *, char const *) + ?trUtf8@QCameraImageProcessingControl@@SA?AVQString@@PBD0H@Z @ 1322 NONAME ; class QString QCameraImageProcessingControl::trUtf8(char const *, char const *, int) + ?getStaticMetaObject@QCameraFocusControl@@SAABUQMetaObject@@XZ @ 1323 NONAME ; struct QMetaObject const & QCameraFocusControl::getStaticMetaObject(void) + ?getStaticMetaObject@QCameraImageProcessingControl@@SAABUQMetaObject@@XZ @ 1324 NONAME ; struct QMetaObject const & QCameraImageProcessingControl::getStaticMetaObject(void) + ?trUtf8@QCameraImageCaptureControl@@SA?AVQString@@PBD0@Z @ 1325 NONAME ; class QString QCameraImageCaptureControl::trUtf8(char const *, char const *) + ?searchAndLock@QCamera@@QAEXXZ @ 1326 NONAME ; void QCamera::searchAndLock(void) + ?getStaticMetaObject@QCameraExposureControl@@SAABUQMetaObject@@XZ @ 1327 NONAME ; struct QMetaObject const & QCameraExposureControl::getStaticMetaObject(void) + ?contrast@QCameraImageProcessing@@QBEHXZ @ 1328 NONAME ; int QCameraImageProcessing::contrast(void) const + ??_EQCameraImageProcessingControl@@UAE@I@Z @ 1329 NONAME ; QCameraImageProcessingControl::~QCameraImageProcessingControl(unsigned int) + ??_EQCameraControl@@UAE@I@Z @ 1330 NONAME ; QCameraControl::~QCameraControl(unsigned int) + ?staticMetaObject@QCameraFocusControl@@2UQMetaObject@@B @ 1331 NONAME ; struct QMetaObject const QCameraFocusControl::staticMetaObject + ??0QCameraFocusControl@@IAE@PAVQObject@@@Z @ 1332 NONAME ; QCameraFocusControl::QCameraFocusControl(class QObject *) + ?setAutoIsoSensitivity@QCameraExposure@@QAEXXZ @ 1333 NONAME ; void QCameraExposure::setAutoIsoSensitivity(void) + ?qt_metacall@QCameraLocksControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1334 NONAME ; int QCameraLocksControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ?trUtf8@QCameraFlashControl@@SA?AVQString@@PBD0@Z @ 1335 NONAME ; class QString QCameraFlashControl::trUtf8(char const *, char const *) + ?getStaticMetaObject@QCameraImageProcessing@@SAABUQMetaObject@@XZ @ 1336 NONAME ; struct QMetaObject const & QCameraImageProcessing::getStaticMetaObject(void) + ??0QCameraLocksControl@@IAE@PAVQObject@@@Z @ 1337 NONAME ; QCameraLocksControl::QCameraLocksControl(class QObject *) + ?stop@QCamera@@QAEXXZ @ 1338 NONAME ; void QCamera::stop(void) + ?supportedShutterSpeeds@QCameraExposure@@QBE?AV?$QList@M@@PA_N@Z @ 1339 NONAME ; class QList QCameraExposure::supportedShutterSpeeds(bool *) const + ?flashReady@QCameraExposure@@IAEX_N@Z @ 1340 NONAME ; void QCameraExposure::flashReady(bool) + ?tr@QCameraViewfinder@@SA?AVQString@@PBD0@Z @ 1341 NONAME ; class QString QCameraViewfinder::tr(char const *, char const *) + ?whiteBalanceMode@QCameraImageProcessing@@QBE?AW4WhiteBalanceMode@1@XZ @ 1342 NONAME ; enum QCameraImageProcessing::WhiteBalanceMode QCameraImageProcessing::whiteBalanceMode(void) const + ?qt_metacast@QCameraExposure@@UAEPAXPBD@Z @ 1343 NONAME ; void * QCameraExposure::qt_metacast(char const *) + ?flashMode@QCameraExposure@@QBE?AV?$QFlags@W4FlashMode@QCameraExposure@@@@XZ @ 1344 NONAME ; class QFlags QCameraExposure::flashMode(void) const + ??1QCameraViewfinder@@UAE@XZ @ 1345 NONAME ; QCameraViewfinder::~QCameraViewfinder(void) + ?manualWhiteBalance@QCameraImageProcessing@@QBEHXZ @ 1346 NONAME ; int QCameraImageProcessing::manualWhiteBalance(void) const + ?isAvailable@QCameraFocus@@QBE_NXZ @ 1347 NONAME ; bool QCameraFocus::isAvailable(void) const + ?readyForCaptureChanged@QCameraImageCapture@@IAEX_N@Z @ 1348 NONAME ; void QCameraImageCapture::readyForCaptureChanged(bool) + ?metaObject@QCameraExposure@@UBEPBUQMetaObject@@XZ @ 1349 NONAME ; struct QMetaObject const * QCameraExposure::metaObject(void) const + ?d_func@QCamera@@ABEPBVQCameraPrivate@@XZ @ 1350 NONAME ; class QCameraPrivate const * QCamera::d_func(void) const + ?opticalZoomChanged@QCameraFocus@@IAEXM@Z @ 1351 NONAME ; void QCameraFocus::opticalZoomChanged(float) + ?isValid@QCameraFocusZone@@QBE_NXZ @ 1352 NONAME ; bool QCameraFocusZone::isValid(void) const + ?tr@QCameraFocus@@SA?AVQString@@PBD0@Z @ 1353 NONAME ; class QString QCameraFocus::tr(char const *, char const *) + ?staticMetaObject@QCameraExposure@@2UQMetaObject@@B @ 1354 NONAME ; struct QMetaObject const QCameraExposure::staticMetaObject + ?setEncodingSettings@QCameraImageCapture@@QAEXABVQImageEncoderSettings@@@Z @ 1355 NONAME ; void QCameraImageCapture::setEncodingSettings(class QImageEncoderSettings const &) + ?metaObject@QCameraImageCapture@@UBEPBUQMetaObject@@XZ @ 1356 NONAME ; struct QMetaObject const * QCameraImageCapture::metaObject(void) const + ?load@QCamera@@QAEXXZ @ 1357 NONAME ; void QCamera::load(void) + ??0QVideoWidget@@IAE@AAVQVideoWidgetPrivate@@PAVQWidget@@@Z @ 1358 NONAME ; QVideoWidget::QVideoWidget(class QVideoWidgetPrivate &, class QWidget *) + ?setFocusPointMode@QCameraFocus@@QAEXW4FocusPointMode@1@@Z @ 1359 NONAME ; void QCameraFocus::setFocusPointMode(enum QCameraFocus::FocusPointMode) + ?tr@QCameraImageProcessing@@SA?AVQString@@PBD0H@Z @ 1360 NONAME ; class QString QCameraImageProcessing::tr(char const *, char const *, int) + ?staticMetaObject@QCameraFlashControl@@2UQMetaObject@@B @ 1361 NONAME ; struct QMetaObject const QCameraFlashControl::staticMetaObject + ?setManualShutterSpeed@QCameraExposure@@QAEXM@Z @ 1362 NONAME ; void QCameraExposure::setManualShutterSpeed(float) + ?mediaObject@QCameraViewfinder@@UBEPAVQMediaObject@@XZ @ 1363 NONAME ; class QMediaObject * QCameraViewfinder::mediaObject(void) const + ?setAutoAperture@QCameraExposure@@QAEXXZ @ 1364 NONAME ; void QCameraExposure::setAutoAperture(void) + ?tr@QCameraExposure@@SA?AVQString@@PBD0@Z @ 1365 NONAME ; class QString QCameraExposure::tr(char const *, char const *) + ?flashReady@QCameraExposureControl@@IAEX_N@Z @ 1366 NONAME ; void QCameraExposureControl::flashReady(bool) + ??1QCameraImageProcessingControl@@UAE@XZ @ 1367 NONAME ; QCameraImageProcessingControl::~QCameraImageProcessingControl(void) + ??1QCameraFocus@@EAE@XZ @ 1368 NONAME ; QCameraFocus::~QCameraFocus(void) + ?statusChanged@QCamera@@IAEXW4Status@1@@Z @ 1369 NONAME ; void QCamera::statusChanged(enum QCamera::Status) + ?apertureRangeChanged@QCameraExposure@@IAEXXZ @ 1370 NONAME ; void QCameraExposure::apertureRangeChanged(void) + ?getStaticMetaObject@QCameraFocus@@SAABUQMetaObject@@XZ @ 1371 NONAME ; struct QMetaObject const & QCameraFocus::getStaticMetaObject(void) + ??0QCameraImageProcessingControl@@IAE@PAVQObject@@@Z @ 1372 NONAME ; QCameraImageProcessingControl::QCameraImageProcessingControl(class QObject *) + ?setWhiteBalanceMode@QCameraImageProcessing@@QAEXW4WhiteBalanceMode@1@@Z @ 1373 NONAME ; void QCameraImageProcessing::setWhiteBalanceMode(enum QCameraImageProcessing::WhiteBalanceMode) + ??0QCamera@@QAE@ABVQByteArray@@PAVQObject@@@Z @ 1374 NONAME ; QCamera::QCamera(class QByteArray const &, class QObject *) + ?focusZonesChanged@QCameraFocusControl@@IAEXXZ @ 1375 NONAME ; void QCameraFocusControl::focusZonesChanged(void) + ?qt_metacall@QCameraImageCapture@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1376 NONAME ; int QCameraImageCapture::qt_metacall(enum QMetaObject::Call, int, void * *) + ?setStatus@QCameraFocusZone@@QAEXW4FocusZoneStatus@1@@Z @ 1377 NONAME ; void QCameraFocusZone::setStatus(enum QCameraFocusZone::FocusZoneStatus) + ?qt_metacall@QCameraFocusControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1378 NONAME ; int QCameraFocusControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ?isFlashModeSupported@QCameraExposure@@QBE_NV?$QFlags@W4FlashMode@QCameraExposure@@@@@Z @ 1379 NONAME ; bool QCameraExposure::isFlashModeSupported(class QFlags) const + ?imageSaved@QCameraImageCapture@@IAEXHABVQString@@@Z @ 1380 NONAME ; void QCameraImageCapture::imageSaved(int, class QString const &) + ?captureModeChanged@QCamera@@IAEXW4CaptureMode@1@@Z @ 1381 NONAME ; void QCamera::captureModeChanged(enum QCamera::CaptureMode) + ?getStaticMetaObject@QCameraFlashControl@@SAABUQMetaObject@@XZ @ 1382 NONAME ; struct QMetaObject const & QCameraFlashControl::getStaticMetaObject(void) + ?focusPointMode@QCameraFocus@@QBE?AW4FocusPointMode@1@XZ @ 1383 NONAME ; enum QCameraFocus::FocusPointMode QCameraFocus::focusPointMode(void) const + ?digitalZoom@QCameraFocus@@QBEMXZ @ 1384 NONAME ; float QCameraFocus::digitalZoom(void) const + ??8QCameraFocusZone@@QBE_NABV0@@Z @ 1385 NONAME ; bool QCameraFocusZone::operator==(class QCameraFocusZone const &) const + ?sharpeningLevel@QCameraImageProcessing@@QBEHXZ @ 1386 NONAME ; int QCameraImageProcessing::sharpeningLevel(void) const + ?tr@QCamera@@SA?AVQString@@PBD0H@Z @ 1387 NONAME ; class QString QCamera::tr(char const *, char const *, int) + ?setManualIsoSensitivity@QCameraExposure@@QAEXH@Z @ 1388 NONAME ; void QCameraExposure::setManualIsoSensitivity(int) + ?setManualWhiteBalance@QCameraImageProcessing@@QAEXH@Z @ 1389 NONAME ; void QCameraImageProcessing::setManualWhiteBalance(int) + ?isCaptureModeSupported@QCamera@@QBE_NW4CaptureMode@1@@Z @ 1390 NONAME ; bool QCamera::isCaptureModeSupported(enum QCamera::CaptureMode) const + ??0QCameraFlashControl@@IAE@PAVQObject@@@Z @ 1391 NONAME ; QCameraFlashControl::QCameraFlashControl(class QObject *) + ?focusZones@QCameraFocus@@QBE?AV?$QList@VQCameraFocusZone@@@@XZ @ 1392 NONAME ; class QList QCameraFocus::focusZones(void) const + ?shutterSpeed@QCameraExposure@@QBEMXZ @ 1393 NONAME ; float QCameraExposure::shutterSpeed(void) const + ?setManualAperture@QCameraExposure@@QAEXM@Z @ 1394 NONAME ; void QCameraExposure::setManualAperture(float) + ?setVideoOutput@QMediaImageViewer@@QAEXPAVQVideoWidget@@@Z @ 1395 NONAME ; void QMediaImageViewer::setVideoOutput(class QVideoWidget *) + ?trUtf8@QCameraLocksControl@@SA?AVQString@@PBD0H@Z @ 1396 NONAME ; class QString QCameraLocksControl::trUtf8(char const *, char const *, int) + ??1QCameraImageCapture@@UAE@XZ @ 1397 NONAME ; QCameraImageCapture::~QCameraImageCapture(void) + ?focusMode@QCameraFocus@@QBE?AW4FocusMode@1@XZ @ 1398 NONAME ; enum QCameraFocus::FocusMode QCameraFocus::focusMode(void) const + ??1QCameraImageProcessing@@EAE@XZ @ 1399 NONAME ; QCameraImageProcessing::~QCameraImageProcessing(void) + ?setFlashMode@QCameraExposure@@QAEXV?$QFlags@W4FlashMode@QCameraExposure@@@@@Z @ 1400 NONAME ; void QCameraExposure::setFlashMode(class QFlags) + ?trUtf8@QCameraImageProcessingControl@@SA?AVQString@@PBD0@Z @ 1401 NONAME ; class QString QCameraImageProcessingControl::trUtf8(char const *, char const *) + ?lockStatusChanged@QCameraLocksControl@@IAEXW4LockType@QCamera@@W4LockStatus@3@W4LockChangeReason@3@@Z @ 1402 NONAME ; void QCameraLocksControl::lockStatusChanged(enum QCamera::LockType, enum QCamera::LockStatus, enum QCamera::LockChangeReason) + ??_EQCameraFocusControl@@UAE@I@Z @ 1403 NONAME ; QCameraFocusControl::~QCameraFocusControl(unsigned int) + ?lockStatus@QCamera@@QBE?AW4LockStatus@1@XZ @ 1404 NONAME ; enum QCamera::LockStatus QCamera::lockStatus(void) const + ?imageCaptured@QCameraImageCaptureControl@@IAEXHABVQImage@@@Z @ 1405 NONAME ; void QCameraImageCaptureControl::imageCaptured(int, class QImage const &) + ?aperture@QCameraExposure@@QBEMXZ @ 1406 NONAME ; float QCameraExposure::aperture(void) const + ?staticMetaObject@QCameraImageCaptureControl@@2UQMetaObject@@B @ 1407 NONAME ; struct QMetaObject const QCameraImageCaptureControl::staticMetaObject + ?isWhiteBalanceModeSupported@QCameraImageProcessing@@QBE_NW4WhiteBalanceMode@1@@Z @ 1408 NONAME ; bool QCameraImageProcessing::isWhiteBalanceModeSupported(enum QCameraImageProcessing::WhiteBalanceMode) const + ?maximumOpticalZoom@QCameraFocus@@QBEMXZ @ 1409 NONAME ; float QCameraFocus::maximumOpticalZoom(void) const + ?qt_metacast@QCameraFocus@@UAEPAXPBD@Z @ 1410 NONAME ; void * QCameraFocus::qt_metacast(char const *) + ?imageProcessing@QCamera@@QBEPAVQCameraImageProcessing@@XZ @ 1411 NONAME ; class QCameraImageProcessing * QCamera::imageProcessing(void) const + ?digitalZoomChanged@QCameraFocusControl@@IAEXM@Z @ 1412 NONAME ; void QCameraFocusControl::digitalZoomChanged(float) + ??0QCameraExposureControl@@IAE@PAVQObject@@@Z @ 1413 NONAME ; QCameraExposureControl::QCameraExposureControl(class QObject *) + ?setMediaObject@QCameraImageCapture@@MAE_NPAVQMediaObject@@@Z @ 1414 NONAME ; bool QCameraImageCapture::setMediaObject(class QMediaObject *) + ?getStaticMetaObject@QCameraControl@@SAABUQMetaObject@@XZ @ 1415 NONAME ; struct QMetaObject const & QCameraControl::getStaticMetaObject(void) + ?setFocusMode@QCameraFocus@@QAEXW4FocusMode@1@@Z @ 1416 NONAME ; void QCameraFocus::setFocusMode(enum QCameraFocus::FocusMode) + ?isoSensitivityChanged@QCameraExposure@@IAEXH@Z @ 1417 NONAME ; void QCameraExposure::isoSensitivityChanged(int) + ?supportedImageCodecs@QCameraImageCapture@@QBE?AVQStringList@@XZ @ 1418 NONAME ; class QStringList QCameraImageCapture::supportedImageCodecs(void) const + ?imageCaptured@QCameraImageCapture@@IAEXHABVQImage@@@Z @ 1419 NONAME ; void QCameraImageCapture::imageCaptured(int, class QImage const &) + ?qt_metacast@QCameraLocksControl@@UAEPAXPBD@Z @ 1420 NONAME ; void * QCameraLocksControl::qt_metacast(char const *) + ?qt_metacast@QCameraFocusControl@@UAEPAXPBD@Z @ 1421 NONAME ; void * QCameraFocusControl::qt_metacast(char const *) + ?trUtf8@QCameraImageCaptureControl@@SA?AVQString@@PBD0H@Z @ 1422 NONAME ; class QString QCameraImageCaptureControl::trUtf8(char const *, char const *, int) + ?trUtf8@QCameraViewfinder@@SA?AVQString@@PBD0@Z @ 1423 NONAME ; class QString QCameraViewfinder::trUtf8(char const *, char const *) + ?getStaticMetaObject@QCameraExposure@@SAABUQMetaObject@@XZ @ 1424 NONAME ; struct QMetaObject const & QCameraExposure::getStaticMetaObject(void) + ?trUtf8@QCamera@@SA?AVQString@@PBD0H@Z @ 1425 NONAME ; class QString QCamera::trUtf8(char const *, char const *, int) + ?tr@QCameraExposureControl@@SA?AVQString@@PBD0H@Z @ 1426 NONAME ; class QString QCameraExposureControl::tr(char const *, char const *, int) + ?trUtf8@QCameraFocus@@SA?AVQString@@PBD0H@Z @ 1427 NONAME ; class QString QCameraFocus::trUtf8(char const *, char const *, int) + ?playlist@QMediaImageViewer@@QBEPAVQMediaPlaylist@@XZ @ 1428 NONAME ; class QMediaPlaylist * QMediaImageViewer::playlist(void) const + ?qt_metacall@QCameraViewfinder@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1429 NONAME ; int QCameraViewfinder::qt_metacall(enum QMetaObject::Call, int, void * *) + ?unlock@QCamera@@QAEXXZ @ 1430 NONAME ; void QCamera::unlock(void) + ?supportedIsoSensitivities@QCameraExposure@@QBE?AV?$QList@H@@PA_N@Z @ 1431 NONAME ; class QList QCameraExposure::supportedIsoSensitivities(bool *) const + ?staticMetaObject@QCameraImageProcessing@@2UQMetaObject@@B @ 1432 NONAME ; struct QMetaObject const QCameraImageProcessing::staticMetaObject + ?staticMetaObject@QCameraViewfinder@@2UQMetaObject@@B @ 1433 NONAME ; struct QMetaObject const QCameraViewfinder::staticMetaObject + ?d_func@QCameraImageProcessing@@ABEPBVQCameraImageProcessingPrivate@@XZ @ 1434 NONAME ; class QCameraImageProcessingPrivate const * QCameraImageProcessing::d_func(void) const + ?isAvailable@QCameraImageCapture@@QBE_NXZ @ 1435 NONAME ; bool QCameraImageCapture::isAvailable(void) const + ?setExposureCompensation@QCameraExposure@@QAEXM@Z @ 1436 NONAME ; void QCameraExposure::setExposureCompensation(float) + ??1QCameraExposure@@EAE@XZ @ 1437 NONAME ; QCameraExposure::~QCameraExposure(void) + ?isAvailable@QCameraExposure@@QBE_NXZ @ 1438 NONAME ; bool QCameraExposure::isAvailable(void) const + ?qt_metacall@QCameraImageProcessingControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1439 NONAME ; int QCameraImageProcessingControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ?setDenoisingLevel@QCameraImageProcessing@@QAEXH@Z @ 1440 NONAME ; void QCameraImageProcessing::setDenoisingLevel(int) + ?tr@QCameraFocusControl@@SA?AVQString@@PBD0H@Z @ 1441 NONAME ; class QString QCameraFocusControl::tr(char const *, char const *, int) + ?tr@QCameraFlashControl@@SA?AVQString@@PBD0H@Z @ 1442 NONAME ; class QString QCameraFlashControl::tr(char const *, char const *, int) + ?area@QCameraFocusZone@@QBE?AVQRectF@@XZ @ 1443 NONAME ; class QRectF QCameraFocusZone::area(void) const + ??_EQCameraImageCapture@@UAE@I@Z @ 1444 NONAME ; QCameraImageCapture::~QCameraImageCapture(unsigned int) + ?status@QCamera@@QBE?AW4Status@1@XZ @ 1445 NONAME ; enum QCamera::Status QCamera::status(void) const + ?isSharpeningSupported@QCameraImageProcessing@@QBE_NXZ @ 1446 NONAME ; bool QCameraImageProcessing::isSharpeningSupported(void) const + ?mediaObject@QCameraImageCapture@@UBEPAVQMediaObject@@XZ @ 1447 NONAME ; class QMediaObject * QCameraImageCapture::mediaObject(void) const + ?trUtf8@QCameraViewfinder@@SA?AVQString@@PBD0H@Z @ 1448 NONAME ; class QString QCameraViewfinder::trUtf8(char const *, char const *, int) + ?d_func@QCameraImageCapture@@AAEPAVQCameraImageCapturePrivate@@XZ @ 1449 NONAME ; class QCameraImageCapturePrivate * QCameraImageCapture::d_func(void) + ?status@QCameraFocusZone@@QBE?AW4FocusZoneStatus@1@XZ @ 1450 NONAME ; enum QCameraFocusZone::FocusZoneStatus QCameraFocusZone::status(void) const + ?error@QCameraControl@@IAEXHABVQString@@@Z @ 1451 NONAME ; void QCameraControl::error(int, class QString const &) + ?metaObject@QCameraImageProcessingControl@@UBEPBUQMetaObject@@XZ @ 1452 NONAME ; struct QMetaObject const * QCameraImageProcessingControl::metaObject(void) const + ?qt_metacall@QCameraFocus@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1453 NONAME ; int QCameraFocus::qt_metacall(enum QMetaObject::Call, int, void * *) + ??0QCameraFocusZone@@QAE@ABV0@@Z @ 1454 NONAME ; QCameraFocusZone::QCameraFocusZone(class QCameraFocusZone const &) + ?setSharpeningLevel@QCameraImageProcessing@@QAEXH@Z @ 1455 NONAME ; void QCameraImageProcessing::setSharpeningLevel(int) + ?qt_metacast@QCameraImageCapture@@UAEPAXPBD@Z @ 1456 NONAME ; void * QCameraImageCapture::qt_metacast(char const *) + ?tr@QCameraImageProcessingControl@@SA?AVQString@@PBD0H@Z @ 1457 NONAME ; class QString QCameraImageProcessingControl::tr(char const *, char const *, int) + ?captureMode@QCamera@@QBE?AW4CaptureMode@1@XZ @ 1458 NONAME ; enum QCamera::CaptureMode QCamera::captureMode(void) const + ?isDenoisingSupported@QCameraImageProcessing@@QBE_NXZ @ 1459 NONAME ; bool QCameraImageProcessing::isDenoisingSupported(void) const + ?shutterSpeedRangeChanged@QCameraExposure@@IAEXXZ @ 1460 NONAME ; void QCameraExposure::shutterSpeedRangeChanged(void) + ??0QCameraFocusZone@@QAE@ABVQRectF@@W4FocusZoneStatus@0@@Z @ 1461 NONAME ; QCameraFocusZone::QCameraFocusZone(class QRectF const &, enum QCameraFocusZone::FocusZoneStatus) + ?qt_metacast@QCameraControl@@UAEPAXPBD@Z @ 1462 NONAME ; void * QCameraControl::qt_metacast(char const *) + ?statusChanged@QCameraControl@@IAEXW4Status@QCamera@@@Z @ 1463 NONAME ; void QCameraControl::statusChanged(enum QCamera::Status) + ?zoomTo@QCameraFocus@@QAEXMM@Z @ 1464 NONAME ; void QCameraFocus::zoomTo(float, float) + ??1QCameraFocusZone@@QAE@XZ @ 1465 NONAME ; QCameraFocusZone::~QCameraFocusZone(void) + ?d_func@QCameraExposure@@ABEPBVQCameraExposurePrivate@@XZ @ 1466 NONAME ; class QCameraExposurePrivate const * QCameraExposure::d_func(void) const + ?tr@QCameraViewfinder@@SA?AVQString@@PBD0H@Z @ 1467 NONAME ; class QString QCameraViewfinder::tr(char const *, char const *, int) + ?qt_metacall@QCamera@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1468 NONAME ; int QCamera::qt_metacall(enum QMetaObject::Call, int, void * *) + ?availabilityError@QCameraImageCapture@@QBE?AW4AvailabilityError@QtMultimediaKit@@XZ @ 1469 NONAME ; enum QtMultimediaKit::AvailabilityError QCameraImageCapture::availabilityError(void) const + ??_EQCamera@@UAE@I@Z @ 1470 NONAME ; QCamera::~QCamera(unsigned int) + ?trUtf8@QCameraControl@@SA?AVQString@@PBD0H@Z @ 1471 NONAME ; class QString QCameraControl::trUtf8(char const *, char const *, int) + ?metaObject@QCameraFocusControl@@UBEPBUQMetaObject@@XZ @ 1472 NONAME ; struct QMetaObject const * QCameraFocusControl::metaObject(void) const + ?metaObject@QCameraFlashControl@@UBEPBUQMetaObject@@XZ @ 1473 NONAME ; struct QMetaObject const * QCameraFlashControl::metaObject(void) const + ?maximumDigitalZoom@QCameraFocus@@QBEMXZ @ 1474 NONAME ; float QCameraFocus::maximumDigitalZoom(void) const + ?error@QCamera@@IAEXW4Error@1@@Z @ 1475 NONAME ; void QCamera::error(enum QCamera::Error) + ?isFocusModeSupported@QCameraFocus@@QBE_NW4FocusMode@1@@Z @ 1476 NONAME ; bool QCameraFocus::isFocusModeSupported(enum QCameraFocus::FocusMode) const + ?locked@QCamera@@IAEXXZ @ 1477 NONAME ; void QCamera::locked(void) + ?supportedResolutions@QCameraImageCapture@@QBE?AV?$QList@VQSize@@@@ABVQImageEncoderSettings@@PA_N@Z @ 1478 NONAME ; class QList QCameraImageCapture::supportedResolutions(class QImageEncoderSettings const &, bool *) const + ?qt_metacall@QCameraImageCaptureControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1479 NONAME ; int QCameraImageCaptureControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ?tr@QCameraLocksControl@@SA?AVQString@@PBD0@Z @ 1480 NONAME ; class QString QCameraLocksControl::tr(char const *, char const *) + ?stateChanged@QCamera@@IAEXW4State@1@@Z @ 1481 NONAME ; void QCamera::stateChanged(enum QCamera::State) + ?lockStatus@QCamera@@QBE?AW4LockStatus@1@W4LockType@1@@Z @ 1482 NONAME ; enum QCamera::LockStatus QCamera::lockStatus(enum QCamera::LockType) const + ?exposureMode@QCameraExposure@@QBE?AW4ExposureMode@1@XZ @ 1483 NONAME ; enum QCameraExposure::ExposureMode QCameraExposure::exposureMode(void) const + ??1QCameraLocksControl@@UAE@XZ @ 1484 NONAME ; QCameraLocksControl::~QCameraLocksControl(void) + ?requestedLocks@QCamera@@QBE?AV?$QFlags@W4LockType@QCamera@@@@XZ @ 1485 NONAME ; class QFlags QCamera::requestedLocks(void) const + ?trUtf8@QCameraControl@@SA?AVQString@@PBD0@Z @ 1486 NONAME ; class QString QCameraControl::trUtf8(char const *, char const *) + ?supportedLocks@QCamera@@QBE?AV?$QFlags@W4LockType@QCamera@@@@XZ @ 1487 NONAME ; class QFlags QCamera::supportedLocks(void) const + ??0QCameraImageCapture@@QAE@PAVQMediaObject@@PAVQObject@@@Z @ 1488 NONAME ; QCameraImageCapture::QCameraImageCapture(class QMediaObject *, class QObject *) + ?d_func@QCameraImageProcessing@@AAEPAVQCameraImageProcessingPrivate@@XZ @ 1489 NONAME ; class QCameraImageProcessingPrivate * QCameraImageProcessing::d_func(void) + ?isMeteringModeSupported@QCameraExposure@@QBE_NW4MeteringMode@1@@Z @ 1490 NONAME ; bool QCameraExposure::isMeteringModeSupported(enum QCameraExposure::MeteringMode) const + ?start@QCamera@@QAEXXZ @ 1491 NONAME ; void QCamera::start(void) + ?staticMetaObject@QCamera@@2UQMetaObject@@B @ 1492 NONAME ; struct QMetaObject const QCamera::staticMetaObject + ??0QCamera@@QAE@PAVQObject@@PAVQMediaServiceProvider@@@Z @ 1493 NONAME ; QCamera::QCamera(class QObject *, class QMediaServiceProvider *) + ?tr@QCameraImageCapture@@SA?AVQString@@PBD0@Z @ 1494 NONAME ; class QString QCameraImageCapture::tr(char const *, char const *) + ?trUtf8@QCameraExposure@@SA?AVQString@@PBD0H@Z @ 1495 NONAME ; class QString QCameraExposure::trUtf8(char const *, char const *, int) + ?staticMetaObject@QCameraImageProcessingControl@@2UQMetaObject@@B @ 1496 NONAME ; struct QMetaObject const QCameraImageProcessingControl::staticMetaObject + ?lockStatusChanged@QCamera@@IAEXW4LockStatus@1@W4LockChangeReason@1@@Z @ 1497 NONAME ; void QCamera::lockStatusChanged(enum QCamera::LockStatus, enum QCamera::LockChangeReason) + ?setAutoShutterSpeed@QCameraExposure@@QAEXXZ @ 1498 NONAME ; void QCameraExposure::setAutoShutterSpeed(void) + ?captureModeChanged@QCameraControl@@IAEXW4CaptureMode@QCamera@@@Z @ 1499 NONAME ; void QCameraControl::captureModeChanged(enum QCamera::CaptureMode) + ?trUtf8@QCameraImageProcessing@@SA?AVQString@@PBD0H@Z @ 1500 NONAME ; class QString QCameraImageProcessing::trUtf8(char const *, char const *, int) + ??_EQCameraExposure@@UAE@I@Z @ 1501 NONAME ; QCameraExposure::~QCameraExposure(unsigned int) + ?flashReady@QCameraFlashControl@@IAEX_N@Z @ 1502 NONAME ; void QCameraFlashControl::flashReady(bool) + ??_EQCameraImageProcessing@@UAE@I@Z @ 1503 NONAME ; QCameraImageProcessing::~QCameraImageProcessing(unsigned int) + ?imageExposed@QCameraImageCapture@@IAEXH@Z @ 1504 NONAME ; void QCameraImageCapture::imageExposed(int) + ?deviceDescription@QCamera@@SA?AVQString@@ABVQByteArray@@@Z @ 1505 NONAME ; class QString QCamera::deviceDescription(class QByteArray const &) + ?staticMetaObject@QCameraImageCapture@@2UQMetaObject@@B @ 1506 NONAME ; struct QMetaObject const QCameraImageCapture::staticMetaObject + ?qt_metacast@QCameraExposureControl@@UAEPAXPBD@Z @ 1507 NONAME ; void * QCameraExposureControl::qt_metacast(char const *) + ??0QCameraImageProcessing@@AAE@PAVQCamera@@@Z @ 1508 NONAME ; QCameraImageProcessing::QCameraImageProcessing(class QCamera *) + ?tr@QCameraLocksControl@@SA?AVQString@@PBD0H@Z @ 1509 NONAME ; class QString QCameraLocksControl::tr(char const *, char const *, int) + ?unload@QCamera@@QAEXXZ @ 1510 NONAME ; void QCamera::unload(void) + ?setVideoOutput@QMediaImageViewer@@QAEXPAVQGraphicsVideoItem@@@Z @ 1511 NONAME ; void QMediaImageViewer::setVideoOutput(class QGraphicsVideoItem *) + ?setCustomFocusPoint@QCameraFocus@@QAEXABVQPointF@@@Z @ 1512 NONAME ; void QCameraFocus::setCustomFocusPoint(class QPointF const &) + ?trUtf8@QCameraFocus@@SA?AVQString@@PBD0@Z @ 1513 NONAME ; class QString QCameraFocus::trUtf8(char const *, char const *) + ?qt_metacall@QCameraFlashControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1514 NONAME ; int QCameraFlashControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ?tr@QCameraFocusControl@@SA?AVQString@@PBD0@Z @ 1515 NONAME ; class QString QCameraFocusControl::tr(char const *, char const *) + ?d_func@QCameraFocus@@ABEPBVQCameraFocusPrivate@@XZ @ 1516 NONAME ; class QCameraFocusPrivate const * QCameraFocus::d_func(void) const + ?getStaticMetaObject@QCamera@@SAABUQMetaObject@@XZ @ 1517 NONAME ; struct QMetaObject const & QCamera::getStaticMetaObject(void) + ?qt_metacast@QCameraViewfinder@@UAEPAXPBD@Z @ 1518 NONAME ; void * QCameraViewfinder::qt_metacast(char const *) + ?trUtf8@QCameraImageCapture@@SA?AVQString@@PBD0H@Z @ 1519 NONAME ; class QString QCameraImageCapture::trUtf8(char const *, char const *, int) + ?tr@QCameraControl@@SA?AVQString@@PBD0@Z @ 1520 NONAME ; class QString QCameraControl::tr(char const *, char const *) + ?apertureChanged@QCameraExposure@@IAEXM@Z @ 1521 NONAME ; void QCameraExposure::apertureChanged(float) + ?d_func@QCamera@@AAEPAVQCameraPrivate@@XZ @ 1522 NONAME ; class QCameraPrivate * QCamera::d_func(void) + ??_EQCameraFocus@@UAE@I@Z @ 1523 NONAME ; QCameraFocus::~QCameraFocus(unsigned int) + ??_EQCameraImageCaptureControl@@UAE@I@Z @ 1524 NONAME ; QCameraImageCaptureControl::~QCameraImageCaptureControl(unsigned int) + ?imageCodecDescription@QCameraImageCapture@@QBE?AVQString@@ABV2@@Z @ 1525 NONAME ; class QString QCameraImageCapture::imageCodecDescription(class QString const &) const + ??_EQCameraExposureControl@@UAE@I@Z @ 1526 NONAME ; QCameraExposureControl::~QCameraExposureControl(unsigned int) + ?setSaturation@QCameraImageProcessing@@QAEXH@Z @ 1527 NONAME ; void QCameraImageProcessing::setSaturation(int) + ?tr@QCameraImageProcessingControl@@SA?AVQString@@PBD0@Z @ 1528 NONAME ; class QString QCameraImageProcessingControl::tr(char const *, char const *) + ?setMeteringMode@QCameraExposure@@QAEXW4MeteringMode@1@@Z @ 1529 NONAME ; void QCameraExposure::setMeteringMode(enum QCameraExposure::MeteringMode) + ?isFlashReady@QCameraExposure@@QBE_NXZ @ 1530 NONAME ; bool QCameraExposure::isFlashReady(void) const + ?denoisingLevel@QCameraImageProcessing@@QBEHXZ @ 1531 NONAME ; int QCameraImageProcessing::denoisingLevel(void) const + ?qt_metacast@QCameraImageProcessing@@UAEPAXPBD@Z @ 1532 NONAME ; void * QCameraImageProcessing::qt_metacast(char const *) + ??1QCameraFlashControl@@UAE@XZ @ 1533 NONAME ; QCameraFlashControl::~QCameraFlashControl(void) + ?tr@QCameraFocus@@SA?AVQString@@PBD0H@Z @ 1534 NONAME ; class QString QCameraFocus::tr(char const *, char const *, int) + ?metaObject@QCameraControl@@UBEPBUQMetaObject@@XZ @ 1535 NONAME ; struct QMetaObject const * QCameraControl::metaObject(void) const + ?setNativeResolution@QAbstractVideoSurface@@IAEXABVQSize@@@Z @ 1536 NONAME ; void QAbstractVideoSurface::setNativeResolution(class QSize const &) + ?searchAndLock@QCamera@@QAEXV?$QFlags@W4LockType@QCamera@@@@@Z @ 1537 NONAME ; void QCamera::searchAndLock(class QFlags) + ?meteringMode@QCameraExposure@@QBE?AW4MeteringMode@1@XZ @ 1538 NONAME ; enum QCameraExposure::MeteringMode QCameraExposure::meteringMode(void) const + ??_EQCameraFlashControl@@UAE@I@Z @ 1539 NONAME ; QCameraFlashControl::~QCameraFlashControl(unsigned int) + ?d_func@QCameraViewfinder@@AAEPAVQCameraViewfinderPrivate@@XZ @ 1540 NONAME ; class QCameraViewfinderPrivate * QCameraViewfinder::d_func(void) + ?metaObject@QCameraFocus@@UBEPBUQMetaObject@@XZ @ 1541 NONAME ; struct QMetaObject const * QCameraFocus::metaObject(void) const + ?metaObject@QCameraLocksControl@@UBEPBUQMetaObject@@XZ @ 1542 NONAME ; struct QMetaObject const * QCameraLocksControl::metaObject(void) const + ?errorString@QCamera@@QBE?AVQString@@XZ @ 1543 NONAME ; class QString QCamera::errorString(void) const + ?staticMetaObject@QCameraExposureControl@@2UQMetaObject@@B @ 1544 NONAME ; struct QMetaObject const QCameraExposureControl::staticMetaObject + ?supportedApertures@QCameraExposure@@QBE?AV?$QList@M@@PA_N@Z @ 1545 NONAME ; class QList QCameraExposure::supportedApertures(bool *) const + ?focusZonesChanged@QCameraFocus@@IAEXXZ @ 1546 NONAME ; void QCameraFocus::focusZonesChanged(void) + ?qt_metacast@QCameraImageCaptureControl@@UAEPAXPBD@Z @ 1547 NONAME ; void * QCameraImageCaptureControl::qt_metacast(char const *) + ?tr@QCameraControl@@SA?AVQString@@PBD0H@Z @ 1548 NONAME ; class QString QCameraControl::tr(char const *, char const *, int) + ?digitalZoomChanged@QCameraFocus@@IAEXM@Z @ 1549 NONAME ; void QCameraFocus::digitalZoomChanged(float) + ?metaObject@QCamera@@UBEPBUQMetaObject@@XZ @ 1550 NONAME ; struct QMetaObject const * QCamera::metaObject(void) const + ?trUtf8@QCameraExposureControl@@SA?AVQString@@PBD0@Z @ 1551 NONAME ; class QString QCameraExposureControl::trUtf8(char const *, char const *) + ?imageExposed@QCameraImageCaptureControl@@IAEXH@Z @ 1552 NONAME ; void QCameraImageCaptureControl::imageExposed(int) + ?tr@QCameraImageCaptureControl@@SA?AVQString@@PBD0@Z @ 1553 NONAME ; class QString QCameraImageCaptureControl::tr(char const *, char const *) + ?trUtf8@QCameraLocksControl@@SA?AVQString@@PBD0@Z @ 1554 NONAME ; class QString QCameraLocksControl::trUtf8(char const *, char const *) + ?isAvailable@QCamera@@UBE_NXZ @ 1555 NONAME ; bool QCamera::isAvailable(void) const + ?stateChanged@QCameraControl@@IAEXW4State@QCamera@@@Z @ 1556 NONAME ; void QCameraControl::stateChanged(enum QCamera::State) + ?nativeResolution@QAbstractVideoSurface@@QBE?AVQSize@@XZ @ 1557 NONAME ; class QSize QAbstractVideoSurface::nativeResolution(void) const + ??0QCameraFocusZone@@QAE@XZ @ 1558 NONAME ; QCameraFocusZone::QCameraFocusZone(void) + ?trUtf8@QCameraImageProcessing@@SA?AVQString@@PBD0@Z @ 1559 NONAME ; class QString QCameraImageProcessing::trUtf8(char const *, char const *) + ?exposureParameterRangeChanged@QCameraExposureControl@@IAEXH@Z @ 1560 NONAME ; void QCameraExposureControl::exposureParameterRangeChanged(int) + ?lockFailed@QCamera@@IAEXXZ @ 1561 NONAME ; void QCamera::lockFailed(void) + ?d_func@QCameraExposure@@AAEPAVQCameraExposurePrivate@@XZ @ 1562 NONAME ; class QCameraExposurePrivate * QCameraExposure::d_func(void) + ?isoSensitivity@QCameraExposure@@QBEHXZ @ 1563 NONAME ; int QCameraExposure::isoSensitivity(void) const + ?qt_metacall@QCameraExposureControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1564 NONAME ; int QCameraExposureControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ?setExposureMode@QCameraExposure@@QAEXW4ExposureMode@1@@Z @ 1565 NONAME ; void QCameraExposure::setExposureMode(enum QCameraExposure::ExposureMode) + ?d_func@QCameraViewfinder@@ABEPBVQCameraViewfinderPrivate@@XZ @ 1566 NONAME ; class QCameraViewfinderPrivate const * QCameraViewfinder::d_func(void) const + ?trUtf8@QCameraImageCapture@@SA?AVQString@@PBD0@Z @ 1567 NONAME ; class QString QCameraImageCapture::trUtf8(char const *, char const *) + ?metaObject@QCameraImageProcessing@@UBEPBUQMetaObject@@XZ @ 1568 NONAME ; struct QMetaObject const * QCameraImageProcessing::metaObject(void) const + ?setMediaObject@QCameraViewfinder@@MAE_NPAVQMediaObject@@@Z @ 1569 NONAME ; bool QCameraViewfinder::setMediaObject(class QMediaObject *) + ?capture@QCameraImageCapture@@QAEHABVQString@@@Z @ 1570 NONAME ; int QCameraImageCapture::capture(class QString const &) + ??0QCameraImageCaptureControl@@IAE@PAVQObject@@@Z @ 1571 NONAME ; QCameraImageCaptureControl::QCameraImageCaptureControl(class QObject *) + ?trUtf8@QCameraExposureControl@@SA?AVQString@@PBD0H@Z @ 1572 NONAME ; class QString QCameraExposureControl::trUtf8(char const *, char const *, int) + ?tr@QCamera@@SA?AVQString@@PBD0@Z @ 1573 NONAME ; class QString QCamera::tr(char const *, char const *) + ?setViewfinder@QCamera@@QAEXPAVQVideoWidget@@@Z @ 1574 NONAME ; void QCamera::setViewfinder(class QVideoWidget *) + ?tr@QCameraFlashControl@@SA?AVQString@@PBD0@Z @ 1575 NONAME ; class QString QCameraFlashControl::tr(char const *, char const *) + ?customFocusPoint@QCameraFocus@@QBE?AVQPointF@@XZ @ 1576 NONAME ; class QPointF QCameraFocus::customFocusPoint(void) const + ??0QCameraExposure@@AAE@PAVQCamera@@@Z @ 1577 NONAME ; QCameraExposure::QCameraExposure(class QCamera *) + ?shutterSpeedChanged@QCameraExposure@@IAEXM@Z @ 1578 NONAME ; void QCameraExposure::shutterSpeedChanged(float) + ?qt_metacast@QCameraImageProcessingControl@@UAEPAXPBD@Z @ 1579 NONAME ; void * QCameraImageProcessingControl::qt_metacast(char const *) + ?error@QCameraImageCapture@@QBE?AW4Error@1@XZ @ 1580 NONAME ; enum QCameraImageCapture::Error QCameraImageCapture::error(void) const + ?state@QCamera@@QBE?AW4State@1@XZ @ 1581 NONAME ; enum QCamera::State QCamera::state(void) const + ?availabilityError@QCamera@@UBE?AW4AvailabilityError@QtMultimediaKit@@XZ @ 1582 NONAME ; enum QtMultimediaKit::AvailabilityError QCamera::availabilityError(void) const + ?cancelCapture@QCameraImageCapture@@QAEXXZ @ 1583 NONAME ; void QCameraImageCapture::cancelCapture(void) + ?trUtf8@QCamera@@SA?AVQString@@PBD0@Z @ 1584 NONAME ; class QString QCamera::trUtf8(char const *, char const *) + ?isExposureModeSupported@QCameraExposure@@QBE_NW4ExposureMode@1@@Z @ 1585 NONAME ; bool QCameraExposure::isExposureModeSupported(enum QCameraExposure::ExposureMode) const + ??0QCameraControl@@IAE@PAVQObject@@@Z @ 1586 NONAME ; QCameraControl::QCameraControl(class QObject *) + ?tr@QCameraExposure@@SA?AVQString@@PBD0H@Z @ 1587 NONAME ; class QString QCameraExposure::tr(char const *, char const *, int) + ?getStaticMetaObject@QCameraViewfinder@@SAABUQMetaObject@@XZ @ 1588 NONAME ; struct QMetaObject const & QCameraViewfinder::getStaticMetaObject(void) + ?stop@QSoundEffect@@QAEXXZ @ 1589 NONAME ; void QSoundEffect::stop(void) + ?loadedChanged@QSoundEffect@@IAEXXZ @ 1590 NONAME ; void QSoundEffect::loadedChanged(void) + ?isLoaded@QSoundEffect@@QBE_NXZ @ 1591 NONAME ; bool QSoundEffect::isLoaded(void) const + ?loopCountChanged@QSoundEffect@@IAEXXZ @ 1592 NONAME ; void QSoundEffect::loopCountChanged(void) + ?maximumOpticalZoomChanged@QCameraFocusControl@@IAEXM@Z @ 1593 NONAME ; void QCameraFocusControl::maximumOpticalZoomChanged(float) + ?maximumDigitalZoomChanged@QCameraFocus@@IAEXM@Z @ 1594 NONAME ; void QCameraFocus::maximumDigitalZoomChanged(float) + ?loopCount@QSoundEffect@@QBEHXZ @ 1595 NONAME ; int QSoundEffect::loopCount(void) const + ?supportedMimeTypes@QSoundEffect@@SA?AVQStringList@@XZ @ 1596 NONAME ; class QStringList QSoundEffect::supportedMimeTypes(void) + ?setLoopCount@QSoundEffect@@QAEXH@Z @ 1597 NONAME ; void QSoundEffect::setLoopCount(int) + ?maximumDigitalZoomChanged@QCameraFocusControl@@IAEXM@Z @ 1598 NONAME ; void QCameraFocusControl::maximumDigitalZoomChanged(float) + ?maximumOpticalZoomChanged@QCameraFocus@@IAEXM@Z @ 1599 NONAME ; void QCameraFocus::maximumOpticalZoomChanged(float) + ?status@QSoundEffect@@QBE?AW4Status@1@XZ @ 1600 NONAME ; enum QSoundEffect::Status QSoundEffect::status(void) const + ?playingChanged@QSoundEffect@@IAEXXZ @ 1601 NONAME ; void QSoundEffect::playingChanged(void) + ?isPlaying@QSoundEffect@@QBE_NXZ @ 1602 NONAME ; bool QSoundEffect::isPlaying(void) const + ?statusChanged@QSoundEffect@@IAEXXZ @ 1603 NONAME ; void QSoundEffect::statusChanged(void) + ?qt_metacall@QMediaNetworkAccessControl@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1604 NONAME ; int QMediaNetworkAccessControl::qt_metacall(enum QMetaObject::Call, int, void * *) + ?getStaticMetaObject@QMediaNetworkAccessControl@@SAABUQMetaObject@@XZ @ 1605 NONAME ; struct QMetaObject const & QMediaNetworkAccessControl::getStaticMetaObject(void) + ?tr@QMediaNetworkAccessControl@@SA?AVQString@@PBD0H@Z @ 1606 NONAME ; class QString QMediaNetworkAccessControl::tr(char const *, char const *, int) + ?setViewfinder@QCamera@@QAEXPAVQAbstractVideoSurface@@@Z @ 1607 NONAME ; void QCamera::setViewfinder(class QAbstractVideoSurface *) + ?trUtf8@QMediaNetworkAccessControl@@SA?AVQString@@PBD0@Z @ 1608 NONAME ; class QString QMediaNetworkAccessControl::trUtf8(char const *, char const *) + ?metaObject@QMediaNetworkAccessControl@@UBEPBUQMetaObject@@XZ @ 1609 NONAME ; struct QMetaObject const * QMediaNetworkAccessControl::metaObject(void) const + ?staticMetaObject@QMediaNetworkAccessControl@@2UQMetaObject@@B @ 1610 NONAME ; struct QMetaObject const QMediaNetworkAccessControl::staticMetaObject + ?setNetworkConfigurations@QMediaPlayer@@QAEXABV?$QList@VQNetworkConfiguration@@@@@Z @ 1611 NONAME ; void QMediaPlayer::setNetworkConfigurations(class QList const &) + ?setVideoOutput@QMediaPlayer@@QAEXPAVQAbstractVideoSurface@@@Z @ 1612 NONAME ; void QMediaPlayer::setVideoOutput(class QAbstractVideoSurface *) + ?networkConfigurationChanged@QMediaPlayer@@IAEXABVQNetworkConfiguration@@@Z @ 1613 NONAME ; void QMediaPlayer::networkConfigurationChanged(class QNetworkConfiguration const &) + ??_EQMediaNetworkAccessControl@@UAE@I@Z @ 1614 NONAME ; QMediaNetworkAccessControl::~QMediaNetworkAccessControl(unsigned int) + ??0QMediaNetworkAccessControl@@IAE@PAVQObject@@@Z @ 1615 NONAME ; QMediaNetworkAccessControl::QMediaNetworkAccessControl(class QObject *) + ?trUtf8@QMediaNetworkAccessControl@@SA?AVQString@@PBD0H@Z @ 1616 NONAME ; class QString QMediaNetworkAccessControl::trUtf8(char const *, char const *, int) + ?currentNetworkConfiguration@QMediaPlayer@@QBE?AVQNetworkConfiguration@@XZ @ 1617 NONAME ; class QNetworkConfiguration QMediaPlayer::currentNetworkConfiguration(void) const + ??1QMediaNetworkAccessControl@@UAE@XZ @ 1618 NONAME ; QMediaNetworkAccessControl::~QMediaNetworkAccessControl(void) + ?setVideoOutput@QMediaImageViewer@@QAEXPAVQAbstractVideoSurface@@@Z @ 1619 NONAME ; void QMediaImageViewer::setVideoOutput(class QAbstractVideoSurface *) + ?configurationChanged@QMediaNetworkAccessControl@@IAEXABVQNetworkConfiguration@@@Z @ 1620 NONAME ; void QMediaNetworkAccessControl::configurationChanged(class QNetworkConfiguration const &) + ?tr@QMediaNetworkAccessControl@@SA?AVQString@@PBD0@Z @ 1621 NONAME ; class QString QMediaNetworkAccessControl::tr(char const *, char const *) + ?qt_metacast@QMediaNetworkAccessControl@@UAEPAXPBD@Z @ 1622 NONAME ; void * QMediaNetworkAccessControl::qt_metacast(char const *) + diff --git a/src/s60installs/deviceconfiguration/.gitignore b/src/s60installs/deviceconfiguration/.gitignore new file mode 100644 index 000000000..2a654a0c7 --- /dev/null +++ b/src/s60installs/deviceconfiguration/.gitignore @@ -0,0 +1,11 @@ +!bld.inf +!config.pri +!mobility.prf +!mobilityconfig.prf +!symbian3_qtmobility.pkg +!symbian4_qtmobility.pkg +!qtmobility.sisx +!qtmobility_nonNR.pkg +!qtmobility_stub.pkg +!qtmobility_stub.sis +!qtmobilityexampleapps.pkg diff --git a/src/s60installs/deviceconfiguration/QtBearer{000a0000}.dll b/src/s60installs/deviceconfiguration/QtBearer{000a0000}.dll new file mode 100644 index 000000000..5c60d4a41 Binary files /dev/null and b/src/s60installs/deviceconfiguration/QtBearer{000a0000}.dll differ diff --git a/src/s60installs/deviceconfiguration/bld.inf b/src/s60installs/deviceconfiguration/bld.inf new file mode 100644 index 000000000..427160ffa --- /dev/null +++ b/src/s60installs/deviceconfiguration/bld.inf @@ -0,0 +1,57 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, version 2.1 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program. If not, +* see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/". +* +* Description: Build information file for Qt Extensions configuration +* +*/ + +#include + +PRJ_PLATFORMS +TOOLS2 + +PRJ_EXPORTS +symbian3_config.pri |../../../config.pri + +qtmobilityconfig.xml /epoc32/tools/makefile_templates/qt/qtmobilityconfig.xml +qtmobilityheaders.flm /epoc32/tools/makefile_templates/qt/qtmobilityheaders.flm + +../../../features/mobility.prf.template /epoc32/tools/qt/mkspecs/features/mobility.prf +mobilityconfig.prf /epoc32/tools/qt/mkspecs/features/mobilityconfig.prf + +qtmobility.iby CORE_MW_LAYER_IBY_EXPORT_PATH(qtmobility.iby) + +qtmobility.confml CONFML_EXPORT_PATH(qtmobility.confml,uda_content) +qtmobility_copy.implml CRML_EXPORT_PATH(qtmobility_copy.implml,uda_content) +qtmobility.sisx CRML_EXPORT_PATH(../content/sis/,uda_content) +qtmobility_stub.sis /epoc32/data/z/system/install/qtmobility_stub.sis + +../../../bin/servicedbgen.exe /epoc32/tools/servicedbgen.exe +../../../features/qtservice.xml /epoc32/tools/makefile_templates/qt/qtservice.xml +../../../features/qtservice.flm /epoc32/tools/makefile_templates/qt/qtservice.flm +../../../features/qtservice.prf /epoc32/tools/qt/mkspecs/features/symbian/qtservice.prf + +PRJ_MMPFILES + + +PRJ_TESTMMPFILES + + +PRJ_EXTENSIONS +START EXTENSION qt/qtmobilityheaders +OPTION MODULES bearer location contacts systeminfo publishsubscribe versit messaging sensors serviceframework multimedia gallery organizer feedback +END diff --git a/src/s60installs/deviceconfiguration/mobilityconfig.prf b/src/s60installs/deviceconfiguration/mobilityconfig.prf new file mode 100644 index 000000000..91a50cf96 --- /dev/null +++ b/src/s60installs/deviceconfiguration/mobilityconfig.prf @@ -0,0 +1,5 @@ +MOBILITY_CONFIG=bearer location contacts systeminfo publishsubscribe versit messaging sensors serviceframework multimedia gallery organizer feedback connectivity +MOBILITY_VERSION = 1.2.0 +MOBILITY_MAJOR_VERSION = 1 +MOBILITY_MINOR_VERSION = 2 +MOBILITY_PATCH_VERSION = 0 diff --git a/src/s60installs/deviceconfiguration/qtmobility.confml b/src/s60installs/deviceconfiguration/qtmobility.confml new file mode 100644 index 000000000..4da8443bc --- /dev/null +++ b/src/s60installs/deviceconfiguration/qtmobility.confml @@ -0,0 +1,16 @@ + + + + QtMobility settings + + To enable QtMobility usage + + + + + true + + + \ No newline at end of file diff --git a/src/s60installs/deviceconfiguration/qtmobility.iby b/src/s60installs/deviceconfiguration/qtmobility.iby new file mode 100644 index 000000000..03e9c40b5 --- /dev/null +++ b/src/s60installs/deviceconfiguration/qtmobility.iby @@ -0,0 +1,134 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, version 2.1 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program. If not, +* see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/". +* +* Description: +* +*/ + +#ifndef __QT_MOBILITY_IBY__ +#define __QT_MOBILITY_IBY__ + +#include +#include + +#ifndef FF_QT_IN_UDA + +//Stub sis +data=ZSYSTEM\install\qtmobility_stub.sis \system\install\qtmobility_stub.sis + +//Core +file=ABI_DIR\BUILD_DIR\qtbearer.dll SHARED_LIB_DIR\qtbearer.dll +file=ABI_DIR\BUILD_DIR\qtlocation.dll SHARED_LIB_DIR\qtlocation.dll +file=ABI_DIR\BUILD_DIR\qtpublishsubscribe.dll SHARED_LIB_DIR\qtpublishsubscribe.dll +file=ABI_DIR\BUILD_DIR\qpspathmapperserver.exe PROGRAMS_DIR\qpspathmapperserver.exe +file=ABI_DIR\BUILD_DIR\qtserviceframework.dll SHARED_LIB_DIR\qtserviceframework.dll +file=ABI_DIR\BUILD_DIR\qsfwdatabasemanagerserver.exe PROGRAMS_DIR\qsfwdatabasemanagerserver.exe +file=ABI_DIR\BUILD_DIR\qtsysteminfo.dll SHARED_LIB_DIR\qtsysteminfo.dll +file=ABI_DIR\BUILD_DIR\qtmessaging.dll SHARED_LIB_DIR\qtmessaging.dll +file=ABI_DIR\BUILD_DIR\qtmultimediakit.dll SHARED_LIB_DIR\qtmultimediakit.dll +file=ABI_DIR\BUILD_DIR\qtsensors.dll SHARED_LIB_DIR\qtsensors.dll +file=ABI_DIR\BUILD_DIR\qtcontacts.dll SHARED_LIB_DIR\qtcontacts.dll +file=ABI_DIR\BUILD_DIR\qtversit.dll SHARED_LIB_DIR\qtversit.dll +file=ABI_DIR\BUILD_DIR\qtversitorganizer.dll SHARED_LIB_DIR\qtversitorganizer.dll +file=ABI_DIR\BUILD_DIR\qtfeedback.dll SHARED_LIB_DIR\qtfeedback.dll +file=ABI_DIR\BUILD_DIR\qtgallery.dll SHARED_LIB_DIR\qtgallery.dll +file=ABI_DIR\BUILD_DIR\qtorganizer.dll SHARED_LIB_DIR\qtorganizer.dll + +//Plugins +file=ABI_DIR\BUILD_DIR\qtcontacts_serviceactionmanager.dll SHARED_LIB_DIR\qtcontacts_serviceactionmanager.dll +data=\epoc32\data\z\resource\qt\plugins\contacts\qtcontacts_serviceactionmanager.qtplugin resource\qt\plugins\contacts\qtcontacts_serviceactionmanager.qtplugin +file=ABI_DIR\BUILD_DIR\qtcontacts_symbian.dll SHARED_LIB_DIR\qtcontacts_symbian.dll +data=\epoc32\data\z\resource\qt\plugins\contacts\qtcontacts_symbian.qtplugin resource\qt\plugins\contacts\qtcontacts_symbian.qtplugin +file=ABI_DIR\BUILD_DIR\qtcontacts_symbiansim.dll SHARED_LIB_DIR\qtcontacts_symbiansim.dll +data=\epoc32\data\z\resource\qt\plugins\contacts\qtcontacts_symbiansim.qtplugin resource\qt\plugins\contacts\qtcontacts_symbiansim.qtplugin +file=ABI_DIR\BUILD_DIR\qtfeedback_mmk.dll SHARED_LIB_DIR\qtfeedback_mmk.dll +data=\epoc32\data\z\resource\qt\plugins\feedback\qtfeedback_mmk.qtplugin resource\qt\plugins\feedback\qtfeedback_mmk.qtplugin +file=ABI_DIR\BUILD_DIR\qtfeedback_symbian.dll SHARED_LIB_DIR\qtfeedback_symbian.dll +data=\epoc32\data\z\resource\qt\plugins\feedback\qtfeedback_symbian.qtplugin resource\qt\plugins\feedback\qtfeedback_symbian.qtplugin +file=ABI_DIR\BUILD_DIR\qtgeoservices_nokia.dll SHARED_LIB_DIR\qtgeoservices_nokia.dll +data=\epoc32\data\z\resource\qt\plugins\geoservices\qtgeoservices_nokia.qtplugin resource\qt\plugins\geoservices\qtgeoservices_nokia.qtplugin +file=ABI_DIR\BUILD_DIR\qtlandmarks_symbian.dll SHARED_LIB_DIR\qtlandmarks_symbian.dll +data=\epoc32\data\z\resource\qt\plugins\landmarks\qtlandmarks_symbian.qtplugin resource\qt\plugins\landmarks\qtlandmarks_symbian.qtplugin +file=ABI_DIR\BUILD_DIR\qtmultimediakit_m3u.dll SHARED_LIB_DIR\qtmultimediakit_m3u.dll +data=\epoc32\data\z\resource\qt\plugins\playlistformats\qtmultimediakit_m3u.qtplugin resource\qt\plugins\playlistformats\qtmultimediakit_m3u.qtplugin +file=ABI_DIR\BUILD_DIR\qtmultimediakit_mmfengine.dll SHARED_LIB_DIR\qtmultimediakit_mmfengine.dll +data=\epoc32\data\z\resource\qt\plugins\mediaservice\qtmultimediakit_mmfengine.qtplugin resource\qt\plugins\mediaservice\qtmultimediakit_mmfengine.qtplugin +file=ABI_DIR\BUILD_DIR\qtmultimediakit_ecamengine.dll SHARED_LIB_DIR\qtmultimediakit_ecamengine.dll +data=\epoc32\data\z\resource\qt\plugins\mediaservice\qtmultimediakit_ecamengine.qtplugin resource\qt\plugins\mediaservice\qtmultimediakit_ecamengine.qtplugin +file=ABI_DIR\BUILD_DIR\qtorganizer_skeleton.dll SHARED_LIB_DIR\qtorganizer_skeleton.dll +data=\epoc32\data\z\resource\qt\plugins\organizer\qtorganizer_skeleton.qtplugin resource\qt\plugins\organizer\qtorganizer_skeleton.qtplugin +file=ABI_DIR\BUILD_DIR\qtorganizer_symbian.dll SHARED_LIB_DIR\qtorganizer_symbian.dll +data=\epoc32\data\z\resource\qt\plugins\organizer\qtorganizer_symbian.qtplugin resource\qt\plugins\organizer\qtorganizer_symbian.qtplugin +file=ABI_DIR\BUILD_DIR\qtsensors_generic.dll SHARED_LIB_DIR\qtsensors_generic.dll +data=\epoc32\data\z\resource\qt\plugins\sensors\qtsensors_generic.qtplugin resource\qt\plugins\sensors\qtsensors_generic.qtplugin +file=ABI_DIR\BUILD_DIR\qtsensors_sym.dll SHARED_LIB_DIR\qtsensors_sym.dll +data=\epoc32\data\z\resource\qt\plugins\sensors\qtsensors_sym.qtplugin resource\qt\plugins\sensors\qtsensors_sym.qtplugin +file=ABI_DIR\BUILD_DIR\qtversit_backuphandler.dll SHARED_LIB_DIR\qtversit_backuphandler.dll +data=\epoc32\data\z\resource\qt\plugins\versit\qtversit_backuphandler.qtplugin resource\qt\plugins\versit\qtversit_backuphandler.qtplugin +file=ABI_DIR\BUILD_DIR\qtversit_vcardpreserver.dll SHARED_LIB_DIR\qtversit_vcardpreserver.dll +data=\epoc32\data\z\resource\qt\plugins\versit\qtversit_vcardpreserver.qtplugin resource\qt\plugins\versit\qtversit_vcardpreserver.qtplugin +file=ABI_DIR\BUILD_DIR\cntversitfavoriteplugin.dll SHARED_LIB_DIR\cntversitfavoriteplugin.dll +data=\epoc32\data\z\resource\qt\plugins\versit\cntversitfavoriteplugin.qtplugin resource\qt\plugins\versit\cntversitfavoriteplugin.qtplugin +file=ABI_DIR\BUILD_DIR\cntversitlandlineplugin.dll SHARED_LIB_DIR\cntversitlandlineplugin.dll +data=\epoc32\data\z\resource\qt\plugins\versit\cntversitlandlineplugin.qtplugin resource\qt\plugins\versit\cntversitlandlineplugin.qtplugin +file=ABI_DIR\BUILD_DIR\cntversitmycardplugin.dll SHARED_LIB_DIR\cntversitmycardplugin.dll +data=\epoc32\data\z\resource\qt\plugins\versit\cntversitmycardplugin.qtplugin resource\qt\plugins\versit\cntversitmycardplugin.qtplugin +file=ABI_DIR\BUILD_DIR\cntversitprefplugin.dll SHARED_LIB_DIR\cntversitprefplugin.dll +data=\epoc32\data\z\resource\qt\plugins\versit\cntversitprefplugin.qtplugin resource\qt\plugins\versit\cntversitprefplugin.qtplugin +file=ABI_DIR\BUILD_DIR\declarative_contacts.dll SHARED_LIB_DIR\declarative_contacts.dll +data=\epoc32\data\z\resource\qt\imports\qtmobility\contacts\declarative_contacts.qtplugin resource\qt\imports\qtmobility\contacts\declarative_contacts.qtplugin +data=\epoc32\data\z\resource\qt\imports\qtmobility\contacts\qmldir resource\qt\imports\qtmobility\contacts\qmldir +file=ABI_DIR\BUILD_DIR\declarative_feedback.dll SHARED_LIB_DIR\declarative_feedback.dll +data=\epoc32\data\z\resource\qt\imports\qtmobility\feedback\declarative_feedback.qtplugin resource\qt\imports\qtmobility\feedback\declarative_feedback.qtplugin +data=\epoc32\data\z\resource\qt\imports\qtmobility\feedback\qmldir resource\qt\imports\qtmobility\feedback\qmldir +file=ABI_DIR\BUILD_DIR\declarative_gallery.dll SHARED_LIB_DIR\declarative_gallery.dll +data=\epoc32\data\z\resource\qt\imports\qtmobility\gallery\declarative_gallery.qtplugin resource\qt\imports\qtmobility\gallery\declarative_gallery.qtplugin +data=\epoc32\data\z\resource\qt\imports\qtmobility\gallery\qmldir resource\qt\imports\qtmobility\gallery\qmldir +file=ABI_DIR\BUILD_DIR\declarative_location.dll SHARED_LIB_DIR\declarative_location.dll +data=\epoc32\data\z\resource\qt\imports\qtmobility\location\declarative_location.qtplugin resource\qt\imports\qtmobility\location\declarative_location.qtplugin +data=\epoc32\data\z\resource\qt\imports\qtmobility\location\qmldir resource\qt\imports\qtmobility\location\qmldir +file=ABI_DIR\BUILD_DIR\declarative_messaging.dll SHARED_LIB_DIR\declarative_messaging.dll +data=\epoc32\data\z\resource\qt\imports\qtmobility\messaging\declarative_messaging.qtplugin resource\qt\imports\qtmobility\messaging\declarative_messaging.qtplugin +data=\epoc32\data\z\resource\qt\imports\qtmobility\messaging\qmldir resource\qt\imports\qtmobility\messaging\qmldir +file=ABI_DIR\BUILD_DIR\declarative_multimedia.dll SHARED_LIB_DIR\declarative_multimedia.dll +data=\epoc32\data\z\resource\qt\imports\qtmultimediakit\declarative_multimedia.qtplugin resource\qt\imports\qtmultimediakit\declarative_multimedia.qtplugin +data=\epoc32\data\z\resource\qt\imports\qtmultimediakit\qmldir resource\qt\imports\qtmultimediakit\qmldir +file=ABI_DIR\BUILD_DIR\declarative_organizer.dll SHARED_LIB_DIR\declarative_organizer.dll +data=\epoc32\data\z\resource\qt\imports\qtmobility\organizer\declarative_organizer.qtplugin resource\qt\imports\qtmobility\organizer\declarative_organizer.qtplugin +data=\epoc32\data\z\resource\qt\imports\qtmobility\organizer\qmldir resource\qt\imports\qtmobility\organizer\qmldir +file=ABI_DIR\BUILD_DIR\declarative_publishsubscribe.dll SHARED_LIB_DIR\declarative_publishsubscribe.dll +data=\epoc32\data\z\resource\qt\imports\qtmobility\publishsubscribe\declarative_publishsubscribe.qtplugin resource\qt\imports\qtmobility\publishsubscribe\declarative_publishsubscribe.qtplugin +data=\epoc32\data\z\resource\qt\imports\qtmobility\publishsubscribe\qmldir resource\qt\imports\qtmobility\publishsubscribe\qmldir +file=ABI_DIR\BUILD_DIR\declarative_sensors.dll SHARED_LIB_DIR\declarative_sensors.dll +data=\epoc32\data\z\resource\qt\imports\qtmobility\sensors\declarative_sensors.qtplugin resource\qt\imports\qtmobility\sensors\declarative_sensors.qtplugin +data=\epoc32\data\z\resource\qt\imports\qtmobility\sensors\qmldir resource\qt\imports\qtmobility\sensors\qmldir +file=ABI_DIR\BUILD_DIR\declarative_serviceframework.dll SHARED_LIB_DIR\declarative_serviceframework.dll +data=\epoc32\data\z\resource\qt\imports\qtmobility\serviceframework\declarative_serviceframework.qtplugin resource\qt\imports\qtmobility\serviceframework\declarative_serviceframework.qtplugin +data=\epoc32\data\z\resource\qt\imports\qtmobility\serviceframework\qmldir resource\qt\imports\qtmobility\serviceframework\qmldir +file=ABI_DIR\BUILD_DIR\declarative_systeminfo.dll SHARED_LIB_DIR\declarative_systeminfo.dll +data=\epoc32\data\z\resource\qt\imports\qtmobility\systeminfo\declarative_systeminfo.qtplugin resource\qt\imports\qtmobility\systeminfo\declarative_systeminfo.qtplugin +data=\epoc32\data\z\resource\qt\imports\qtmobility\systeminfo\qmldir resource\qt\imports\qtmobility\systeminfo\qmldir + +//Resource +data=\epoc32\data\z\private\2002ac7f\qtserviceframework_4.7_system.db private\2002ac7f\qtserviceframework_4.7_system.db +data=\epoc32\data\z\private\10202D56\import\packages\2002AC89\backup_registration.xml private\10202D56\import\packages\2002AC89\backup_registration.xml + +// Symbian3 PS1 support +file=\sf\mw\qtmobility\src\s60installs\deviceconfiguration\QtBearer{000a0000}.dll SHARED_LIB_DIR\QtBearer{000a0000}.dll +#endif // FF_QT_IN_UDA + +#endif // __QT_MOBILITY_IBY__ diff --git a/src/s60installs/deviceconfiguration/qtmobility.sisx b/src/s60installs/deviceconfiguration/qtmobility.sisx new file mode 100644 index 000000000..56a6051ca --- /dev/null +++ b/src/s60installs/deviceconfiguration/qtmobility.sisx @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/s60installs/deviceconfiguration/qtmobility_copy.implml b/src/s60installs/deviceconfiguration/qtmobility_copy.implml new file mode 100644 index 000000000..34608e883 --- /dev/null +++ b/src/s60installs/deviceconfiguration/qtmobility_copy.implml @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/src/s60installs/deviceconfiguration/qtmobility_stub.pkg b/src/s60installs/deviceconfiguration/qtmobility_stub.pkg new file mode 100644 index 000000000..cad6632c6 --- /dev/null +++ b/src/s60installs/deviceconfiguration/qtmobility_stub.pkg @@ -0,0 +1,12 @@ + +; Language +&EN + +; SIS header: name, uid, version +#{"QtMobility"},(0x2002AC89),1,2,0,TYPE=SA + +; Localised Vendor name +%{"Nokia"} + +; Unique Vendor name +:"Nokia" diff --git a/src/s60installs/deviceconfiguration/qtmobility_stub.sis b/src/s60installs/deviceconfiguration/qtmobility_stub.sis new file mode 100644 index 000000000..730cc96f3 Binary files /dev/null and b/src/s60installs/deviceconfiguration/qtmobility_stub.sis differ diff --git a/src/s60installs/deviceconfiguration/qtmobilityconfig.xml b/src/s60installs/deviceconfiguration/qtmobilityconfig.xml new file mode 100644 index 000000000..095a0d6ea --- /dev/null +++ b/src/s60installs/deviceconfiguration/qtmobilityconfig.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/s60installs/deviceconfiguration/qtmobilityexampleapps.pkg b/src/s60installs/deviceconfiguration/qtmobilityexampleapps.pkg new file mode 100644 index 000000000..7da132bdf --- /dev/null +++ b/src/s60installs/deviceconfiguration/qtmobilityexampleapps.pkg @@ -0,0 +1,111 @@ +; Language +&EN + +; SIS header: name, uid, version +#{"QtMobilityExamples"},(0xE001E61D),1,2,0,TYPE=SA + +; Localised Vendor name +%{"Nokia"} + +; Unique Vendor name +:"Nokia" + +; Default dependency to Qt libraries +(0x2001E61C), 4, 7, 2, {"Qt"} +; Default HW/platform dependencies +[0x101F7961],0,0,0,{"S60ProductID"} +[0x102032BE],0,0,0,{"S60ProductID"} +[0x102752AE],0,0,0,{"S60ProductID"} +[0x1028315F],0,0,0,{"S60ProductID"} +[0x20022E6D],0,0,0,{"S60ProductID"} +[0x20032DE7],0,0,0,{"S60ProductID"} +; Default dependency to QtMobility libraries +(0x2002AC89), 1, 2, 0, {"QtMobility"} + +;Bearer +"/epoc32/release/armv5/urel/bearercloud.exe" - "!:\sys\bin\bearercloud.exe" +"/epoc32/data/z/resource/apps/bearercloud.rsc" - "!:\resource\apps\bearercloud.rsc" +"/epoc32/data/z/private/10003a3f/import/apps/bearercloud_reg.rsc" - "!:\private\10003a3f\import\apps\bearercloud_reg.rsc" + +"/epoc32/release/armv5/urel/bearermonitor.exe" - "!:\sys\bin\bearermonitor.exe" +"/epoc32/data/z/resource/apps/bearermonitor.rsc" - "!:\resource\apps\bearermonitor.rsc" +"/epoc32/data/z/private/10003a3f/import/apps/bearermonitor_reg.rsc" - "!:\private\10003a3f\import\apps\bearermonitor_reg.rsc" + +;Contacts +"/epoc32/release/armv5/urel/samplephonebook.exe" - "!:\sys\bin\samplephonebook.exe" +"/epoc32/data/z/resource/apps/samplephonebook.rsc" - "!:\resource\apps\samplephonebook.rsc" +"/epoc32/data/z/private/10003a3f/import/apps/samplephonebook_reg.rsc" - "!:\private\10003a3f\import\apps\samplephonebook_reg.rsc" + +;Feedback +"/epoc32/release/armv5/urel/hapticsplayer.exe" - "!:\sys\bin\hapticsplayer.exe" +"/epoc32/data/z/resource/apps/hapticsplayer.rsc" - "!:\resource\apps\hapticsplayer.rsc" +"/epoc32/data/z/private/10003a3f/import/apps/hapticsplayer_reg.rsc" - "!:\private\10003a3f\import\apps\hapticsplayer_reg.rsc" + +;Gallery +"/epoc32/release/armv5/urel/mediabrowser.exe" - "!:\sys\bin\mediabrowser.exe" +"/epoc32/data/z/resource/apps/mediabrowser.rsc" - "!:\resource\apps\mediabrowser.rsc" +"/epoc32/data/z/private/10003a3f/import/apps/mediabrowser_reg.rsc" - "!:\private\10003a3f\import\apps\mediabrowser_reg.rsc" + +"/epoc32/release/armv5/urel/documentproperties.exe" - "!:\sys\bin\documentproperties.exe" +"/epoc32/data/z/resource/apps/documentproperties.rsc" - "!:\resource\apps\documentproperties.rsc" +"/epoc32/data/z/private/10003a3f/import/apps/documentproperties_reg.rsc" - "!:\private\10003a3f\import\apps\documentproperties_reg.rsc" + +;Location +"/epoc32/release/armv5/urel/satellitedialog.exe" - "!:\sys\bin\satellitedialog.exe" +"/epoc32/data/z/resource/apps/satellitedialog.rsc" - "!:\resource\apps\satellitedialog.rsc" +"/epoc32/data/z/private/10003a3f/import/apps/satellitedialog_reg.rsc" - "!:\private\10003a3f\import\apps\satellitedialog_reg.rsc" + +;Messaging +"/epoc32/release/armv5/urel/querymessages.exe" - "!:\sys\bin\querymessages.exe" +"/epoc32/data/z/resource/apps/querymessages.rsc" - "!:\resource\apps\querymessages.rsc" +"/epoc32/data/z/private/10003a3f/import/apps/querymessages_reg.rsc" - "!:\private\10003a3f\import\apps\querymessages_reg.rsc" + +"/epoc32/release/armv5/urel/writemessage.exe" - "!:\sys\bin\writemessage.exe" +"/epoc32/data/z/resource/apps/writemessage.rsc" - "!:\resource\apps\writemessage.rsc" +"/epoc32/data/z/private/10003a3f/import/apps/writemessage_reg.rsc" - "!:\private\10003a3f\import\apps\writemessage_reg.rsc" + +"/epoc32/release/armv5/urel/serviceactions.exe" - "!:\sys\bin\serviceactions.exe" +"/epoc32/data/z/resource/apps/serviceactions.rsc" - "!:\resource\apps\serviceactions.rsc" +"/epoc32/data/z/private/10003a3f/import/apps/serviceactions_reg.rsc" - "!:\private\10003a3f\import\apps\serviceactions_reg.rsc" + +;Multimedia +"/epoc32/release/armv5/urel/player.exe" - "!:\sys\bin\player.exe" +"/epoc32/data/z/resource/apps/player.rsc" - "!:\resource\apps\player.rsc" +"/epoc32/data/z/private/10003a3f/import/apps/player_reg.rsc" - "!:\private\10003a3f\import\apps\player_reg.rsc" + +"/epoc32/release/armv5/urel/audiorecorder.exe" - "!:\sys\bin\audiorecorder.exe" +"/epoc32/data/z/resource/apps/audiorecorder.rsc" - "!:\resource\apps\audiorecorder.rsc" +"/epoc32/data/z/private/10003a3f/import/apps/audiorecorder_reg.rsc" - "!:\private\10003a3f\import\apps\audiorecorder_reg.rsc" + +"/epoc32/release/armv5/urel/radio.exe" - "!:\sys\bin\radio.exe" +"/epoc32/data/z/resource/apps/radio.rsc" - "!:\resource\apps\radio.rsc" +"/epoc32/data/z/private/10003a3f/import/apps/radio_reg.rsc" - "!:\private\10003a3f\import\apps\radio.rsc" + +"/epoc32/release/armv5/urel/slideshow.exe" - "!:\sys\bin\slideshow.exe" +"/epoc32/data/z/resource/apps/slideshow.rsc" - "!:\resource\apps\slideshow.rsc" +"/epoc32/data/z/private/10003a3f/import/apps/slideshow_reg.rsc" - "!:\private\10003a3f\import\apps\slideshow_reg.rsc" + +;Organizer +"/epoc32/release/armv5/urel/calendardemo.exe" - "!:\sys\bin\calendardemo.exe" +"/epoc32/data/z/resource/apps/calendardemo.rsc" - "!:\resource\apps\calendardemo.rsc" +"/epoc32/data/z/private/10003a3f/import/apps/calendardemo_reg.rsc" - "!:\private\10003a3f\import\apps\calendardemo_reg.rsc" + +;Publish and Subscribe +"/epoc32/release/armv5/urel/publish_subscribe.exe" - "!:\sys\bin\publish_subscribe.exe" +"/epoc32/data/z/resource/apps/publish_subscribe.rsc" - "!:\resource\apps\publish_subscribe.rsc" +"/epoc32/data/z/private/10003a3f/import/apps/publish_subscribe_reg.rsc" - "!:\private\10003a3f\import\apps\publish_subscribe_reg.rsc" + +;Sensors +"/epoc32/release/armv5/urel/smallsensors.exe" - "!:\sys\bin\smallsensors.exe" +"/epoc32/data/z/resource/apps/smallsensors.rsc" - "!:\resource\apps\smallsensors.rsc" +"/epoc32/data/z/private/10003a3f/import/apps/smallsensors_reg.rsc" - "!:\private\10003a3f\import\apps\smallsensors_reg.rsc" + +;ServiceFramework +"/epoc32/release/armv5/urel/servicebrowser.exe" - "!:\sys\bin\servicebrowser.exe" +"/epoc32/data/z/resource/apps/servicebrowser.rsc" - "!:\resource\apps\servicebrowser.rsc" +"/epoc32/data/z/private/10003a3f/import/apps/servicebrowser_reg.rsc" - "!:\private\10003a3f\import\apps\servicebrowser_reg.rsc" + +;SystemInfo +"/epoc32/release/armv5/urel/qsysinfo.exe" - "!:\sys\bin\qsysinfo.exe" +"/epoc32/data/z/resource/apps/qsysinfo.rsc" - "!:\resource\apps\qsysinfo.rsc" +"/epoc32/data/z/private/10003a3f/import/apps/qsysinfo_reg.rsc" - "!:\private\10003a3f\import\apps\qsysinfo_reg.rsc" diff --git a/src/s60installs/deviceconfiguration/qtmobilityexamples.iby b/src/s60installs/deviceconfiguration/qtmobilityexamples.iby new file mode 100644 index 000000000..531d251ff --- /dev/null +++ b/src/s60installs/deviceconfiguration/qtmobilityexamples.iby @@ -0,0 +1,128 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, version 2.1 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program. If not, +* see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/". +* +* Description: +* +*/ + +#ifndef __QT_MOBILITYEXAMPLES_IBY__ +#define __QT_MOBILITYEXAMPLES_IBY__ + +#include + +#define UPGRADABLE_APP_REG_RSC(NAME) data=DATAZ_\PRIVATE\10003A3F\IMPORT\APPS\ ## NAME ## _reg.rsc Private\10003a3f\import\apps\ ## NAME ## _reg.rsc + +S60_APP_EXE(audiorecorder) +S60_APP_RESOURCE(audiorecorder) +UPGRADABLE_APP_REG_RSC(audiorecorder) + +S60_APP_EXE(battery-publisher) +S60_APP_RESOURCE(battery-publisher) +UPGRADABLE_APP_REG_RSC(battery-publisher) + +S60_APP_EXE(battery-subscriber) +S60_APP_RESOURCE(battery-subscriber) +UPGRADABLE_APP_REG_RSC(battery-subscriber) + +S60_APP_EXE(bearercloud) +S60_APP_RESOURCE(bearercloud) +UPGRADABLE_APP_REG_RSC(bearercloud) + +S60_APP_EXE(bearermonitor) +S60_APP_RESOURCE(bearermonitor) +UPGRADABLE_APP_REG_RSC(bearermonitor) + +file=ABI_DIR\BUILD_DIR\serviceframework_bluetoothtransferplugin.dll SHARED_LIB_DIR\serviceframework_bluetoothtransferplugin.dll +data=\epoc32\data\z\resource\qt\plugins\serviceframework_bluetoothtransferplugin.qtplugin resource\qt\plugins\serviceframework_bluetoothtransferplugin.qtplugin + +S60_APP_EXE(sfw-kinetic-example) +S60_APP_RESOURCE(sfw-kinetic-example) +UPGRADABLE_APP_REG_RSC(sfw-kinetic-example) +file=ABI_DIR\BUILD_DIR\serviceframework_landlinedialerservice.dll SHARED_LIB_DIR\serviceframework_landlinedialerservice.dll +file=ABI_DIR\BUILD_DIR\serviceframework_voipdialerservice.dll SHARED_LIB_DIR\serviceframework_voipdialerservice.dll + +file=ABI_DIR\BUILD_DIR\serviceframework_filemanagerplugin.dll SHARED_LIB_DIR\serviceframework_filemanagerplugin.dll +data=\epoc32\data\z\resource\qt\plugins\serviceframework_filemanagerplugin.qtplugin resource\qt\plugins\serviceframework_filemanagerplugin.qtplugin + +file=ABI_DIR\BUILD_DIR\serviceframework_notesmanagerplugin.dll SHARED_LIB_DIR\serviceframework_notesmanagerplugin.dll +data=\epoc32\data\z\resource\qt\plugins\serviceframework_notesmanagerplugin.qtplugin resource\qt\plugins\serviceframework_notesmanagerplugin.qtplugin + +S60_APP_EXE(player) +S60_APP_RESOURCE(player) +UPGRADABLE_APP_REG_RSC(player) + +S60_APP_EXE(publish-subscribe) +S60_APP_RESOURCE(publish-subscribe) +UPGRADABLE_APP_REG_RSC(publish-subscribe) +data=\epoc32\data\z\resource\qt\crml\example.qcrml resource\qt\crml\example.qcrml + +S60_APP_EXE(querymessages) +S60_APP_RESOURCE(querymessages) +UPGRADABLE_APP_REG_RSC(querymessages) + +S60_APP_EXE(quickstart) +S60_APP_RESOURCE(quickstart) +UPGRADABLE_APP_REG_RSC(quickstart) + +S60_APP_EXE(radio) +S60_APP_RESOURCE(radio) +UPGRADABLE_APP_REG_RSC(radio) + +S60_APP_EXE(satellitedialog) +S60_APP_RESOURCE(satellitedialog) +UPGRADABLE_APP_REG_RSC(satellitedialog) + +S60_APP_EXE(accel) +S60_APP_RESOURCE(accel) +UPGRADABLE_APP_REG_RSC(accel) + +S60_APP_EXE(grueapp) +S60_APP_RESOURCE(grueapp) +UPGRADABLE_APP_REG_RSC(grueapp) + +file=ABI_DIR\BUILD_DIR\grueplugin.dll SHARED_LIB_DIR\grueplugin.dll +data=\epoc32\data\z\resource\qt\plugins\sensors\grueplugin.qtplugin resource\qt\plugins\sensors\grueplugin.qtplugin + +S60_APP_EXE(orientation) +S60_APP_RESOURCE(orientation) +UPGRADABLE_APP_REG_RSC(orientation) + +S60_APP_EXE(reading_perf) +S60_APP_RESOURCE(reading_perf) +UPGRADABLE_APP_REG_RSC(reading_perf) + +S60_APP_EXE(sensor_explorer) +S60_APP_RESOURCE(sensor_explorer) +UPGRADABLE_APP_REG_RSC(sensor_explorer) + +S60_APP_EXE(serviceactions) +S60_APP_RESOURCE(serviceactions) +UPGRADABLE_APP_REG_RSC(serviceactions) + +S60_APP_EXE(slideshow) +S60_APP_RESOURCE(slideshow) +UPGRADABLE_APP_REG_RSC(slideshow) + +S60_APP_EXE(sysinfo) +S60_APP_RESOURCE(sysinfo) +UPGRADABLE_APP_REG_RSC(sysinfo) + +S60_APP_EXE(writemessage) +S60_APP_RESOURCE(writemessage) +UPGRADABLE_APP_REG_RSC(writemessage) + +#endif //__QT_MOBILITYEXAMPLES_IBY__ diff --git a/src/s60installs/deviceconfiguration/qtmobilityheaders.flm b/src/s60installs/deviceconfiguration/qtmobilityheaders.flm new file mode 100644 index 000000000..0b2cfcb53 --- /dev/null +++ b/src/s60installs/deviceconfiguration/qtmobilityheaders.flm @@ -0,0 +1,146 @@ +# /**************************************************************************** +# ** +# ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) +# ** Contact: +# ** +# ****************************************************************************/ + +# FLM to generate Qt style headers for QtMobility +QTMOBILITY_ROOT := $(subst src/s60installs/deviceconfiguration,,$(subst \,/,$(EXTENSION_ROOT))) +QTMOBILITY_BIN := $(QTMOBILITY_ROOT)bin +QTMOBILITY_INCLUDE := $(QTMOBILITY_ROOT)include +QTMOBILITY_BEARER_INCLUDE := $(QTMOBILITY_INCLUDE)/QtBearer +QTMOBILITY_CONTACTS_INCLUDE := $(QTMOBILITY_INCLUDE)/QtContacts +QTMOBILITY_LOCATION_INCLUDE := $(QTMOBILITY_INCLUDE)/QtLocation +QTMOBILITY_MESSAGING_INCLUDE := $(QTMOBILITY_INCLUDE)/QtMessaging +QTMOBILITY_MULTIMEDIA_INCLUDE := $(QTMOBILITY_INCLUDE)/QtMultimediaKit +QTMOBILITY_PUBLISHSUBSCRIBE_INCLUDE := $(QTMOBILITY_INCLUDE)/QtPublishSubscribe +QTMOBILITY_SYSTEMINFO_INCLUDE := $(QTMOBILITY_INCLUDE)/QtSystemInfo +QTMOBILITY_SERVICEFRAMEWORK_INCLUDE := $(QTMOBILITY_INCLUDE)/QtServiceFramework +QTMOBILITY_VERSIT_INCLUDE := $(QTMOBILITY_INCLUDE)/QtVersit +QTMOBILITY_VERSITORGANIZER_INCLUDE := $(QTMOBILITY_INCLUDE)/QtVersitOrganizer +QTMOBILITY_SENSORS_INCLUDE := $(QTMOBILITY_INCLUDE)/QtSensors +QTMOBILITY_GALLERY_INCLUDE := $(QTMOBILITY_INCLUDE)/QtGallery +QTMOBILITY_ORGANIZER_INCLUDE := $(QTMOBILITY_INCLUDE)/QtOrganizer +QTMOBILITY_FEEDBACK_INCLUDE := $(QTMOBILITY_INCLUDE)/QtFeedback +QTMOBILITY_CONNECTIVITY_INCLUDE := $(QTMOBILITY_INCLUDE)/QtConnectivity +QTMOBILITY_SRC := $(QTMOBILITY_ROOT)src +QTMOBILITY_GLOBAL_SRC := $(QTMOBILITY_SRC)/global +QTMOBILITY_BEARER_SRC := $(QTMOBILITY_SRC)/bearer +QTMOBILITY_CONTACTS_SRC := $(QTMOBILITY_SRC)/contacts +QTMOBILITY_LOCATION_SRC := $(QTMOBILITY_SRC)/location +QTMOBILITY_MESSAGING_SRC := $(QTMOBILITY_SRC)/messaging +QTMOBILITY_MULTIMEDIA_SRC := $(QTMOBILITY_SRC)/multimedia +QTMOBILITY_PUBLISHSUBSCRIBE_SRC := $(QTMOBILITY_SRC)/publishsubscribe +QTMOBILITY_SYSTEMINFO_SRC := $(QTMOBILITY_SRC)/systeminfo +QTMOBILITY_SERVICEFRAMEWORK_SRC := $(QTMOBILITY_SRC)/serviceframework +QTMOBILITY_VERSIT_SRC := $(QTMOBILITY_SRC)/versit +QTMOBILITY_SENSORS_SRC := $(QTMOBILITY_SRC)/sensors +QTMOBILITY_VERSITORGANIZER_SRC := $(QTMOBILITY_SRC)/versitorganizer +QTMOBILITY_GALLERY_SRC := $(QTMOBILITY_SRC)/gallery +QTMOBILITY_ORGANIZER_SRC := $(QTMOBILITY_SRC)/organizer +QTMOBILITY_FEEDBACK_SRC := $(QTMOBILITY_SRC)/feedback +QTMOBILITY_CONNECTIVITY_SRC := $(QTMOBILITY_SRC)/connectivity + +define generate_module_headers + +EXPORT:: + $(call startrule,generate_module_headers,FORCESUCCESS) \ + cd $(QTMOBILITY_ROOT) && \ + $(PERL) -S $(QTMOBILITY_BIN)/$(SYNCHEADERS) $(1) $(2) \ + $(call endrule,generate_module_headers) + +CLEAN:: + $(call startrule,clean) \ + $(GNURM) -rf $(1) \ + $(call endrule,clean) + +WHAT:: + @(echo ""; \ + $(GNUFIND) $(1) -type f -print | (read LINE; \ + while [ $$$$? -eq 0 ]; do \ + echo "$$$$LINE"; \ + read LINE; \ + done); \ + echo "") $(if $(DESCRAMBLE),2>&1 | $(DESCRAMBLE)) + +endef + +GUARD:=done_$(call sanitise,$(QTMOBILITY_INCLUDE)) +ifeq ($($(GUARD)),) +$(GUARD) := 1 + +ifneq (,$(findstring bearer,$(MODULES))) +$(eval $(call generate_module_headers, $(QTMOBILITY_BEARER_INCLUDE), $(QTMOBILITY_BEARER_SRC))) +endif + +ifneq (,$(findstring contacts,$(MODULES))) +$(eval $(call generate_module_headers, $(QTMOBILITY_CONTACTS_INCLUDE), $(QTMOBILITY_CONTACTS_SRC))) +$(eval $(call generate_module_headers, $(QTMOBILITY_CONTACTS_INCLUDE), $(QTMOBILITY_CONTACTS_SRC)/requests)) +$(eval $(call generate_module_headers, $(QTMOBILITY_CONTACTS_INCLUDE), $(QTMOBILITY_CONTACTS_SRC)/filters)) +$(eval $(call generate_module_headers, $(QTMOBILITY_CONTACTS_INCLUDE), $(QTMOBILITY_CONTACTS_SRC)/details)) +endif + +ifneq (,$(findstring location,$(MODULES))) +$(eval $(call generate_module_headers, $(QTMOBILITY_LOCATION_INCLUDE), $(QTMOBILITY_LOCATION_SRC))) +$(eval $(call generate_module_headers, $(QTMOBILITY_LOCATION_INCLUDE), $(QTMOBILITY_LOCATION_SRC)/landmarks)) +$(eval $(call generate_module_headers, $(QTMOBILITY_LOCATION_INCLUDE), $(QTMOBILITY_LOCATION_SRC)/maps)) +$(eval $(call generate_module_headers, $(QTMOBILITY_LOCATION_INCLUDE), $(QTMOBILITY_LOCATION_SRC)/maps/tiled)) +endif + +ifneq (,$(findstring messaging,$(MODULES))) +$(eval $(call generate_module_headers, $(QTMOBILITY_MESSAGING_INCLUDE), $(QTMOBILITY_MESSAGING_SRC))) +endif + +ifneq (,$(findstring multimedia,$(MODULES))) +$(eval $(call generate_module_headers, $(QTMOBILITY_MULTIMEDIA_INCLUDE), $(QTMOBILITY_MULTIMEDIA_SRC))) +$(eval $(call generate_module_headers, $(QTMOBILITY_MULTIMEDIA_INCLUDE), $(QTMOBILITY_MULTIMEDIA_SRC)/audio)) +$(eval $(call generate_module_headers, $(QTMOBILITY_MULTIMEDIA_INCLUDE), $(QTMOBILITY_MULTIMEDIA_SRC)/video)) +endif + +ifneq (,$(findstring publishsubscribe,$(MODULES))) +$(eval $(call generate_module_headers, $(QTMOBILITY_PUBLISHSUBSCRIBE_INCLUDE), $(QTMOBILITY_PUBLISHSUBSCRIBE_SRC))) +endif + +ifneq (,$(findstring systeminfo,$(MODULES))) +$(eval $(call generate_module_headers, $(QTMOBILITY_SYSTEMINFO_INCLUDE), $(QTMOBILITY_SYSTEMINFO_SRC))) +endif + +ifneq (,$(findstring serviceframework,$(MODULES))) +$(eval $(call generate_module_headers, $(QTMOBILITY_SERVICEFRAMEWORK_INCLUDE), $(QTMOBILITY_SERVICEFRAMEWORK_SRC))) +endif + +ifneq (,$(findstring versit,$(MODULES))) +$(eval $(call generate_module_headers, $(QTMOBILITY_VERSIT_INCLUDE), $(QTMOBILITY_VERSIT_SRC))) +$(eval $(call generate_module_headers, $(QTMOBILITY_VERSITORGANIZER_INCLUDE), $(QTMOBILITY_VERSITORGANIZER_SRC))) +endif + +ifneq (,$(findstring sensors,$(MODULES))) +$(eval $(call generate_module_headers, $(QTMOBILITY_SENSORS_INCLUDE), $(QTMOBILITY_SENSORS_SRC))) +endif + +ifneq (,$(findstring gallery,$(MODULES))) +$(eval $(call generate_module_headers, $(QTMOBILITY_GALLERY_INCLUDE), $(QTMOBILITY_GALLERY_SRC))) +endif + +ifneq (,$(findstring organizer,$(MODULES))) +$(eval $(call generate_module_headers, $(QTMOBILITY_ORGANIZER_INCLUDE), $(QTMOBILITY_ORGANIZER_SRC))) +$(eval $(call generate_module_headers, $(QTMOBILITY_ORGANIZER_INCLUDE), $(QTMOBILITY_ORGANIZER_SRC)/items)) +$(eval $(call generate_module_headers, $(QTMOBILITY_ORGANIZER_INCLUDE), $(QTMOBILITY_ORGANIZER_SRC)/requests)) +$(eval $(call generate_module_headers, $(QTMOBILITY_ORGANIZER_INCLUDE), $(QTMOBILITY_ORGANIZER_SRC)/filters)) +$(eval $(call generate_module_headers, $(QTMOBILITY_ORGANIZER_INCLUDE), $(QTMOBILITY_ORGANIZER_SRC)/details)) +endif + +ifneq (,$(findstring feedback,$(MODULES))) +$(eval $(call generate_module_headers, $(QTMOBILITY_FEEDBACK_INCLUDE), $(QTMOBILITY_FEEDBACK_SRC))) +endif + +ifneq (,$(findstring connectivity,$(MODULES))) +$(eval $(call generate_module_headers, $(QTMOBILITY_CONNECTIVITY_INCLUDE), $(QTMOBILITY_CONNECTIVITY_SRC))) +$(eval $(call generate_module_headers, $(QTMOBILITY_CONNECTIVITY_INCLUDE), $(QTMOBILITY_CONNECTIVITY_SRC)/bluetooth)) +$(eval $(call generate_module_headers, $(QTMOBILITY_CONNECTIVITY_INCLUDE), $(QTMOBILITY_CONNECTIVITY_SRC)/nfc)) +endif + +$(eval $(call generate_module_headers, $(QTMOBILITY_INCLUDE), $(QTMOBILITY_GLOBAL_SRC))) + +endif diff --git a/src/s60installs/deviceconfiguration/qtmobilitytests.iby b/src/s60installs/deviceconfiguration/qtmobilitytests.iby new file mode 100644 index 000000000..31968ae2e --- /dev/null +++ b/src/s60installs/deviceconfiguration/qtmobilitytests.iby @@ -0,0 +1,47 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, version 2.1 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program. If not, +* see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/". +* +* Description: +* +*/ + +#ifndef __QT_MOBILITYTESTS_IBY__ +#define __QT_MOBILITYTESTS_IBY__ + +#include + +#define UPGRADABLE_APP_REG_RSC(NAME) data=DATAZ_\PRIVATE\10003A3F\IMPORT\APPS\ ## NAME ## _reg.rsc Private\10003a3f\import\apps\ ## NAME ## _reg.rsc + +S60_APP_EXE(bearerex) +S60_APP_RESOURCE(bearerex) +UPGRADABLE_APP_REG_RSC(bearerex) + +S60_APP_EXE(messagingex) +S60_APP_RESOURCE(messagingex) +UPGRADABLE_APP_REG_RSC(messagingex) + +S60_APP_EXE(s60player) +S60_APP_RESOURCE(s60player) +UPGRADABLE_APP_REG_RSC(s60player) + +S60_APP_EXE(publishsubscribeex) +S60_APP_RESOURCE(publishsubscribeex) +UPGRADABLE_APP_REG_RSC(publishsubscribeex) +data=\epoc32\data\z\resource\qt\crml\resources.qcrml resource\qt\crml\resources.qcrml +data=\epoc32\data\z\resource\qt\crml\profile.qcrml resource\qt\crml\profile.qcrml + +#endif //__QT_MOBILITYTESTS_IBY__ diff --git a/src/s60installs/deviceconfiguration/symbian3_config.pri b/src/s60installs/deviceconfiguration/symbian3_config.pri new file mode 100644 index 000000000..b97fa8d45 --- /dev/null +++ b/src/s60installs/deviceconfiguration/symbian3_config.pri @@ -0,0 +1,50 @@ +CONFIG += release +CONFIG_WIN32 += debug_and_release build_all release +build_unit_tests = no +build_public_unit_tests = no +build_examples = no +build_demos = no +build_docs = no +build_tools = no +qmf_enabled = no +!symbian:isEmpty($$QT_MOBILITY_INCLUDE):QT_MOBILITY_INCLUDE=$$QT_MOBILITY_PREFIX/include +isEmpty($$QT_MOBILITY_LIB):QT_MOBILITY_LIB=$$QT_MOBILITY_PREFIX/lib +isEmpty($$QT_MOBILITY_BIN):QT_MOBILITY_BIN=$$QT_MOBILITY_PREFIX/bin +isEmpty($$QT_MOBILITY_PLUGINS):QT_MOBILITY_PLUGINS=$$QT_MOBILITY_PREFIX/plugins +isEmpty($$QT_MOBILITY_EXAMPLES):QT_MOBILITY_EXAMPLES=$$QT_MOBILITY_PREFIX/bin +isEmpty($$QT_MOBILITY_DEMOS):QT_MOBILITY_DEMOS=$$QT_MOBILITY_PREFIX/bin +mobility_modules = bearer location contacts systeminfo publishsubscribe versit messaging sensors serviceframework multimedia gallery organizer feedback connectivity +contains(mobility_modules,versit): mobility_modules *= contacts +contains(mobility_modules,connectivity): mobility_modules *= serviceframework +lbt_enabled = yes +snap_enabled = yes +occ_enabled = yes +symbianenote_enabled = no +symbiancntsim_enabled = yes +symbiancntmodel_enabled = yes +symbiancntmodelv2_enabled = no +sensors_s60_31_enabled = no +sensors_symbian_enabled = yes +sensors_symbian_light_enabled = no +hb_symbian_enabled = no +audiorouting_s60_enabled = yes +tunerlib_s60_enabled = no +radioutility_s60_enabled = yes +openmaxal_symbian_enabled = no +surfaces_s60_enabled = yes +messaging_freestyle_enabled = yes +messaging_freestyle_mapi12_enabled = no +callinformation_symbian_enabled = yes +immersion_enabled = no +symbian_camera_camautofocus_enabled = no +symbian_camera_ecamadvsettings_enabled = yes +symbian_camera_devvideorecord_enabled = yes +advancedtouchfeedback_enabled = yes +chwrmhaptics_enabled = yes +mds_enabled = yes +mds_25_enabled = yes +mds_25_92mcl_enabled = yes +nfc_enabled = yes +btengconnman_symbian_enabled = yes +btengdevman_symbian_enabled = yes +MOBILITY_SD_MCL_BUILD = yes diff --git a/src/s60installs/deviceconfiguration/symbian3_qtmobility.pkg b/src/s60installs/deviceconfiguration/symbian3_qtmobility.pkg new file mode 100644 index 000000000..a96e9ac49 --- /dev/null +++ b/src/s60installs/deviceconfiguration/symbian3_qtmobility.pkg @@ -0,0 +1,128 @@ + +; Language +&EN + +; SIS header: name, uid, version +#{"QtMobility"},(0x2002AC89),1,2,0,TYPE=SA,RU + +; Default dependency to Qt libraries +(0x2001E61C), 4, 7, 2, {"Qt"} +; Default HW/platform dependencies +[0x102032BE],0,0,0,{"S60ProductID"} +[0x102752AE],0,0,0,{"S60ProductID"} +[0x1028315F],0,0,0,{"S60ProductID"} +[0x20022E6D],0,0,0,{"S60ProductID"} +[0x20032DE7],0,0,0,{"S60ProductID"} + +; Localised Vendor name +%{"Nokia"} + +; Unique Vendor name +:"Nokia" + +; DEPLOYMENT +"/epoc32/release/armv5/urel/qtbearer.dll" - "!:\sys\bin\qtbearer.dll" +"qtbearer{000a0000}.dll" - "!:\sys\bin\qtbearer{000a0000}.dll" +"/epoc32/release/armv5/urel/qtlocation.dll" - "!:\sys\bin\qtlocation.dll" +"/epoc32/release/armv5/urel/qtpublishsubscribe.dll" - "!:\sys\bin\qtpublishsubscribe.dll" +"/epoc32/release/armv5/urel/qpspathmapperserver.exe" - "!:\sys\bin\qpspathmapperserver.exe" +"/epoc32/release/armv5/urel/qtserviceframework.dll" - "!:\sys\bin\qtserviceframework.dll" +"/epoc32/release/armv5/urel/qsfwdatabasemanagerserver.exe" - "!:\sys\bin\qsfwdatabasemanagerserver.exe" +"/epoc32/release/armv5/urel/qtsysteminfo.dll" - "!:\sys\bin\qtsysteminfo.dll" +"/epoc32/release/armv5/urel/qtmessaging.dll" - "!:\sys\bin\qtmessaging.dll" +"/epoc32/release/armv5/urel/qtmultimediakit.dll" - "!:\sys\bin\qtmultimediakit.dll" +"/epoc32/release/armv5/urel/qtsensors.dll" - "!:\sys\bin\qtsensors.dll" +"/epoc32/release/armv5/urel/qtcontacts.dll" - "!:\sys\bin\qtcontacts.dll" +"/epoc32/release/armv5/urel/qtversit.dll" - "!:\sys\bin\qtversit.dll" +"/epoc32/release/armv5/urel/qtversitorganizer.dll" - "!:\sys\bin\qtversitorganizer.dll" +"/epoc32/release/armv5/urel/qtfeedback.dll" - "!:\sys\bin\qtfeedback.dll" +"/epoc32/release/armv5/urel/qtgallery.dll" - "!:\sys\bin\qtgallery.dll" +"/epoc32/release/armv5/urel/qtorganizer.dll" - "!:\sys\bin\qtorganizer.dll" +"/epoc32/release/armv5/urel/qtconnectivity.dll" - "!:\sys\bin\qtconnectivity.dll" + +"/epoc32/release/armv5/urel/qtcontacts_serviceactionmanager.dll" - "!:\sys\bin\qtcontacts_serviceactionmanager.dll" +"/epoc32/data/z/resource/qt/plugins/contacts/qtcontacts_serviceactionmanager.qtplugin" - "!:\resource\qt\plugins\contacts\qtcontacts_serviceactionmanager.qtplugin" +"/epoc32/release/armv5/urel/qtcontacts_symbian.dll" - "!:\sys\bin\qtcontacts_symbian.dll" +"/epoc32/data/z/resource/qt/plugins/contacts/qtcontacts_symbian.qtplugin" - "!:\resource\qt\plugins\contacts\qtcontacts_symbian.qtplugin" +"/epoc32/release/armv5/urel/qtcontacts_symbiansim.dll" - "!:\sys\bin\qtcontacts_symbiansim.dll" +"/epoc32/data/z/resource/qt/plugins/contacts/qtcontacts_symbiansim.qtplugin" - "!:\resource\qt\plugins\contacts\qtcontacts_symbiansim.qtplugin" +"/epoc32/release/armv5/urel/qtfeedback_mmk.dll" - "!:\sys\bin\qtfeedback_mmk.dll" +"/epoc32/data/z/resource/qt/plugins/feedback/qtfeedback_mmk.qtplugin" - "!:\resource\qt\plugins\feedback\qtfeedback_mmk.qtplugin" +"/epoc32/release/armv5/urel/qtfeedback_symbian.dll" - "!:\sys\bin\qtfeedback_symbian.dll" +"/epoc32/data/z/resource/qt/plugins/feedback/qtfeedback_symbian.qtplugin" - "!:\resource\qt\plugins\feedback\qtfeedback_symbian.qtplugin" +"/epoc32/release/armv5/urel/qtgeoservices_nokia.dll" - "!:\sys\bin\qtgeoservices_nokia.dll" +"/epoc32/data/z/resource/qt/plugins/geoservices/qtgeoservices_nokia.qtplugin" - "!:\resource\qt\plugins\geoservices\qtgeoservices_nokia.qtplugin" +"/epoc32/release/armv5/urel/qtlandmarks_symbian.dll" - "!:\sys\bin\qtlandmarks_symbian.dll" +"/epoc32/data/z/resource/qt/plugins/landmarks/qtlandmarks_symbian.qtplugin" - "!:\resource\qt\plugins\landmarks\qtlandmarks_symbian.qtplugin" +"/epoc32/release/armv5/urel/qtmultimediakit_m3u.dll" - "!:\sys\bin\qtmultimediakit_m3u.dll" +"/epoc32/data/z/resource/qt/plugins/playlistformats/qtmultimediakit_m3u.qtplugin" - "!:\resource\qt\plugins\playlistformats\qtmultimediakit_m3u.qtplugin" +"/epoc32/release/armv5/urel/qtmultimediakit_mmfengine.dll" - "!:\sys\bin\qtmultimediakit_mmfengine.dll" +"/epoc32/data/z/resource/qt/plugins/mediaservice/qtmultimediakit_mmfengine.qtplugin" - "!:\resource\qt\plugins\mediaservice\qtmultimediakit_mmfengine.qtplugin" +"/epoc32/release/armv5/urel/qtmultimediakit_ecamengine.dll" - "!:\sys\bin\qtmultimediakit_ecamengine.dll" +"/epoc32/data/z/resource/qt/plugins/mediaservice/qtmultimediakit_ecamengine.qtplugin" - "!:\resource\qt\plugins\mediaservice\qtmultimediakit_ecamengine.qtplugin" +"/epoc32/release/armv5/urel/qtorganizer_skeleton.dll" - "!:\sys\bin\qtorganizer_skeleton.dll" +"/epoc32/data/z/resource/qt/plugins/organizer/qtorganizer_skeleton.qtplugin" - "!:\resource\qt\plugins\organizer\qtorganizer_skeleton.qtplugin" +"/epoc32/release/armv5/urel/qtorganizer_symbian.dll" - "!:\sys\bin\qtorganizer_symbian.dll" +"/epoc32/data/z/resource/qt/plugins/organizer/qtorganizer_symbian.qtplugin" - "!:\resource\qt\plugins\organizer\qtorganizer_symbian.qtplugin" +"/epoc32/release/armv5/urel/qtsensors_generic.dll" - "!:\sys\bin\qtsensors_generic.dll" +"/epoc32/data/z/resource/qt/plugins/sensors/qtsensors_generic.qtplugin" - "!:\resource\qt\plugins\sensors\qtsensors_generic.qtplugin" +"/epoc32/release/armv5/urel/qtsensors_sym.dll" - "!:\sys\bin\qtsensors_sym.dll" +"/epoc32/data/z/resource/qt/plugins/sensors/qtsensors_sym.qtplugin" - "!:\resource\qt\plugins\sensors\qtsensors_sym.qtplugin" +"/epoc32/release/armv5/urel/qtversit_backuphandler.dll" - "!:\sys\bin\qtversit_backuphandler.dll" +"/epoc32/data/z/resource/qt/plugins/versit/qtversit_backuphandler.qtplugin" - "!:\resource\qt\plugins\versit\qtversit_backuphandler.qtplugin" +"/epoc32/release/armv5/urel/qtversit_vcardpreserver.dll" - "!:\sys\bin\qtversit_vcardpreserver.dll" +"/epoc32/data/z/resource/qt/plugins/versit/qtversit_vcardpreserver.qtplugin" - "!:\resource\qt\plugins\versit\qtversit_vcardpreserver.qtplugin" +"/epoc32/release/armv5/urel/cntversitfavoriteplugin.dll" - "!:\sys\bin\cntversitfavoriteplugin.dll" +"/epoc32/data/z/resource/qt/plugins/versit/cntversitfavoriteplugin.qtplugin" - "!:\resource\qt\plugins\versit\cntversitfavoriteplugin.qtplugin" +"/epoc32/release/armv5/urel/cntversitlandlineplugin.dll" - "!:\sys\bin\cntversitlandlineplugin.dll" +"/epoc32/data/z/resource/qt/plugins/versit/cntversitlandlineplugin.qtplugin" - "!:\resource\qt\plugins\versit\cntversitlandlineplugin.qtplugin" +"/epoc32/release/armv5/urel/cntversitmycardplugin.dll" - "!:\sys\bin\cntversitmycardplugin.dll" +"/epoc32/data/z/resource/qt/plugins/versit/cntversitmycardplugin.qtplugin" - "!:\resource\qt\plugins\versit\cntversitmycardplugin.qtplugin" +"/epoc32/release/armv5/urel/cntversitprefplugin.dll" - "!:\sys\bin\cntversitprefplugin.dll" +"/epoc32/data/z/resource/qt/plugins/versit/cntversitprefplugin.qtplugin" - "!:\resource\qt\plugins\versit\cntversitprefplugin.qtplugin" +"/epoc32/release/armv5/urel/declarative_contacts.dll" - "!:\sys\bin\declarative_contacts.dll" +"/epoc32/data/z/resource/qt/imports/qtmobility/contacts/declarative_contacts.qtplugin" - "!:\resource\qt\imports\qtmobility\contacts\declarative_contacts.qtplugin" +"/epoc32/data/z/resource/qt/imports/qtmobility/contacts/qmldir" - "!:\resource\qt\imports\qtmobility\contacts\qmldir" +"/epoc32/release/armv5/urel/declarative_feedback.dll" - "!:\sys\bin\declarative_feedback.dll" +"/epoc32/data/z/resource/qt/imports/qtmobility/feedback/declarative_feedback.qtplugin" - "!:\resource\qt\imports\qtmobility\feedback\declarative_feedback.qtplugin" +"/epoc32/data/z/resource/qt/imports/qtmobility/feedback/qmldir" - "!:\resource\qt\imports\qtmobility\feedback\qmldir" +"/epoc32/release/armv5/urel/declarative_gallery.dll" - "!:\sys\bin\declarative_gallery.dll" +"/epoc32/data/z/resource/qt/imports/qtmobility/gallery/declarative_gallery.qtplugin" - "!:\resource\qt\imports\qtmobility\gallery\declarative_gallery.qtplugin" +"/epoc32/data/z/resource/qt/imports/qtmobility/gallery/qmldir" - "!:\resource\qt\imports\qtmobility\gallery\qmldir" +"/epoc32/release/armv5/urel/declarative_location.dll" - "!:\sys\bin\declarative_location.dll" +"/epoc32/data/z/resource/qt/imports/qtmobility/location/declarative_location.qtplugin" - "!:\resource\qt\imports\qtmobility\location\declarative_location.qtplugin" +"/epoc32/data/z/resource/qt/imports/qtmobility/location/qmldir" - "!:\resource\qt\imports\qtmobility\location\qmldir" +"/epoc32/release/armv5/urel/declarative_messaging.dll" - "!:\sys\bin\declarative_messaging.dll" +"/epoc32/data/z/resource/qt/imports/qtmobility/messaging/declarative_messaging.qtplugin" - "!:\resource\qt\imports\qtmobility\messaging\declarative_messaging.qtplugin" +"/epoc32/data/z/resource/qt/imports/qtmobility/messaging/qmldir" - "!:\resource\qt\imports\qtmobility\messaging\qmldir" +"/epoc32/release/armv5/urel/declarative_multimedia.dll" - "!:\sys\bin\declarative_multimedia.dll" +"/epoc32/data/z/resource/qt/imports/qtmultimediakit/declarative_multimedia.qtplugin" - "!:\resource\qt\imports\qtmultimediakit\declarative_multimedia.qtplugin" +"/epoc32/data/z/resource/qt/imports/qtmultimediakit/qmldir" - "!:\resource\qt\imports\qtmultimediakit\qmldir" +"/epoc32/release/armv5/urel/declarative_organizer.dll" - "!:\sys\bin\declarative_organizer.dll" +"/epoc32/data/z/resource/qt/imports/qtmobility/organizer/declarative_organizer.qtplugin" - "!:\resource\qt\imports\qtmobility\organizer\declarative_organizer.qtplugin" +"/epoc32/data/z/resource/qt/imports/qtmobility/organizer/qmldir" - "!:\resource\qt\imports\qtmobility\organizer\qmldir" +"/epoc32/release/armv5/urel/declarative_publishsubscribe.dll" - "!:\sys\bin\declarative_publishsubscribe.dll" +"/epoc32/data/z/resource/qt/imports/qtmobility/publishsubscribe/declarative_publishsubscribe.qtplugin" - "!:\resource\qt\imports\qtmobility\publishsubscribe\declarative_publishsubscribe.qtplugin" +"/epoc32/data/z/resource/qt/imports/qtmobility/publishsubscribe/qmldir" - "!:\resource\qt\imports\qtmobility\publishsubscribe\qmldir" +"/epoc32/release/armv5/urel/declarative_sensors.dll" - "!:\sys\bin\declarative_sensors.dll" +"/epoc32/data/z/resource/qt/imports/qtmobility/sensors/declarative_sensors.qtplugin" - "!:\resource\qt\imports\qtmobility\sensors\declarative_sensors.qtplugin" +"/epoc32/data/z/resource/qt/imports/qtmobility/sensors/qmldir" - "!:\resource\qt\imports\qtmobility\sensors\qmldir" +"/epoc32/release/armv5/urel/declarative_serviceframework.dll" - "!:\sys\bin\declarative_serviceframework.dll" +"/epoc32/data/z/resource/qt/imports/qtmobility/serviceframework/declarative_serviceframework.qtplugin" - "!:\resource\qt\imports\qtmobility\serviceframework\declarative_serviceframework.qtplugin" +"/epoc32/data/z/resource/qt/imports/qtmobility/serviceframework/qmldir" - "!:\resource\qt\imports\qtmobility\serviceframework\qmldir" +"/epoc32/release/armv5/urel/declarative_systeminfo.dll" - "!:\sys\bin\declarative_systeminfo.dll" +"/epoc32/data/z/resource/qt/imports/qtmobility/systeminfo/declarative_systeminfo.qtplugin" - "!:\resource\qt\imports\qtmobility\systeminfo\declarative_systeminfo.qtplugin" +"/epoc32/data/z/resource/qt/imports/qtmobility/systeminfo/qmldir" - "!:\resource\qt\imports\qtmobility\systeminfo\qmldir" + +"/epoc32/data/z/private/10202D56/import/packages/2002AC89/backup_registration.xml" - "!:\private\10202D56\import\packages\2002AC89\backup_registration.xml" + +"/epoc32/release/armv5/urel/cntsrv.exe" - "!:\sys\bin\cntsrv.exe" +"/epoc32/release/armv5/urel/cntmodel.dll" - "!:\sys\bin\cntmodel.dll" +"/epoc32/release/armv5/urel/cntview.dll" - "!:\sys\bin\cntview.dll" +"/epoc32/release/armv5/urel/cntplsql.dll" - "!:\sys\bin\cntplsql.dll" +"/epoc32/release/armv5/urel/cntvcard.dll" - "!:\sys\bin\cntvcard.dll" +"/epoc32/release/armv5/urel/cntphone.dll" - "!:\sys\bin\cntphone.dll" +"/epoc32/release/armv5/urel/cntmatchlog.dll" - "!:\sys\bin\cntmatchlog.dll" +"/epoc32/data/z/resource/plugins/cntvcard.rsc" - "!:\resource\plugins\cntvcard.rsc" +"/epoc32/data/z/resource/plugins/cntphone.rsc" - "!:\resource\plugins\cntphone.rsc" +"/epoc32/data/z/resource/plugins/cntmatchlog.rsc" - "!:\resource\plugins\cntmatchlog.rsc" diff --git a/src/s60installs/eabi/QtMultimediaKitu.def b/src/s60installs/eabi/QtMultimediaKitu.def new file mode 100644 index 000000000..178d78430 --- /dev/null +++ b/src/s60installs/eabi/QtMultimediaKitu.def @@ -0,0 +1,1640 @@ +EXPORTS + _ZN11QAudioInput11qt_metacallEN11QMetaObject4CallEiPPv @ 1 NONAME + _ZN11QAudioInput11qt_metacastEPKc @ 2 NONAME + _ZN11QAudioInput12stateChangedEN6QAudio5StateE @ 3 NONAME + _ZN11QAudioInput13setBufferSizeEi @ 4 NONAME + _ZN11QAudioInput16staticMetaObjectE @ 5 NONAME DATA 16 + _ZN11QAudioInput17setNotifyIntervalEi @ 6 NONAME + _ZN11QAudioInput19getStaticMetaObjectEv @ 7 NONAME + _ZN11QAudioInput4stopEv @ 8 NONAME + _ZN11QAudioInput5resetEv @ 9 NONAME + _ZN11QAudioInput5startEP9QIODevice @ 10 NONAME + _ZN11QAudioInput5startEv @ 11 NONAME + _ZN11QAudioInput6notifyEv @ 12 NONAME + _ZN11QAudioInput6resumeEv @ 13 NONAME + _ZN11QAudioInput7suspendEv @ 14 NONAME + _ZN11QAudioInputC1ERK12QAudioFormatP7QObject @ 15 NONAME + _ZN11QAudioInputC1ERK16QAudioDeviceInfoRK12QAudioFormatP7QObject @ 16 NONAME + _ZN11QAudioInputC2ERK12QAudioFormatP7QObject @ 17 NONAME + _ZN11QAudioInputC2ERK16QAudioDeviceInfoRK12QAudioFormatP7QObject @ 18 NONAME + _ZN11QAudioInputD0Ev @ 19 NONAME + _ZN11QAudioInputD1Ev @ 20 NONAME + _ZN11QAudioInputD2Ev @ 21 NONAME + _ZN11QRadioTuner11bandChangedENS_4BandE @ 22 NONAME + _ZN11QRadioTuner11qt_metacallEN11QMetaObject4CallEiPPv @ 23 NONAME + _ZN11QRadioTuner11qt_metacastEPKc @ 24 NONAME + _ZN11QRadioTuner12cancelSearchEv @ 25 NONAME + _ZN11QRadioTuner12mutedChangedEb @ 26 NONAME + _ZN11QRadioTuner12setFrequencyEi @ 27 NONAME + _ZN11QRadioTuner12stateChangedENS_5StateE @ 28 NONAME + _ZN11QRadioTuner13searchForwardEv @ 29 NONAME + _ZN11QRadioTuner13setStereoModeENS_10StereoModeE @ 30 NONAME + _ZN11QRadioTuner13volumeChangedEi @ 31 NONAME + _ZN11QRadioTuner14searchBackwardEv @ 32 NONAME + _ZN11QRadioTuner16frequencyChangedEi @ 33 NONAME + _ZN11QRadioTuner16searchingChangedEb @ 34 NONAME + _ZN11QRadioTuner16staticMetaObjectE @ 35 NONAME DATA 16 + _ZN11QRadioTuner19getStaticMetaObjectEv @ 36 NONAME + _ZN11QRadioTuner19stereoStatusChangedEb @ 37 NONAME + _ZN11QRadioTuner21signalStrengthChangedEi @ 38 NONAME + _ZN11QRadioTuner4stopEv @ 39 NONAME + _ZN11QRadioTuner5errorENS_5ErrorE @ 40 NONAME + _ZN11QRadioTuner5startEv @ 41 NONAME + _ZN11QRadioTuner7setBandENS_4BandE @ 42 NONAME + _ZN11QRadioTuner8setMutedEb @ 43 NONAME + _ZN11QRadioTuner9setVolumeEi @ 44 NONAME + _ZN11QRadioTunerC1EP7QObjectP21QMediaServiceProvider @ 45 NONAME + _ZN11QRadioTunerC2EP7QObjectP21QMediaServiceProvider @ 46 NONAME + _ZN11QRadioTunerD0Ev @ 47 NONAME + _ZN11QRadioTunerD1Ev @ 48 NONAME + _ZN11QRadioTunerD2Ev @ 49 NONAME + _ZN11QVideoFrame10setEndTimeEx @ 50 NONAME + _ZN11QVideoFrame12setFieldTypeENS_9FieldTypeE @ 51 NONAME + _ZN11QVideoFrame12setStartTimeEx @ 52 NONAME + _ZN11QVideoFrame26imageFormatFromPixelFormatENS_11PixelFormatE @ 53 NONAME + _ZN11QVideoFrame26pixelFormatFromImageFormatEN6QImage6FormatE @ 54 NONAME + _ZN11QVideoFrame3mapEN20QAbstractVideoBuffer7MapModeE @ 55 NONAME + _ZN11QVideoFrame4bitsEv @ 56 NONAME + _ZN11QVideoFrame5unmapEv @ 57 NONAME + _ZN11QVideoFrameC1EP20QAbstractVideoBufferRK5QSizeNS_11PixelFormatE @ 58 NONAME + _ZN11QVideoFrameC1ERK6QImage @ 59 NONAME + _ZN11QVideoFrameC1ERKS_ @ 60 NONAME + _ZN11QVideoFrameC1EiRK5QSizeiNS_11PixelFormatE @ 61 NONAME + _ZN11QVideoFrameC1Ev @ 62 NONAME + _ZN11QVideoFrameC2EP20QAbstractVideoBufferRK5QSizeNS_11PixelFormatE @ 63 NONAME + _ZN11QVideoFrameC2ERK6QImage @ 64 NONAME + _ZN11QVideoFrameC2ERKS_ @ 65 NONAME + _ZN11QVideoFrameC2EiRK5QSizeiNS_11PixelFormatE @ 66 NONAME + _ZN11QVideoFrameC2Ev @ 67 NONAME + _ZN11QVideoFrameD1Ev @ 68 NONAME + _ZN11QVideoFrameD2Ev @ 69 NONAME + _ZN11QVideoFrameaSERKS_ @ 70 NONAME + _ZN12QAudioFormat11setChannelsEi @ 71 NONAME + _ZN12QAudioFormat12setByteOrderENS_6EndianE @ 72 NONAME + _ZN12QAudioFormat12setFrequencyEi @ 73 NONAME + _ZN12QAudioFormat13setSampleRateEi @ 74 NONAME + _ZN12QAudioFormat13setSampleSizeEi @ 75 NONAME + _ZN12QAudioFormat13setSampleTypeENS_10SampleTypeE @ 76 NONAME + _ZN12QAudioFormat15setChannelCountEi @ 77 NONAME + _ZN12QAudioFormat8setCodecERK7QString @ 78 NONAME + _ZN12QAudioFormatC1ERKS_ @ 79 NONAME + _ZN12QAudioFormatC1Ev @ 80 NONAME + _ZN12QAudioFormatC2ERKS_ @ 81 NONAME + _ZN12QAudioFormatC2Ev @ 82 NONAME + _ZN12QAudioFormatD1Ev @ 83 NONAME + _ZN12QAudioFormatD2Ev @ 84 NONAME + _ZN12QAudioFormataSERKS_ @ 85 NONAME + _ZN12QAudioOutput11qt_metacallEN11QMetaObject4CallEiPPv @ 86 NONAME + _ZN12QAudioOutput11qt_metacastEPKc @ 87 NONAME + _ZN12QAudioOutput12stateChangedEN6QAudio5StateE @ 88 NONAME + _ZN12QAudioOutput13setBufferSizeEi @ 89 NONAME + _ZN12QAudioOutput16staticMetaObjectE @ 90 NONAME DATA 16 + _ZN12QAudioOutput17setNotifyIntervalEi @ 91 NONAME + _ZN12QAudioOutput19getStaticMetaObjectEv @ 92 NONAME + _ZN12QAudioOutput4stopEv @ 93 NONAME + _ZN12QAudioOutput5resetEv @ 94 NONAME + _ZN12QAudioOutput5startEP9QIODevice @ 95 NONAME + _ZN12QAudioOutput5startEv @ 96 NONAME + _ZN12QAudioOutput6notifyEv @ 97 NONAME + _ZN12QAudioOutput6resumeEv @ 98 NONAME + _ZN12QAudioOutput7suspendEv @ 99 NONAME + _ZN12QAudioOutputC1ERK12QAudioFormatP7QObject @ 100 NONAME + _ZN12QAudioOutputC1ERK16QAudioDeviceInfoRK12QAudioFormatP7QObject @ 101 NONAME + _ZN12QAudioOutputC2ERK12QAudioFormatP7QObject @ 102 NONAME + _ZN12QAudioOutputC2ERK16QAudioDeviceInfoRK12QAudioFormatP7QObject @ 103 NONAME + _ZN12QAudioOutputD0Ev @ 104 NONAME + _ZN12QAudioOutputD1Ev @ 105 NONAME + _ZN12QAudioOutputD2Ev @ 106 NONAME + _ZN12QMediaObject11qt_metacallEN11QMetaObject4CallEiPPv @ 107 NONAME + _ZN12QMediaObject11qt_metacastEPKc @ 108 NONAME + _ZN12QMediaObject13setupMetaDataEv @ 109 NONAME + _ZN12QMediaObject15metaDataChangedEv @ 110 NONAME + _ZN12QMediaObject16addPropertyWatchERK10QByteArray @ 111 NONAME + _ZN12QMediaObject16staticMetaObjectE @ 112 NONAME DATA 16 + _ZN12QMediaObject17setNotifyIntervalEi @ 113 NONAME + _ZN12QMediaObject19availabilityChangedEb @ 114 NONAME + _ZN12QMediaObject19getStaticMetaObjectEv @ 115 NONAME + _ZN12QMediaObject19removePropertyWatchERK10QByteArray @ 116 NONAME + _ZN12QMediaObject21notifyIntervalChangedEi @ 117 NONAME + _ZN12QMediaObject24metaDataAvailableChangedEb @ 118 NONAME + _ZN12QMediaObject4bindEP7QObject @ 119 NONAME + _ZN12QMediaObject6unbindEP7QObject @ 120 NONAME + _ZN12QMediaObjectC1EP7QObjectP13QMediaService @ 121 NONAME + _ZN12QMediaObjectC1ER19QMediaObjectPrivateP7QObjectP13QMediaService @ 122 NONAME + _ZN12QMediaObjectC2EP7QObjectP13QMediaService @ 123 NONAME + _ZN12QMediaObjectC2ER19QMediaObjectPrivateP7QObjectP13QMediaService @ 124 NONAME + _ZN12QMediaObjectD0Ev @ 125 NONAME + _ZN12QMediaObjectD1Ev @ 126 NONAME + _ZN12QMediaObjectD2Ev @ 127 NONAME + _ZN12QMediaPlayer10hasSupportERK7QStringRK11QStringList6QFlagsINS_4FlagEE @ 128 NONAME + _ZN12QMediaPlayer11qt_metacallEN11QMetaObject4CallEiPPv @ 129 NONAME + _ZN12QMediaPlayer11qt_metacastEPKc @ 130 NONAME + _ZN12QMediaPlayer11setPlaylistEP14QMediaPlaylist @ 131 NONAME + _ZN12QMediaPlayer11setPositionEx @ 132 NONAME + _ZN12QMediaPlayer12mediaChangedERK13QMediaContent @ 133 NONAME + _ZN12QMediaPlayer12mutedChangedEb @ 134 NONAME + _ZN12QMediaPlayer12stateChangedENS_5StateE @ 135 NONAME + _ZN12QMediaPlayer13volumeChangedEi @ 136 NONAME + _ZN12QMediaPlayer14setVideoOutputEP12QVideoWidget @ 137 NONAME + _ZN12QMediaPlayer14setVideoOutputEP18QGraphicsVideoItem @ 138 NONAME + _ZN12QMediaPlayer15durationChangedEx @ 139 NONAME + _ZN12QMediaPlayer15positionChangedEx @ 140 NONAME + _ZN12QMediaPlayer15seekableChangedEb @ 141 NONAME + _ZN12QMediaPlayer15setPlaybackRateEf @ 142 NONAME + _ZN12QMediaPlayer16staticMetaObjectE @ 143 NONAME DATA 16 + _ZN12QMediaPlayer18mediaStatusChangedENS_11MediaStatusE @ 144 NONAME + _ZN12QMediaPlayer18supportedMimeTypesE6QFlagsINS_4FlagEE @ 145 NONAME + _ZN12QMediaPlayer19bufferStatusChangedEi @ 146 NONAME + _ZN12QMediaPlayer19getStaticMetaObjectEv @ 147 NONAME + _ZN12QMediaPlayer19playbackRateChangedEf @ 148 NONAME + _ZN12QMediaPlayer21audioAvailableChangedEb @ 149 NONAME + _ZN12QMediaPlayer21videoAvailableChangedEb @ 150 NONAME + _ZN12QMediaPlayer4bindEP7QObject @ 151 NONAME + _ZN12QMediaPlayer4playEv @ 152 NONAME + _ZN12QMediaPlayer4stopEv @ 153 NONAME + _ZN12QMediaPlayer5errorENS_5ErrorE @ 154 NONAME + _ZN12QMediaPlayer5pauseEv @ 155 NONAME + _ZN12QMediaPlayer6unbindEP7QObject @ 156 NONAME + _ZN12QMediaPlayer8setMediaERK13QMediaContentP9QIODevice @ 157 NONAME + _ZN12QMediaPlayer8setMutedEb @ 158 NONAME + _ZN12QMediaPlayer9setVolumeEi @ 159 NONAME + _ZN12QMediaPlayerC1EP7QObject6QFlagsINS_4FlagEEP21QMediaServiceProvider @ 160 NONAME + _ZN12QMediaPlayerC2EP7QObject6QFlagsINS_4FlagEEP21QMediaServiceProvider @ 161 NONAME + _ZN12QMediaPlayerD0Ev @ 162 NONAME + _ZN12QMediaPlayerD1Ev @ 163 NONAME + _ZN12QMediaPlayerD2Ev @ 164 NONAME + _ZN12QSoundEffect11qt_metacallEN11QMetaObject4CallEiPPv @ 165 NONAME + _ZN12QSoundEffect11qt_metacastEPKc @ 166 NONAME + _ZN12QSoundEffect12loopsChangedEv @ 167 NONAME ABSENT + _ZN12QSoundEffect12mutedChangedEv @ 168 NONAME + _ZN12QSoundEffect13sourceChangedEv @ 169 NONAME + _ZN12QSoundEffect13volumeChangedEv @ 170 NONAME + _ZN12QSoundEffect16staticMetaObjectE @ 171 NONAME DATA 16 + _ZN12QSoundEffect19getStaticMetaObjectEv @ 172 NONAME + _ZN12QSoundEffect4playEv @ 173 NONAME + _ZN12QSoundEffect8setLoopsEi @ 174 NONAME ABSENT + _ZN12QSoundEffect8setMutedEb @ 175 NONAME + _ZN12QSoundEffect9setSourceERK4QUrl @ 176 NONAME + _ZN12QSoundEffect9setVolumeEf @ 177 NONAME + _ZN12QSoundEffectC1EP7QObject @ 178 NONAME + _ZN12QSoundEffectC2EP7QObject @ 179 NONAME + _ZN12QSoundEffectD0Ev @ 180 NONAME + _ZN12QSoundEffectD1Ev @ 181 NONAME + _ZN12QSoundEffectD2Ev @ 182 NONAME + _ZN12QVideoWidget10hueChangedEi @ 183 NONAME + _ZN12QVideoWidget10paintEventEP11QPaintEvent @ 184 NONAME + _ZN12QVideoWidget11qt_metacallEN11QMetaObject4CallEiPPv @ 185 NONAME + _ZN12QVideoWidget11qt_metacastEPKc @ 186 NONAME + _ZN12QVideoWidget11resizeEventEP12QResizeEvent @ 187 NONAME + _ZN12QVideoWidget11setContrastEi @ 188 NONAME + _ZN12QVideoWidget13setBrightnessEi @ 189 NONAME + _ZN12QVideoWidget13setFullScreenEb @ 190 NONAME + _ZN12QVideoWidget13setSaturationEi @ 191 NONAME + _ZN12QVideoWidget14setMediaObjectEP12QMediaObject @ 192 NONAME + _ZN12QVideoWidget15contrastChangedEi @ 193 NONAME + _ZN12QVideoWidget16staticMetaObjectE @ 194 NONAME DATA 16 + _ZN12QVideoWidget17brightnessChangedEi @ 195 NONAME + _ZN12QVideoWidget17fullScreenChangedEb @ 196 NONAME + _ZN12QVideoWidget17saturationChangedEi @ 197 NONAME + _ZN12QVideoWidget18setAspectRatioModeEN2Qt15AspectRatioModeE @ 198 NONAME + _ZN12QVideoWidget19getStaticMetaObjectEv @ 199 NONAME + _ZN12QVideoWidget5eventEP6QEvent @ 200 NONAME + _ZN12QVideoWidget6setHueEi @ 201 NONAME + _ZN12QVideoWidget9hideEventEP10QHideEvent @ 202 NONAME + _ZN12QVideoWidget9moveEventEP10QMoveEvent @ 203 NONAME + _ZN12QVideoWidget9showEventEP10QShowEvent @ 204 NONAME + _ZN12QVideoWidgetC1EP7QWidget @ 205 NONAME + _ZN12QVideoWidgetC2EP7QWidget @ 206 NONAME + _ZN12QVideoWidgetD0Ev @ 207 NONAME + _ZN12QVideoWidgetD1Ev @ 208 NONAME + _ZN12QVideoWidgetD2Ev @ 209 NONAME + _ZN13QMediaContentC1ERK14QMediaResource @ 210 NONAME + _ZN13QMediaContentC1ERK15QNetworkRequest @ 211 NONAME + _ZN13QMediaContentC1ERK4QUrl @ 212 NONAME + _ZN13QMediaContentC1ERK5QListI14QMediaResourceE @ 213 NONAME + _ZN13QMediaContentC1ERKS_ @ 214 NONAME + _ZN13QMediaContentC1Ev @ 215 NONAME + _ZN13QMediaContentC2ERK14QMediaResource @ 216 NONAME + _ZN13QMediaContentC2ERK15QNetworkRequest @ 217 NONAME + _ZN13QMediaContentC2ERK4QUrl @ 218 NONAME + _ZN13QMediaContentC2ERK5QListI14QMediaResourceE @ 219 NONAME + _ZN13QMediaContentC2ERKS_ @ 220 NONAME + _ZN13QMediaContentC2Ev @ 221 NONAME + _ZN13QMediaContentD1Ev @ 222 NONAME + _ZN13QMediaContentD2Ev @ 223 NONAME + _ZN13QMediaContentaSERKS_ @ 224 NONAME + _ZN13QMediaControl11qt_metacallEN11QMetaObject4CallEiPPv @ 225 NONAME + _ZN13QMediaControl11qt_metacastEPKc @ 226 NONAME + _ZN13QMediaControl16staticMetaObjectE @ 227 NONAME DATA 16 + _ZN13QMediaControl19getStaticMetaObjectEv @ 228 NONAME + _ZN13QMediaControlC1EP7QObject @ 229 NONAME + _ZN13QMediaControlC1ER20QMediaControlPrivateP7QObject @ 230 NONAME + _ZN13QMediaControlC2EP7QObject @ 231 NONAME + _ZN13QMediaControlC2ER20QMediaControlPrivateP7QObject @ 232 NONAME + _ZN13QMediaControlD0Ev @ 233 NONAME + _ZN13QMediaControlD1Ev @ 234 NONAME + _ZN13QMediaControlD2Ev @ 235 NONAME + _ZN13QMediaService11qt_metacallEN11QMetaObject4CallEiPPv @ 236 NONAME + _ZN13QMediaService11qt_metacastEPKc @ 237 NONAME + _ZN13QMediaService16staticMetaObjectE @ 238 NONAME DATA 16 + _ZN13QMediaService19getStaticMetaObjectEv @ 239 NONAME + _ZN13QMediaServiceC2EP7QObject @ 240 NONAME + _ZN13QMediaServiceC2ER20QMediaServicePrivateP7QObject @ 241 NONAME + _ZN13QMediaServiceD0Ev @ 242 NONAME + _ZN13QMediaServiceD1Ev @ 243 NONAME + _ZN13QMediaServiceD2Ev @ 244 NONAME + _ZN14QMediaPlaylist10loadFailedEv @ 245 NONAME + _ZN14QMediaPlaylist11insertMediaEiRK13QMediaContent @ 246 NONAME + _ZN14QMediaPlaylist11insertMediaEiRK5QListI13QMediaContentE @ 247 NONAME + _ZN14QMediaPlaylist11qt_metacallEN11QMetaObject4CallEiPPv @ 248 NONAME + _ZN14QMediaPlaylist11qt_metacastEPKc @ 249 NONAME + _ZN14QMediaPlaylist11removeMediaEi @ 250 NONAME + _ZN14QMediaPlaylist11removeMediaEii @ 251 NONAME + _ZN14QMediaPlaylist12mediaChangedEii @ 252 NONAME + _ZN14QMediaPlaylist12mediaRemovedEii @ 253 NONAME + _ZN14QMediaPlaylist13mediaInsertedEii @ 254 NONAME + _ZN14QMediaPlaylist14setMediaObjectEP12QMediaObject @ 255 NONAME + _ZN14QMediaPlaylist15setCurrentIndexEi @ 256 NONAME + _ZN14QMediaPlaylist15setPlaybackModeENS_12PlaybackModeE @ 257 NONAME + _ZN14QMediaPlaylist16staticMetaObjectE @ 258 NONAME DATA 16 + _ZN14QMediaPlaylist19currentIndexChangedEi @ 259 NONAME + _ZN14QMediaPlaylist19currentMediaChangedERK13QMediaContent @ 260 NONAME + _ZN14QMediaPlaylist19getStaticMetaObjectEv @ 261 NONAME + _ZN14QMediaPlaylist19playbackModeChangedENS_12PlaybackModeE @ 262 NONAME + _ZN14QMediaPlaylist21mediaAboutToBeRemovedEii @ 263 NONAME + _ZN14QMediaPlaylist22mediaAboutToBeInsertedEii @ 264 NONAME + _ZN14QMediaPlaylist4loadEP9QIODevicePKc @ 265 NONAME + _ZN14QMediaPlaylist4loadERK4QUrlPKc @ 266 NONAME + _ZN14QMediaPlaylist4nextEv @ 267 NONAME + _ZN14QMediaPlaylist4saveEP9QIODevicePKc @ 268 NONAME + _ZN14QMediaPlaylist4saveERK4QUrlPKc @ 269 NONAME + _ZN14QMediaPlaylist5clearEv @ 270 NONAME + _ZN14QMediaPlaylist6loadedEv @ 271 NONAME + _ZN14QMediaPlaylist7shuffleEv @ 272 NONAME + _ZN14QMediaPlaylist8addMediaERK13QMediaContent @ 273 NONAME + _ZN14QMediaPlaylist8addMediaERK5QListI13QMediaContentE @ 274 NONAME + _ZN14QMediaPlaylist8previousEv @ 275 NONAME + _ZN14QMediaPlaylistC1EP7QObject @ 276 NONAME + _ZN14QMediaPlaylistC2EP7QObject @ 277 NONAME + _ZN14QMediaPlaylistD0Ev @ 278 NONAME + _ZN14QMediaPlaylistD1Ev @ 279 NONAME + _ZN14QMediaPlaylistD2Ev @ 280 NONAME + _ZN14QMediaRecorder11qt_metacallEN11QMetaObject4CallEiPPv @ 281 NONAME + _ZN14QMediaRecorder11qt_metacastEPKc @ 282 NONAME + _ZN14QMediaRecorder11setMetaDataEN15QtMultimediaKit8MetaDataERK8QVariant @ 283 NONAME + _ZN14QMediaRecorder12mutedChangedEb @ 284 NONAME + _ZN14QMediaRecorder12stateChangedENS_5StateE @ 285 NONAME + _ZN14QMediaRecorder14setMediaObjectEP12QMediaObject @ 286 NONAME + _ZN14QMediaRecorder15durationChangedEx @ 287 NONAME + _ZN14QMediaRecorder15metaDataChangedEv @ 288 NONAME + _ZN14QMediaRecorder16staticMetaObjectE @ 289 NONAME DATA 16 + _ZN14QMediaRecorder17setOutputLocationERK4QUrl @ 290 NONAME + _ZN14QMediaRecorder19getStaticMetaObjectEv @ 291 NONAME + _ZN14QMediaRecorder19setEncodingSettingsERK21QAudioEncoderSettingsRK21QVideoEncoderSettingsRK7QString @ 292 NONAME + _ZN14QMediaRecorder19setExtendedMetaDataERK7QStringRK8QVariant @ 293 NONAME + _ZN14QMediaRecorder23metaDataWritableChangedEb @ 294 NONAME + _ZN14QMediaRecorder24metaDataAvailableChangedEb @ 295 NONAME + _ZN14QMediaRecorder4stopEv @ 296 NONAME + _ZN14QMediaRecorder5errorENS_5ErrorE @ 297 NONAME + _ZN14QMediaRecorder5pauseEv @ 298 NONAME + _ZN14QMediaRecorder6recordEv @ 299 NONAME + _ZN14QMediaRecorder8setMutedEb @ 300 NONAME + _ZN14QMediaRecorderC1EP12QMediaObjectP7QObject @ 301 NONAME + _ZN14QMediaRecorderC2EP12QMediaObjectP7QObject @ 302 NONAME + _ZN14QMediaRecorderD0Ev @ 303 NONAME + _ZN14QMediaRecorderD1Ev @ 304 NONAME + _ZN14QMediaRecorderD2Ev @ 305 NONAME + _ZN14QMediaResource11setDataSizeEx @ 306 NONAME + _ZN14QMediaResource11setLanguageERK7QString @ 307 NONAME + _ZN14QMediaResource13setAudioCodecERK7QString @ 308 NONAME + _ZN14QMediaResource13setResolutionERK5QSize @ 309 NONAME + _ZN14QMediaResource13setResolutionEii @ 310 NONAME + _ZN14QMediaResource13setSampleRateEi @ 311 NONAME + _ZN14QMediaResource13setVideoCodecERK7QString @ 312 NONAME + _ZN14QMediaResource15setAudioBitRateEi @ 313 NONAME + _ZN14QMediaResource15setChannelCountEi @ 314 NONAME + _ZN14QMediaResource15setVideoBitRateEi @ 315 NONAME + _ZN14QMediaResourceC1ERK15QNetworkRequestRK7QString @ 316 NONAME + _ZN14QMediaResourceC1ERK4QUrlRK7QString @ 317 NONAME + _ZN14QMediaResourceC1ERKS_ @ 318 NONAME + _ZN14QMediaResourceC1Ev @ 319 NONAME + _ZN14QMediaResourceC2ERK15QNetworkRequestRK7QString @ 320 NONAME + _ZN14QMediaResourceC2ERK4QUrlRK7QString @ 321 NONAME + _ZN14QMediaResourceC2ERKS_ @ 322 NONAME + _ZN14QMediaResourceC2Ev @ 323 NONAME + _ZN14QMediaResourceD1Ev @ 324 NONAME + _ZN14QMediaResourceD2Ev @ 325 NONAME + _ZN14QMediaResourceaSERKS_ @ 326 NONAME + _ZN15QMediaTimeRange11addIntervalERK18QMediaTimeInterval @ 327 NONAME + _ZN15QMediaTimeRange11addIntervalExx @ 328 NONAME + _ZN15QMediaTimeRange12addTimeRangeERKS_ @ 329 NONAME + _ZN15QMediaTimeRange14removeIntervalERK18QMediaTimeInterval @ 330 NONAME + _ZN15QMediaTimeRange14removeIntervalExx @ 331 NONAME + _ZN15QMediaTimeRange15removeTimeRangeERKS_ @ 332 NONAME + _ZN15QMediaTimeRange5clearEv @ 333 NONAME + _ZN15QMediaTimeRangeC1ERK18QMediaTimeInterval @ 334 NONAME + _ZN15QMediaTimeRangeC1ERKS_ @ 335 NONAME + _ZN15QMediaTimeRangeC1Ev @ 336 NONAME + _ZN15QMediaTimeRangeC1Exx @ 337 NONAME + _ZN15QMediaTimeRangeC2ERK18QMediaTimeInterval @ 338 NONAME + _ZN15QMediaTimeRangeC2ERKS_ @ 339 NONAME + _ZN15QMediaTimeRangeC2Ev @ 340 NONAME + _ZN15QMediaTimeRangeC2Exx @ 341 NONAME + _ZN15QMediaTimeRangeD1Ev @ 342 NONAME + _ZN15QMediaTimeRangeD2Ev @ 343 NONAME + _ZN15QMediaTimeRangeaSERK18QMediaTimeInterval @ 344 NONAME + _ZN15QMediaTimeRangeaSERKS_ @ 345 NONAME + _ZN15QMediaTimeRangemIERK18QMediaTimeInterval @ 346 NONAME + _ZN15QMediaTimeRangemIERKS_ @ 347 NONAME + _ZN15QMediaTimeRangepLERK18QMediaTimeInterval @ 348 NONAME + _ZN15QMediaTimeRangepLERKS_ @ 349 NONAME + _ZN16QAudioDeviceInfo16availableDevicesEN6QAudio4ModeE @ 350 NONAME + _ZN16QAudioDeviceInfo18defaultInputDeviceEv @ 351 NONAME + _ZN16QAudioDeviceInfo19defaultOutputDeviceEv @ 352 NONAME + _ZN16QAudioDeviceInfoC1ERK7QStringRK10QByteArrayN6QAudio4ModeE @ 353 NONAME + _ZN16QAudioDeviceInfoC1ERKS_ @ 354 NONAME + _ZN16QAudioDeviceInfoC1Ev @ 355 NONAME + _ZN16QAudioDeviceInfoC2ERK7QStringRK10QByteArrayN6QAudio4ModeE @ 356 NONAME + _ZN16QAudioDeviceInfoC2ERKS_ @ 357 NONAME + _ZN16QAudioDeviceInfoC2Ev @ 358 NONAME + _ZN16QAudioDeviceInfoD1Ev @ 359 NONAME + _ZN16QAudioDeviceInfoD2Ev @ 360 NONAME + _ZN16QAudioDeviceInfoaSERKS_ @ 361 NONAME + _ZN17QImageVideoBuffer3mapEN20QAbstractVideoBuffer7MapModeEPiS2_ @ 362 NONAME + _ZN17QImageVideoBuffer5unmapEv @ 363 NONAME + _ZN17QImageVideoBufferC1ERK6QImage @ 364 NONAME + _ZN17QImageVideoBufferC2ERK6QImage @ 365 NONAME + _ZN17QImageVideoBufferD0Ev @ 366 NONAME + _ZN17QImageVideoBufferD1Ev @ 367 NONAME + _ZN17QImageVideoBufferD2Ev @ 368 NONAME + _ZN17QMediaImageViewer10setTimeoutEi @ 369 NONAME + _ZN17QMediaImageViewer10timerEventEP11QTimerEvent @ 370 NONAME + _ZN17QMediaImageViewer11qt_metacallEN11QMetaObject4CallEiPPv @ 371 NONAME + _ZN17QMediaImageViewer11qt_metacastEPKc @ 372 NONAME + _ZN17QMediaImageViewer11setPlaylistEP14QMediaPlaylist @ 373 NONAME + _ZN17QMediaImageViewer12mediaChangedERK13QMediaContent @ 374 NONAME + _ZN17QMediaImageViewer12stateChangedENS_5StateE @ 375 NONAME + _ZN17QMediaImageViewer16staticMetaObjectE @ 376 NONAME DATA 16 + _ZN17QMediaImageViewer18elapsedTimeChangedEi @ 377 NONAME + _ZN17QMediaImageViewer18mediaStatusChangedENS_11MediaStatusE @ 378 NONAME + _ZN17QMediaImageViewer19getStaticMetaObjectEv @ 379 NONAME + _ZN17QMediaImageViewer4bindEP7QObject @ 380 NONAME + _ZN17QMediaImageViewer4playEv @ 381 NONAME + _ZN17QMediaImageViewer4stopEv @ 382 NONAME + _ZN17QMediaImageViewer5pauseEv @ 383 NONAME + _ZN17QMediaImageViewer6unbindEP7QObject @ 384 NONAME + _ZN17QMediaImageViewer8setMediaERK13QMediaContent @ 385 NONAME + _ZN17QMediaImageViewerC1EP7QObject @ 386 NONAME + _ZN17QMediaImageViewerC2EP7QObject @ 387 NONAME + _ZN17QMediaImageViewerD0Ev @ 388 NONAME + _ZN17QMediaImageViewerD1Ev @ 389 NONAME + _ZN17QMediaImageViewerD2Ev @ 390 NONAME + _ZN18QAudioSystemPlugin11qt_metacallEN11QMetaObject4CallEiPPv @ 391 NONAME + _ZN18QAudioSystemPlugin11qt_metacastEPKc @ 392 NONAME + _ZN18QAudioSystemPlugin16staticMetaObjectE @ 393 NONAME DATA 16 + _ZN18QAudioSystemPlugin19getStaticMetaObjectEv @ 394 NONAME + _ZN18QAudioSystemPluginC2EP7QObject @ 395 NONAME + _ZN18QAudioSystemPluginD0Ev @ 396 NONAME + _ZN18QAudioSystemPluginD1Ev @ 397 NONAME + _ZN18QAudioSystemPluginD2Ev @ 398 NONAME + _ZN18QGraphicsVideoItem10itemChangeEN13QGraphicsItem18GraphicsItemChangeERK8QVariant @ 399 NONAME + _ZN18QGraphicsVideoItem10timerEventEP11QTimerEvent @ 400 NONAME + _ZN18QGraphicsVideoItem11qt_metacallEN11QMetaObject4CallEiPPv @ 401 NONAME + _ZN18QGraphicsVideoItem11qt_metacastEPKc @ 402 NONAME + _ZN18QGraphicsVideoItem14setMediaObjectEP12QMediaObject @ 403 NONAME + _ZN18QGraphicsVideoItem16staticMetaObjectE @ 404 NONAME DATA 16 + _ZN18QGraphicsVideoItem17nativeSizeChangedERK6QSizeF @ 405 NONAME + _ZN18QGraphicsVideoItem18setAspectRatioModeEN2Qt15AspectRatioModeE @ 406 NONAME + _ZN18QGraphicsVideoItem19getStaticMetaObjectEv @ 407 NONAME + _ZN18QGraphicsVideoItem5paintEP8QPainterPK24QStyleOptionGraphicsItemP7QWidget @ 408 NONAME + _ZN18QGraphicsVideoItem7setSizeERK6QSizeF @ 409 NONAME + _ZN18QGraphicsVideoItem9setOffsetERK7QPointF @ 410 NONAME + _ZN18QGraphicsVideoItemC1EP13QGraphicsItem @ 411 NONAME + _ZN18QGraphicsVideoItemC2EP13QGraphicsItem @ 412 NONAME + _ZN18QGraphicsVideoItemD0Ev @ 413 NONAME + _ZN18QGraphicsVideoItemD1Ev @ 414 NONAME + _ZN18QGraphicsVideoItemD2Ev @ 415 NONAME + _ZN18QMediaTimeIntervalC1ERKS_ @ 416 NONAME + _ZN18QMediaTimeIntervalC1Ev @ 417 NONAME + _ZN18QMediaTimeIntervalC1Exx @ 418 NONAME + _ZN18QMediaTimeIntervalC2ERKS_ @ 419 NONAME + _ZN18QMediaTimeIntervalC2Ev @ 420 NONAME + _ZN18QMediaTimeIntervalC2Exx @ 421 NONAME + _ZN18QMemoryVideoBuffer3mapEN20QAbstractVideoBuffer7MapModeEPiS2_ @ 422 NONAME + _ZN18QMemoryVideoBuffer5unmapEv @ 423 NONAME + _ZN18QMemoryVideoBufferC1ERK10QByteArrayi @ 424 NONAME + _ZN18QMemoryVideoBufferC2ERK10QByteArrayi @ 425 NONAME + _ZN18QMemoryVideoBufferD0Ev @ 426 NONAME + _ZN18QMemoryVideoBufferD1Ev @ 427 NONAME + _ZN18QMemoryVideoBufferD2Ev @ 428 NONAME + _ZN18QRadioTunerControl11bandChangedEN11QRadioTuner4BandE @ 429 NONAME + _ZN18QRadioTunerControl11qt_metacallEN11QMetaObject4CallEiPPv @ 430 NONAME + _ZN18QRadioTunerControl11qt_metacastEPKc @ 431 NONAME + _ZN18QRadioTunerControl12mutedChangedEb @ 432 NONAME + _ZN18QRadioTunerControl12stateChangedEN11QRadioTuner5StateE @ 433 NONAME + _ZN18QRadioTunerControl13volumeChangedEi @ 434 NONAME + _ZN18QRadioTunerControl16frequencyChangedEi @ 435 NONAME + _ZN18QRadioTunerControl16searchingChangedEb @ 436 NONAME + _ZN18QRadioTunerControl16staticMetaObjectE @ 437 NONAME DATA 16 + _ZN18QRadioTunerControl19getStaticMetaObjectEv @ 438 NONAME + _ZN18QRadioTunerControl19stereoStatusChangedEb @ 439 NONAME + _ZN18QRadioTunerControl21signalStrengthChangedEi @ 440 NONAME + _ZN18QRadioTunerControl5errorEN11QRadioTuner5ErrorE @ 441 NONAME + _ZN18QRadioTunerControlC2EP7QObject @ 442 NONAME + _ZN18QRadioTunerControlD0Ev @ 443 NONAME + _ZN18QRadioTunerControlD1Ev @ 444 NONAME + _ZN18QRadioTunerControlD2Ev @ 445 NONAME + _ZN19QAbstractAudioInput11qt_metacallEN11QMetaObject4CallEiPPv @ 446 NONAME + _ZN19QAbstractAudioInput11qt_metacastEPKc @ 447 NONAME + _ZN19QAbstractAudioInput12errorChangedEN6QAudio5ErrorE @ 448 NONAME + _ZN19QAbstractAudioInput12stateChangedEN6QAudio5StateE @ 449 NONAME + _ZN19QAbstractAudioInput16staticMetaObjectE @ 450 NONAME DATA 16 + _ZN19QAbstractAudioInput19getStaticMetaObjectEv @ 451 NONAME + _ZN19QAbstractAudioInput6notifyEv @ 452 NONAME + _ZN19QAudioCaptureSource11qt_metacallEN11QMetaObject4CallEiPPv @ 453 NONAME + _ZN19QAudioCaptureSource11qt_metacastEPKc @ 454 NONAME + _ZN19QAudioCaptureSource13setAudioInputERK7QString @ 455 NONAME + _ZN19QAudioCaptureSource13statusChangedEv @ 456 NONAME + _ZN19QAudioCaptureSource16staticMetaObjectE @ 457 NONAME DATA 16 + _ZN19QAudioCaptureSource19getStaticMetaObjectEv @ 458 NONAME + _ZN19QAudioCaptureSource23activeAudioInputChangedERK7QString @ 459 NONAME + _ZN19QAudioCaptureSource27availableAudioInputsChangedEv @ 460 NONAME + _ZN19QAudioCaptureSourceC1EP7QObjectP21QMediaServiceProvider @ 461 NONAME + _ZN19QAudioCaptureSourceC2EP7QObjectP21QMediaServiceProvider @ 462 NONAME + _ZN19QAudioCaptureSourceD0Ev @ 463 NONAME + _ZN19QAudioCaptureSourceD1Ev @ 464 NONAME + _ZN19QAudioCaptureSourceD2Ev @ 465 NONAME + _ZN19QMediaPlayerControl11qt_metacallEN11QMetaObject4CallEiPPv @ 466 NONAME + _ZN19QMediaPlayerControl11qt_metacastEPKc @ 467 NONAME + _ZN19QMediaPlayerControl12mediaChangedERK13QMediaContent @ 468 NONAME + _ZN19QMediaPlayerControl12mutedChangedEb @ 469 NONAME + _ZN19QMediaPlayerControl12stateChangedEN12QMediaPlayer5StateE @ 470 NONAME + _ZN19QMediaPlayerControl13volumeChangedEi @ 471 NONAME + _ZN19QMediaPlayerControl15durationChangedEx @ 472 NONAME + _ZN19QMediaPlayerControl15positionChangedEx @ 473 NONAME + _ZN19QMediaPlayerControl15seekableChangedEb @ 474 NONAME + _ZN19QMediaPlayerControl16staticMetaObjectE @ 475 NONAME DATA 16 + _ZN19QMediaPlayerControl18mediaStatusChangedEN12QMediaPlayer11MediaStatusE @ 476 NONAME + _ZN19QMediaPlayerControl19bufferStatusChangedEi @ 477 NONAME + _ZN19QMediaPlayerControl19getStaticMetaObjectEv @ 478 NONAME + _ZN19QMediaPlayerControl19playbackRateChangedEf @ 479 NONAME + _ZN19QMediaPlayerControl21audioAvailableChangedEb @ 480 NONAME + _ZN19QMediaPlayerControl21videoAvailableChangedEb @ 481 NONAME + _ZN19QMediaPlayerControl30availablePlaybackRangesChangedERK15QMediaTimeRange @ 482 NONAME + _ZN19QMediaPlayerControl5errorEiRK7QString @ 483 NONAME + _ZN19QMediaPlayerControlC2EP7QObject @ 484 NONAME + _ZN19QMediaPlayerControlD0Ev @ 485 NONAME + _ZN19QMediaPlayerControlD1Ev @ 486 NONAME + _ZN19QMediaPlayerControlD2Ev @ 487 NONAME + _ZN19QVideoDeviceControl11qt_metacallEN11QMetaObject4CallEiPPv @ 488 NONAME + _ZN19QVideoDeviceControl11qt_metacastEPKc @ 489 NONAME + _ZN19QVideoDeviceControl14devicesChangedEv @ 490 NONAME + _ZN19QVideoDeviceControl16staticMetaObjectE @ 491 NONAME DATA 16 + _ZN19QVideoDeviceControl19getStaticMetaObjectEv @ 492 NONAME + _ZN19QVideoDeviceControl21selectedDeviceChangedERK7QString @ 493 NONAME + _ZN19QVideoDeviceControl21selectedDeviceChangedEi @ 494 NONAME + _ZN19QVideoDeviceControlC2EP7QObject @ 495 NONAME + _ZN19QVideoDeviceControlD0Ev @ 496 NONAME + _ZN19QVideoDeviceControlD1Ev @ 497 NONAME + _ZN19QVideoDeviceControlD2Ev @ 498 NONAME + _ZN19QVideoSurfaceFormat11setPropertyEPKcRK8QVariant @ 499 NONAME + _ZN19QVideoSurfaceFormat11setViewportERK5QRect @ 500 NONAME + _ZN19QVideoSurfaceFormat12setFrameRateEf @ 501 NONAME + _ZN19QVideoSurfaceFormat12setFrameSizeERK5QSize @ 502 NONAME + _ZN19QVideoSurfaceFormat12setFrameSizeEii @ 503 NONAME + _ZN19QVideoSurfaceFormat18setYCbCrColorSpaceENS_15YCbCrColorSpaceE @ 504 NONAME + _ZN19QVideoSurfaceFormat19setPixelAspectRatioERK5QSize @ 505 NONAME + _ZN19QVideoSurfaceFormat19setPixelAspectRatioEii @ 506 NONAME + _ZN19QVideoSurfaceFormat20setScanLineDirectionENS_9DirectionE @ 507 NONAME + _ZN19QVideoSurfaceFormatC1ERK5QSizeN11QVideoFrame11PixelFormatEN20QAbstractVideoBuffer10HandleTypeE @ 508 NONAME + _ZN19QVideoSurfaceFormatC1ERKS_ @ 509 NONAME + _ZN19QVideoSurfaceFormatC1Ev @ 510 NONAME + _ZN19QVideoSurfaceFormatC2ERK5QSizeN11QVideoFrame11PixelFormatEN20QAbstractVideoBuffer10HandleTypeE @ 511 NONAME + _ZN19QVideoSurfaceFormatC2ERKS_ @ 512 NONAME + _ZN19QVideoSurfaceFormatC2Ev @ 513 NONAME + _ZN19QVideoSurfaceFormatD1Ev @ 514 NONAME + _ZN19QVideoSurfaceFormatD2Ev @ 515 NONAME + _ZN19QVideoSurfaceFormataSERKS_ @ 516 NONAME + _ZN19QVideoWidgetControl10hueChangedEi @ 517 NONAME + _ZN19QVideoWidgetControl11qt_metacallEN11QMetaObject4CallEiPPv @ 518 NONAME + _ZN19QVideoWidgetControl11qt_metacastEPKc @ 519 NONAME + _ZN19QVideoWidgetControl15contrastChangedEi @ 520 NONAME + _ZN19QVideoWidgetControl16staticMetaObjectE @ 521 NONAME DATA 16 + _ZN19QVideoWidgetControl17brightnessChangedEi @ 522 NONAME + _ZN19QVideoWidgetControl17fullScreenChangedEb @ 523 NONAME + _ZN19QVideoWidgetControl17saturationChangedEi @ 524 NONAME + _ZN19QVideoWidgetControl19getStaticMetaObjectEv @ 525 NONAME + _ZN19QVideoWidgetControlC2EP7QObject @ 526 NONAME + _ZN19QVideoWidgetControlD0Ev @ 527 NONAME + _ZN19QVideoWidgetControlD1Ev @ 528 NONAME + _ZN19QVideoWidgetControlD2Ev @ 529 NONAME + _ZN19QVideoWindowControl10hueChangedEi @ 530 NONAME + _ZN19QVideoWindowControl11qt_metacallEN11QMetaObject4CallEiPPv @ 531 NONAME + _ZN19QVideoWindowControl11qt_metacastEPKc @ 532 NONAME + _ZN19QVideoWindowControl15contrastChangedEi @ 533 NONAME + _ZN19QVideoWindowControl16staticMetaObjectE @ 534 NONAME DATA 16 + _ZN19QVideoWindowControl17brightnessChangedEi @ 535 NONAME + _ZN19QVideoWindowControl17fullScreenChangedEb @ 536 NONAME + _ZN19QVideoWindowControl17nativeSizeChangedEv @ 537 NONAME + _ZN19QVideoWindowControl17saturationChangedEi @ 538 NONAME + _ZN19QVideoWindowControl19getStaticMetaObjectEv @ 539 NONAME + _ZN19QVideoWindowControlC2EP7QObject @ 540 NONAME + _ZN19QVideoWindowControlD0Ev @ 541 NONAME + _ZN19QVideoWindowControlD1Ev @ 542 NONAME + _ZN19QVideoWindowControlD2Ev @ 543 NONAME + _ZN20QAbstractAudioOutput11qt_metacallEN11QMetaObject4CallEiPPv @ 544 NONAME + _ZN20QAbstractAudioOutput11qt_metacastEPKc @ 545 NONAME + _ZN20QAbstractAudioOutput12errorChangedEN6QAudio5ErrorE @ 546 NONAME + _ZN20QAbstractAudioOutput12stateChangedEN6QAudio5StateE @ 547 NONAME + _ZN20QAbstractAudioOutput16staticMetaObjectE @ 548 NONAME DATA 16 + _ZN20QAbstractAudioOutput19getStaticMetaObjectEv @ 549 NONAME + _ZN20QAbstractAudioOutput6notifyEv @ 550 NONAME + _ZN20QAbstractVideoBufferC2ENS_10HandleTypeE @ 551 NONAME + _ZN20QAbstractVideoBufferC2ER27QAbstractVideoBufferPrivateNS_10HandleTypeE @ 552 NONAME + _ZN20QAbstractVideoBufferD0Ev @ 553 NONAME + _ZN20QAbstractVideoBufferD1Ev @ 554 NONAME + _ZN20QAbstractVideoBufferD2Ev @ 555 NONAME + _ZN20QAudioEncoderControl11qt_metacallEN11QMetaObject4CallEiPPv @ 556 NONAME + _ZN20QAudioEncoderControl11qt_metacastEPKc @ 557 NONAME + _ZN20QAudioEncoderControl16staticMetaObjectE @ 558 NONAME DATA 16 + _ZN20QAudioEncoderControl19getStaticMetaObjectEv @ 559 NONAME + _ZN20QAudioEncoderControlC2EP7QObject @ 560 NONAME + _ZN20QAudioEncoderControlD0Ev @ 561 NONAME + _ZN20QAudioEncoderControlD1Ev @ 562 NONAME + _ZN20QAudioEncoderControlD2Ev @ 563 NONAME + _ZN20QImageEncoderControl11qt_metacallEN11QMetaObject4CallEiPPv @ 564 NONAME + _ZN20QImageEncoderControl11qt_metacastEPKc @ 565 NONAME + _ZN20QImageEncoderControl16staticMetaObjectE @ 566 NONAME DATA 16 + _ZN20QImageEncoderControl19getStaticMetaObjectEv @ 567 NONAME + _ZN20QImageEncoderControlC2EP7QObject @ 568 NONAME + _ZN20QImageEncoderControlD0Ev @ 569 NONAME + _ZN20QImageEncoderControlD1Ev @ 570 NONAME + _ZN20QImageEncoderControlD2Ev @ 571 NONAME + _ZN20QMediaPlaylistReaderD0Ev @ 572 NONAME + _ZN20QMediaPlaylistReaderD1Ev @ 573 NONAME + _ZN20QMediaPlaylistReaderD2Ev @ 574 NONAME + _ZN20QMediaPlaylistWriterD0Ev @ 575 NONAME + _ZN20QMediaPlaylistWriterD1Ev @ 576 NONAME + _ZN20QMediaPlaylistWriterD2Ev @ 577 NONAME + _ZN20QMediaStreamsControl11qt_metacallEN11QMetaObject4CallEiPPv @ 578 NONAME + _ZN20QMediaStreamsControl11qt_metacastEPKc @ 579 NONAME + _ZN20QMediaStreamsControl14streamsChangedEv @ 580 NONAME + _ZN20QMediaStreamsControl16staticMetaObjectE @ 581 NONAME DATA 16 + _ZN20QMediaStreamsControl19getStaticMetaObjectEv @ 582 NONAME + _ZN20QMediaStreamsControl20activeStreamsChangedEv @ 583 NONAME + _ZN20QMediaStreamsControlC2EP7QObject @ 584 NONAME + _ZN20QMediaStreamsControlD0Ev @ 585 NONAME + _ZN20QMediaStreamsControlD1Ev @ 586 NONAME + _ZN20QMediaStreamsControlD2Ev @ 587 NONAME + _ZN20QVideoEncoderControl11qt_metacallEN11QMetaObject4CallEiPPv @ 588 NONAME + _ZN20QVideoEncoderControl11qt_metacastEPKc @ 589 NONAME + _ZN20QVideoEncoderControl16staticMetaObjectE @ 590 NONAME DATA 16 + _ZN20QVideoEncoderControl19getStaticMetaObjectEv @ 591 NONAME + _ZN20QVideoEncoderControlC2EP7QObject @ 592 NONAME + _ZN20QVideoEncoderControlD0Ev @ 593 NONAME + _ZN20QVideoEncoderControlD1Ev @ 594 NONAME + _ZN20QVideoEncoderControlD2Ev @ 595 NONAME + _ZN21QAbstractVideoSurface11qt_metacallEN11QMetaObject4CallEiPPv @ 596 NONAME + _ZN21QAbstractVideoSurface11qt_metacastEPKc @ 597 NONAME + _ZN21QAbstractVideoSurface13activeChangedEb @ 598 NONAME + _ZN21QAbstractVideoSurface16staticMetaObjectE @ 599 NONAME DATA 16 + _ZN21QAbstractVideoSurface19getStaticMetaObjectEv @ 600 NONAME + _ZN21QAbstractVideoSurface20surfaceFormatChangedERK19QVideoSurfaceFormat @ 601 NONAME + _ZN21QAbstractVideoSurface23supportedFormatsChangedEv @ 602 NONAME + _ZN21QAbstractVideoSurface4stopEv @ 603 NONAME + _ZN21QAbstractVideoSurface5startERK19QVideoSurfaceFormat @ 604 NONAME + _ZN21QAbstractVideoSurface8setErrorENS_5ErrorE @ 605 NONAME + _ZN21QAbstractVideoSurfaceC2EP7QObject @ 606 NONAME + _ZN21QAbstractVideoSurfaceC2ER28QAbstractVideoSurfacePrivateP7QObject @ 607 NONAME + _ZN21QAbstractVideoSurfaceD0Ev @ 608 NONAME + _ZN21QAbstractVideoSurfaceD1Ev @ 609 NONAME + _ZN21QAbstractVideoSurfaceD2Ev @ 610 NONAME + _ZN21QAudioEncoderSettings10setBitRateEi @ 611 NONAME + _ZN21QAudioEncoderSettings10setQualityEN15QtMultimediaKit15EncodingQualityE @ 612 NONAME + _ZN21QAudioEncoderSettings13setSampleRateEi @ 613 NONAME + _ZN21QAudioEncoderSettings15setChannelCountEi @ 614 NONAME + _ZN21QAudioEncoderSettings15setEncodingModeEN15QtMultimediaKit12EncodingModeE @ 615 NONAME + _ZN21QAudioEncoderSettings8setCodecERK7QString @ 616 NONAME + _ZN21QAudioEncoderSettingsC1ERKS_ @ 617 NONAME + _ZN21QAudioEncoderSettingsC1Ev @ 618 NONAME + _ZN21QAudioEncoderSettingsC2ERKS_ @ 619 NONAME + _ZN21QAudioEncoderSettingsC2Ev @ 620 NONAME + _ZN21QAudioEncoderSettingsD1Ev @ 621 NONAME + _ZN21QAudioEncoderSettingsD2Ev @ 622 NONAME + _ZN21QAudioEncoderSettingsaSERKS_ @ 623 NONAME + _ZN21QImageEncoderSettings10setQualityEN15QtMultimediaKit15EncodingQualityE @ 624 NONAME + _ZN21QImageEncoderSettings13setResolutionERK5QSize @ 625 NONAME + _ZN21QImageEncoderSettings13setResolutionEii @ 626 NONAME + _ZN21QImageEncoderSettings8setCodecERK7QString @ 627 NONAME + _ZN21QImageEncoderSettingsC1ERKS_ @ 628 NONAME + _ZN21QImageEncoderSettingsC1Ev @ 629 NONAME + _ZN21QImageEncoderSettingsC2ERKS_ @ 630 NONAME + _ZN21QImageEncoderSettingsC2Ev @ 631 NONAME + _ZN21QImageEncoderSettingsD1Ev @ 632 NONAME + _ZN21QImageEncoderSettingsD2Ev @ 633 NONAME + _ZN21QImageEncoderSettingsaSERKS_ @ 634 NONAME + _ZN21QMediaPlaylistControl11qt_metacallEN11QMetaObject4CallEiPPv @ 635 NONAME + _ZN21QMediaPlaylistControl11qt_metacastEPKc @ 636 NONAME + _ZN21QMediaPlaylistControl16staticMetaObjectE @ 637 NONAME DATA 16 + _ZN21QMediaPlaylistControl19currentIndexChangedEi @ 638 NONAME + _ZN21QMediaPlaylistControl19currentMediaChangedERK13QMediaContent @ 639 NONAME + _ZN21QMediaPlaylistControl19getStaticMetaObjectEv @ 640 NONAME + _ZN21QMediaPlaylistControl19playbackModeChangedEN14QMediaPlaylist12PlaybackModeE @ 641 NONAME + _ZN21QMediaPlaylistControl23playlistProviderChangedEv @ 642 NONAME + _ZN21QMediaPlaylistControlC2EP7QObject @ 643 NONAME + _ZN21QMediaPlaylistControlD0Ev @ 644 NONAME + _ZN21QMediaPlaylistControlD1Ev @ 645 NONAME + _ZN21QMediaPlaylistControlD2Ev @ 646 NONAME + _ZN21QMediaRecorderControl11qt_metacallEN11QMetaObject4CallEiPPv @ 647 NONAME + _ZN21QMediaRecorderControl11qt_metacastEPKc @ 648 NONAME + _ZN21QMediaRecorderControl12mutedChangedEb @ 649 NONAME + _ZN21QMediaRecorderControl12stateChangedEN14QMediaRecorder5StateE @ 650 NONAME + _ZN21QMediaRecorderControl15durationChangedEx @ 651 NONAME + _ZN21QMediaRecorderControl16staticMetaObjectE @ 652 NONAME DATA 16 + _ZN21QMediaRecorderControl19getStaticMetaObjectEv @ 653 NONAME + _ZN21QMediaRecorderControl5errorEiRK7QString @ 654 NONAME + _ZN21QMediaRecorderControlC2EP7QObject @ 655 NONAME + _ZN21QMediaRecorderControlD0Ev @ 656 NONAME + _ZN21QMediaRecorderControlD1Ev @ 657 NONAME + _ZN21QMediaRecorderControlD2Ev @ 658 NONAME + _ZN21QMediaServiceProvider11qt_metacallEN11QMetaObject4CallEiPPv @ 659 NONAME + _ZN21QMediaServiceProvider11qt_metacastEPKc @ 660 NONAME + _ZN21QMediaServiceProvider16staticMetaObjectE @ 661 NONAME DATA 16 + _ZN21QMediaServiceProvider17deviceDescriptionERK10QByteArrayS2_ @ 662 NONAME + _ZN21QMediaServiceProvider19getStaticMetaObjectEv @ 663 NONAME + _ZN21QMediaServiceProvider22defaultServiceProviderEv @ 664 NONAME + _ZN21QVideoEncoderSettings10setBitRateEi @ 665 NONAME + _ZN21QVideoEncoderSettings10setQualityEN15QtMultimediaKit15EncodingQualityE @ 666 NONAME + _ZN21QVideoEncoderSettings12setFrameRateEf @ 667 NONAME + _ZN21QVideoEncoderSettings13setResolutionERK5QSize @ 668 NONAME + _ZN21QVideoEncoderSettings13setResolutionEii @ 669 NONAME + _ZN21QVideoEncoderSettings15setEncodingModeEN15QtMultimediaKit12EncodingModeE @ 670 NONAME + _ZN21QVideoEncoderSettings8setCodecERK7QString @ 671 NONAME + _ZN21QVideoEncoderSettingsC1ERKS_ @ 672 NONAME + _ZN21QVideoEncoderSettingsC1Ev @ 673 NONAME + _ZN21QVideoEncoderSettingsC2ERKS_ @ 674 NONAME + _ZN21QVideoEncoderSettingsC2Ev @ 675 NONAME + _ZN21QVideoEncoderSettingsD1Ev @ 676 NONAME + _ZN21QVideoEncoderSettingsD2Ev @ 677 NONAME + _ZN21QVideoEncoderSettingsaSERKS_ @ 678 NONAME + _ZN21QVideoRendererControl11qt_metacallEN11QMetaObject4CallEiPPv @ 679 NONAME + _ZN21QVideoRendererControl11qt_metacastEPKc @ 680 NONAME + _ZN21QVideoRendererControl16staticMetaObjectE @ 681 NONAME DATA 16 + _ZN21QVideoRendererControl19getStaticMetaObjectEv @ 682 NONAME + _ZN21QVideoRendererControlC2EP7QObject @ 683 NONAME + _ZN21QVideoRendererControlD0Ev @ 684 NONAME + _ZN21QVideoRendererControlD1Ev @ 685 NONAME + _ZN21QVideoRendererControlD2Ev @ 686 NONAME + _ZN22QAudioEndpointSelector11qt_metacallEN11QMetaObject4CallEiPPv @ 687 NONAME + _ZN22QAudioEndpointSelector11qt_metacastEPKc @ 688 NONAME + _ZN22QAudioEndpointSelector16staticMetaObjectE @ 689 NONAME DATA 16 + _ZN22QAudioEndpointSelector19getStaticMetaObjectEv @ 690 NONAME + _ZN22QAudioEndpointSelector21activeEndpointChangedERK7QString @ 691 NONAME + _ZN22QAudioEndpointSelector25availableEndpointsChangedEv @ 692 NONAME + _ZN22QAudioEndpointSelectorC2EP7QObject @ 693 NONAME + _ZN22QAudioEndpointSelectorD0Ev @ 694 NONAME + _ZN22QAudioEndpointSelectorD1Ev @ 695 NONAME + _ZN22QAudioEndpointSelectorD2Ev @ 696 NONAME + _ZN22QMediaContainerControl11qt_metacallEN11QMetaObject4CallEiPPv @ 697 NONAME + _ZN22QMediaContainerControl11qt_metacastEPKc @ 698 NONAME + _ZN22QMediaContainerControl16staticMetaObjectE @ 699 NONAME DATA 16 + _ZN22QMediaContainerControl19getStaticMetaObjectEv @ 700 NONAME + _ZN22QMediaContainerControlC2EP7QObject @ 701 NONAME + _ZN22QMediaContainerControlD0Ev @ 702 NONAME + _ZN22QMediaContainerControlD1Ev @ 703 NONAME + _ZN22QMediaContainerControlD2Ev @ 704 NONAME + _ZN22QMediaPlaylistIOPlugin11qt_metacallEN11QMetaObject4CallEiPPv @ 705 NONAME + _ZN22QMediaPlaylistIOPlugin11qt_metacastEPKc @ 706 NONAME + _ZN22QMediaPlaylistIOPlugin16staticMetaObjectE @ 707 NONAME DATA 16 + _ZN22QMediaPlaylistIOPlugin19getStaticMetaObjectEv @ 708 NONAME + _ZN22QMediaPlaylistIOPluginC2EP7QObject @ 709 NONAME + _ZN22QMediaPlaylistIOPluginD0Ev @ 710 NONAME + _ZN22QMediaPlaylistIOPluginD1Ev @ 711 NONAME + _ZN22QMediaPlaylistIOPluginD2Ev @ 712 NONAME + _ZN22QMediaPlaylistProvider10loadFailedEN14QMediaPlaylist5ErrorERK7QString @ 713 NONAME + _ZN22QMediaPlaylistProvider11insertMediaEiRK13QMediaContent @ 714 NONAME + _ZN22QMediaPlaylistProvider11insertMediaEiRK5QListI13QMediaContentE @ 715 NONAME + _ZN22QMediaPlaylistProvider11qt_metacallEN11QMetaObject4CallEiPPv @ 716 NONAME + _ZN22QMediaPlaylistProvider11qt_metacastEPKc @ 717 NONAME + _ZN22QMediaPlaylistProvider11removeMediaEi @ 718 NONAME + _ZN22QMediaPlaylistProvider11removeMediaEii @ 719 NONAME + _ZN22QMediaPlaylistProvider12mediaChangedEii @ 720 NONAME + _ZN22QMediaPlaylistProvider12mediaRemovedEii @ 721 NONAME + _ZN22QMediaPlaylistProvider13mediaInsertedEii @ 722 NONAME + _ZN22QMediaPlaylistProvider16staticMetaObjectE @ 723 NONAME DATA 16 + _ZN22QMediaPlaylistProvider19getStaticMetaObjectEv @ 724 NONAME + _ZN22QMediaPlaylistProvider21mediaAboutToBeRemovedEii @ 725 NONAME + _ZN22QMediaPlaylistProvider22mediaAboutToBeInsertedEii @ 726 NONAME + _ZN22QMediaPlaylistProvider4loadEP9QIODevicePKc @ 727 NONAME + _ZN22QMediaPlaylistProvider4loadERK4QUrlPKc @ 728 NONAME + _ZN22QMediaPlaylistProvider4saveEP9QIODevicePKc @ 729 NONAME + _ZN22QMediaPlaylistProvider4saveERK4QUrlPKc @ 730 NONAME + _ZN22QMediaPlaylistProvider5clearEv @ 731 NONAME + _ZN22QMediaPlaylistProvider6loadedEv @ 732 NONAME + _ZN22QMediaPlaylistProvider7shuffleEv @ 733 NONAME + _ZN22QMediaPlaylistProvider8addMediaERK13QMediaContent @ 734 NONAME + _ZN22QMediaPlaylistProvider8addMediaERK5QListI13QMediaContentE @ 735 NONAME + _ZN22QMediaPlaylistProviderC2EP7QObject @ 736 NONAME + _ZN22QMediaPlaylistProviderC2ER29QMediaPlaylistProviderPrivateP7QObject @ 737 NONAME + _ZN22QMediaPlaylistProviderD0Ev @ 738 NONAME + _ZN22QMediaPlaylistProviderD1Ev @ 739 NONAME + _ZN22QMediaPlaylistProviderD2Ev @ 740 NONAME + _ZN22QMetaDataReaderControl11qt_metacallEN11QMetaObject4CallEiPPv @ 741 NONAME + _ZN22QMetaDataReaderControl11qt_metacastEPKc @ 742 NONAME + _ZN22QMetaDataReaderControl15metaDataChangedEv @ 743 NONAME + _ZN22QMetaDataReaderControl16staticMetaObjectE @ 744 NONAME DATA 16 + _ZN22QMetaDataReaderControl19getStaticMetaObjectEv @ 745 NONAME + _ZN22QMetaDataReaderControl24metaDataAvailableChangedEb @ 746 NONAME + _ZN22QMetaDataReaderControlC2EP7QObject @ 747 NONAME + _ZN22QMetaDataReaderControlD0Ev @ 748 NONAME + _ZN22QMetaDataReaderControlD1Ev @ 749 NONAME + _ZN22QMetaDataReaderControlD2Ev @ 750 NONAME + _ZN22QMetaDataWriterControl11qt_metacallEN11QMetaObject4CallEiPPv @ 751 NONAME + _ZN22QMetaDataWriterControl11qt_metacastEPKc @ 752 NONAME + _ZN22QMetaDataWriterControl15metaDataChangedEv @ 753 NONAME + _ZN22QMetaDataWriterControl15writableChangedEb @ 754 NONAME + _ZN22QMetaDataWriterControl16staticMetaObjectE @ 755 NONAME DATA 16 + _ZN22QMetaDataWriterControl19getStaticMetaObjectEv @ 756 NONAME + _ZN22QMetaDataWriterControl24metaDataAvailableChangedEb @ 757 NONAME + _ZN22QMetaDataWriterControlC2EP7QObject @ 758 NONAME + _ZN22QMetaDataWriterControlD0Ev @ 759 NONAME + _ZN22QMetaDataWriterControlD1Ev @ 760 NONAME + _ZN22QMetaDataWriterControlD2Ev @ 761 NONAME + _ZN23QMediaBindableInterfaceD0Ev @ 762 NONAME + _ZN23QMediaBindableInterfaceD1Ev @ 763 NONAME + _ZN23QMediaBindableInterfaceD2Ev @ 764 NONAME + _ZN23QMediaPlaylistNavigator11qt_metacallEN11QMetaObject4CallEiPPv @ 765 NONAME + _ZN23QMediaPlaylistNavigator11qt_metacastEPKc @ 766 NONAME + _ZN23QMediaPlaylistNavigator11setPlaylistEP22QMediaPlaylistProvider @ 767 NONAME + _ZN23QMediaPlaylistNavigator15setPlaybackModeEN14QMediaPlaylist12PlaybackModeE @ 768 NONAME + _ZN23QMediaPlaylistNavigator16staticMetaObjectE @ 769 NONAME DATA 16 + _ZN23QMediaPlaylistNavigator19currentIndexChangedEi @ 770 NONAME + _ZN23QMediaPlaylistNavigator19getStaticMetaObjectEv @ 771 NONAME + _ZN23QMediaPlaylistNavigator19playbackModeChangedEN14QMediaPlaylist12PlaybackModeE @ 772 NONAME + _ZN23QMediaPlaylistNavigator23surroundingItemsChangedEv @ 773 NONAME + _ZN23QMediaPlaylistNavigator4jumpEi @ 774 NONAME + _ZN23QMediaPlaylistNavigator4nextEv @ 775 NONAME + _ZN23QMediaPlaylistNavigator8previousEv @ 776 NONAME + _ZN23QMediaPlaylistNavigator9activatedERK13QMediaContent @ 777 NONAME + _ZN23QMediaPlaylistNavigatorC1EP22QMediaPlaylistProviderP7QObject @ 778 NONAME + _ZN23QMediaPlaylistNavigatorC2EP22QMediaPlaylistProviderP7QObject @ 779 NONAME + _ZN23QMediaPlaylistNavigatorD0Ev @ 780 NONAME + _ZN23QMediaPlaylistNavigatorD1Ev @ 781 NONAME + _ZN23QMediaPlaylistNavigatorD2Ev @ 782 NONAME + _ZN24QAbstractAudioDeviceInfo11qt_metacallEN11QMetaObject4CallEiPPv @ 783 NONAME + _ZN24QAbstractAudioDeviceInfo11qt_metacastEPKc @ 784 NONAME + _ZN24QAbstractAudioDeviceInfo16staticMetaObjectE @ 785 NONAME DATA 16 + _ZN24QAbstractAudioDeviceInfo19getStaticMetaObjectEv @ 786 NONAME + _ZN25QMediaServiceProviderHintC1E6QFlagsINS_7FeatureEE @ 787 NONAME + _ZN25QMediaServiceProviderHintC1ERK10QByteArray @ 788 NONAME + _ZN25QMediaServiceProviderHintC1ERK7QStringRK11QStringList @ 789 NONAME + _ZN25QMediaServiceProviderHintC1ERKS_ @ 790 NONAME + _ZN25QMediaServiceProviderHintC1Ev @ 791 NONAME + _ZN25QMediaServiceProviderHintC2E6QFlagsINS_7FeatureEE @ 792 NONAME + _ZN25QMediaServiceProviderHintC2ERK10QByteArray @ 793 NONAME + _ZN25QMediaServiceProviderHintC2ERK7QStringRK11QStringList @ 794 NONAME + _ZN25QMediaServiceProviderHintC2ERKS_ @ 795 NONAME + _ZN25QMediaServiceProviderHintC2Ev @ 796 NONAME + _ZN25QMediaServiceProviderHintD1Ev @ 797 NONAME + _ZN25QMediaServiceProviderHintD2Ev @ 798 NONAME + _ZN25QMediaServiceProviderHintaSERKS_ @ 799 NONAME + _ZN27QLocalMediaPlaylistProvider11insertMediaEiRK13QMediaContent @ 800 NONAME + _ZN27QLocalMediaPlaylistProvider11insertMediaEiRK5QListI13QMediaContentE @ 801 NONAME + _ZN27QLocalMediaPlaylistProvider11qt_metacallEN11QMetaObject4CallEiPPv @ 802 NONAME + _ZN27QLocalMediaPlaylistProvider11qt_metacastEPKc @ 803 NONAME + _ZN27QLocalMediaPlaylistProvider11removeMediaEi @ 804 NONAME + _ZN27QLocalMediaPlaylistProvider11removeMediaEii @ 805 NONAME + _ZN27QLocalMediaPlaylistProvider16staticMetaObjectE @ 806 NONAME DATA 16 + _ZN27QLocalMediaPlaylistProvider19getStaticMetaObjectEv @ 807 NONAME + _ZN27QLocalMediaPlaylistProvider5clearEv @ 808 NONAME + _ZN27QLocalMediaPlaylistProvider7shuffleEv @ 809 NONAME + _ZN27QLocalMediaPlaylistProvider8addMediaERK13QMediaContent @ 810 NONAME + _ZN27QLocalMediaPlaylistProvider8addMediaERK5QListI13QMediaContentE @ 811 NONAME + _ZN27QLocalMediaPlaylistProviderC1EP7QObject @ 812 NONAME + _ZN27QLocalMediaPlaylistProviderC2EP7QObject @ 813 NONAME + _ZN27QLocalMediaPlaylistProviderD0Ev @ 814 NONAME + _ZN27QLocalMediaPlaylistProviderD1Ev @ 815 NONAME + _ZN27QLocalMediaPlaylistProviderD2Ev @ 816 NONAME + _ZN27QMediaPlaylistSourceControl11qt_metacallEN11QMetaObject4CallEiPPv @ 817 NONAME + _ZN27QMediaPlaylistSourceControl11qt_metacastEPKc @ 818 NONAME + _ZN27QMediaPlaylistSourceControl15playlistChangedEP14QMediaPlaylist @ 819 NONAME + _ZN27QMediaPlaylistSourceControl16staticMetaObjectE @ 820 NONAME DATA 16 + _ZN27QMediaPlaylistSourceControl19getStaticMetaObjectEv @ 821 NONAME + _ZN27QMediaPlaylistSourceControlC2EP7QObject @ 822 NONAME + _ZN27QMediaPlaylistSourceControlD0Ev @ 823 NONAME + _ZN27QMediaPlaylistSourceControlD1Ev @ 824 NONAME + _ZN27QMediaPlaylistSourceControlD2Ev @ 825 NONAME + _ZN27QMediaServiceProviderPlugin11qt_metacallEN11QMetaObject4CallEiPPv @ 826 NONAME + _ZN27QMediaServiceProviderPlugin11qt_metacastEPKc @ 827 NONAME + _ZN27QMediaServiceProviderPlugin16staticMetaObjectE @ 828 NONAME DATA 16 + _ZN27QMediaServiceProviderPlugin19getStaticMetaObjectEv @ 829 NONAME + _ZNK11QAudioInput10bufferSizeEv @ 830 NONAME + _ZNK11QAudioInput10bytesReadyEv @ 831 NONAME + _ZNK11QAudioInput10metaObjectEv @ 832 NONAME + _ZNK11QAudioInput10periodSizeEv @ 833 NONAME + _ZNK11QAudioInput12elapsedUSecsEv @ 834 NONAME + _ZNK11QAudioInput14notifyIntervalEv @ 835 NONAME + _ZNK11QAudioInput14processedUSecsEv @ 836 NONAME + _ZNK11QAudioInput5errorEv @ 837 NONAME + _ZNK11QAudioInput5stateEv @ 838 NONAME + _ZNK11QAudioInput6formatEv @ 839 NONAME + _ZNK11QRadioTuner10metaObjectEv @ 840 NONAME + _ZNK11QRadioTuner10stereoModeEv @ 841 NONAME + _ZNK11QRadioTuner11errorStringEv @ 842 NONAME + _ZNK11QRadioTuner11isAvailableEv @ 843 NONAME + _ZNK11QRadioTuner11isSearchingEv @ 844 NONAME + _ZNK11QRadioTuner13frequencyStepENS_4BandE @ 845 NONAME + _ZNK11QRadioTuner14frequencyRangeENS_4BandE @ 846 NONAME + _ZNK11QRadioTuner14signalStrengthEv @ 847 NONAME + _ZNK11QRadioTuner15isBandSupportedENS_4BandE @ 848 NONAME + _ZNK11QRadioTuner17availabilityErrorEv @ 849 NONAME + _ZNK11QRadioTuner4bandEv @ 850 NONAME + _ZNK11QRadioTuner5errorEv @ 851 NONAME + _ZNK11QRadioTuner5stateEv @ 852 NONAME + _ZNK11QRadioTuner6volumeEv @ 853 NONAME + _ZNK11QRadioTuner7isMutedEv @ 854 NONAME + _ZNK11QRadioTuner8isStereoEv @ 855 NONAME + _ZNK11QRadioTuner9frequencyEv @ 856 NONAME + _ZNK11QVideoFrame10handleTypeEv @ 857 NONAME + _ZNK11QVideoFrame10isReadableEv @ 858 NONAME + _ZNK11QVideoFrame10isWritableEv @ 859 NONAME + _ZNK11QVideoFrame11mappedBytesEv @ 860 NONAME + _ZNK11QVideoFrame11pixelFormatEv @ 861 NONAME + _ZNK11QVideoFrame12bytesPerLineEv @ 862 NONAME + _ZNK11QVideoFrame4bitsEv @ 863 NONAME + _ZNK11QVideoFrame4sizeEv @ 864 NONAME + _ZNK11QVideoFrame5widthEv @ 865 NONAME + _ZNK11QVideoFrame6handleEv @ 866 NONAME + _ZNK11QVideoFrame6heightEv @ 867 NONAME + _ZNK11QVideoFrame7endTimeEv @ 868 NONAME + _ZNK11QVideoFrame7isValidEv @ 869 NONAME + _ZNK11QVideoFrame7mapModeEv @ 870 NONAME + _ZNK11QVideoFrame8isMappedEv @ 871 NONAME + _ZNK11QVideoFrame9fieldTypeEv @ 872 NONAME + _ZNK11QVideoFrame9startTimeEv @ 873 NONAME + _ZNK12QAudioFormat10sampleRateEv @ 874 NONAME + _ZNK12QAudioFormat10sampleSizeEv @ 875 NONAME + _ZNK12QAudioFormat10sampleTypeEv @ 876 NONAME + _ZNK12QAudioFormat12channelCountEv @ 877 NONAME + _ZNK12QAudioFormat5codecEv @ 878 NONAME + _ZNK12QAudioFormat7isValidEv @ 879 NONAME + _ZNK12QAudioFormat8channelsEv @ 880 NONAME + _ZNK12QAudioFormat9byteOrderEv @ 881 NONAME + _ZNK12QAudioFormat9frequencyEv @ 882 NONAME + _ZNK12QAudioFormateqERKS_ @ 883 NONAME + _ZNK12QAudioFormatneERKS_ @ 884 NONAME + _ZNK12QAudioOutput10bufferSizeEv @ 885 NONAME + _ZNK12QAudioOutput10metaObjectEv @ 886 NONAME + _ZNK12QAudioOutput10periodSizeEv @ 887 NONAME + _ZNK12QAudioOutput12elapsedUSecsEv @ 888 NONAME + _ZNK12QAudioOutput14notifyIntervalEv @ 889 NONAME + _ZNK12QAudioOutput14processedUSecsEv @ 890 NONAME + _ZNK12QAudioOutput5errorEv @ 891 NONAME + _ZNK12QAudioOutput5stateEv @ 892 NONAME + _ZNK12QAudioOutput6formatEv @ 893 NONAME + _ZNK12QAudioOutput9bytesFreeEv @ 894 NONAME + _ZNK12QMediaObject10metaObjectEv @ 895 NONAME + _ZNK12QMediaObject11isAvailableEv @ 896 NONAME + _ZNK12QMediaObject14notifyIntervalEv @ 897 NONAME + _ZNK12QMediaObject16extendedMetaDataERK7QString @ 898 NONAME + _ZNK12QMediaObject17availabilityErrorEv @ 899 NONAME + _ZNK12QMediaObject17availableMetaDataEv @ 900 NONAME + _ZNK12QMediaObject19isMetaDataAvailableEv @ 901 NONAME + _ZNK12QMediaObject25availableExtendedMetaDataEv @ 902 NONAME + _ZNK12QMediaObject7serviceEv @ 903 NONAME + _ZNK12QMediaObject8metaDataEN15QtMultimediaKit8MetaDataE @ 904 NONAME + _ZNK12QMediaPlayer10isSeekableEv @ 905 NONAME + _ZNK12QMediaPlayer10metaObjectEv @ 906 NONAME + _ZNK12QMediaPlayer11errorStringEv @ 907 NONAME + _ZNK12QMediaPlayer11mediaStatusEv @ 908 NONAME + _ZNK12QMediaPlayer11mediaStreamEv @ 909 NONAME + _ZNK12QMediaPlayer12bufferStatusEv @ 910 NONAME + _ZNK12QMediaPlayer12playbackRateEv @ 911 NONAME + _ZNK12QMediaPlayer16isAudioAvailableEv @ 912 NONAME + _ZNK12QMediaPlayer16isVideoAvailableEv @ 913 NONAME + _ZNK12QMediaPlayer5errorEv @ 914 NONAME + _ZNK12QMediaPlayer5mediaEv @ 915 NONAME + _ZNK12QMediaPlayer5stateEv @ 916 NONAME + _ZNK12QMediaPlayer6volumeEv @ 917 NONAME + _ZNK12QMediaPlayer7isMutedEv @ 918 NONAME + _ZNK12QMediaPlayer8durationEv @ 919 NONAME + _ZNK12QMediaPlayer8playlistEv @ 920 NONAME + _ZNK12QMediaPlayer8positionEv @ 921 NONAME + _ZNK12QSoundEffect10metaObjectEv @ 922 NONAME + _ZNK12QSoundEffect5loopsEv @ 923 NONAME ABSENT + _ZNK12QSoundEffect6sourceEv @ 924 NONAME + _ZNK12QSoundEffect6volumeEv @ 925 NONAME + _ZNK12QSoundEffect7isMutedEv @ 926 NONAME + _ZNK12QVideoWidget10brightnessEv @ 927 NONAME + _ZNK12QVideoWidget10metaObjectEv @ 928 NONAME + _ZNK12QVideoWidget10saturationEv @ 929 NONAME + _ZNK12QVideoWidget11mediaObjectEv @ 930 NONAME + _ZNK12QVideoWidget15aspectRatioModeEv @ 931 NONAME + _ZNK12QVideoWidget3hueEv @ 932 NONAME + _ZNK12QVideoWidget8contrastEv @ 933 NONAME + _ZNK12QVideoWidget8sizeHintEv @ 934 NONAME + _ZNK13QMediaContent12canonicalUrlEv @ 935 NONAME + _ZNK13QMediaContent16canonicalRequestEv @ 936 NONAME + _ZNK13QMediaContent17canonicalResourceEv @ 937 NONAME + _ZNK13QMediaContent6isNullEv @ 938 NONAME + _ZNK13QMediaContent9resourcesEv @ 939 NONAME + _ZNK13QMediaContenteqERKS_ @ 940 NONAME + _ZNK13QMediaContentneERKS_ @ 941 NONAME + _ZNK13QMediaControl10metaObjectEv @ 942 NONAME + _ZNK13QMediaService10metaObjectEv @ 943 NONAME + _ZNK14QMediaPlaylist10isReadOnlyEv @ 944 NONAME + _ZNK14QMediaPlaylist10mediaCountEv @ 945 NONAME + _ZNK14QMediaPlaylist10metaObjectEv @ 946 NONAME + _ZNK14QMediaPlaylist11errorStringEv @ 947 NONAME + _ZNK14QMediaPlaylist11mediaObjectEv @ 948 NONAME + _ZNK14QMediaPlaylist12currentIndexEv @ 949 NONAME + _ZNK14QMediaPlaylist12currentMediaEv @ 950 NONAME + _ZNK14QMediaPlaylist12playbackModeEv @ 951 NONAME + _ZNK14QMediaPlaylist13previousIndexEi @ 952 NONAME + _ZNK14QMediaPlaylist5errorEv @ 953 NONAME + _ZNK14QMediaPlaylist5mediaEi @ 954 NONAME + _ZNK14QMediaPlaylist7isEmptyEv @ 955 NONAME + _ZNK14QMediaPlaylist9nextIndexEi @ 956 NONAME + _ZNK14QMediaRecorder10metaObjectEv @ 957 NONAME + _ZNK14QMediaRecorder11errorStringEv @ 958 NONAME + _ZNK14QMediaRecorder11isAvailableEv @ 959 NONAME + _ZNK14QMediaRecorder11mediaObjectEv @ 960 NONAME + _ZNK14QMediaRecorder13audioSettingsEv @ 961 NONAME + _ZNK14QMediaRecorder13videoSettingsEv @ 962 NONAME + _ZNK14QMediaRecorder14outputLocationEv @ 963 NONAME + _ZNK14QMediaRecorder16extendedMetaDataERK7QString @ 964 NONAME + _ZNK14QMediaRecorder17availabilityErrorEv @ 965 NONAME + _ZNK14QMediaRecorder17availableMetaDataEv @ 966 NONAME + _ZNK14QMediaRecorder17containerMimeTypeEv @ 967 NONAME + _ZNK14QMediaRecorder18isMetaDataWritableEv @ 968 NONAME + _ZNK14QMediaRecorder19isMetaDataAvailableEv @ 969 NONAME + _ZNK14QMediaRecorder19supportedContainersEv @ 970 NONAME + _ZNK14QMediaRecorder19supportedFrameRatesERK21QVideoEncoderSettingsPb @ 971 NONAME + _ZNK14QMediaRecorder20containerDescriptionERK7QString @ 972 NONAME + _ZNK14QMediaRecorder20supportedAudioCodecsEv @ 973 NONAME + _ZNK14QMediaRecorder20supportedResolutionsERK21QVideoEncoderSettingsPb @ 974 NONAME + _ZNK14QMediaRecorder20supportedVideoCodecsEv @ 975 NONAME + _ZNK14QMediaRecorder21audioCodecDescriptionERK7QString @ 976 NONAME + _ZNK14QMediaRecorder21videoCodecDescriptionERK7QString @ 977 NONAME + _ZNK14QMediaRecorder25availableExtendedMetaDataEv @ 978 NONAME + _ZNK14QMediaRecorder25supportedAudioSampleRatesERK21QAudioEncoderSettingsPb @ 979 NONAME + _ZNK14QMediaRecorder5errorEv @ 980 NONAME + _ZNK14QMediaRecorder5stateEv @ 981 NONAME + _ZNK14QMediaRecorder7isMutedEv @ 982 NONAME + _ZNK14QMediaRecorder8durationEv @ 983 NONAME + _ZNK14QMediaRecorder8metaDataEN15QtMultimediaKit8MetaDataE @ 984 NONAME + _ZNK14QMediaResource10audioCodecEv @ 985 NONAME + _ZNK14QMediaResource10resolutionEv @ 986 NONAME + _ZNK14QMediaResource10sampleRateEv @ 987 NONAME + _ZNK14QMediaResource10videoCodecEv @ 988 NONAME + _ZNK14QMediaResource12audioBitRateEv @ 989 NONAME + _ZNK14QMediaResource12channelCountEv @ 990 NONAME + _ZNK14QMediaResource12videoBitRateEv @ 991 NONAME + _ZNK14QMediaResource3urlEv @ 992 NONAME + _ZNK14QMediaResource6isNullEv @ 993 NONAME + _ZNK14QMediaResource7requestEv @ 994 NONAME + _ZNK14QMediaResource8dataSizeEv @ 995 NONAME + _ZNK14QMediaResource8languageEv @ 996 NONAME + _ZNK14QMediaResource8mimeTypeEv @ 997 NONAME + _ZNK14QMediaResourceeqERKS_ @ 998 NONAME + _ZNK14QMediaResourceneERKS_ @ 999 NONAME + _ZNK15QMediaTimeRange10latestTimeEv @ 1000 NONAME + _ZNK15QMediaTimeRange12earliestTimeEv @ 1001 NONAME + _ZNK15QMediaTimeRange12isContinuousEv @ 1002 NONAME + _ZNK15QMediaTimeRange7isEmptyEv @ 1003 NONAME + _ZNK15QMediaTimeRange8containsEx @ 1004 NONAME + _ZNK15QMediaTimeRange9intervalsEv @ 1005 NONAME + _ZNK16QAudioDeviceInfo10deviceNameEv @ 1006 NONAME + _ZNK16QAudioDeviceInfo13nearestFormatERK12QAudioFormat @ 1007 NONAME + _ZNK16QAudioDeviceInfo15preferredFormatEv @ 1008 NONAME + _ZNK16QAudioDeviceInfo15supportedCodecsEv @ 1009 NONAME + _ZNK16QAudioDeviceInfo17isFormatSupportedERK12QAudioFormat @ 1010 NONAME + _ZNK16QAudioDeviceInfo17supportedChannelsEv @ 1011 NONAME + _ZNK16QAudioDeviceInfo19supportedByteOrdersEv @ 1012 NONAME + _ZNK16QAudioDeviceInfo20supportedFrequenciesEv @ 1013 NONAME + _ZNK16QAudioDeviceInfo20supportedSampleRatesEv @ 1014 NONAME + _ZNK16QAudioDeviceInfo20supportedSampleSizesEv @ 1015 NONAME + _ZNK16QAudioDeviceInfo20supportedSampleTypesEv @ 1016 NONAME + _ZNK16QAudioDeviceInfo22supportedChannelCountsEv @ 1017 NONAME + _ZNK16QAudioDeviceInfo4modeEv @ 1018 NONAME + _ZNK16QAudioDeviceInfo5realmEv @ 1019 NONAME + _ZNK16QAudioDeviceInfo6handleEv @ 1020 NONAME + _ZNK16QAudioDeviceInfo6isNullEv @ 1021 NONAME + _ZNK17QImageVideoBuffer7mapModeEv @ 1022 NONAME + _ZNK17QMediaImageViewer10metaObjectEv @ 1023 NONAME + _ZNK17QMediaImageViewer11elapsedTimeEv @ 1024 NONAME + _ZNK17QMediaImageViewer11mediaStatusEv @ 1025 NONAME + _ZNK17QMediaImageViewer5mediaEv @ 1026 NONAME + _ZNK17QMediaImageViewer5stateEv @ 1027 NONAME + _ZNK17QMediaImageViewer7timeoutEv @ 1028 NONAME + _ZNK18QAudioSystemPlugin10metaObjectEv @ 1029 NONAME + _ZNK18QGraphicsVideoItem10metaObjectEv @ 1030 NONAME + _ZNK18QGraphicsVideoItem10nativeSizeEv @ 1031 NONAME + _ZNK18QGraphicsVideoItem11mediaObjectEv @ 1032 NONAME + _ZNK18QGraphicsVideoItem12boundingRectEv @ 1033 NONAME + _ZNK18QGraphicsVideoItem15aspectRatioModeEv @ 1034 NONAME + _ZNK18QGraphicsVideoItem4sizeEv @ 1035 NONAME + _ZNK18QGraphicsVideoItem6offsetEv @ 1036 NONAME + _ZNK18QMediaTimeInterval10normalizedEv @ 1037 NONAME + _ZNK18QMediaTimeInterval10translatedEx @ 1038 NONAME + _ZNK18QMediaTimeInterval3endEv @ 1039 NONAME + _ZNK18QMediaTimeInterval5startEv @ 1040 NONAME + _ZNK18QMediaTimeInterval8containsEx @ 1041 NONAME + _ZNK18QMediaTimeInterval8isNormalEv @ 1042 NONAME + _ZNK18QMemoryVideoBuffer7mapModeEv @ 1043 NONAME + _ZNK18QRadioTunerControl10metaObjectEv @ 1044 NONAME + _ZNK19QAbstractAudioInput10metaObjectEv @ 1045 NONAME + _ZNK19QAudioCaptureSource10metaObjectEv @ 1046 NONAME + _ZNK19QAudioCaptureSource11audioInputsEv @ 1047 NONAME + _ZNK19QAudioCaptureSource11isAvailableEv @ 1048 NONAME + _ZNK19QAudioCaptureSource16activeAudioInputEv @ 1049 NONAME + _ZNK19QAudioCaptureSource16audioDescriptionERK7QString @ 1050 NONAME + _ZNK19QAudioCaptureSource17availabilityErrorEv @ 1051 NONAME + _ZNK19QAudioCaptureSource17defaultAudioInputEv @ 1052 NONAME + _ZNK19QMediaPlayerControl10metaObjectEv @ 1053 NONAME + _ZNK19QVideoDeviceControl10metaObjectEv @ 1054 NONAME + _ZNK19QVideoSurfaceFormat10frameWidthEv @ 1055 NONAME + _ZNK19QVideoSurfaceFormat10handleTypeEv @ 1056 NONAME + _ZNK19QVideoSurfaceFormat11frameHeightEv @ 1057 NONAME + _ZNK19QVideoSurfaceFormat11pixelFormatEv @ 1058 NONAME + _ZNK19QVideoSurfaceFormat13propertyNamesEv @ 1059 NONAME + _ZNK19QVideoSurfaceFormat15yCbCrColorSpaceEv @ 1060 NONAME + _ZNK19QVideoSurfaceFormat16pixelAspectRatioEv @ 1061 NONAME + _ZNK19QVideoSurfaceFormat17scanLineDirectionEv @ 1062 NONAME + _ZNK19QVideoSurfaceFormat7isValidEv @ 1063 NONAME + _ZNK19QVideoSurfaceFormat8propertyEPKc @ 1064 NONAME + _ZNK19QVideoSurfaceFormat8sizeHintEv @ 1065 NONAME + _ZNK19QVideoSurfaceFormat8viewportEv @ 1066 NONAME + _ZNK19QVideoSurfaceFormat9frameRateEv @ 1067 NONAME + _ZNK19QVideoSurfaceFormat9frameSizeEv @ 1068 NONAME + _ZNK19QVideoSurfaceFormateqERKS_ @ 1069 NONAME + _ZNK19QVideoSurfaceFormatneERKS_ @ 1070 NONAME + _ZNK19QVideoWidgetControl10metaObjectEv @ 1071 NONAME + _ZNK19QVideoWindowControl10metaObjectEv @ 1072 NONAME + _ZNK20QAbstractAudioOutput10metaObjectEv @ 1073 NONAME + _ZNK20QAbstractVideoBuffer10handleTypeEv @ 1074 NONAME + _ZNK20QAbstractVideoBuffer6handleEv @ 1075 NONAME + _ZNK20QAudioEncoderControl10metaObjectEv @ 1076 NONAME + _ZNK20QImageEncoderControl10metaObjectEv @ 1077 NONAME + _ZNK20QMediaStreamsControl10metaObjectEv @ 1078 NONAME + _ZNK20QVideoEncoderControl10metaObjectEv @ 1079 NONAME + _ZNK21QAbstractVideoSurface10metaObjectEv @ 1080 NONAME + _ZNK21QAbstractVideoSurface13nearestFormatERK19QVideoSurfaceFormat @ 1081 NONAME + _ZNK21QAbstractVideoSurface13surfaceFormatEv @ 1082 NONAME + _ZNK21QAbstractVideoSurface17isFormatSupportedERK19QVideoSurfaceFormat @ 1083 NONAME + _ZNK21QAbstractVideoSurface5errorEv @ 1084 NONAME + _ZNK21QAbstractVideoSurface8isActiveEv @ 1085 NONAME + _ZNK21QAudioEncoderSettings10sampleRateEv @ 1086 NONAME + _ZNK21QAudioEncoderSettings12channelCountEv @ 1087 NONAME + _ZNK21QAudioEncoderSettings12encodingModeEv @ 1088 NONAME + _ZNK21QAudioEncoderSettings5codecEv @ 1089 NONAME + _ZNK21QAudioEncoderSettings6isNullEv @ 1090 NONAME + _ZNK21QAudioEncoderSettings7bitRateEv @ 1091 NONAME + _ZNK21QAudioEncoderSettings7qualityEv @ 1092 NONAME + _ZNK21QAudioEncoderSettingseqERKS_ @ 1093 NONAME + _ZNK21QAudioEncoderSettingsneERKS_ @ 1094 NONAME + _ZNK21QImageEncoderSettings10resolutionEv @ 1095 NONAME + _ZNK21QImageEncoderSettings5codecEv @ 1096 NONAME + _ZNK21QImageEncoderSettings6isNullEv @ 1097 NONAME + _ZNK21QImageEncoderSettings7qualityEv @ 1098 NONAME + _ZNK21QImageEncoderSettingseqERKS_ @ 1099 NONAME + _ZNK21QImageEncoderSettingsneERKS_ @ 1100 NONAME + _ZNK21QMediaPlaylistControl10metaObjectEv @ 1101 NONAME + _ZNK21QMediaRecorderControl10metaObjectEv @ 1102 NONAME + _ZNK21QMediaServiceProvider10hasSupportERK10QByteArrayRK7QStringRK11QStringListi @ 1103 NONAME + _ZNK21QMediaServiceProvider10metaObjectEv @ 1104 NONAME + _ZNK21QMediaServiceProvider18supportedMimeTypesERK10QByteArrayi @ 1105 NONAME + _ZNK21QMediaServiceProvider7devicesERK10QByteArray @ 1106 NONAME + _ZNK21QVideoEncoderSettings10resolutionEv @ 1107 NONAME + _ZNK21QVideoEncoderSettings12encodingModeEv @ 1108 NONAME + _ZNK21QVideoEncoderSettings5codecEv @ 1109 NONAME + _ZNK21QVideoEncoderSettings6isNullEv @ 1110 NONAME + _ZNK21QVideoEncoderSettings7bitRateEv @ 1111 NONAME + _ZNK21QVideoEncoderSettings7qualityEv @ 1112 NONAME + _ZNK21QVideoEncoderSettings9frameRateEv @ 1113 NONAME + _ZNK21QVideoEncoderSettingseqERKS_ @ 1114 NONAME + _ZNK21QVideoEncoderSettingsneERKS_ @ 1115 NONAME + _ZNK21QVideoRendererControl10metaObjectEv @ 1116 NONAME + _ZNK22QAudioEndpointSelector10metaObjectEv @ 1117 NONAME + _ZNK22QMediaContainerControl10metaObjectEv @ 1118 NONAME + _ZNK22QMediaPlaylistIOPlugin10metaObjectEv @ 1119 NONAME + _ZNK22QMediaPlaylistProvider10isReadOnlyEv @ 1120 NONAME + _ZNK22QMediaPlaylistProvider10metaObjectEv @ 1121 NONAME + _ZNK22QMetaDataReaderControl10metaObjectEv @ 1122 NONAME + _ZNK22QMetaDataWriterControl10metaObjectEv @ 1123 NONAME + _ZNK23QMediaPlaylistNavigator10metaObjectEv @ 1124 NONAME + _ZNK23QMediaPlaylistNavigator11currentItemEv @ 1125 NONAME + _ZNK23QMediaPlaylistNavigator12currentIndexEv @ 1126 NONAME + _ZNK23QMediaPlaylistNavigator12playbackModeEv @ 1127 NONAME + _ZNK23QMediaPlaylistNavigator12previousItemEi @ 1128 NONAME + _ZNK23QMediaPlaylistNavigator13previousIndexEi @ 1129 NONAME + _ZNK23QMediaPlaylistNavigator6itemAtEi @ 1130 NONAME + _ZNK23QMediaPlaylistNavigator8nextItemEi @ 1131 NONAME + _ZNK23QMediaPlaylistNavigator8playlistEv @ 1132 NONAME + _ZNK23QMediaPlaylistNavigator9nextIndexEi @ 1133 NONAME + _ZNK24QAbstractAudioDeviceInfo10metaObjectEv @ 1134 NONAME + _ZNK25QMediaServiceProviderHint4typeEv @ 1135 NONAME + _ZNK25QMediaServiceProviderHint6codecsEv @ 1136 NONAME + _ZNK25QMediaServiceProviderHint6deviceEv @ 1137 NONAME + _ZNK25QMediaServiceProviderHint6isNullEv @ 1138 NONAME + _ZNK25QMediaServiceProviderHint8featuresEv @ 1139 NONAME + _ZNK25QMediaServiceProviderHint8mimeTypeEv @ 1140 NONAME + _ZNK25QMediaServiceProviderHinteqERKS_ @ 1141 NONAME + _ZNK25QMediaServiceProviderHintneERKS_ @ 1142 NONAME + _ZNK27QLocalMediaPlaylistProvider10isReadOnlyEv @ 1143 NONAME + _ZNK27QLocalMediaPlaylistProvider10mediaCountEv @ 1144 NONAME + _ZNK27QLocalMediaPlaylistProvider10metaObjectEv @ 1145 NONAME + _ZNK27QLocalMediaPlaylistProvider5mediaEi @ 1146 NONAME + _ZNK27QMediaPlaylistSourceControl10metaObjectEv @ 1147 NONAME + _ZNK27QMediaServiceProviderPlugin10metaObjectEv @ 1148 NONAME + _ZTI11QAudioInput @ 1149 NONAME + _ZTI11QRadioTuner @ 1150 NONAME + _ZTI12QAudioOutput @ 1151 NONAME + _ZTI12QMediaObject @ 1152 NONAME + _ZTI12QMediaPlayer @ 1153 NONAME + _ZTI12QSoundEffect @ 1154 NONAME + _ZTI12QVideoWidget @ 1155 NONAME + _ZTI13QMediaControl @ 1156 NONAME + _ZTI13QMediaService @ 1157 NONAME + _ZTI14QMediaPlaylist @ 1158 NONAME + _ZTI14QMediaRecorder @ 1159 NONAME + _ZTI17QImageVideoBuffer @ 1160 NONAME + _ZTI17QMediaImageViewer @ 1161 NONAME + _ZTI18QAudioSystemPlugin @ 1162 NONAME + _ZTI18QGraphicsVideoItem @ 1163 NONAME + _ZTI18QMemoryVideoBuffer @ 1164 NONAME + _ZTI18QRadioTunerControl @ 1165 NONAME + _ZTI19QAbstractAudioInput @ 1166 NONAME + _ZTI19QAudioCaptureSource @ 1167 NONAME + _ZTI19QMediaPlayerControl @ 1168 NONAME + _ZTI19QVideoDeviceControl @ 1169 NONAME + _ZTI19QVideoWidgetControl @ 1170 NONAME + _ZTI19QVideoWindowControl @ 1171 NONAME + _ZTI20QAbstractAudioOutput @ 1172 NONAME + _ZTI20QAbstractVideoBuffer @ 1173 NONAME + _ZTI20QAudioEncoderControl @ 1174 NONAME + _ZTI20QImageEncoderControl @ 1175 NONAME + _ZTI20QMediaPlaylistReader @ 1176 NONAME + _ZTI20QMediaPlaylistWriter @ 1177 NONAME + _ZTI20QMediaStreamsControl @ 1178 NONAME + _ZTI20QVideoEncoderControl @ 1179 NONAME + _ZTI21QAbstractVideoSurface @ 1180 NONAME + _ZTI21QMediaPlaylistControl @ 1181 NONAME + _ZTI21QMediaRecorderControl @ 1182 NONAME + _ZTI21QMediaServiceProvider @ 1183 NONAME + _ZTI21QVideoRendererControl @ 1184 NONAME + _ZTI22QAudioEndpointSelector @ 1185 NONAME + _ZTI22QMediaContainerControl @ 1186 NONAME + _ZTI22QMediaPlaylistIOPlugin @ 1187 NONAME + _ZTI22QMediaPlaylistProvider @ 1188 NONAME + _ZTI22QMetaDataReaderControl @ 1189 NONAME + _ZTI22QMetaDataWriterControl @ 1190 NONAME + _ZTI23QMediaBindableInterface @ 1191 NONAME + _ZTI23QMediaPlaylistNavigator @ 1192 NONAME + _ZTI24QAbstractAudioDeviceInfo @ 1193 NONAME + _ZTI25QMediaPlaylistIOInterface @ 1194 NONAME + _ZTI27QLocalMediaPlaylistProvider @ 1195 NONAME + _ZTI27QMediaPlaylistSourceControl @ 1196 NONAME + _ZTI27QMediaServiceProviderPlugin @ 1197 NONAME + _ZTI28QAudioSystemFactoryInterface @ 1198 NONAME + _ZTI37QMediaServiceProviderFactoryInterface @ 1199 NONAME + _ZTV11QAudioInput @ 1200 NONAME + _ZTV11QRadioTuner @ 1201 NONAME + _ZTV12QAudioOutput @ 1202 NONAME + _ZTV12QMediaObject @ 1203 NONAME + _ZTV12QMediaPlayer @ 1204 NONAME + _ZTV12QSoundEffect @ 1205 NONAME + _ZTV12QVideoWidget @ 1206 NONAME + _ZTV13QMediaControl @ 1207 NONAME + _ZTV13QMediaService @ 1208 NONAME + _ZTV14QMediaPlaylist @ 1209 NONAME + _ZTV14QMediaRecorder @ 1210 NONAME + _ZTV17QImageVideoBuffer @ 1211 NONAME + _ZTV17QMediaImageViewer @ 1212 NONAME + _ZTV18QAudioSystemPlugin @ 1213 NONAME + _ZTV18QGraphicsVideoItem @ 1214 NONAME + _ZTV18QMemoryVideoBuffer @ 1215 NONAME + _ZTV18QRadioTunerControl @ 1216 NONAME + _ZTV19QAbstractAudioInput @ 1217 NONAME + _ZTV19QAudioCaptureSource @ 1218 NONAME + _ZTV19QMediaPlayerControl @ 1219 NONAME + _ZTV19QVideoDeviceControl @ 1220 NONAME + _ZTV19QVideoWidgetControl @ 1221 NONAME + _ZTV19QVideoWindowControl @ 1222 NONAME + _ZTV20QAbstractAudioOutput @ 1223 NONAME + _ZTV20QAbstractVideoBuffer @ 1224 NONAME + _ZTV20QAudioEncoderControl @ 1225 NONAME + _ZTV20QImageEncoderControl @ 1226 NONAME + _ZTV20QMediaPlaylistReader @ 1227 NONAME + _ZTV20QMediaPlaylistWriter @ 1228 NONAME + _ZTV20QMediaStreamsControl @ 1229 NONAME + _ZTV20QVideoEncoderControl @ 1230 NONAME + _ZTV21QAbstractVideoSurface @ 1231 NONAME + _ZTV21QMediaPlaylistControl @ 1232 NONAME + _ZTV21QMediaRecorderControl @ 1233 NONAME + _ZTV21QMediaServiceProvider @ 1234 NONAME + _ZTV21QVideoRendererControl @ 1235 NONAME + _ZTV22QAudioEndpointSelector @ 1236 NONAME + _ZTV22QMediaContainerControl @ 1237 NONAME + _ZTV22QMediaPlaylistIOPlugin @ 1238 NONAME + _ZTV22QMediaPlaylistProvider @ 1239 NONAME + _ZTV22QMetaDataReaderControl @ 1240 NONAME + _ZTV22QMetaDataWriterControl @ 1241 NONAME + _ZTV23QMediaBindableInterface @ 1242 NONAME + _ZTV23QMediaPlaylistNavigator @ 1243 NONAME + _ZTV24QAbstractAudioDeviceInfo @ 1244 NONAME + _ZTV27QLocalMediaPlaylistProvider @ 1245 NONAME + _ZTV27QMediaPlaylistSourceControl @ 1246 NONAME + _ZTV27QMediaServiceProviderPlugin @ 1247 NONAME + _ZThn16_N18QGraphicsVideoItem14setMediaObjectEP12QMediaObject @ 1248 NONAME + _ZThn16_N18QGraphicsVideoItemD0Ev @ 1249 NONAME + _ZThn16_N18QGraphicsVideoItemD1Ev @ 1250 NONAME + _ZThn16_NK18QGraphicsVideoItem11mediaObjectEv @ 1251 NONAME + _ZThn20_N12QVideoWidget14setMediaObjectEP12QMediaObject @ 1252 NONAME + _ZThn20_N12QVideoWidgetD0Ev @ 1253 NONAME + _ZThn20_N12QVideoWidgetD1Ev @ 1254 NONAME + _ZThn20_NK12QVideoWidget11mediaObjectEv @ 1255 NONAME + _ZThn8_N12QVideoWidgetD0Ev @ 1256 NONAME + _ZThn8_N12QVideoWidgetD1Ev @ 1257 NONAME + _ZThn8_N14QMediaPlaylist14setMediaObjectEP12QMediaObject @ 1258 NONAME + _ZThn8_N14QMediaPlaylistD0Ev @ 1259 NONAME + _ZThn8_N14QMediaPlaylistD1Ev @ 1260 NONAME + _ZThn8_N14QMediaRecorder14setMediaObjectEP12QMediaObject @ 1261 NONAME + _ZThn8_N14QMediaRecorderD0Ev @ 1262 NONAME + _ZThn8_N14QMediaRecorderD1Ev @ 1263 NONAME + _ZThn8_N18QAudioSystemPluginD0Ev @ 1264 NONAME + _ZThn8_N18QAudioSystemPluginD1Ev @ 1265 NONAME + _ZThn8_N18QGraphicsVideoItem10itemChangeEN13QGraphicsItem18GraphicsItemChangeERK8QVariant @ 1266 NONAME + _ZThn8_N18QGraphicsVideoItem5paintEP8QPainterPK24QStyleOptionGraphicsItemP7QWidget @ 1267 NONAME + _ZThn8_N18QGraphicsVideoItemD0Ev @ 1268 NONAME + _ZThn8_N18QGraphicsVideoItemD1Ev @ 1269 NONAME + _ZThn8_N22QMediaPlaylistIOPluginD0Ev @ 1270 NONAME + _ZThn8_N22QMediaPlaylistIOPluginD1Ev @ 1271 NONAME + _ZThn8_NK14QMediaPlaylist11mediaObjectEv @ 1272 NONAME + _ZThn8_NK14QMediaRecorder11mediaObjectEv @ 1273 NONAME + _ZThn8_NK18QGraphicsVideoItem12boundingRectEv @ 1274 NONAME + _ZeqRK15QMediaTimeRangeS1_ @ 1275 NONAME + _ZeqRK18QMediaTimeIntervalS1_ @ 1276 NONAME + _Zls6QDebugRK19QVideoSurfaceFormat @ 1277 NONAME + _ZmiRK15QMediaTimeRangeS1_ @ 1278 NONAME + _ZneRK15QMediaTimeRangeS1_ @ 1279 NONAME + _ZneRK18QMediaTimeIntervalS1_ @ 1280 NONAME + _ZplRK15QMediaTimeRangeS1_ @ 1281 NONAME + _ZN12QCameraFocus11qt_metacallEN11QMetaObject4CallEiPPv @ 1282 NONAME + _ZN12QCameraFocus11qt_metacastEPKc @ 1283 NONAME + _ZN12QCameraFocus12setFocusModeENS_9FocusModeE @ 1284 NONAME + _ZN12QCameraFocus16staticMetaObjectE @ 1285 NONAME DATA 16 + _ZN12QCameraFocus17focusZonesChangedEv @ 1286 NONAME + _ZN12QCameraFocus17setFocusPointModeENS_14FocusPointModeE @ 1287 NONAME + _ZN12QCameraFocus18digitalZoomChangedEf @ 1288 NONAME + _ZN12QCameraFocus18opticalZoomChangedEf @ 1289 NONAME + _ZN12QCameraFocus19getStaticMetaObjectEv @ 1290 NONAME + _ZN12QCameraFocus19setCustomFocusPointERK7QPointF @ 1291 NONAME + _ZN12QCameraFocus6zoomToEff @ 1292 NONAME + _ZN12QCameraFocusC1EP7QCamera @ 1293 NONAME + _ZN12QCameraFocusC2EP7QCamera @ 1294 NONAME + _ZN12QCameraFocusD0Ev @ 1295 NONAME + _ZN12QCameraFocusD1Ev @ 1296 NONAME + _ZN12QCameraFocusD2Ev @ 1297 NONAME + _ZN12QVideoWidgetC1ER19QVideoWidgetPrivateP7QWidget @ 1298 NONAME + _ZN12QVideoWidgetC2ER19QVideoWidgetPrivateP7QWidget @ 1299 NONAME + _ZN14QCameraControl11qt_metacallEN11QMetaObject4CallEiPPv @ 1300 NONAME + _ZN14QCameraControl11qt_metacastEPKc @ 1301 NONAME + _ZN14QCameraControl12stateChangedEN7QCamera5StateE @ 1302 NONAME + _ZN14QCameraControl16staticMetaObjectE @ 1303 NONAME DATA 16 + _ZN14QCameraControl18captureModeChangedEN7QCamera11CaptureModeE @ 1304 NONAME + _ZN14QCameraControl19getStaticMetaObjectEv @ 1305 NONAME + _ZN14QCameraControl5errorEiRK7QString @ 1306 NONAME + _ZN14QCameraControlC2EP7QObject @ 1307 NONAME + _ZN14QCameraControlD0Ev @ 1308 NONAME + _ZN14QCameraControlD1Ev @ 1309 NONAME + _ZN14QCameraControlD2Ev @ 1310 NONAME + _ZN15QCameraExposure10flashReadyEb @ 1311 NONAME + _ZN15QCameraExposure11qt_metacallEN11QMetaObject4CallEiPPv @ 1312 NONAME + _ZN15QCameraExposure11qt_metacastEPKc @ 1313 NONAME + _ZN15QCameraExposure12setFlashModeE6QFlagsINS_9FlashModeEE @ 1314 NONAME + _ZN15QCameraExposure15apertureChangedEf @ 1315 NONAME + _ZN15QCameraExposure15setAutoApertureEv @ 1316 NONAME + _ZN15QCameraExposure15setExposureModeENS_12ExposureModeE @ 1317 NONAME + _ZN15QCameraExposure15setMeteringModeENS_12MeteringModeE @ 1318 NONAME + _ZN15QCameraExposure16staticMetaObjectE @ 1319 NONAME DATA 16 + _ZN15QCameraExposure17setManualApertureEf @ 1320 NONAME + _ZN15QCameraExposure19getStaticMetaObjectEv @ 1321 NONAME + _ZN15QCameraExposure19setAutoShutterSpeedEv @ 1322 NONAME + _ZN15QCameraExposure19shutterSpeedChangedEf @ 1323 NONAME + _ZN15QCameraExposure20apertureRangeChangedEv @ 1324 NONAME + _ZN15QCameraExposure21isoSensitivityChangedEi @ 1325 NONAME + _ZN15QCameraExposure21setAutoIsoSensitivityEv @ 1326 NONAME + _ZN15QCameraExposure21setManualShutterSpeedEf @ 1327 NONAME + _ZN15QCameraExposure23setExposureCompensationEf @ 1328 NONAME + _ZN15QCameraExposure23setManualIsoSensitivityEi @ 1329 NONAME + _ZN15QCameraExposure24shutterSpeedRangeChangedEv @ 1330 NONAME + _ZN15QCameraExposureC1EP7QCamera @ 1331 NONAME + _ZN15QCameraExposureC2EP7QCamera @ 1332 NONAME + _ZN15QCameraExposureD0Ev @ 1333 NONAME + _ZN15QCameraExposureD1Ev @ 1334 NONAME + _ZN15QCameraExposureD2Ev @ 1335 NONAME + _ZN16QCameraFocusZone9setStatusENS_15FocusZoneStatusE @ 1336 NONAME + _ZN16QCameraFocusZoneC1ERK6QRectFNS_15FocusZoneStatusE @ 1337 NONAME + _ZN16QCameraFocusZoneC1ERKS_ @ 1338 NONAME + _ZN16QCameraFocusZoneC1Ev @ 1339 NONAME + _ZN16QCameraFocusZoneC2ERK6QRectFNS_15FocusZoneStatusE @ 1340 NONAME + _ZN16QCameraFocusZoneC2ERKS_ @ 1341 NONAME + _ZN16QCameraFocusZoneC2Ev @ 1342 NONAME + _ZN16QCameraFocusZoneD1Ev @ 1343 NONAME + _ZN16QCameraFocusZoneD2Ev @ 1344 NONAME + _ZN16QCameraFocusZoneaSERKS_ @ 1345 NONAME + _ZN17QCameraViewfinder11qt_metacallEN11QMetaObject4CallEiPPv @ 1346 NONAME + _ZN17QCameraViewfinder11qt_metacastEPKc @ 1347 NONAME + _ZN17QCameraViewfinder14setMediaObjectEP12QMediaObject @ 1348 NONAME + _ZN17QCameraViewfinder16staticMetaObjectE @ 1349 NONAME DATA 16 + _ZN17QCameraViewfinder19getStaticMetaObjectEv @ 1350 NONAME + _ZN17QCameraViewfinderC1EP7QWidget @ 1351 NONAME + _ZN17QCameraViewfinderC2EP7QWidget @ 1352 NONAME + _ZN17QCameraViewfinderD0Ev @ 1353 NONAME + _ZN17QCameraViewfinderD1Ev @ 1354 NONAME + _ZN17QCameraViewfinderD2Ev @ 1355 NONAME + _ZN19QCameraFocusControl11qt_metacallEN11QMetaObject4CallEiPPv @ 1356 NONAME + _ZN19QCameraFocusControl11qt_metacastEPKc @ 1357 NONAME + _ZN19QCameraFocusControl16staticMetaObjectE @ 1358 NONAME DATA 16 + _ZN19QCameraFocusControl17focusZonesChangedEv @ 1359 NONAME + _ZN19QCameraFocusControl18digitalZoomChangedEf @ 1360 NONAME + _ZN19QCameraFocusControl18opticalZoomChangedEf @ 1361 NONAME + _ZN19QCameraFocusControl19getStaticMetaObjectEv @ 1362 NONAME + _ZN19QCameraFocusControlC2EP7QObject @ 1363 NONAME + _ZN19QCameraFocusControlD0Ev @ 1364 NONAME + _ZN19QCameraFocusControlD1Ev @ 1365 NONAME + _ZN19QCameraFocusControlD2Ev @ 1366 NONAME + _ZN19QCameraImageCapture10imageSavedEiRK7QString @ 1367 NONAME + _ZN19QCameraImageCapture11qt_metacallEN11QMetaObject4CallEiPPv @ 1368 NONAME + _ZN19QCameraImageCapture11qt_metacastEPKc @ 1369 NONAME + _ZN19QCameraImageCapture12imageExposedEi @ 1370 NONAME + _ZN19QCameraImageCapture13cancelCaptureEv @ 1371 NONAME + _ZN19QCameraImageCapture13imageCapturedEiRK6QImage @ 1372 NONAME + _ZN19QCameraImageCapture14setMediaObjectEP12QMediaObject @ 1373 NONAME + _ZN19QCameraImageCapture16staticMetaObjectE @ 1374 NONAME DATA 16 + _ZN19QCameraImageCapture19getStaticMetaObjectEv @ 1375 NONAME + _ZN19QCameraImageCapture19setEncodingSettingsERK21QImageEncoderSettings @ 1376 NONAME + _ZN19QCameraImageCapture22readyForCaptureChangedEb @ 1377 NONAME + _ZN19QCameraImageCapture5errorEiNS_5ErrorERK7QString @ 1378 NONAME + _ZN19QCameraImageCapture7captureERK7QString @ 1379 NONAME + _ZN19QCameraImageCaptureC1EP12QMediaObjectP7QObject @ 1380 NONAME + _ZN19QCameraImageCaptureC2EP12QMediaObjectP7QObject @ 1381 NONAME + _ZN19QCameraImageCaptureD0Ev @ 1382 NONAME + _ZN19QCameraImageCaptureD1Ev @ 1383 NONAME + _ZN19QCameraImageCaptureD2Ev @ 1384 NONAME + _ZN19QCameraLocksControl11qt_metacallEN11QMetaObject4CallEiPPv @ 1385 NONAME + _ZN19QCameraLocksControl11qt_metacastEPKc @ 1386 NONAME + _ZN19QCameraLocksControl16staticMetaObjectE @ 1387 NONAME DATA 16 + _ZN19QCameraLocksControl17lockStatusChangedEN7QCamera8LockTypeENS0_10LockStatusENS0_16LockChangeReasonE @ 1388 NONAME + _ZN19QCameraLocksControl19getStaticMetaObjectEv @ 1389 NONAME + _ZN19QCameraLocksControlC2EP7QObject @ 1390 NONAME + _ZN19QCameraLocksControlD0Ev @ 1391 NONAME + _ZN19QCameraLocksControlD1Ev @ 1392 NONAME + _ZN19QCameraLocksControlD2Ev @ 1393 NONAME + _ZN22QCameraExposureControl10flashReadyEb @ 1394 NONAME + _ZN22QCameraExposureControl11qt_metacallEN11QMetaObject4CallEiPPv @ 1395 NONAME + _ZN22QCameraExposureControl11qt_metacastEPKc @ 1396 NONAME + _ZN22QCameraExposureControl16staticMetaObjectE @ 1397 NONAME DATA 16 + _ZN22QCameraExposureControl19getStaticMetaObjectEv @ 1398 NONAME + _ZN22QCameraExposureControl24exposureParameterChangedEi @ 1399 NONAME + _ZN22QCameraExposureControl29exposureParameterRangeChangedEi @ 1400 NONAME + _ZN22QCameraExposureControlC2EP7QObject @ 1401 NONAME + _ZN22QCameraExposureControlD0Ev @ 1402 NONAME + _ZN22QCameraExposureControlD1Ev @ 1403 NONAME + _ZN22QCameraExposureControlD2Ev @ 1404 NONAME + _ZN22QCameraImageProcessing11qt_metacallEN11QMetaObject4CallEiPPv @ 1405 NONAME + _ZN22QCameraImageProcessing11qt_metacastEPKc @ 1406 NONAME + _ZN22QCameraImageProcessing11setContrastEi @ 1407 NONAME + _ZN22QCameraImageProcessing13setSaturationEi @ 1408 NONAME + _ZN22QCameraImageProcessing16staticMetaObjectE @ 1409 NONAME DATA 16 + _ZN22QCameraImageProcessing17setDenoisingLevelEi @ 1410 NONAME + _ZN22QCameraImageProcessing18setSharpeningLevelEi @ 1411 NONAME + _ZN22QCameraImageProcessing19getStaticMetaObjectEv @ 1412 NONAME + _ZN22QCameraImageProcessing19setWhiteBalanceModeENS_16WhiteBalanceModeE @ 1413 NONAME + _ZN22QCameraImageProcessing21setManualWhiteBalanceEi @ 1414 NONAME + _ZN22QCameraImageProcessingC1EP7QCamera @ 1415 NONAME + _ZN22QCameraImageProcessingC2EP7QCamera @ 1416 NONAME + _ZN22QCameraImageProcessingD0Ev @ 1417 NONAME + _ZN22QCameraImageProcessingD1Ev @ 1418 NONAME + _ZN22QCameraImageProcessingD2Ev @ 1419 NONAME + _ZN26QCameraImageCaptureControl10imageSavedEiRK7QString @ 1420 NONAME + _ZN26QCameraImageCaptureControl11qt_metacallEN11QMetaObject4CallEiPPv @ 1421 NONAME + _ZN26QCameraImageCaptureControl11qt_metacastEPKc @ 1422 NONAME + _ZN26QCameraImageCaptureControl12imageExposedEi @ 1423 NONAME + _ZN26QCameraImageCaptureControl13imageCapturedEiRK6QImage @ 1424 NONAME + _ZN26QCameraImageCaptureControl16staticMetaObjectE @ 1425 NONAME DATA 16 + _ZN26QCameraImageCaptureControl19getStaticMetaObjectEv @ 1426 NONAME + _ZN26QCameraImageCaptureControl22readyForCaptureChangedEb @ 1427 NONAME + _ZN26QCameraImageCaptureControl5errorEiiRK7QString @ 1428 NONAME + _ZN26QCameraImageCaptureControlC2EP7QObject @ 1429 NONAME + _ZN26QCameraImageCaptureControlD0Ev @ 1430 NONAME + _ZN26QCameraImageCaptureControlD1Ev @ 1431 NONAME + _ZN26QCameraImageCaptureControlD2Ev @ 1432 NONAME + _ZN29QCameraImageProcessingControl11qt_metacallEN11QMetaObject4CallEiPPv @ 1433 NONAME + _ZN29QCameraImageProcessingControl11qt_metacastEPKc @ 1434 NONAME + _ZN29QCameraImageProcessingControl16staticMetaObjectE @ 1435 NONAME DATA 16 + _ZN29QCameraImageProcessingControl19getStaticMetaObjectEv @ 1436 NONAME + _ZN29QCameraImageProcessingControlC2EP7QObject @ 1437 NONAME + _ZN29QCameraImageProcessingControlD0Ev @ 1438 NONAME + _ZN29QCameraImageProcessingControlD1Ev @ 1439 NONAME + _ZN29QCameraImageProcessingControlD2Ev @ 1440 NONAME + _ZN7QCamera10lockFailedEv @ 1441 NONAME + _ZN7QCamera11qt_metacallEN11QMetaObject4CallEiPPv @ 1442 NONAME + _ZN7QCamera11qt_metacastEPKc @ 1443 NONAME + _ZN7QCamera12stateChangedENS_5StateE @ 1444 NONAME + _ZN7QCamera13searchAndLockE6QFlagsINS_8LockTypeEE @ 1445 NONAME + _ZN7QCamera13searchAndLockEv @ 1446 NONAME + _ZN7QCamera13setViewfinderEP12QVideoWidget @ 1447 NONAME + _ZN7QCamera13setViewfinderEP18QGraphicsVideoItem @ 1448 NONAME + _ZN7QCamera14setCaptureModeENS_11CaptureModeE @ 1449 NONAME + _ZN7QCamera16availableDevicesEv @ 1450 NONAME + _ZN7QCamera16staticMetaObjectE @ 1451 NONAME DATA 16 + _ZN7QCamera17deviceDescriptionERK10QByteArray @ 1452 NONAME + _ZN7QCamera17lockStatusChangedENS_10LockStatusENS_16LockChangeReasonE @ 1453 NONAME + _ZN7QCamera17lockStatusChangedENS_8LockTypeENS_10LockStatusENS_16LockChangeReasonE @ 1454 NONAME + _ZN7QCamera18captureModeChangedENS_11CaptureModeE @ 1455 NONAME + _ZN7QCamera19getStaticMetaObjectEv @ 1456 NONAME + _ZN7QCamera4stopEv @ 1457 NONAME + _ZN7QCamera5errorENS_5ErrorE @ 1458 NONAME + _ZN7QCamera5startEv @ 1459 NONAME + _ZN7QCamera6lockedEv @ 1460 NONAME + _ZN7QCamera6unlockE6QFlagsINS_8LockTypeEE @ 1461 NONAME + _ZN7QCamera6unlockEv @ 1462 NONAME + _ZN7QCameraC1EP7QObjectP21QMediaServiceProvider @ 1463 NONAME + _ZN7QCameraC1ERK10QByteArrayP7QObject @ 1464 NONAME + _ZN7QCameraC2EP7QObjectP21QMediaServiceProvider @ 1465 NONAME + _ZN7QCameraC2ERK10QByteArrayP7QObject @ 1466 NONAME + _ZN7QCameraD0Ev @ 1467 NONAME + _ZN7QCameraD1Ev @ 1468 NONAME + _ZN7QCameraD2Ev @ 1469 NONAME + _ZNK12QCameraFocus10focusZonesEv @ 1470 NONAME + _ZNK12QCameraFocus10metaObjectEv @ 1471 NONAME + _ZNK12QCameraFocus11digitalZoomEv @ 1472 NONAME + _ZNK12QCameraFocus11isAvailableEv @ 1473 NONAME + _ZNK12QCameraFocus11opticalZoomEv @ 1474 NONAME + _ZNK12QCameraFocus14focusPointModeEv @ 1475 NONAME + _ZNK12QCameraFocus16customFocusPointEv @ 1476 NONAME + _ZNK12QCameraFocus18maximumDigitalZoomEv @ 1477 NONAME + _ZNK12QCameraFocus18maximumOpticalZoomEv @ 1478 NONAME + _ZNK12QCameraFocus20isFocusModeSupportedENS_9FocusModeE @ 1479 NONAME + _ZNK12QCameraFocus25isFocusPointModeSupportedENS_14FocusPointModeE @ 1480 NONAME + _ZNK12QCameraFocus9focusModeEv @ 1481 NONAME + _ZNK14QCameraControl10metaObjectEv @ 1482 NONAME + _ZNK15QCameraExposure10metaObjectEv @ 1483 NONAME + _ZNK15QCameraExposure11isAvailableEv @ 1484 NONAME + _ZNK15QCameraExposure12exposureModeEv @ 1485 NONAME + _ZNK15QCameraExposure12isFlashReadyEv @ 1486 NONAME + _ZNK15QCameraExposure12meteringModeEv @ 1487 NONAME + _ZNK15QCameraExposure12shutterSpeedEv @ 1488 NONAME + _ZNK15QCameraExposure14isoSensitivityEv @ 1489 NONAME + _ZNK15QCameraExposure18supportedAperturesEPb @ 1490 NONAME + _ZNK15QCameraExposure20exposureCompensationEv @ 1491 NONAME + _ZNK15QCameraExposure20isFlashModeSupportedE6QFlagsINS_9FlashModeEE @ 1492 NONAME + _ZNK15QCameraExposure22supportedShutterSpeedsEPb @ 1493 NONAME + _ZNK15QCameraExposure23isExposureModeSupportedENS_12ExposureModeE @ 1494 NONAME + _ZNK15QCameraExposure23isMeteringModeSupportedENS_12MeteringModeE @ 1495 NONAME + _ZNK15QCameraExposure25supportedIsoSensitivitiesEPb @ 1496 NONAME + _ZNK15QCameraExposure8apertureEv @ 1497 NONAME + _ZNK15QCameraExposure9flashModeEv @ 1498 NONAME + _ZNK16QCameraFocusZone4areaEv @ 1499 NONAME + _ZNK16QCameraFocusZone6statusEv @ 1500 NONAME + _ZNK16QCameraFocusZone7isValidEv @ 1501 NONAME + _ZNK16QCameraFocusZoneeqERKS_ @ 1502 NONAME + _ZNK16QCameraFocusZoneneERKS_ @ 1503 NONAME + _ZNK17QCameraViewfinder10metaObjectEv @ 1504 NONAME + _ZNK17QCameraViewfinder11mediaObjectEv @ 1505 NONAME + _ZNK17QMediaImageViewer8playlistEv @ 1506 NONAME + _ZNK19QCameraFocusControl10metaObjectEv @ 1507 NONAME + _ZNK19QCameraImageCapture10metaObjectEv @ 1508 NONAME + _ZNK19QCameraImageCapture11errorStringEv @ 1509 NONAME + _ZNK19QCameraImageCapture11isAvailableEv @ 1510 NONAME + _ZNK19QCameraImageCapture11mediaObjectEv @ 1511 NONAME + _ZNK19QCameraImageCapture16encodingSettingsEv @ 1512 NONAME + _ZNK19QCameraImageCapture17availabilityErrorEv @ 1513 NONAME + _ZNK19QCameraImageCapture17isReadyForCaptureEv @ 1514 NONAME + _ZNK19QCameraImageCapture20supportedImageCodecsEv @ 1515 NONAME + _ZNK19QCameraImageCapture20supportedResolutionsERK21QImageEncoderSettingsPb @ 1516 NONAME + _ZNK19QCameraImageCapture21imageCodecDescriptionERK7QString @ 1517 NONAME + _ZNK19QCameraImageCapture5errorEv @ 1518 NONAME + _ZNK19QCameraLocksControl10metaObjectEv @ 1519 NONAME + _ZNK22QCameraExposureControl10metaObjectEv @ 1520 NONAME + _ZNK22QCameraImageProcessing10metaObjectEv @ 1521 NONAME + _ZNK22QCameraImageProcessing10saturationEv @ 1522 NONAME + _ZNK22QCameraImageProcessing11isAvailableEv @ 1523 NONAME + _ZNK22QCameraImageProcessing14denoisingLevelEv @ 1524 NONAME + _ZNK22QCameraImageProcessing15sharpeningLevelEv @ 1525 NONAME + _ZNK22QCameraImageProcessing16whiteBalanceModeEv @ 1526 NONAME + _ZNK22QCameraImageProcessing18manualWhiteBalanceEv @ 1527 NONAME + _ZNK22QCameraImageProcessing20isDenoisingSupportedEv @ 1528 NONAME + _ZNK22QCameraImageProcessing21isSharpeningSupportedEv @ 1529 NONAME + _ZNK22QCameraImageProcessing27isWhiteBalanceModeSupportedENS_16WhiteBalanceModeE @ 1530 NONAME + _ZNK22QCameraImageProcessing8contrastEv @ 1531 NONAME + _ZNK26QCameraImageCaptureControl10metaObjectEv @ 1532 NONAME + _ZNK29QCameraImageProcessingControl10metaObjectEv @ 1533 NONAME + _ZNK7QCamera10lockStatusENS_8LockTypeE @ 1534 NONAME + _ZNK7QCamera10lockStatusEv @ 1535 NONAME + _ZNK7QCamera10metaObjectEv @ 1536 NONAME + _ZNK7QCamera11captureModeEv @ 1537 NONAME + _ZNK7QCamera11errorStringEv @ 1538 NONAME + _ZNK7QCamera11isAvailableEv @ 1539 NONAME + _ZNK7QCamera14requestedLocksEv @ 1540 NONAME + _ZNK7QCamera14supportedLocksEv @ 1541 NONAME + _ZNK7QCamera15imageProcessingEv @ 1542 NONAME + _ZNK7QCamera17availabilityErrorEv @ 1543 NONAME + _ZNK7QCamera22isCaptureModeSupportedENS_11CaptureModeE @ 1544 NONAME + _ZNK7QCamera5errorEv @ 1545 NONAME + _ZNK7QCamera5focusEv @ 1546 NONAME + _ZNK7QCamera5stateEv @ 1547 NONAME + _ZNK7QCamera8exposureEv @ 1548 NONAME + _ZTI12QCameraFocus @ 1549 NONAME + _ZTI14QCameraControl @ 1550 NONAME + _ZTI15QCameraExposure @ 1551 NONAME + _ZTI17QCameraViewfinder @ 1552 NONAME + _ZTI19QCameraFocusControl @ 1553 NONAME + _ZTI19QCameraImageCapture @ 1554 NONAME + _ZTI19QCameraLocksControl @ 1555 NONAME + _ZTI22QCameraExposureControl @ 1556 NONAME + _ZTI22QCameraImageProcessing @ 1557 NONAME + _ZTI26QCameraImageCaptureControl @ 1558 NONAME + _ZTI29QCameraImageProcessingControl @ 1559 NONAME + _ZTI7QCamera @ 1560 NONAME + _ZTV12QCameraFocus @ 1561 NONAME + _ZTV14QCameraControl @ 1562 NONAME + _ZTV15QCameraExposure @ 1563 NONAME + _ZTV17QCameraViewfinder @ 1564 NONAME + _ZTV19QCameraFocusControl @ 1565 NONAME + _ZTV19QCameraImageCapture @ 1566 NONAME + _ZTV19QCameraLocksControl @ 1567 NONAME + _ZTV22QCameraExposureControl @ 1568 NONAME + _ZTV22QCameraImageProcessing @ 1569 NONAME + _ZTV26QCameraImageCaptureControl @ 1570 NONAME + _ZTV29QCameraImageProcessingControl @ 1571 NONAME + _ZTV7QCamera @ 1572 NONAME + _ZThn20_N17QCameraViewfinder14setMediaObjectEP12QMediaObject @ 1573 NONAME + _ZThn20_N17QCameraViewfinderD0Ev @ 1574 NONAME + _ZThn20_N17QCameraViewfinderD1Ev @ 1575 NONAME + _ZThn20_NK17QCameraViewfinder11mediaObjectEv @ 1576 NONAME + _ZThn8_N17QCameraViewfinderD0Ev @ 1577 NONAME + _ZThn8_N17QCameraViewfinderD1Ev @ 1578 NONAME + _ZThn8_N19QCameraImageCapture14setMediaObjectEP12QMediaObject @ 1579 NONAME + _ZThn8_N19QCameraImageCaptureD0Ev @ 1580 NONAME + _ZThn8_N19QCameraImageCaptureD1Ev @ 1581 NONAME + _ZThn8_NK19QCameraImageCapture11mediaObjectEv @ 1582 NONAME + _ZN17QMediaImageViewer14setVideoOutputEP12QVideoWidget @ 1583 NONAME + _ZN17QMediaImageViewer14setVideoOutputEP18QGraphicsVideoItem @ 1584 NONAME + _ZN21QAbstractVideoSurface19setNativeResolutionERK5QSize @ 1585 NONAME + _ZN21QAbstractVideoSurface23nativeResolutionChangedERK5QSize @ 1586 NONAME + _ZNK21QAbstractVideoSurface16nativeResolutionEv @ 1587 NONAME + _ZN14QCameraControl13statusChangedEN7QCamera6StatusE @ 1588 NONAME + _ZN15QCameraExposure27exposureCompensationChangedEf @ 1589 NONAME + _ZN19QCameraFlashControl10flashReadyEb @ 1590 NONAME + _ZN19QCameraFlashControl11qt_metacallEN11QMetaObject4CallEiPPv @ 1591 NONAME + _ZN19QCameraFlashControl11qt_metacastEPKc @ 1592 NONAME + _ZN19QCameraFlashControl16staticMetaObjectE @ 1593 NONAME DATA 16 + _ZN19QCameraFlashControl19getStaticMetaObjectEv @ 1594 NONAME + _ZN19QCameraFlashControlC2EP7QObject @ 1595 NONAME + _ZN19QCameraFlashControlD0Ev @ 1596 NONAME + _ZN19QCameraFlashControlD1Ev @ 1597 NONAME + _ZN19QCameraFlashControlD2Ev @ 1598 NONAME + _ZN7QCamera13statusChangedENS_6StatusE @ 1599 NONAME + _ZN7QCamera4loadEv @ 1600 NONAME + _ZN7QCamera6unloadEv @ 1601 NONAME + _ZNK19QCameraFlashControl10metaObjectEv @ 1602 NONAME + _ZNK7QCamera6statusEv @ 1603 NONAME + _ZTI19QCameraFlashControl @ 1604 NONAME + _ZTV19QCameraFlashControl @ 1605 NONAME + _ZN12QCameraFocus25maximumDigitalZoomChangedEf @ 1606 NONAME + _ZN12QCameraFocus25maximumOpticalZoomChangedEf @ 1607 NONAME + _ZN12QSoundEffect12setLoopCountEi @ 1608 NONAME + _ZN12QSoundEffect13loadedChangedEv @ 1609 NONAME + _ZN12QSoundEffect16loopCountChangedEv @ 1610 NONAME + _ZN12QSoundEffect18supportedMimeTypesEv @ 1611 NONAME + _ZN12QSoundEffect4stopEv @ 1612 NONAME + _ZN19QCameraFocusControl25maximumDigitalZoomChangedEf @ 1613 NONAME + _ZN19QCameraFocusControl25maximumOpticalZoomChangedEf @ 1614 NONAME + _ZNK12QSoundEffect8isLoadedEv @ 1615 NONAME + _ZNK12QSoundEffect9loopCountEv @ 1616 NONAME + _ZN12QSoundEffect13statusChangedEv @ 1617 NONAME + _ZN12QSoundEffect14playingChangedEv @ 1618 NONAME + _ZNK12QSoundEffect6statusEv @ 1619 NONAME + _ZNK12QSoundEffect9isPlayingEv @ 1620 NONAME + _ZN12QMediaPlayer14setVideoOutputEP21QAbstractVideoSurface @ 1621 NONAME + _ZN12QMediaPlayer24setNetworkConfigurationsERK5QListI21QNetworkConfigurationE @ 1622 NONAME + _ZN12QMediaPlayer27networkConfigurationChangedERK21QNetworkConfiguration @ 1623 NONAME + _ZN17QMediaImageViewer14setVideoOutputEP21QAbstractVideoSurface @ 1624 NONAME + _ZN26QMediaNetworkAccessControl11qt_metacallEN11QMetaObject4CallEiPPv @ 1625 NONAME + _ZN26QMediaNetworkAccessControl11qt_metacastEPKc @ 1626 NONAME + _ZN26QMediaNetworkAccessControl16staticMetaObjectE @ 1627 NONAME DATA 16 + _ZN26QMediaNetworkAccessControl19getStaticMetaObjectEv @ 1628 NONAME + _ZN26QMediaNetworkAccessControl20configurationChangedERK21QNetworkConfiguration @ 1629 NONAME + _ZN26QMediaNetworkAccessControlC2EP7QObject @ 1630 NONAME + _ZN26QMediaNetworkAccessControlD0Ev @ 1631 NONAME + _ZN26QMediaNetworkAccessControlD1Ev @ 1632 NONAME + _ZN26QMediaNetworkAccessControlD2Ev @ 1633 NONAME + _ZN7QCamera13setViewfinderEP21QAbstractVideoSurface @ 1634 NONAME + _ZNK12QMediaPlayer27currentNetworkConfigurationEv @ 1635 NONAME + _ZNK26QMediaNetworkAccessControl10metaObjectEv @ 1636 NONAME + _ZTI26QMediaNetworkAccessControl @ 1637 NONAME + _ZTV26QMediaNetworkAccessControl @ 1638 NONAME + diff --git a/src/s60installs/s60installs.pro b/src/s60installs/s60installs.pro new file mode 100644 index 000000000..3ce0af604 --- /dev/null +++ b/src/s60installs/s60installs.pro @@ -0,0 +1,514 @@ +TEMPLATE = subdirs + +isEmpty(QT_LIBINFIX):symbian { + include(../../staticconfig.pri) + load(data_caging_paths) + include($$QT_MOBILITY_BUILD_TREE/config.pri) + + SUBDIRS = + TARGET = "QtMobility" + TARGET.UID3 = 0x2002ac89 + + VERSION = 1.2.0 + + vendorinfo = \ + "; Localised Vendor name" \ + "%{\"Nokia\"}" \ + " " \ + "; Unique Vendor name" \ + ":\"Nokia\"" \ + " " + qtmobilitydeployment.pkg_prerules += vendorinfo + + + epoc31 = $$(EPOCROOT31) + epoc32 = $$(EPOCROOT32) + epoc50 = $$(EPOCROOT50) + epoc51 = $$(EPOCROOT51) + epocS3PS1 = $$(EPOCROOT_S3PS1) + epocS3PS2 = $$(EPOCROOT_S3PS2) + + # default to EPOCROOT if EPOCROOTxy not defined + isEmpty(epoc31) { + EPOCROOT31 = $${EPOCROOT} + } else { + EPOCROOT31 = $$(EPOCROOT31) + } + isEmpty(epoc32) { + EPOCROOT32 = $${EPOCROOT} + }else { + EPOCROOT32 = $$(EPOCROOT32) + } + isEmpty(epoc50) { + EPOCROOT50 = $${EPOCROOT} + } else { + EPOCROOT50 = $$(EPOCROOT50) + } + #Epocroot 51 is based on a N97 sdk + isEmpty(epoc51) { + EPOCROOT51 = $${EPOCROOT} + } else { + EPOCROOT51 = $$(EPOCROOT51) + } + isEmpty(epocS3PS1) { + EPOCROOT_S3PS1 = $${EPOCROOT} + } else { + EPOCROOT_S3PS1 = $$(EPOCROOT_S3PS1) + } + isEmpty(epocS3PS2) { + EPOCROOT_S3PS2 = $${EPOCROOT} + } else { + EPOCROOT_S3PS2 = $$(EPOCROOT_S3PS2) + } + + #Symbian^3 and beyond requires special package flags + #we cannot use S60_VERSION == 5.2 as Qt 4.6.x does not define it yet + #see $QTDIR/mkspecs/common/symbian/symbian.conf for details + exists($${EPOCROOT}epoc32/release/winscw/udeb/z/system/install/series60v5.2.sis)|exists($${EPOCROOT}epoc32/data/z/system/install/series60v5.2.sis)|exists($${EPOCROOT}epoc32/release/armv5/lib/libstdcppv5.dso) { + pkg_version = $$replace(VERSION,"\\.",",") + qtmobilitydeployment.pkg_prerules += "$${LITERAL_HASH}{\"QtMobility\"},(0x2002AC89),$${pkg_version},TYPE=SA,RU,NR" + } + + contains(mobility_modules, messaging) { + qtmobilitydeployment.sources += \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtMessaging.dll + + contains(QT_CONFIG, declarative): { + qtmobilitydeployment.sources += \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/declarative_messaging.dll + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\messaging\\qmakepluginstubs\\declarative_messaging.qtplugin\" - \"!:\\resource\\qt\\imports\\QtMobility\\messaging\\declarative_messaging.qtplugin\"" + qmldirs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\messaging\\qmldir\" - \"!:\\resource\\qt\\imports\\QtMobility\\messaging\\qmldir\"" + } + } + + contains(mobility_modules, connectivity) { + # QtConnectivity needs to be built and deployed to each Symbian version differently. This + # is because NFC support is only available from Symbian^3 PS2 onwards. There are also some + # differences with Bluetooth, hence the Symbian^1 variants. + # + # - PS2 build has NFC and Bluetooth support, requires Symbian^3 device with PS2 firmware + # - PS1 build has Bluetooth support only (NFC is a stub), requires Symbian^3 device with + # PS1 firmware + # Installing Qt Mobility on a Symbian^3 PS1 device then upgrading device firmware to PS2 + # will leave Qt Mobility NFC support disabled until Qt Mobility is reinstalled/upgraded. + # - S60 5.0 build has Bluetooth support only (NFC is a stub) + # - S60 3.1 and 3.2 build only produces a stub library. + connectivity = \ + "IF package(0x20022E6D) AND exists(\"z:\\sys\\bin\\nfc.dll\")" \ + " \"$${EPOCROOT_S3PS2}epoc32/release/$(PLATFORM)/$(TARGET)/QtConnectivity.dll\" - \"!:\\sys\\bin\\QtConnectivity.dll\"" \ + "ELSEIF package(0x20022E6D)" \ + " \"$${EPOCROOT_S3PS1}epoc32/release/$(PLATFORM)/$(TARGET)/QtConnectivity.dll\" - \"!:\\sys\\bin\\QtConnectivity.dll\"" \ + "ELSEIF package(0x1028315F)" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtConnectivity.dll\" - \"!:\\sys\\bin\\QtConnectivity.dll\"" \ + "ELSEIF package(0x102752AE) OR package(0x102032BE)" \ + " \"$${EPOCROOT32}epoc32/release/$(PLATFORM)/$(TARGET)/QtConnectivity.dll\" - \"!:\\sys\\bin\\QtConnectivity.dll\"" \ + "ELSE" \ + " \"$${EPOCROOT}epoc32/release/$(PLATFORM)/$(TARGET)/QtConnectivity.dll\" - \"!:\\sys\\bin\\QtConnectivity.dll\"" \ + "ENDIF" + + contains(QT_CONFIG, declarative): { + qtmobilitydeployment.sources += \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/declarative_connectivity.dll + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\connectivity\\qmakepluginstubs\\declarative_connectivity.qtplugin\" - \"!:\\resource\\qt\\imports\\QtMobility\\connectivity\\declarative_connectivity.qtplugin\"" + qmldirs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\connectivity\\qmldir\" - \"!:\\resource\\qt\\imports\\QtMobility\\connectivity\\qmldir\"" + } + + + qtmobilitydeployment.pkg_postrules += connectivity + } + + contains(mobility_modules, serviceframework) { + qtmobilitydeployment.sources += \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtServiceFramework.dll \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qsfwdatabasemanagerserver.exe + contains(QT_CONFIG, declarative): { + qtmobilitydeployment.sources += \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/declarative_serviceframework.dll + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\serviceframework\\qmakepluginstubs\\declarative_serviceframework.qtplugin\" - \"!:\\resource\\qt\\imports\\QtMobility\\serviceframework\\declarative_serviceframework.qtplugin\"" + qmldirs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\serviceframework\\qmldir\" - \"!:\\resource\\qt\\imports\\QtMobility\\serviceframework\\qmldir\"" + } + } + + contains(mobility_modules, location) { + qtmobilitydeployment.sources += $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtLocation.dll + qtmobilitydeployment.sources += $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtgeoservices_nokia.dll + qtmobilitydeployment.sources += $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtlandmarks_symbian.dll + pluginstubs += "\"$$QT_MOBILITY_BUILD_TREE/plugins/geoservices/nokia/qmakepluginstubs/qtgeoservices_nokia.qtplugin\" - \"!:\\resource\\qt\\plugins\\geoservices\\qtgeoservices_nokia.qtplugin\"" + pluginstubs += "\"$$QT_MOBILITY_BUILD_TREE/plugins/landmarks/symbian_landmarks/qmakepluginstubs/qtlandmarks_symbian.qtplugin\" - \"!:\\resource\\qt\\plugins\\landmarks\\qtlandmarks_symbian.qtplugin\"" + contains(QT_CONFIG, declarative): { + qtmobilitydeployment.sources += \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/declarative_location.dll + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\location\\qmakepluginstubs\\declarative_location.qtplugin\" - \"!:\\resource\\qt\\imports\\QtMobility\\location\\declarative_location.qtplugin\"" + qmldirs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\location\\qmldir\" - \"!:\\resource\\qt\\imports\\QtMobility\\location\\qmldir\"" + } + } + + contains(mobility_modules, systeminfo) { + sysinfo = \ + "IF package(0x1028315F)" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtSystemInfo.dll\" - \"!:\\sys\\bin\\QtSystemInfo.dll\"" \ + "ELSEIF package(0x102032BE)" \ + " \"$${EPOCROOT31}epoc32/release/$(PLATFORM)/$(TARGET)/QtSystemInfo.dll\" - \"!:\\sys\\bin\\QtSystemInfo.dll\"" \ + "ELSEIF package(0x102752AE)" \ + " \"$${EPOCROOT32}epoc32/release/$(PLATFORM)/$(TARGET)/QtSystemInfo.dll\" - \"!:\\sys\\bin\\QtSystemInfo.dll\"" \ + "ELSE" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtSystemInfo.dll\" - \"!:\\sys\\bin\\QtSystemInfo.dll\"" \ + "ENDIF" + + qtmobilitydeployment.pkg_postrules += sysinfo + contains(QT_CONFIG, declarative): { + qtmobilitydeployment.sources += \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/declarative_systeminfo.dll + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\systeminfo\\qmakepluginstubs\\declarative_systeminfo.qtplugin\" - \"!:\\resource\\qt\\imports\\QtMobility\\systeminfo\\declarative_systeminfo.qtplugin\"" + qmldirs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\systeminfo\\qmldir\" - \"!:\\resource\\qt\\imports\\QtMobility\\systeminfo\\qmldir\"" + } + } + + contains(mobility_modules, publishsubscribe) { + qtmobilitydeployment.sources += \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtPublishSubscribe.dll \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qpspathmapperserver.exe + contains(QT_CONFIG, declarative) { + qtmobilitydeployment.sources += \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/declarative_publishsubscribe.dll + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\publishsubscribe\\qmakepluginstubs\\declarative_publishsubscribe.qtplugin\" - \"!:\\resource\\qt\\imports\\QtMobility\\publishsubscribe\\declarative_publishsubscribe.qtplugin\"" + qmldirs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\publishsubscribe\\qmldir\" - \"!:\\resource\\qt\\imports\\QtMobility\\publishsubscribe\\qmldir\"" + } + } + + contains(mobility_modules, versit) { + qtmobilitydeployment.sources += $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtVersit.dll + qtmobilitydeployment.sources += $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtversit_backuphandler.dll + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\versit\\backuphandler\\qmakepluginstubs\\qtversit_backuphandler.qtplugin\" - \"!:\\resource\\qt\\plugins\\versit\\qtversit_backuphandler.qtplugin\"" + + ## now the versit organizer module - depends on versit and organizer. + contains(mobility_modules, organizer) { + qtmobilitydeployment.sources += $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtVersitOrganizer.dll + } + } + + contains(mobility_modules, feedback) { + qtmobilitydeployment.sources += $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtFeedback.dll + contains(immersion_enabled, yes) { + qtmobilitydeployment.sources += $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtfeedback_immersion.dll + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\feedback\\immersion\\qmakepluginstubs\\qtfeedback_immersion.qtplugin\" - \"!:\\resource\\qt\\plugins\\feedback\\qtfeedback_immersion.qtplugin\"" + } + + equals(QT_MAJOR_VERSION, 4) : greaterThan(QT_MINOR_VERSION, 6):contains(mobility_modules,multimedia) { + qtmobilitydeployment.sources += $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtfeedback_mmk.dll + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\feedback\\mmk\\qmakepluginstubs\\qtfeedback_mmk.qtplugin\" - \"!:\\resource\\qt\\plugins\\feedback\\qtfeedback_mmk.qtplugin\"" + } + + feedback = \ + "IF package(0x1028315F)" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtfeedback_symbian.dll\" - \"!:\\sys\\bin\\qtfeedback_symbian.dll\"" \ + "ELSEIF package(0x102752AE)" \ + " \"$${EPOCROOT32}epoc32/release/$(PLATFORM)/$(TARGET)/qtfeedback_symbian.dll\" - \"!:\\sys\\bin\\qtfeedback_symbian.dll\"" \ + "ELSEIF package(0x102032BE)" \ + " \"$${EPOCROOT31}epoc32/release/$(PLATFORM)/$(TARGET)/qtfeedback_symbian.dll\" - \"!:\\sys\\bin\\qtfeedback_symbian.dll\"" \ + "ELSE" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtfeedback_symbian.dll\" - \"!:\\sys\\bin\\qtfeedback_symbian.dll\"" \ + "ENDIF" + + qtmobilitydeployment.pkg_postrules += feedback + + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\feedback\\symbian\\qmakepluginstubs\\qtfeedback_symbian.qtplugin\" - \"!:\\resource\\qt\\plugins\\feedback\\qtfeedback_symbian.qtplugin\"" + + contains(QT_CONFIG, declarative): { + qtmobilitydeployment.sources += \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/declarative_feedback.dll + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\feedback\\qmakepluginstubs\\declarative_feedback.qtplugin\" - \"!:\\resource\\qt\\imports\\QtMobility\\feedback\\declarative_feedback.qtplugin\"" + qmldirs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\feedback\\qmldir\" - \"!:\\resource\\qt\\imports\\QtMobility\\feedback\\qmldir\"" + } + } + + contains(mobility_modules, organizer) { + qtmobilitydeployment.sources += $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtOrganizer.dll + organizer = \ + "IF package(0x1028315F)" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtorganizer_symbian.dll\" - \"!:\\sys\\bin\\qtorganizer_symbian.dll\"" \ + "ELSEIF package(0x102752AE)" \ + " \"$${EPOCROOT32}epoc32/release/$(PLATFORM)/$(TARGET)/qtorganizer_symbian.dll\" - \"!:\\sys\\bin\\qtorganizer_symbian.dll\"" \ + "ELSEIF package(0x102032BE)" \ + " \"$${EPOCROOT31}epoc32/release/$(PLATFORM)/$(TARGET)/qtorganizer_symbian.dll\" - \"!:\\sys\\bin\\qtorganizer_symbian.dll\"" \ + "ELSE" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtorganizer_symbian.dll\" - \"!:\\sys\\bin\\qtorganizer_symbian.dll\"" \ + "ENDIF" + + qtmobilitydeployment.pkg_postrules += organizer + + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\organizer\\symbian\\qmakepluginstubs\\qtorganizer_symbian.qtplugin\" - \"!:\\resource\\qt\\plugins\\organizer\\qtorganizer_symbian.qtplugin\"" + contains(QT_CONFIG, declarative):contains(mobility_modules,versit) { + qtmobilitydeployment.sources += \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/declarative_organizer.dll + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\organizer\\qmakepluginstubs\\declarative_organizer.qtplugin\" - \"!:\\resource\\qt\\imports\\QtMobility\\organizer\\declarative_organizer.qtplugin\"" + qmldirs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\organizer\\qmldir\" - \"!:\\resource\\qt\\imports\\QtMobility\\organizer\\qmldir\"" + } + } + + contains(mobility_modules, gallery) { + #QDocumentGallery on S60/Symbian relies on MetaDataSystem. There exists few different versions of it and we must + #check what version is currently installed on devices. Check is made a with known dlls. + #Installation has these preconditions: + # QDocumentGallery built against EPOCROOT50 has mds 2.0 libs in place (3.1/3.2/5.0) + # QDocumentGallery built against EPOCROOT51 has mds 2.5 libs in place (Symbian^3 and N97) + # QDocumentGallery built against EPOCROOT32 has no mds libs at all (stub implementation, api only) + # Also if checked mds library is present on c-drive then also check whether mds is installed + gallerymdscheck = \ + "if exists(\"z:\sys\bin\locationutility.dll\")" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtGallery.dll\" - \"!:\\sys\\bin\\QtGallery.dll\"" \ + "elseif exists(\"c:\sys\bin\locationutility.dll\") AND package(0x200009F5)" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtGallery.dll\" - \"!:\\sys\\bin\\QtGallery.dll\"" \ + "elseif exists(\"z:\sys\bin\locationmanagerserver.exe\")" \ + " \"$${EPOCROOT51}epoc32/release/$(PLATFORM)/$(TARGET)/QtGallery.dll\" - \"!:\\sys\\bin\\QtGallery.dll\"" \ + "elseif exists(\"c:\sys\bin\locationmanagerserver.exe\") AND package(0x200009F5)" \ + " \"$${EPOCROOT51}epoc32/release/$(PLATFORM)/$(TARGET)/QtGallery.dll\" - \"!:\\sys\\bin\\QtGallery.dll\"" \ + "else" \ + " \"$${EPOCROOT32}epoc32/release/$(PLATFORM)/$(TARGET)/QtGallery.dll\" - \"!:\\sys\\bin\\QtGallery.dll\"" \ + "endif" + + qtmobilitydeployment.pkg_postrules += gallerymdscheck + + # QDocumentGallery QML plugin + contains(QT_CONFIG, declarative): { + qtmobilitydeployment.sources += \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/declarative_gallery.dll + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\gallery\\qmakepluginstubs\\declarative_gallery.qtplugin\" - \"!:\\resource\\qt\\imports\\QtMobility\\gallery\\declarative_gallery.qtplugin\"" + qmldirs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\gallery\\qmldir\" - \"!:\\resource\\qt\\imports\\QtMobility\\gallery\\qmldir\"" + } + } + + contains(mobility_modules, bearer) { + bearer = \ + "IF package(0x1028315F)" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtBearer.dll\" - \"!:\\sys\\bin\\QtBearer.dll\"" \ + "ELSEIF package(0x102752AE)" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtBearer.dll\" - \"!:\\sys\\bin\\QtBearer.dll\"" \ + "ELSEIF package(0x102032BE)" \ + " \"$${EPOCROOT31}epoc32/release/$(PLATFORM)/$(TARGET)/QtBearer.dll\" - \"!:\\sys\\bin\\QtBearer.dll\"" \ + "ELSE" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtBearer.dll\" - \"!:\\sys\\bin\\QtBearer.dll\"" \ + "ENDIF" + + qtmobilitydeployment.pkg_postrules += bearer + } + + contains(mobility_modules, bearer) { + !contains(MOBILITY_SD_MCL_BUILD, yes):exists($${EPOCROOT}epoc32/release/winscw/udeb/z/system/install/series60v5.2.sis)|exists($${EPOCROOT}epoc32/data/z/system/install/series60v5.2.sis)|exists($${EPOCROOT}epoc32/release/armv5/lib/libstdcppv5.dso) { + bearer10_0 = \ + "IF package(0x1028315F)" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtBearer{000a0000}.dll\" - \"!:\\sys\\bin\\QtBearer{000a0000}.dll\"" \ + "ELSEIF package(0x102752AE)" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtBearer{000a0000}.dll\" - \"!:\\sys\\bin\\QtBearer{000a0000}.dll\"" \ + "ELSEIF package(0x102032BE)" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtBearer{000a0000}.dll\" - \"!:\\sys\\bin\\QtBearer{000a0000}.dll\"" \ + "ELSE" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtBearer{000a0000}.dll\" - \"!:\\sys\\bin\\QtBearer{000a0000}.dll\"" \ + "ENDIF" + qtmobilitydeployment.pkg_postrules += bearer10_0 + } + } + + contains(mobility_modules, contacts) { + + qtmobilitydeployment.sources += \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtContacts.dll + contains(mobility_modules,serviceframework):qtmobilitydeployment.sources += \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtcontacts_serviceactionmanager.dll + + contacts = \ + "IF package(0x1028315F)" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtcontacts_symbian.dll\" - \"!:\\sys\\bin\\qtcontacts_symbian.dll\"" \ + "ELSEIF package(0x102752AE)" \ + " \"$${EPOCROOT32}epoc32/release/$(PLATFORM)/$(TARGET)/qtcontacts_symbian.dll\" - \"!:\\sys\\bin\\qtcontacts_symbian.dll\"" \ + "ELSEIF package(0x102032BE)" \ + " \"$${EPOCROOT31}epoc32/release/$(PLATFORM)/$(TARGET)/qtcontacts_symbian.dll\" - \"!:\\sys\\bin\\qtcontacts_symbian.dll\"" \ + "ELSE" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtcontacts_symbian.dll\" - \"!:\\sys\\bin\\qtcontacts_symbian.dll\"" \ + "ENDIF" + + qtmobilitydeployment.pkg_postrules += contacts + + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE/plugins/contacts/symbian/plugin/qmakepluginstubs/qtcontacts_symbian.qtplugin\" - \"!:\\resource\\qt\\plugins\\contacts\\qtcontacts_symbian.qtplugin\"" + contains(mobility_modules,serviceframework):pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE/plugins/contacts/serviceactionmanager/qmakepluginstubs/qtcontacts_serviceactionmanager.qtplugin\" - \"!:\\resource\\qt\\plugins\\contacts\\qtcontacts_serviceactionmanager.qtplugin\"" + + contains(symbiancntsim_enabled, yes) { + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE/plugins/contacts/symbiansim/qmakepluginstubs/qtcontacts_symbiansim.qtplugin\" - \"!:\\resource\\qt\\plugins\\contacts\\qtcontacts_symbiansim.qtplugin\"" + + symbiancntsim = \ + "IF package(0x1028315F)" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtcontacts_symbiansim.dll\" - \"!:\\sys\\bin\\qtcontacts_symbiansim.dll\"" \ + "ELSEIF package(0x102752AE)" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtcontacts_symbiansim.dll\" - \"!:\\sys\\bin\\qtcontacts_symbiansim.dll\"" \ + "ELSEIF package(0x102032BE)" \ + " \"$${EPOCROOT31}epoc32/release/$(PLATFORM)/$(TARGET)/qtcontacts_symbiansim.dll\" - \"!:\\sys\\bin\\qtcontacts_symbiansim.dll\"" \ + "ELSE" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtcontacts_symbiansim.dll\" - \"!:\\sys\\bin\\qtcontacts_symbiansim.dll\"" \ + "ENDIF" + + qtmobilitydeployment.pkg_postrules += symbiancntsim + } + contains(QT_CONFIG, declarative):contains(mobility_modules,versit) { + qtmobilitydeployment.sources += \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/declarative_contacts.dll + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\contacts\\qmakepluginstubs\\declarative_contacts.qtplugin\" - \"!:\\resource\\qt\\imports\\QtMobility\\contacts\\declarative_contacts.qtplugin\"" + qmldirs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\contacts\\qmldir\" - \"!:\\resource\\qt\\imports\\QtMobility\\contacts\\qmldir\"" + } + } + + contains(mobility_modules, multimedia) { + + qtmobilitydeployment.sources += \ + $$(EPOCROOT50)epoc32/release/$(PLATFORM)/$(TARGET)/QtMultimediaKit.dll \ + $$(EPOCROOT50)epoc32/release/$(PLATFORM)/$(TARGET)/qtmultimediakit_m3u.dll + + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE/plugins/multimedia/m3u/qmakepluginstubs/qtmultimediakit_m3u.qtplugin\" - \"!:\\resource\\qt\\plugins\\playlistformats\\qtmultimediakit_m3u.qtplugin\"" + + contains(openmaxal_symbian_enabled, yes) { + openmax = \ + "\"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtmultimediakit_openmaxalengine.dll\" - \"!:\\sys\\bin\\qtmultimediakit_openmaxalengine.dll\"" + + qtmobilitydeployment.pkg_postrules += openmax + + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE/plugins/multimedia/symbian/openmaxal/qmakepluginstubs/qtmultimediakit_openmaxalengine.qtplugin\" - \"!:\\resource\\qt\\plugins\\mediaservice\\qtmultimediakit_openmaxalengine.qtplugin\"" + } else { + + multimedia = \ + "IF package(0x1028315F)" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtmultimediakit_mmfengine.dll\" - \"!:\\sys\\bin\\qtmultimediakit_mmfengine.dll\"" \ + "ELSEIF package(0x102752AE)" \ + " \"$${EPOCROOT32}epoc32/release/$(PLATFORM)/$(TARGET)/qtmultimediakit_mmfengine.dll\" - \"!:\\sys\\bin\\qtmultimediakit_mmfengine.dll\"" \ + "ELSEIF package(0x102032BE)" \ + " \"$${EPOCROOT31}epoc32/release/$(PLATFORM)/$(TARGET)/qtmultimediakit_mmfengine.dll\" - \"!:\\sys\\bin\\qtmultimediakit_mmfengine.dll\"" \ + "ELSEIF package(0x20022E6D)" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtmultimediakit_mmfengine.dll\" - \"!:\\sys\\bin\\qtmultimediakit_mmfengine.dll\"" \ + "ENDIF" + + qtmobilitydeployment.pkg_postrules += multimedia + + pluginstubs += \ + "IF package(0x1028315F)" \ + "\"$$QT_MOBILITY_BUILD_TREE/plugins/multimedia/symbian/mmf/qmakepluginstubs/qtmultimediakit_mmfengine.qtplugin\" - \"!:\\resource\\qt\\plugins\\mediaservice\\qtmultimediakit_mmfengine.qtplugin\"" \ + "ELSEIF package(0x102752AE)" \ + "\"$$QT_MOBILITY_BUILD_TREE/plugins/multimedia/symbian/mmf/qmakepluginstubs/qtmultimediakit_mmfengine.qtplugin\" - \"!:\\resource\\qt\\plugins\\mediaservice\\qtmultimediakit_mmfengine.qtplugin\"" \ + "ELSEIF package(0x102032BE)" \ + "\"$$QT_MOBILITY_BUILD_TREE/plugins/multimedia/symbian/mmf/qmakepluginstubs/qtmultimediakit_mmfengine.qtplugin\" - \"!:\\resource\\qt\\plugins\\mediaservice\\qtmultimediakit_mmfengine.qtplugin\"" \ + "ELSEIF package(0x20022E6D)" \ + "\"$$QT_MOBILITY_BUILD_TREE/plugins/multimedia/symbian/mmf/qmakepluginstubs/qtmultimediakit_mmfengine.qtplugin\" - \"!:\\resource\\qt\\plugins\\mediaservice\\qtmultimediakit_mmfengine.qtplugin\"" \ + "ENDIF" + } + + camera = \ + "IF package(0x1028315F)" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtmultimediakit_ecamengine.dll\" - \"!:\\sys\\bin\\qtmultimediakit_ecamengine.dll\"" \ + "ELSEIF package(0x102752AE)" \ + " \"$${EPOCROOT32}epoc32/release/$(PLATFORM)/$(TARGET)/qtmultimediakit_ecamengine.dll\" - \"!:\\sys\\bin\\qtmultimediakit_ecamengine.dll\"" \ + "ELSEIF package(0x102032BE)" \ + " \"$${EPOCROOT31}epoc32/release/$(PLATFORM)/$(TARGET)/qtmultimediakit_ecamengine.dll\" - \"!:\\sys\\bin\\qtmultimediakit_ecamengine.dll\"" \ + "ELSEIF package(0x20022E6D)" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtmultimediakit_ecamengine.dll\" - \"!:\\sys\\bin\\qtmultimediakit_ecamengine.dll\"" \ + "ENDIF" + + qtmobilitydeployment.pkg_postrules += camera + + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE/plugins/multimedia/symbian/ecam/qmakepluginstubs/qtmultimediakit_ecamengine.qtplugin\" - \"!:\\resource\\qt\\plugins\\mediaservice\\qtmultimediakit_ecamengine.qtplugin\"" + + + contains(QT_CONFIG, declarative): { + qtmobilitydeployment.sources += \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/declarative_multimedia.dll + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\multimedia\\qmakepluginstubs\\declarative_multimedia.qtplugin\" - \"!:\\resource\\qt\\imports\\QtMultimediaKit\\declarative_multimedia.qtplugin\"" + qmldirs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\multimedia\\qmldir\" - \"!:\\resource\\qt\\imports\\QtMultimediaKit\\qmldir\"" + } + } + + contains(mobility_modules, sensors) { + + equals(sensors_symbian_enabled,yes) { + sensorplugin=symbian + } else:equals(sensors_s60_31_enabled,yes) { + sensorplugin=s60_sensor_api + } else { + error("Must have a Symbian sensor backend available") + } + + qtmobilitydeployment.sources += \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/QtSensors.dll + + sensors = \ + "IF package(0x1028315F)" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtsensors_sym.dll\" - \"!:\\sys\\bin\\qtsensors_sym.dll\"" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtsensors_generic.dll\" - \"!:\\sys\\bin\\qtsensors_generic.dll\"" \ + "ELSEIF package(0x102752AE)" \ + " \"$${EPOCROOT32}epoc32/release/$(PLATFORM)/$(TARGET)/qtsensors_sym.dll\" - \"!:\\sys\\bin\\qtsensors_sym.dll\"" \ + " \"$${EPOCROOT32}epoc32/release/$(PLATFORM)/$(TARGET)/qtsensors_generic.dll\" - \"!:\\sys\\bin\\qtsensors_generic.dll\"" \ + "ELSEIF package(0x102032BE)" \ + " \"$${EPOCROOT31}epoc32/release/$(PLATFORM)/$(TARGET)/qtsensors_sym.dll\" - \"!:\\sys\\bin\\qtsensors_sym.dll\"" \ + " \"$${EPOCROOT31}epoc32/release/$(PLATFORM)/$(TARGET)/qtsensors_generic.dll\" - \"!:\\sys\\bin\\qtsensors_generic.dll\"" \ + "ELSE" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtsensors_sym.dll\" - \"!:\\sys\\bin\\qtsensors_sym.dll\"" \ + " \"$${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/qtsensors_generic.dll\" - \"!:\\sys\\bin\\qtsensors_generic.dll\"" \ + "ENDIF" + + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE/plugins/sensors/$$sensorplugin/qmakepluginstubs/qtsensors_sym.qtplugin\" - \"!:\\resource\\qt\\plugins\\sensors\\qtsensors_sym.qtplugin\"" \ + "\"$$QT_MOBILITY_BUILD_TREE/plugins/sensors/generic/qmakepluginstubs/qtsensors_generic.qtplugin\" - \"!:\\resource\\qt\\plugins\\sensors\\qtsensors_generic.qtplugin\"" + + !isEmpty(sensors):qtmobilitydeployment.pkg_postrules += sensors + contains(QT_CONFIG, declarative): { + qtmobilitydeployment.sources += \ + $${EPOCROOT50}epoc32/release/$(PLATFORM)/$(TARGET)/declarative_sensors.dll + pluginstubs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\sensors\\qmakepluginstubs\\declarative_sensors.qtplugin\" - \"!:\\resource\\qt\\imports\\QtMobility\\sensors\\declarative_sensors.qtplugin\"" + qmldirs += \ + "\"$$QT_MOBILITY_BUILD_TREE\\plugins\\declarative\\sensors\\qmldir\" - \"!:\\resource\\qt\\imports\\QtMobility\\sensors\\qmldir\"" + } + } + + !isEmpty(pluginstubs):qtmobilitydeployment.pkg_postrules += pluginstubs + !isEmpty(qmldirs):qtmobilitydeployment.pkg_postrules += qmldirs + + qtmobilitydeployment.path = /sys/bin + + # Support backup and restore for QtMobility libraries and applications + mobilitybackup.sources = backup_registration.xml + mobilitybackup.path = c:/private/10202d56/import/packages/$$replace(TARGET.UID3, 0x,) + + DEPLOYMENT += qtmobilitydeployment\ + mobilitybackup +} else { + message(Deployment of infixed library names not supported) +} diff --git a/src/src.pro b/src/src.pro new file mode 100644 index 000000000..282c1b38a --- /dev/null +++ b/src/src.pro @@ -0,0 +1,12 @@ + +TEMPLATE = subdirs +CONFIG += ordered + +SUBDIRS += multimediakit +SUBDIRS += imports +SUBDIRS += plugins + +symbian { + SUBDIRS += s60installs +} + -- cgit v1.2.3